11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_cinamespace runtime { 61cb0ef41Sopenharmony_ciextern transitioning runtime ToString(Context, BigInt): String; 71cb0ef41Sopenharmony_ci} 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciextern enum OrdinaryToPrimitiveHint { kString, kNumber } 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciextern macro OrdinaryToPrimitive(implicit context: Context)( 121cb0ef41Sopenharmony_ci JSAny, constexpr OrdinaryToPrimitiveHint): JSPrimitive; 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace conversion { 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cibuiltin StringToNumber(implicit context: Context)(input: String): Number { 171cb0ef41Sopenharmony_ci return ::StringToNumber(input); 181cb0ef41Sopenharmony_ci} 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_citransitioning builtin NonNumberToNumber(implicit context: Context)( 211cb0ef41Sopenharmony_ci input: JSAnyNotNumber): Number { 221cb0ef41Sopenharmony_ci return ::NonNumberToNumber(input); 231cb0ef41Sopenharmony_ci} 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_citransitioning builtin NonNumberToNumeric(implicit context: Context)( 261cb0ef41Sopenharmony_ci input: JSAnyNotNumber): Numeric { 271cb0ef41Sopenharmony_ci return ::NonNumberToNumeric(input); 281cb0ef41Sopenharmony_ci} 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_citransitioning builtin ToNumeric(implicit context: Context)(input: JSAny): 311cb0ef41Sopenharmony_ci Numeric { 321cb0ef41Sopenharmony_ci typeswitch (input) { 331cb0ef41Sopenharmony_ci case (n: Number): { 341cb0ef41Sopenharmony_ci return n; 351cb0ef41Sopenharmony_ci } 361cb0ef41Sopenharmony_ci case (h: JSAnyNotNumber): { 371cb0ef41Sopenharmony_ci return conversion::NonNumberToNumeric(h); 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci// ES section #sec-tostring-applied-to-the-number-type 431cb0ef41Sopenharmony_cibuiltin NumberToString(implicit context: Context)(input: Number): String { 441cb0ef41Sopenharmony_ci return ::NumberToString(input); 451cb0ef41Sopenharmony_ci} 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// ES6 section 7.1.2 ToBoolean ( argument ) 481cb0ef41Sopenharmony_cibuiltin ToBoolean(input: JSAny): Boolean { 491cb0ef41Sopenharmony_ci BranchIfToBooleanIsTrue(input) otherwise return TrueConstant(), 501cb0ef41Sopenharmony_ci return FalseConstant(); 511cb0ef41Sopenharmony_ci} 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_cistruct ToBooleanForBaselineJumpResult { 541cb0ef41Sopenharmony_ci value: JSAny; 551cb0ef41Sopenharmony_ci is_to_boolean: Smi; 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci// ToBoolean for baseline code jumps, which 581cb0ef41Sopenharmony_ci// a) returns the original value as the first return value, to avoid needing 591cb0ef41Sopenharmony_ci// to save it in the caller, and 601cb0ef41Sopenharmony_ci// b) returns the true/false value as a Smi, to make the baseline-side 611cb0ef41Sopenharmony_ci// comparison cheaper. 621cb0ef41Sopenharmony_cibuiltin ToBooleanForBaselineJump(input: JSAny): ToBooleanForBaselineJumpResult { 631cb0ef41Sopenharmony_ci try { 641cb0ef41Sopenharmony_ci BranchIfToBooleanIsTrue(input) otherwise IsTrue, IsFalse; 651cb0ef41Sopenharmony_ci } label IsTrue { 661cb0ef41Sopenharmony_ci return ToBooleanForBaselineJumpResult{value: input, is_to_boolean: 1}; 671cb0ef41Sopenharmony_ci } label IsFalse { 681cb0ef41Sopenharmony_ci return ToBooleanForBaselineJumpResult{value: input, is_to_boolean: 0}; 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_citransitioning builtin ToLength(implicit context: Context)(input: JSAny): 731cb0ef41Sopenharmony_ci Number { 741cb0ef41Sopenharmony_ci // We might need to loop once for ToNumber conversion. 751cb0ef41Sopenharmony_ci let x: JSAny = input; 761cb0ef41Sopenharmony_ci while (true) { 771cb0ef41Sopenharmony_ci typeswitch (x) { 781cb0ef41Sopenharmony_ci case (s: Smi): { 791cb0ef41Sopenharmony_ci if (s < 0) return 0; 801cb0ef41Sopenharmony_ci return s; 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci case (h: HeapNumber): { 831cb0ef41Sopenharmony_ci let value: float64 = Convert<float64>(h); 841cb0ef41Sopenharmony_ci // The sense of this test is important for the NaN and -0 cases. 851cb0ef41Sopenharmony_ci if (!(value > 0)) return 0; 861cb0ef41Sopenharmony_ci if (value > kMaxSafeInteger) return kMaxSafeInteger; 871cb0ef41Sopenharmony_ci value = math::Float64Floor(value); 881cb0ef41Sopenharmony_ci return ChangeFloat64ToTagged(value); 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci case (h: JSAnyNotNumber): { 911cb0ef41Sopenharmony_ci x = ::NonNumberToNumber(h); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci VerifiedUnreachable(); 961cb0ef41Sopenharmony_ci} 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_citransitioning builtin ToName(implicit context: Context)(input: JSAny): Name { 991cb0ef41Sopenharmony_ci // We might need to loop once for ToNumber conversion. 1001cb0ef41Sopenharmony_ci let x: JSAny = input; 1011cb0ef41Sopenharmony_ci while (true) { 1021cb0ef41Sopenharmony_ci typeswitch (x) { 1031cb0ef41Sopenharmony_ci case (n: Name): { 1041cb0ef41Sopenharmony_ci return n; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci case (n: Number): { 1071cb0ef41Sopenharmony_ci return ::NumberToString(n); 1081cb0ef41Sopenharmony_ci } 1091cb0ef41Sopenharmony_ci case (b: BigInt): { 1101cb0ef41Sopenharmony_ci // We don't have a fast-path for BigInt currently, so just 1111cb0ef41Sopenharmony_ci // tail call to the %ToString runtime function here for now. 1121cb0ef41Sopenharmony_ci tail runtime::ToString(context, b); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci case (o: Oddball): { 1151cb0ef41Sopenharmony_ci return o.to_string; 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci case (o: JSReceiver): { 1181cb0ef41Sopenharmony_ci x = NonPrimitiveToPrimitive_String(o); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci VerifiedUnreachable(); 1231cb0ef41Sopenharmony_ci} 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ciconst kNoConstructorFunctionIndex: 1261cb0ef41Sopenharmony_ci constexpr int31 generates 'Map::kNoConstructorFunctionIndex'; 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci// ES6 section 7.1.13 ToObject (argument) 1291cb0ef41Sopenharmony_citransitioning builtin ToObject(implicit context: Context)(input: JSAny): 1301cb0ef41Sopenharmony_ci JSReceiver { 1311cb0ef41Sopenharmony_ci try { 1321cb0ef41Sopenharmony_ci typeswitch (input) { 1331cb0ef41Sopenharmony_ci case (Smi): { 1341cb0ef41Sopenharmony_ci goto WrapPrimitive(ContextSlot::NUMBER_FUNCTION_INDEX); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci case (o: JSReceiver): { 1371cb0ef41Sopenharmony_ci return o; 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci case (o: JSAnyNotSmi): { 1401cb0ef41Sopenharmony_ci const index: intptr = Convert<intptr>( 1411cb0ef41Sopenharmony_ci o.map.inobject_properties_start_or_constructor_function_index); 1421cb0ef41Sopenharmony_ci if (index != kNoConstructorFunctionIndex) 1431cb0ef41Sopenharmony_ci goto WrapPrimitive( 1441cb0ef41Sopenharmony_ci %RawDownCast<Slot<NativeContext, JSFunction>>(index)); 1451cb0ef41Sopenharmony_ci ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject, 'ToObject'); 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci } label WrapPrimitive(constructorIndex: Slot<NativeContext, JSFunction>) { 1491cb0ef41Sopenharmony_ci const constructor = *NativeContextSlot(constructorIndex); 1501cb0ef41Sopenharmony_ci const map: Map = UnsafeCast<Map>(constructor.prototype_or_initial_map); 1511cb0ef41Sopenharmony_ci const wrapper = 1521cb0ef41Sopenharmony_ci UnsafeCast<JSPrimitiveWrapper>(AllocateFastOrSlowJSObjectFromMap(map)); 1531cb0ef41Sopenharmony_ci wrapper.value = input; 1541cb0ef41Sopenharmony_ci return wrapper; 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci} 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_citransitioning macro TryGetExoticToPrimitive(implicit context: Context)( 1611cb0ef41Sopenharmony_ci input: JSAny): JSAny labels OrdinaryToPrimitive { 1621cb0ef41Sopenharmony_ci // Look up the @@toPrimitive property. 1631cb0ef41Sopenharmony_ci const exoticToPrimitive: JSAny = 1641cb0ef41Sopenharmony_ci GetProperty(input, ToPrimitiveSymbolConstant()); 1651cb0ef41Sopenharmony_ci if (IsNullOrUndefined(exoticToPrimitive)) goto OrdinaryToPrimitive; 1661cb0ef41Sopenharmony_ci return exoticToPrimitive; 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_citransitioning macro CallExoticToPrimitive(implicit context: Context)( 1701cb0ef41Sopenharmony_ci input: JSAny, exoticToPrimitive: JSAny, hint: String): JSPrimitive { 1711cb0ef41Sopenharmony_ci // Invoke the exoticToPrimitive method on the input with a string 1721cb0ef41Sopenharmony_ci // representation of the hint. 1731cb0ef41Sopenharmony_ci const result: JSAny = Call(context, exoticToPrimitive, input, hint); 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci // Verify that the result is primitive. 1761cb0ef41Sopenharmony_ci typeswitch (result) { 1771cb0ef41Sopenharmony_ci case (o: JSPrimitive): { 1781cb0ef41Sopenharmony_ci return o; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci case (JSReceiver): { 1811cb0ef41Sopenharmony_ci // Somehow the @@toPrimitive method on input didn't yield a primitive. 1821cb0ef41Sopenharmony_ci ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci} 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_citransitioning builtin NonPrimitiveToPrimitive_Default( 1881cb0ef41Sopenharmony_ci implicit context: Context)(input: JSReceiver): JSPrimitive { 1891cb0ef41Sopenharmony_ci const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) 1901cb0ef41Sopenharmony_ci otherwise return OrdinaryToPrimitive_Number(input); 1911cb0ef41Sopenharmony_ci return CallExoticToPrimitive( 1921cb0ef41Sopenharmony_ci input, exoticToPrimitive, DefaultStringConstant()); 1931cb0ef41Sopenharmony_ci} 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_citransitioning builtin NonPrimitiveToPrimitive_Number(implicit context: Context)( 1961cb0ef41Sopenharmony_ci input: JSReceiver): JSPrimitive { 1971cb0ef41Sopenharmony_ci const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) 1981cb0ef41Sopenharmony_ci otherwise return OrdinaryToPrimitive_Number(input); 1991cb0ef41Sopenharmony_ci return CallExoticToPrimitive( 2001cb0ef41Sopenharmony_ci input, exoticToPrimitive, NumberStringConstant()); 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_citransitioning builtin NonPrimitiveToPrimitive_String(implicit context: Context)( 2041cb0ef41Sopenharmony_ci input: JSReceiver): JSPrimitive { 2051cb0ef41Sopenharmony_ci const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) 2061cb0ef41Sopenharmony_ci otherwise return OrdinaryToPrimitive_String(input); 2071cb0ef41Sopenharmony_ci return CallExoticToPrimitive( 2081cb0ef41Sopenharmony_ci input, exoticToPrimitive, StringStringConstant()); 2091cb0ef41Sopenharmony_ci} 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci// 7.1.1.1 OrdinaryToPrimitive ( O, hint ) 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_citransitioning macro TryToPrimitiveMethod(implicit context: Context)( 2141cb0ef41Sopenharmony_ci input: JSAny, name: String): JSPrimitive labels Continue { 2151cb0ef41Sopenharmony_ci const method: JSAny = GetProperty(input, name); 2161cb0ef41Sopenharmony_ci typeswitch (method) { 2171cb0ef41Sopenharmony_ci case (Callable): { 2181cb0ef41Sopenharmony_ci const value: JSAny = Call(context, method, input); 2191cb0ef41Sopenharmony_ci return Cast<JSPrimitive>(value) otherwise Continue; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci case (JSAny): { 2221cb0ef41Sopenharmony_ci goto Continue; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci} 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_citransitioning builtin OrdinaryToPrimitive_Number(implicit context: Context)( 2281cb0ef41Sopenharmony_ci input: JSAny): JSPrimitive { 2291cb0ef41Sopenharmony_ci try { 2301cb0ef41Sopenharmony_ci return TryToPrimitiveMethod(input, ValueOfStringConstant()) 2311cb0ef41Sopenharmony_ci otherwise String; 2321cb0ef41Sopenharmony_ci } label String { 2331cb0ef41Sopenharmony_ci return TryToPrimitiveMethod(input, ToStringStringConstant()) 2341cb0ef41Sopenharmony_ci otherwise Throw; 2351cb0ef41Sopenharmony_ci } label Throw { 2361cb0ef41Sopenharmony_ci ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_citransitioning builtin OrdinaryToPrimitive_String(implicit context: Context)( 2411cb0ef41Sopenharmony_ci input: JSAny): JSPrimitive { 2421cb0ef41Sopenharmony_ci try { 2431cb0ef41Sopenharmony_ci return TryToPrimitiveMethod(input, ToStringStringConstant()) 2441cb0ef41Sopenharmony_ci otherwise String; 2451cb0ef41Sopenharmony_ci } label String { 2461cb0ef41Sopenharmony_ci return TryToPrimitiveMethod(input, ValueOfStringConstant()) otherwise Throw; 2471cb0ef41Sopenharmony_ci } label Throw { 2481cb0ef41Sopenharmony_ci ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci} 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci} // namespace conversion 253