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