• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5namespace runtime {
6extern transitioning runtime ToString(Context, BigInt): String;
7}
8
9extern enum OrdinaryToPrimitiveHint { kString, kNumber }
10
11extern macro OrdinaryToPrimitive(implicit context: Context)(
12    JSAny, constexpr OrdinaryToPrimitiveHint): JSPrimitive;
13
14namespace conversion {
15
16builtin StringToNumber(implicit context: Context)(input: String): Number {
17  return ::StringToNumber(input);
18}
19
20transitioning builtin NonNumberToNumber(implicit context: Context)(
21    input: JSAnyNotNumber): Number {
22  return ::NonNumberToNumber(input);
23}
24
25transitioning builtin NonNumberToNumeric(implicit context: Context)(
26    input: JSAnyNotNumber): Numeric {
27  return ::NonNumberToNumeric(input);
28}
29
30transitioning builtin ToNumeric(implicit context: Context)(input: JSAny):
31    Numeric {
32  typeswitch (input) {
33    case (n: Number): {
34      return n;
35    }
36    case (h: JSAnyNotNumber): {
37      return conversion::NonNumberToNumeric(h);
38    }
39  }
40}
41
42// ES section #sec-tostring-applied-to-the-number-type
43builtin NumberToString(implicit context: Context)(input: Number): String {
44  return ::NumberToString(input);
45}
46
47// ES6 section 7.1.2 ToBoolean ( argument )
48builtin ToBoolean(input: JSAny): Boolean {
49  BranchIfToBooleanIsTrue(input) otherwise return TrueConstant(),
50      return FalseConstant();
51}
52
53struct ToBooleanForBaselineJumpResult {
54  value: JSAny;
55  is_to_boolean: Smi;
56}
57// ToBoolean for baseline code jumps, which
58//   a) returns the original value as the first return value, to avoid needing
59//      to save it in the caller, and
60//   b) returns the true/false value as a Smi, to make the baseline-side
61//      comparison cheaper.
62builtin ToBooleanForBaselineJump(input: JSAny): ToBooleanForBaselineJumpResult {
63  try {
64    BranchIfToBooleanIsTrue(input) otherwise IsTrue, IsFalse;
65  } label IsTrue {
66    return ToBooleanForBaselineJumpResult{value: input, is_to_boolean: 1};
67  } label IsFalse {
68    return ToBooleanForBaselineJumpResult{value: input, is_to_boolean: 0};
69  }
70}
71
72transitioning builtin ToLength(implicit context: Context)(input: JSAny):
73    Number {
74  // We might need to loop once for ToNumber conversion.
75  let x: JSAny = input;
76  while (true) {
77    typeswitch (x) {
78      case (s: Smi): {
79        if (s < 0) return 0;
80        return s;
81      }
82      case (h: HeapNumber): {
83        let value: float64 = Convert<float64>(h);
84        // The sense of this test is important for the NaN and -0 cases.
85        if (!(value > 0)) return 0;
86        if (value > kMaxSafeInteger) return kMaxSafeInteger;
87        value = math::Float64Floor(value);
88        return ChangeFloat64ToTagged(value);
89      }
90      case (h: JSAnyNotNumber): {
91        x = ::NonNumberToNumber(h);
92      }
93    }
94  }
95  VerifiedUnreachable();
96}
97
98transitioning builtin ToName(implicit context: Context)(input: JSAny): Name {
99  // We might need to loop once for ToNumber conversion.
100  let x: JSAny = input;
101  while (true) {
102    typeswitch (x) {
103      case (n: Name): {
104        return n;
105      }
106      case (n: Number): {
107        return ::NumberToString(n);
108      }
109      case (b: BigInt): {
110        // We don't have a fast-path for BigInt currently, so just
111        // tail call to the %ToString runtime function here for now.
112        tail runtime::ToString(context, b);
113      }
114      case (o: Oddball): {
115        return o.to_string;
116      }
117      case (o: JSReceiver): {
118        x = NonPrimitiveToPrimitive_String(o);
119      }
120    }
121  }
122  VerifiedUnreachable();
123}
124
125const kNoConstructorFunctionIndex:
126    constexpr int31 generates 'Map::kNoConstructorFunctionIndex';
127
128// ES6 section 7.1.13 ToObject (argument)
129transitioning builtin ToObject(implicit context: Context)(input: JSAny):
130    JSReceiver {
131  try {
132    typeswitch (input) {
133      case (Smi): {
134        goto WrapPrimitive(ContextSlot::NUMBER_FUNCTION_INDEX);
135      }
136      case (o: JSReceiver): {
137        return o;
138      }
139      case (o: JSAnyNotSmi): {
140        const index: intptr = Convert<intptr>(
141            o.map.inobject_properties_start_or_constructor_function_index);
142        if (index != kNoConstructorFunctionIndex)
143          goto WrapPrimitive(
144              %RawDownCast<Slot<NativeContext, JSFunction>>(index));
145        ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject, 'ToObject');
146      }
147    }
148  } label WrapPrimitive(constructorIndex: Slot<NativeContext, JSFunction>) {
149    const constructor = *NativeContextSlot(constructorIndex);
150    const map: Map = UnsafeCast<Map>(constructor.prototype_or_initial_map);
151    const wrapper =
152        UnsafeCast<JSPrimitiveWrapper>(AllocateFastOrSlowJSObjectFromMap(map));
153    wrapper.value = input;
154    return wrapper;
155  }
156}
157
158// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
159
160transitioning macro TryGetExoticToPrimitive(implicit context: Context)(
161    input: JSAny): JSAny labels OrdinaryToPrimitive {
162  // Look up the @@toPrimitive property.
163  const exoticToPrimitive: JSAny =
164      GetProperty(input, ToPrimitiveSymbolConstant());
165  if (IsNullOrUndefined(exoticToPrimitive)) goto OrdinaryToPrimitive;
166  return exoticToPrimitive;
167}
168
169transitioning macro CallExoticToPrimitive(implicit context: Context)(
170    input: JSAny, exoticToPrimitive: JSAny, hint: String): JSPrimitive {
171  // Invoke the exoticToPrimitive method on the input with a string
172  // representation of the hint.
173  const result: JSAny = Call(context, exoticToPrimitive, input, hint);
174
175  // Verify that the result is primitive.
176  typeswitch (result) {
177    case (o: JSPrimitive): {
178      return o;
179    }
180    case (JSReceiver): {
181      // Somehow the @@toPrimitive method on input didn't yield a primitive.
182      ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
183    }
184  }
185}
186
187transitioning builtin NonPrimitiveToPrimitive_Default(
188    implicit context: Context)(input: JSReceiver): JSPrimitive {
189  const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
190      otherwise return OrdinaryToPrimitive_Number(input);
191  return CallExoticToPrimitive(
192      input, exoticToPrimitive, DefaultStringConstant());
193}
194
195transitioning builtin NonPrimitiveToPrimitive_Number(implicit context: Context)(
196    input: JSReceiver): JSPrimitive {
197  const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
198      otherwise return OrdinaryToPrimitive_Number(input);
199  return CallExoticToPrimitive(
200      input, exoticToPrimitive, NumberStringConstant());
201}
202
203transitioning builtin NonPrimitiveToPrimitive_String(implicit context: Context)(
204    input: JSReceiver): JSPrimitive {
205  const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input)
206      otherwise return OrdinaryToPrimitive_String(input);
207  return CallExoticToPrimitive(
208      input, exoticToPrimitive, StringStringConstant());
209}
210
211// 7.1.1.1 OrdinaryToPrimitive ( O, hint )
212
213transitioning macro TryToPrimitiveMethod(implicit context: Context)(
214    input: JSAny, name: String): JSPrimitive labels Continue {
215  const method: JSAny = GetProperty(input, name);
216  typeswitch (method) {
217    case (Callable): {
218      const value: JSAny = Call(context, method, input);
219      return Cast<JSPrimitive>(value) otherwise Continue;
220    }
221    case (JSAny): {
222      goto Continue;
223    }
224  }
225}
226
227transitioning builtin OrdinaryToPrimitive_Number(implicit context: Context)(
228    input: JSAny): JSPrimitive {
229  try {
230    return TryToPrimitiveMethod(input, ValueOfStringConstant())
231        otherwise String;
232  } label String {
233    return TryToPrimitiveMethod(input, ToStringStringConstant())
234        otherwise Throw;
235  } label Throw {
236    ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
237  }
238}
239
240transitioning builtin OrdinaryToPrimitive_String(implicit context: Context)(
241    input: JSAny): JSPrimitive {
242  try {
243    return TryToPrimitiveMethod(input, ToStringStringConstant())
244        otherwise String;
245  } label String {
246    return TryToPrimitiveMethod(input, ValueOfStringConstant()) otherwise Throw;
247  } label Throw {
248    ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive);
249  }
250}
251
252}  // namespace conversion
253