11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved. Use of this 21cb0ef41Sopenharmony_ci// source code is governed by a BSD-style license that can be found in the 31cb0ef41Sopenharmony_ci// LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include 'src/ic/binary-op-assembler.h' 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciextern enum Operation extends uint31 { 81cb0ef41Sopenharmony_ci // Binary operations. 91cb0ef41Sopenharmony_ci kAdd, 101cb0ef41Sopenharmony_ci kSubtract, 111cb0ef41Sopenharmony_ci kMultiply, 121cb0ef41Sopenharmony_ci kDivide, 131cb0ef41Sopenharmony_ci kModulus, 141cb0ef41Sopenharmony_ci kExponentiate, 151cb0ef41Sopenharmony_ci kBitwiseAnd, 161cb0ef41Sopenharmony_ci kBitwiseOr, 171cb0ef41Sopenharmony_ci kBitwiseXor, 181cb0ef41Sopenharmony_ci kShiftLeft, 191cb0ef41Sopenharmony_ci kShiftRight, 201cb0ef41Sopenharmony_ci kShiftRightLogical, 211cb0ef41Sopenharmony_ci // Unary operations. 221cb0ef41Sopenharmony_ci kBitwiseNot, 231cb0ef41Sopenharmony_ci kNegate, 241cb0ef41Sopenharmony_ci kIncrement, 251cb0ef41Sopenharmony_ci kDecrement, 261cb0ef41Sopenharmony_ci // Compare operations. 271cb0ef41Sopenharmony_ci kEqual, 281cb0ef41Sopenharmony_ci kStrictEqual, 291cb0ef41Sopenharmony_ci kLessThan, 301cb0ef41Sopenharmony_ci kLessThanOrEqual, 311cb0ef41Sopenharmony_ci kGreaterThan, 321cb0ef41Sopenharmony_ci kGreaterThanOrEqual 331cb0ef41Sopenharmony_ci} 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_cinamespace runtime { 361cb0ef41Sopenharmony_ciextern transitioning runtime 371cb0ef41Sopenharmony_ciDoubleToStringWithRadix(implicit context: Context)(Number, Number): String; 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciextern transitioning runtime StringParseFloat(implicit context: Context)( 401cb0ef41Sopenharmony_ci String): Number; 411cb0ef41Sopenharmony_ciextern transitioning runtime StringParseInt(implicit context: Context)( 421cb0ef41Sopenharmony_ci JSAny, JSAny): Number; 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciextern runtime BigIntUnaryOp(Context, BigInt, SmiTagged<Operation>): BigInt; 451cb0ef41Sopenharmony_ciextern runtime BigIntBinaryOp( 461cb0ef41Sopenharmony_ci Context, Numeric, Numeric, SmiTagged<Operation>): BigInt; 471cb0ef41Sopenharmony_ci} // namespace runtime 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_cinamespace number { 501cb0ef41Sopenharmony_ciextern macro NaNStringConstant(): String; 511cb0ef41Sopenharmony_ciextern macro ZeroStringConstant(): String; 521cb0ef41Sopenharmony_ciextern macro InfinityStringConstant(): String; 531cb0ef41Sopenharmony_ciextern macro MinusInfinityStringConstant(): String; 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ciconst kAsciiZero: constexpr int32 = 48; // '0' (ascii) 561cb0ef41Sopenharmony_ciconst kAsciiLowerCaseA: constexpr int32 = 97; // 'a' (ascii) 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_citransitioning macro ThisNumberValue(implicit context: Context)( 591cb0ef41Sopenharmony_ci receiver: JSAny, method: constexpr string): Number { 601cb0ef41Sopenharmony_ci return UnsafeCast<Number>( 611cb0ef41Sopenharmony_ci ToThisValue(receiver, PrimitiveType::kNumber, method)); 621cb0ef41Sopenharmony_ci} 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_cimacro ToCharCode(input: int32): char8 { 651cb0ef41Sopenharmony_ci dcheck(0 <= input && input < 36); 661cb0ef41Sopenharmony_ci return input < 10 ? 671cb0ef41Sopenharmony_ci %RawDownCast<char8>(Unsigned(input + kAsciiZero)) : 681cb0ef41Sopenharmony_ci %RawDownCast<char8>(Unsigned(input - 10 + kAsciiLowerCaseA)); 691cb0ef41Sopenharmony_ci} 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci@export 721cb0ef41Sopenharmony_cimacro NumberToStringSmi(x: int32, radix: int32): String labels Slow { 731cb0ef41Sopenharmony_ci const isNegative: bool = x < 0; 741cb0ef41Sopenharmony_ci let n: int32 = x; 751cb0ef41Sopenharmony_ci if (!isNegative) { 761cb0ef41Sopenharmony_ci // Fast case where the result is a one character string. 771cb0ef41Sopenharmony_ci if (x < radix) { 781cb0ef41Sopenharmony_ci if (x == 0) { 791cb0ef41Sopenharmony_ci return ZeroStringConstant(); 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci return StringFromSingleCharCode(ToCharCode(n)); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci } else { 841cb0ef41Sopenharmony_ci dcheck(isNegative); 851cb0ef41Sopenharmony_ci if (n == kMinInt32) { 861cb0ef41Sopenharmony_ci goto Slow; 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci n = 0 - n; 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci // Calculate length and pre-allocate the result string. 921cb0ef41Sopenharmony_ci let temp: int32 = n; 931cb0ef41Sopenharmony_ci let length: int32 = isNegative ? Convert<int32>(1) : Convert<int32>(0); 941cb0ef41Sopenharmony_ci while (temp > 0) { 951cb0ef41Sopenharmony_ci temp = temp / radix; 961cb0ef41Sopenharmony_ci length = length + 1; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci dcheck(length > 0); 991cb0ef41Sopenharmony_ci const strSeq = AllocateNonEmptySeqOneByteString(Unsigned(length)); 1001cb0ef41Sopenharmony_ci let cursor: intptr = Convert<intptr>(length) - 1; 1011cb0ef41Sopenharmony_ci while (n > 0) { 1021cb0ef41Sopenharmony_ci const digit: int32 = n % radix; 1031cb0ef41Sopenharmony_ci n = n / radix; 1041cb0ef41Sopenharmony_ci *UnsafeConstCast(&strSeq.chars[cursor]) = ToCharCode(digit); 1051cb0ef41Sopenharmony_ci cursor = cursor - 1; 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci if (isNegative) { 1081cb0ef41Sopenharmony_ci dcheck(cursor == 0); 1091cb0ef41Sopenharmony_ci // Insert '-' to result. 1101cb0ef41Sopenharmony_ci *UnsafeConstCast(&strSeq.chars[0]) = 45; 1111cb0ef41Sopenharmony_ci } else { 1121cb0ef41Sopenharmony_ci dcheck(cursor == -1); 1131cb0ef41Sopenharmony_ci // In sync with Factory::SmiToString: If radix = 10 and positive number, 1141cb0ef41Sopenharmony_ci // update hash for string. 1151cb0ef41Sopenharmony_ci if (radix == 10) { 1161cb0ef41Sopenharmony_ci dcheck(strSeq.raw_hash_field == kNameEmptyHashField); 1171cb0ef41Sopenharmony_ci strSeq.raw_hash_field = MakeArrayIndexHash(Unsigned(x), Unsigned(length)); 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci return strSeq; 1211cb0ef41Sopenharmony_ci} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci// https://tc39.github.io/ecma262/#sec-number.prototype.tostring 1241cb0ef41Sopenharmony_citransitioning javascript builtin NumberPrototypeToString( 1251cb0ef41Sopenharmony_ci js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { 1261cb0ef41Sopenharmony_ci // 1. Let x be ? thisNumberValue(this value). 1271cb0ef41Sopenharmony_ci const x = ThisNumberValue(receiver, 'Number.prototype.toString'); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci // 2. If radix is not present, let radixNumber be 10. 1301cb0ef41Sopenharmony_ci // 3. Else if radix is undefined, let radixNumber be 10. 1311cb0ef41Sopenharmony_ci // 4. Else, let radixNumber be ? ToInteger(radix). 1321cb0ef41Sopenharmony_ci const radix: JSAny = arguments[0]; 1331cb0ef41Sopenharmony_ci const radixNumber: Number = radix == Undefined ? 10 : ToInteger_Inline(radix); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. 1361cb0ef41Sopenharmony_ci if (radixNumber < 2 || radixNumber > 36) { 1371cb0ef41Sopenharmony_ci ThrowRangeError(MessageTemplate::kToRadixFormatRange); 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci // 6. If radixNumber = 10, return ! ToString(x). 1411cb0ef41Sopenharmony_ci if (radixNumber == 10) { 1421cb0ef41Sopenharmony_ci return NumberToString(x); 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci // 7. Return the String representation of this Number 1461cb0ef41Sopenharmony_ci // value using the radix specified by radixNumber. 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci if (TaggedIsSmi(x)) { 1491cb0ef41Sopenharmony_ci return NumberToStringSmi(Convert<int32>(x), Convert<int32>(radixNumber)) 1501cb0ef41Sopenharmony_ci otherwise return runtime::DoubleToStringWithRadix(x, radixNumber); 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci if (x == -0) { 1541cb0ef41Sopenharmony_ci return ZeroStringConstant(); 1551cb0ef41Sopenharmony_ci } else if (::NumberIsNaN(x)) { 1561cb0ef41Sopenharmony_ci return NaNStringConstant(); 1571cb0ef41Sopenharmony_ci } else if (x == V8_INFINITY) { 1581cb0ef41Sopenharmony_ci return InfinityStringConstant(); 1591cb0ef41Sopenharmony_ci } else if (x == MINUS_V8_INFINITY) { 1601cb0ef41Sopenharmony_ci return MinusInfinityStringConstant(); 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci return runtime::DoubleToStringWithRadix(x, radixNumber); 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci// ES6 #sec-number.isfinite 1671cb0ef41Sopenharmony_cijavascript builtin NumberIsFinite( 1681cb0ef41Sopenharmony_ci js-implicit context: NativeContext, 1691cb0ef41Sopenharmony_ci receiver: JSAny)(value: JSAny): Boolean { 1701cb0ef41Sopenharmony_ci typeswitch (value) { 1711cb0ef41Sopenharmony_ci case (Smi): { 1721cb0ef41Sopenharmony_ci return True; 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci case (h: HeapNumber): { 1751cb0ef41Sopenharmony_ci const number: float64 = Convert<float64>(h); 1761cb0ef41Sopenharmony_ci const infiniteOrNaN: bool = Float64IsNaN(number - number); 1771cb0ef41Sopenharmony_ci return Convert<Boolean>(!infiniteOrNaN); 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci case (JSAnyNotNumber): { 1801cb0ef41Sopenharmony_ci return False; 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci} 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci// ES6 #sec-number.isinteger 1861cb0ef41Sopenharmony_cijavascript builtin NumberIsInteger(js-implicit context: NativeContext)( 1871cb0ef41Sopenharmony_ci value: JSAny): Boolean { 1881cb0ef41Sopenharmony_ci return SelectBooleanConstant(IsInteger(value)); 1891cb0ef41Sopenharmony_ci} 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci// ES6 #sec-number.isnan 1921cb0ef41Sopenharmony_cijavascript builtin NumberIsNaN(js-implicit context: NativeContext)( 1931cb0ef41Sopenharmony_ci value: JSAny): Boolean { 1941cb0ef41Sopenharmony_ci typeswitch (value) { 1951cb0ef41Sopenharmony_ci case (Smi): { 1961cb0ef41Sopenharmony_ci return False; 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci case (h: HeapNumber): { 1991cb0ef41Sopenharmony_ci const number: float64 = Convert<float64>(h); 2001cb0ef41Sopenharmony_ci return Convert<Boolean>(Float64IsNaN(number)); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci case (JSAnyNotNumber): { 2031cb0ef41Sopenharmony_ci return False; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci// ES6 #sec-number.issafeinteger 2091cb0ef41Sopenharmony_cijavascript builtin NumberIsSafeInteger(js-implicit context: NativeContext)( 2101cb0ef41Sopenharmony_ci value: JSAny): Boolean { 2111cb0ef41Sopenharmony_ci return SelectBooleanConstant(IsSafeInteger(value)); 2121cb0ef41Sopenharmony_ci} 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci// ES6 #sec-number.prototype.valueof 2151cb0ef41Sopenharmony_citransitioning javascript builtin NumberPrototypeValueOf( 2161cb0ef41Sopenharmony_ci js-implicit context: NativeContext, receiver: JSAny)(): JSAny { 2171cb0ef41Sopenharmony_ci return ToThisValue( 2181cb0ef41Sopenharmony_ci receiver, PrimitiveType::kNumber, 'Number.prototype.valueOf'); 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci// ES6 #sec-number.parsefloat 2221cb0ef41Sopenharmony_citransitioning javascript builtin NumberParseFloat( 2231cb0ef41Sopenharmony_ci js-implicit context: NativeContext)(value: JSAny): Number { 2241cb0ef41Sopenharmony_ci try { 2251cb0ef41Sopenharmony_ci typeswitch (value) { 2261cb0ef41Sopenharmony_ci case (s: Smi): { 2271cb0ef41Sopenharmony_ci return s; 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci case (h: HeapNumber): { 2301cb0ef41Sopenharmony_ci // The input is already a Number. Take care of -0. 2311cb0ef41Sopenharmony_ci // The sense of comparison is important for the NaN case. 2321cb0ef41Sopenharmony_ci return (Convert<float64>(h) == 0) ? SmiConstant(0) : h; 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci case (s: String): { 2351cb0ef41Sopenharmony_ci goto String(s); 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci case (HeapObject): { 2381cb0ef41Sopenharmony_ci goto String(string::ToString(context, value)); 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci } label String(s: String) { 2421cb0ef41Sopenharmony_ci // Check if the string is a cached array index. 2431cb0ef41Sopenharmony_ci const hash: NameHash = s.raw_hash_field; 2441cb0ef41Sopenharmony_ci if (IsIntegerIndex(hash) && 2451cb0ef41Sopenharmony_ci hash.array_index_length < kMaxCachedArrayIndexLength) { 2461cb0ef41Sopenharmony_ci const arrayIndex: uint32 = hash.array_index_value; 2471cb0ef41Sopenharmony_ci return SmiFromUint32(arrayIndex); 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci // Fall back to the runtime to convert string to a number. 2501cb0ef41Sopenharmony_ci return runtime::StringParseFloat(s); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciextern macro TruncateFloat64ToWord32(float64): uint32; 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_citransitioning builtin ParseInt(implicit context: Context)( 2571cb0ef41Sopenharmony_ci input: JSAny, radix: JSAny): Number { 2581cb0ef41Sopenharmony_ci try { 2591cb0ef41Sopenharmony_ci // Check if radix should be 10 (i.e. undefined, 0 or 10). 2601cb0ef41Sopenharmony_ci if (radix != Undefined && !TaggedEqual(radix, SmiConstant(10)) && 2611cb0ef41Sopenharmony_ci !TaggedEqual(radix, SmiConstant(0))) { 2621cb0ef41Sopenharmony_ci goto CallRuntime; 2631cb0ef41Sopenharmony_ci } 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci typeswitch (input) { 2661cb0ef41Sopenharmony_ci case (s: Smi): { 2671cb0ef41Sopenharmony_ci return s; 2681cb0ef41Sopenharmony_ci } 2691cb0ef41Sopenharmony_ci case (h: HeapNumber): { 2701cb0ef41Sopenharmony_ci // Check if the input value is in Signed32 range. 2711cb0ef41Sopenharmony_ci const asFloat64: float64 = Convert<float64>(h); 2721cb0ef41Sopenharmony_ci const asInt32: int32 = Signed(TruncateFloat64ToWord32(asFloat64)); 2731cb0ef41Sopenharmony_ci // The sense of comparison is important for the NaN case. 2741cb0ef41Sopenharmony_ci if (asFloat64 == ChangeInt32ToFloat64(asInt32)) goto Int32(asInt32); 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci // Check if the absolute value of input is in the [1,1<<31[ range. Call 2771cb0ef41Sopenharmony_ci // the runtime for the range [0,1[ because the result could be -0. 2781cb0ef41Sopenharmony_ci const kMaxAbsValue: float64 = 2147483648.0; 2791cb0ef41Sopenharmony_ci const absInput: float64 = math::Float64Abs(asFloat64); 2801cb0ef41Sopenharmony_ci if (absInput < kMaxAbsValue && absInput >= 1.0) goto Int32(asInt32); 2811cb0ef41Sopenharmony_ci goto CallRuntime; 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci case (s: String): { 2841cb0ef41Sopenharmony_ci goto String(s); 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci case (HeapObject): { 2871cb0ef41Sopenharmony_ci goto CallRuntime; 2881cb0ef41Sopenharmony_ci } 2891cb0ef41Sopenharmony_ci } 2901cb0ef41Sopenharmony_ci } label Int32(i: int32) { 2911cb0ef41Sopenharmony_ci return ChangeInt32ToTagged(i); 2921cb0ef41Sopenharmony_ci } label String(s: String) { 2931cb0ef41Sopenharmony_ci // Check if the string is a cached array index. 2941cb0ef41Sopenharmony_ci const hash: NameHash = s.raw_hash_field; 2951cb0ef41Sopenharmony_ci if (IsIntegerIndex(hash) && 2961cb0ef41Sopenharmony_ci hash.array_index_length < kMaxCachedArrayIndexLength) { 2971cb0ef41Sopenharmony_ci const arrayIndex: uint32 = hash.array_index_value; 2981cb0ef41Sopenharmony_ci return SmiFromUint32(arrayIndex); 2991cb0ef41Sopenharmony_ci } 3001cb0ef41Sopenharmony_ci // Fall back to the runtime. 3011cb0ef41Sopenharmony_ci goto CallRuntime; 3021cb0ef41Sopenharmony_ci } label CallRuntime { 3031cb0ef41Sopenharmony_ci tail runtime::StringParseInt(input, radix); 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci} 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci// ES6 #sec-number.parseint 3081cb0ef41Sopenharmony_citransitioning javascript builtin NumberParseInt( 3091cb0ef41Sopenharmony_ci js-implicit context: NativeContext)(value: JSAny, radix: JSAny): Number { 3101cb0ef41Sopenharmony_ci return ParseInt(value, radix); 3111cb0ef41Sopenharmony_ci} 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ciextern builtin NonNumberToNumeric(implicit context: Context)(JSAny): Numeric; 3141cb0ef41Sopenharmony_ciextern builtin BitwiseXor(implicit context: Context)(Number, Number): Number; 3151cb0ef41Sopenharmony_ciextern builtin Subtract(implicit context: Context)(Number, Number): Number; 3161cb0ef41Sopenharmony_ciextern builtin Add(implicit context: Context)(Number, Number): Number; 3171cb0ef41Sopenharmony_ciextern builtin StringAddConvertLeft(implicit context: Context)( 3181cb0ef41Sopenharmony_ci JSAny, String): JSAny; 3191cb0ef41Sopenharmony_ciextern builtin StringAddConvertRight(implicit context: Context)( 3201cb0ef41Sopenharmony_ci String, JSAny): JSAny; 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ciextern macro BitwiseOp(int32, int32, constexpr Operation): Number; 3231cb0ef41Sopenharmony_ciextern macro RelationalComparison( 3241cb0ef41Sopenharmony_ci constexpr Operation, JSAny, JSAny, Context): Boolean; 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci// TODO(bbudge) Use a simpler macro structure that doesn't loop when converting 3271cb0ef41Sopenharmony_ci// non-numbers, if such a code sequence doesn't make the builtin bigger. 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_citransitioning macro ToNumericOrPrimitive(implicit context: Context)( 3301cb0ef41Sopenharmony_ci value: JSAny): JSAny { 3311cb0ef41Sopenharmony_ci typeswitch (value) { 3321cb0ef41Sopenharmony_ci case (v: JSReceiver): { 3331cb0ef41Sopenharmony_ci return NonPrimitiveToPrimitive_Default(context, v); 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci case (v: JSPrimitive): { 3361cb0ef41Sopenharmony_ci return NonNumberToNumeric(v); 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci} 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_citransitioning builtin Add(implicit context: Context)( 3421cb0ef41Sopenharmony_ci leftArg: JSAny, rightArg: JSAny): JSAny { 3431cb0ef41Sopenharmony_ci let left: JSAny = leftArg; 3441cb0ef41Sopenharmony_ci let right: JSAny = rightArg; 3451cb0ef41Sopenharmony_ci try { 3461cb0ef41Sopenharmony_ci while (true) { 3471cb0ef41Sopenharmony_ci typeswitch (left) { 3481cb0ef41Sopenharmony_ci case (left: Smi): { 3491cb0ef41Sopenharmony_ci typeswitch (right) { 3501cb0ef41Sopenharmony_ci case (right: Smi): { 3511cb0ef41Sopenharmony_ci return math::TrySmiAdd(left, right) otherwise goto Float64s( 3521cb0ef41Sopenharmony_ci SmiToFloat64(left), SmiToFloat64(right)); 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci case (right: HeapNumber): { 3551cb0ef41Sopenharmony_ci goto Float64s(SmiToFloat64(left), Convert<float64>(right)); 3561cb0ef41Sopenharmony_ci } 3571cb0ef41Sopenharmony_ci case (right: BigInt): { 3581cb0ef41Sopenharmony_ci goto Numerics(left, right); 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci case (right: String): { 3611cb0ef41Sopenharmony_ci goto StringAddConvertLeft(left, right); 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci case (HeapObject): { 3641cb0ef41Sopenharmony_ci right = ToNumericOrPrimitive(right); 3651cb0ef41Sopenharmony_ci continue; 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci } 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci case (left: HeapNumber): { 3701cb0ef41Sopenharmony_ci typeswitch (right) { 3711cb0ef41Sopenharmony_ci case (right: Smi): { 3721cb0ef41Sopenharmony_ci goto Float64s(Convert<float64>(left), SmiToFloat64(right)); 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci case (right: HeapNumber): { 3751cb0ef41Sopenharmony_ci goto Float64s(Convert<float64>(left), Convert<float64>(right)); 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci case (right: BigInt): { 3781cb0ef41Sopenharmony_ci goto Numerics(left, right); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci case (right: String): { 3811cb0ef41Sopenharmony_ci goto StringAddConvertLeft(left, right); 3821cb0ef41Sopenharmony_ci } 3831cb0ef41Sopenharmony_ci case (HeapObject): { 3841cb0ef41Sopenharmony_ci right = ToNumericOrPrimitive(right); 3851cb0ef41Sopenharmony_ci continue; 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci } 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci case (left: BigInt): { 3901cb0ef41Sopenharmony_ci typeswitch (right) { 3911cb0ef41Sopenharmony_ci case (right: Numeric): { 3921cb0ef41Sopenharmony_ci goto Numerics(left, right); 3931cb0ef41Sopenharmony_ci } 3941cb0ef41Sopenharmony_ci case (right: String): { 3951cb0ef41Sopenharmony_ci goto StringAddConvertLeft(left, right); 3961cb0ef41Sopenharmony_ci } 3971cb0ef41Sopenharmony_ci case (HeapObject): { 3981cb0ef41Sopenharmony_ci right = ToNumericOrPrimitive(right); 3991cb0ef41Sopenharmony_ci continue; 4001cb0ef41Sopenharmony_ci } 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci case (left: String): { 4041cb0ef41Sopenharmony_ci goto StringAddConvertRight(left, right); 4051cb0ef41Sopenharmony_ci } 4061cb0ef41Sopenharmony_ci case (leftReceiver: JSReceiver): { 4071cb0ef41Sopenharmony_ci left = ToPrimitiveDefault(leftReceiver); 4081cb0ef41Sopenharmony_ci } 4091cb0ef41Sopenharmony_ci case (HeapObject): { 4101cb0ef41Sopenharmony_ci // left: HeapObject 4111cb0ef41Sopenharmony_ci typeswitch (right) { 4121cb0ef41Sopenharmony_ci case (right: String): { 4131cb0ef41Sopenharmony_ci goto StringAddConvertLeft(left, right); 4141cb0ef41Sopenharmony_ci } 4151cb0ef41Sopenharmony_ci case (rightReceiver: JSReceiver): { 4161cb0ef41Sopenharmony_ci // left is JSPrimitive and right is JSReceiver, convert right 4171cb0ef41Sopenharmony_ci // with priority. 4181cb0ef41Sopenharmony_ci right = ToPrimitiveDefault(rightReceiver); 4191cb0ef41Sopenharmony_ci continue; 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci case (JSPrimitive): { 4221cb0ef41Sopenharmony_ci // Neither left or right is JSReceiver, convert left. 4231cb0ef41Sopenharmony_ci left = NonNumberToNumeric(left); 4241cb0ef41Sopenharmony_ci continue; 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci } 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci } 4301cb0ef41Sopenharmony_ci } label StringAddConvertLeft(left: JSAny, right: String) { 4311cb0ef41Sopenharmony_ci tail StringAddConvertLeft(left, right); 4321cb0ef41Sopenharmony_ci } label StringAddConvertRight(left: String, right: JSAny) { 4331cb0ef41Sopenharmony_ci tail StringAddConvertRight(left, right); 4341cb0ef41Sopenharmony_ci } label Numerics(left: Numeric, right: Numeric) { 4351cb0ef41Sopenharmony_ci tail bigint::BigIntAdd(left, right); 4361cb0ef41Sopenharmony_ci } label Float64s(left: float64, right: float64) { 4371cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(left + right); 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci unreachable; 4401cb0ef41Sopenharmony_ci} 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ci// Unary type switch on Number | BigInt. 4431cb0ef41Sopenharmony_cimacro UnaryOp1(implicit context: Context)(value: JSAny): never labels 4441cb0ef41Sopenharmony_ciNumber(Number), BigInt(BigInt) { 4451cb0ef41Sopenharmony_ci let x: JSAny = value; 4461cb0ef41Sopenharmony_ci while (true) { 4471cb0ef41Sopenharmony_ci typeswitch (x) { 4481cb0ef41Sopenharmony_ci case (n: Number): { 4491cb0ef41Sopenharmony_ci goto Number(n); 4501cb0ef41Sopenharmony_ci } 4511cb0ef41Sopenharmony_ci case (b: BigInt): { 4521cb0ef41Sopenharmony_ci goto BigInt(b); 4531cb0ef41Sopenharmony_ci } 4541cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 4551cb0ef41Sopenharmony_ci x = NonNumberToNumeric(x); 4561cb0ef41Sopenharmony_ci } 4571cb0ef41Sopenharmony_ci } 4581cb0ef41Sopenharmony_ci } 4591cb0ef41Sopenharmony_ci unreachable; 4601cb0ef41Sopenharmony_ci} 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci// Unary type switch on Smi | HeapNumber | BigInt. 4631cb0ef41Sopenharmony_cimacro UnaryOp2(implicit context: Context)(value: JSAny): never labels 4641cb0ef41Sopenharmony_ciSmi(Smi), HeapNumber(HeapNumber), BigInt(BigInt) { 4651cb0ef41Sopenharmony_ci let x: JSAny = value; 4661cb0ef41Sopenharmony_ci while (true) { 4671cb0ef41Sopenharmony_ci typeswitch (x) { 4681cb0ef41Sopenharmony_ci case (s: Smi): { 4691cb0ef41Sopenharmony_ci goto Smi(s); 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci case (h: HeapNumber): { 4721cb0ef41Sopenharmony_ci goto HeapNumber(h); 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci case (b: BigInt): { 4751cb0ef41Sopenharmony_ci goto BigInt(b); 4761cb0ef41Sopenharmony_ci } 4771cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 4781cb0ef41Sopenharmony_ci x = NonNumberToNumeric(x); 4791cb0ef41Sopenharmony_ci } 4801cb0ef41Sopenharmony_ci } 4811cb0ef41Sopenharmony_ci } 4821cb0ef41Sopenharmony_ci unreachable; 4831cb0ef41Sopenharmony_ci} 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci// Binary type switch on Number | BigInt. 4861cb0ef41Sopenharmony_cimacro BinaryOp1(implicit context: Context)( 4871cb0ef41Sopenharmony_ci leftVal: JSAny, rightVal: JSAny): never labels 4881cb0ef41Sopenharmony_ciNumber(Number, Number), AtLeastOneBigInt(Numeric, Numeric) { 4891cb0ef41Sopenharmony_ci let left: JSAny = leftVal; 4901cb0ef41Sopenharmony_ci let right: JSAny = rightVal; 4911cb0ef41Sopenharmony_ci while (true) { 4921cb0ef41Sopenharmony_ci try { 4931cb0ef41Sopenharmony_ci typeswitch (left) { 4941cb0ef41Sopenharmony_ci case (left: Number): { 4951cb0ef41Sopenharmony_ci typeswitch (right) { 4961cb0ef41Sopenharmony_ci case (right: Number): { 4971cb0ef41Sopenharmony_ci goto Number(left, right); 4981cb0ef41Sopenharmony_ci } 4991cb0ef41Sopenharmony_ci case (right: BigInt): { 5001cb0ef41Sopenharmony_ci goto AtLeastOneBigInt(left, right); 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5031cb0ef41Sopenharmony_ci goto RightNotNumeric; 5041cb0ef41Sopenharmony_ci } 5051cb0ef41Sopenharmony_ci } 5061cb0ef41Sopenharmony_ci } 5071cb0ef41Sopenharmony_ci case (left: BigInt): { 5081cb0ef41Sopenharmony_ci typeswitch (right) { 5091cb0ef41Sopenharmony_ci case (right: Numeric): { 5101cb0ef41Sopenharmony_ci goto AtLeastOneBigInt(left, right); 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5131cb0ef41Sopenharmony_ci goto RightNotNumeric; 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci } 5171cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5181cb0ef41Sopenharmony_ci left = NonNumberToNumeric(left); 5191cb0ef41Sopenharmony_ci } 5201cb0ef41Sopenharmony_ci } 5211cb0ef41Sopenharmony_ci } label RightNotNumeric { 5221cb0ef41Sopenharmony_ci right = NonNumberToNumeric(right); 5231cb0ef41Sopenharmony_ci } 5241cb0ef41Sopenharmony_ci } 5251cb0ef41Sopenharmony_ci unreachable; 5261cb0ef41Sopenharmony_ci} 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci// Binary type switch on Smi | HeapNumber | BigInt. 5291cb0ef41Sopenharmony_cimacro BinaryOp2(implicit context: Context)(leftVal: JSAny, rightVal: JSAny): 5301cb0ef41Sopenharmony_ci never labels Smis(Smi, Smi), Float64s(float64, float64), 5311cb0ef41Sopenharmony_ci AtLeastOneBigInt(Numeric, Numeric) { 5321cb0ef41Sopenharmony_ci let left: JSAny = leftVal; 5331cb0ef41Sopenharmony_ci let right: JSAny = rightVal; 5341cb0ef41Sopenharmony_ci while (true) { 5351cb0ef41Sopenharmony_ci try { 5361cb0ef41Sopenharmony_ci typeswitch (left) { 5371cb0ef41Sopenharmony_ci case (left: Smi): { 5381cb0ef41Sopenharmony_ci typeswitch (right) { 5391cb0ef41Sopenharmony_ci case (right: Smi): { 5401cb0ef41Sopenharmony_ci goto Smis(left, right); 5411cb0ef41Sopenharmony_ci } 5421cb0ef41Sopenharmony_ci case (right: HeapNumber): { 5431cb0ef41Sopenharmony_ci goto Float64s(SmiToFloat64(left), Convert<float64>(right)); 5441cb0ef41Sopenharmony_ci } 5451cb0ef41Sopenharmony_ci case (right: BigInt): { 5461cb0ef41Sopenharmony_ci goto AtLeastOneBigInt(left, right); 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5491cb0ef41Sopenharmony_ci goto RightNotNumeric; 5501cb0ef41Sopenharmony_ci } 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci case (left: HeapNumber): { 5541cb0ef41Sopenharmony_ci typeswitch (right) { 5551cb0ef41Sopenharmony_ci case (right: Smi): { 5561cb0ef41Sopenharmony_ci goto Float64s(Convert<float64>(left), SmiToFloat64(right)); 5571cb0ef41Sopenharmony_ci } 5581cb0ef41Sopenharmony_ci case (right: HeapNumber): { 5591cb0ef41Sopenharmony_ci goto Float64s(Convert<float64>(left), Convert<float64>(right)); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci case (right: BigInt): { 5621cb0ef41Sopenharmony_ci goto AtLeastOneBigInt(left, right); 5631cb0ef41Sopenharmony_ci } 5641cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5651cb0ef41Sopenharmony_ci goto RightNotNumeric; 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci } 5681cb0ef41Sopenharmony_ci } 5691cb0ef41Sopenharmony_ci case (left: BigInt): { 5701cb0ef41Sopenharmony_ci typeswitch (right) { 5711cb0ef41Sopenharmony_ci case (right: Numeric): { 5721cb0ef41Sopenharmony_ci goto AtLeastOneBigInt(left, right); 5731cb0ef41Sopenharmony_ci } 5741cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5751cb0ef41Sopenharmony_ci goto RightNotNumeric; 5761cb0ef41Sopenharmony_ci } 5771cb0ef41Sopenharmony_ci } 5781cb0ef41Sopenharmony_ci } 5791cb0ef41Sopenharmony_ci case (JSAnyNotNumeric): { 5801cb0ef41Sopenharmony_ci left = NonNumberToNumeric(left); 5811cb0ef41Sopenharmony_ci } 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci } label RightNotNumeric { 5841cb0ef41Sopenharmony_ci right = NonNumberToNumeric(right); 5851cb0ef41Sopenharmony_ci } 5861cb0ef41Sopenharmony_ci } 5871cb0ef41Sopenharmony_ci unreachable; 5881cb0ef41Sopenharmony_ci} 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_cibuiltin Subtract(implicit context: Context)( 5911cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Numeric { 5921cb0ef41Sopenharmony_ci try { 5931cb0ef41Sopenharmony_ci BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; 5941cb0ef41Sopenharmony_ci } label Smis(left: Smi, right: Smi) { 5951cb0ef41Sopenharmony_ci try { 5961cb0ef41Sopenharmony_ci return math::TrySmiSub(left, right) otherwise Overflow; 5971cb0ef41Sopenharmony_ci } label Overflow { 5981cb0ef41Sopenharmony_ci goto Float64s(SmiToFloat64(left), SmiToFloat64(right)); 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci } label Float64s(left: float64, right: float64) { 6011cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(left - right); 6021cb0ef41Sopenharmony_ci } label AtLeastOneBigInt(left: Numeric, right: Numeric) { 6031cb0ef41Sopenharmony_ci tail bigint::BigIntSubtract(left, right); 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci} 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_cibuiltin Multiply(implicit context: Context)( 6081cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Numeric { 6091cb0ef41Sopenharmony_ci try { 6101cb0ef41Sopenharmony_ci BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; 6111cb0ef41Sopenharmony_ci } label Smis(left: Smi, right: Smi) { 6121cb0ef41Sopenharmony_ci // The result is not necessarily a smi, in case of overflow. 6131cb0ef41Sopenharmony_ci return SmiMul(left, right); 6141cb0ef41Sopenharmony_ci } label Float64s(left: float64, right: float64) { 6151cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(left * right); 6161cb0ef41Sopenharmony_ci } label AtLeastOneBigInt(left: Numeric, right: Numeric) { 6171cb0ef41Sopenharmony_ci tail runtime::BigIntBinaryOp( 6181cb0ef41Sopenharmony_ci context, left, right, SmiTag<Operation>(Operation::kMultiply)); 6191cb0ef41Sopenharmony_ci } 6201cb0ef41Sopenharmony_ci} 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ciconst kSmiValueSize: constexpr int32 generates 'kSmiValueSize'; 6231cb0ef41Sopenharmony_ciconst kMinInt32: constexpr int32 generates 'kMinInt'; 6241cb0ef41Sopenharmony_ciconst kMinInt31: constexpr int32 generates 'kMinInt31'; 6251cb0ef41Sopenharmony_ciconst kMinimumDividend: int32 = (kSmiValueSize == 32) ? kMinInt32 : kMinInt31; 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_cibuiltin Divide(implicit context: Context)(left: JSAny, right: JSAny): Numeric { 6281cb0ef41Sopenharmony_ci try { 6291cb0ef41Sopenharmony_ci BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; 6301cb0ef41Sopenharmony_ci } label Smis(left: Smi, right: Smi) { 6311cb0ef41Sopenharmony_ci // TODO(jkummerow): Consider just always doing a double division. 6321cb0ef41Sopenharmony_ci // Bail out if {divisor} is zero. 6331cb0ef41Sopenharmony_ci if (right == 0) goto SmiBailout(left, right); 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci // Bail out if dividend is zero and divisor is negative. 6361cb0ef41Sopenharmony_ci if (left == 0 && right < 0) goto SmiBailout(left, right); 6371cb0ef41Sopenharmony_ci 6381cb0ef41Sopenharmony_ci const dividend: int32 = SmiToInt32(left); 6391cb0ef41Sopenharmony_ci const divisor: int32 = SmiToInt32(right); 6401cb0ef41Sopenharmony_ci 6411cb0ef41Sopenharmony_ci // Bail out if dividend is kMinInt31 (or kMinInt32 if Smis are 32 bits) 6421cb0ef41Sopenharmony_ci // and divisor is -1. 6431cb0ef41Sopenharmony_ci if (divisor == -1 && dividend == kMinimumDividend) { 6441cb0ef41Sopenharmony_ci goto SmiBailout(left, right); 6451cb0ef41Sopenharmony_ci } 6461cb0ef41Sopenharmony_ci // TODO(epertoso): consider adding a machine instruction that returns 6471cb0ef41Sopenharmony_ci // both the result and the remainder. 6481cb0ef41Sopenharmony_ci const result: int32 = dividend / divisor; 6491cb0ef41Sopenharmony_ci const truncated: int32 = result * divisor; 6501cb0ef41Sopenharmony_ci if (dividend != truncated) goto SmiBailout(left, right); 6511cb0ef41Sopenharmony_ci return SmiFromInt32(result); 6521cb0ef41Sopenharmony_ci } label SmiBailout(left: Smi, right: Smi) { 6531cb0ef41Sopenharmony_ci goto Float64s(SmiToFloat64(left), SmiToFloat64(right)); 6541cb0ef41Sopenharmony_ci } label Float64s(left: float64, right: float64) { 6551cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(left / right); 6561cb0ef41Sopenharmony_ci } label AtLeastOneBigInt(left: Numeric, right: Numeric) { 6571cb0ef41Sopenharmony_ci tail runtime::BigIntBinaryOp( 6581cb0ef41Sopenharmony_ci context, left, right, SmiTag<Operation>(Operation::kDivide)); 6591cb0ef41Sopenharmony_ci } 6601cb0ef41Sopenharmony_ci} 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_cibuiltin Modulus(implicit context: Context)(left: JSAny, right: JSAny): Numeric { 6631cb0ef41Sopenharmony_ci try { 6641cb0ef41Sopenharmony_ci BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; 6651cb0ef41Sopenharmony_ci } label Smis(left: Smi, right: Smi) { 6661cb0ef41Sopenharmony_ci return SmiMod(left, right); 6671cb0ef41Sopenharmony_ci } label Float64s(left: float64, right: float64) { 6681cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(left % right); 6691cb0ef41Sopenharmony_ci } label AtLeastOneBigInt(left: Numeric, right: Numeric) { 6701cb0ef41Sopenharmony_ci tail runtime::BigIntBinaryOp( 6711cb0ef41Sopenharmony_ci context, left, right, SmiTag<Operation>(Operation::kModulus)); 6721cb0ef41Sopenharmony_ci } 6731cb0ef41Sopenharmony_ci} 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_cibuiltin Exponentiate(implicit context: Context)( 6761cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Numeric { 6771cb0ef41Sopenharmony_ci try { 6781cb0ef41Sopenharmony_ci BinaryOp1(left, right) otherwise Numbers, AtLeastOneBigInt; 6791cb0ef41Sopenharmony_ci } label Numbers(left: Number, right: Number) { 6801cb0ef41Sopenharmony_ci return math::MathPowImpl(left, right); 6811cb0ef41Sopenharmony_ci } label AtLeastOneBigInt(left: Numeric, right: Numeric) { 6821cb0ef41Sopenharmony_ci tail runtime::BigIntBinaryOp( 6831cb0ef41Sopenharmony_ci context, left, right, SmiTag<Operation>(Operation::kExponentiate)); 6841cb0ef41Sopenharmony_ci } 6851cb0ef41Sopenharmony_ci} 6861cb0ef41Sopenharmony_ci 6871cb0ef41Sopenharmony_cibuiltin Negate(implicit context: Context)(value: JSAny): Numeric { 6881cb0ef41Sopenharmony_ci try { 6891cb0ef41Sopenharmony_ci UnaryOp2(value) otherwise Smi, HeapNumber, BigInt; 6901cb0ef41Sopenharmony_ci } label Smi(s: Smi) { 6911cb0ef41Sopenharmony_ci return SmiMul(s, -1); 6921cb0ef41Sopenharmony_ci } label HeapNumber(h: HeapNumber) { 6931cb0ef41Sopenharmony_ci return AllocateHeapNumberWithValue(Convert<float64>(h) * -1.0); 6941cb0ef41Sopenharmony_ci } label BigInt(b: BigInt) { 6951cb0ef41Sopenharmony_ci tail runtime::BigIntUnaryOp( 6961cb0ef41Sopenharmony_ci context, b, SmiTag<Operation>(Operation::kNegate)); 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci} 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_cibuiltin BitwiseNot(implicit context: Context)(value: JSAny): Numeric { 7011cb0ef41Sopenharmony_ci try { 7021cb0ef41Sopenharmony_ci UnaryOp1(value) otherwise Number, BigInt; 7031cb0ef41Sopenharmony_ci } label Number(n: Number) { 7041cb0ef41Sopenharmony_ci tail BitwiseXor(n, -1); 7051cb0ef41Sopenharmony_ci } label BigInt(b: BigInt) { 7061cb0ef41Sopenharmony_ci return runtime::BigIntUnaryOp( 7071cb0ef41Sopenharmony_ci context, b, SmiTag<Operation>(Operation::kBitwiseNot)); 7081cb0ef41Sopenharmony_ci } 7091cb0ef41Sopenharmony_ci} 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_cibuiltin Decrement(implicit context: Context)(value: JSAny): Numeric { 7121cb0ef41Sopenharmony_ci try { 7131cb0ef41Sopenharmony_ci UnaryOp1(value) otherwise Number, BigInt; 7141cb0ef41Sopenharmony_ci } label Number(n: Number) { 7151cb0ef41Sopenharmony_ci tail Subtract(n, 1); 7161cb0ef41Sopenharmony_ci } label BigInt(b: BigInt) { 7171cb0ef41Sopenharmony_ci return runtime::BigIntUnaryOp( 7181cb0ef41Sopenharmony_ci context, b, SmiTag<Operation>(Operation::kDecrement)); 7191cb0ef41Sopenharmony_ci } 7201cb0ef41Sopenharmony_ci} 7211cb0ef41Sopenharmony_ci 7221cb0ef41Sopenharmony_cibuiltin Increment(implicit context: Context)(value: JSAny): Numeric { 7231cb0ef41Sopenharmony_ci try { 7241cb0ef41Sopenharmony_ci UnaryOp1(value) otherwise Number, BigInt; 7251cb0ef41Sopenharmony_ci } label Number(n: Number) { 7261cb0ef41Sopenharmony_ci tail Add(n, 1); 7271cb0ef41Sopenharmony_ci } label BigInt(b: BigInt) { 7281cb0ef41Sopenharmony_ci return runtime::BigIntUnaryOp( 7291cb0ef41Sopenharmony_ci context, b, SmiTag<Operation>(Operation::kIncrement)); 7301cb0ef41Sopenharmony_ci } 7311cb0ef41Sopenharmony_ci} 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_ci// Bitwise binary operations. 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ciextern macro BinaryOpAssembler::Generate_BitwiseBinaryOp( 7361cb0ef41Sopenharmony_ci constexpr Operation, JSAny, JSAny, Context): Object; 7371cb0ef41Sopenharmony_ci 7381cb0ef41Sopenharmony_cibuiltin ShiftLeft(implicit context: Context)( 7391cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7401cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp(Operation::kShiftLeft, left, right, context); 7411cb0ef41Sopenharmony_ci} 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_cibuiltin ShiftRight(implicit context: Context)( 7441cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7451cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp(Operation::kShiftRight, left, right, context); 7461cb0ef41Sopenharmony_ci} 7471cb0ef41Sopenharmony_ci 7481cb0ef41Sopenharmony_cibuiltin ShiftRightLogical(implicit context: Context)( 7491cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7501cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp( 7511cb0ef41Sopenharmony_ci Operation::kShiftRightLogical, left, right, context); 7521cb0ef41Sopenharmony_ci} 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_cibuiltin BitwiseAnd(implicit context: Context)( 7551cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7561cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp(Operation::kBitwiseAnd, left, right, context); 7571cb0ef41Sopenharmony_ci} 7581cb0ef41Sopenharmony_ci 7591cb0ef41Sopenharmony_cibuiltin BitwiseOr(implicit context: Context)( 7601cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7611cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp(Operation::kBitwiseOr, left, right, context); 7621cb0ef41Sopenharmony_ci} 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_cibuiltin BitwiseXor(implicit context: Context)( 7651cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7661cb0ef41Sopenharmony_ci return Generate_BitwiseBinaryOp(Operation::kBitwiseXor, left, right, context); 7671cb0ef41Sopenharmony_ci} 7681cb0ef41Sopenharmony_ci 7691cb0ef41Sopenharmony_ci// Relational builtins. 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_cibuiltin LessThan(implicit context: Context)(left: JSAny, right: JSAny): Object { 7721cb0ef41Sopenharmony_ci return RelationalComparison(Operation::kLessThan, left, right, context); 7731cb0ef41Sopenharmony_ci} 7741cb0ef41Sopenharmony_ci 7751cb0ef41Sopenharmony_cibuiltin LessThanOrEqual(implicit context: Context)( 7761cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7771cb0ef41Sopenharmony_ci return RelationalComparison( 7781cb0ef41Sopenharmony_ci Operation::kLessThanOrEqual, left, right, context); 7791cb0ef41Sopenharmony_ci} 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_cibuiltin GreaterThan(implicit context: Context)( 7821cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7831cb0ef41Sopenharmony_ci return RelationalComparison(Operation::kGreaterThan, left, right, context); 7841cb0ef41Sopenharmony_ci} 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_cibuiltin GreaterThanOrEqual(implicit context: Context)( 7871cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7881cb0ef41Sopenharmony_ci return RelationalComparison( 7891cb0ef41Sopenharmony_ci Operation::kGreaterThanOrEqual, left, right, context); 7901cb0ef41Sopenharmony_ci} 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_cibuiltin Equal(implicit context: Context)(left: JSAny, right: JSAny): Object { 7931cb0ef41Sopenharmony_ci return Equal(left, right, context); 7941cb0ef41Sopenharmony_ci} 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_cibuiltin StrictEqual(implicit context: Context)( 7971cb0ef41Sopenharmony_ci left: JSAny, right: JSAny): Object { 7981cb0ef41Sopenharmony_ci return ::StrictEqual(left, right); 7991cb0ef41Sopenharmony_ci} 8001cb0ef41Sopenharmony_ci 8011cb0ef41Sopenharmony_ci} // namespace number 802