1 // Copyright 2006-2008 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.
5 // This files contains runtime support implemented in JavaScript.
7 // CAUTION: Some of the functions specified in this file are called
8 // directly from compiled code. These are the functions with names in
9 // ALL CAPS. The compiled code passes the first argument in 'this'.
12 // The following declarations are shared with other native JS files.
13 // They are all declared at this one spot to avoid redeclaration errors.
16 var $nonNumberToNumber;
17 var $nonStringToString;
23 var $toPositiveInteger;
27 (function(global, utils) {
29 %CheckIsBootstrapping();
31 var GlobalArray = global.Array;
32 var GlobalBoolean = global.Boolean;
33 var GlobalString = global.String;
34 var GlobalNumber = global.Number;
35 var isConcatSpreadableSymbol =
36 utils.ImportNow("is_concat_spreadable_symbol");
38 // ----------------------------------------------------------------------------
40 /* -----------------------------------
41 - - - C o m p a r i s o n - - -
42 -----------------------------------
45 // ECMA-262 Section 11.9.3.
47 if (IS_STRING(this) && IS_STRING(y)) return %StringEquals(this, y);
53 if (IS_NUMBER(y)) return %NumberEquals(x, y);
54 if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
55 if (!IS_SPEC_OBJECT(y)) {
56 if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) return 1; // not equal
58 return %NumberEquals(x, %to_number_fun(y));
60 y = %to_primitive(y, NO_HINT);
62 } else if (IS_STRING(x)) {
64 if (IS_STRING(y)) return %StringEquals(x, y);
65 if (IS_NUMBER(y)) return %NumberEquals(%to_number_fun(x), y);
67 return %NumberEquals(%to_number_fun(x), %to_number_fun(y));
69 if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
70 if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) return 1; // not equal
71 y = %to_primitive(y, NO_HINT);
73 } else if (IS_SYMBOL(x)) {
74 if (IS_SYMBOL(y)) return %_ObjectEquals(x, y) ? 0 : 1;
75 return 1; // not equal
76 } else if (IS_BOOLEAN(x)) {
77 if (IS_BOOLEAN(y)) return %_ObjectEquals(x, y) ? 0 : 1;
78 if (IS_NULL_OR_UNDEFINED(y)) return 1;
79 if (IS_NUMBER(y)) return %NumberEquals(%to_number_fun(x), y);
81 return %NumberEquals(%to_number_fun(x), %to_number_fun(y));
83 if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) return 1; // not equal
85 x = %to_number_fun(x);
86 y = %to_primitive(y, NO_HINT);
87 } else if (IS_NULL_OR_UNDEFINED(x)) {
88 return IS_NULL_OR_UNDEFINED(y) ? 0 : 1;
89 } else if (IS_SIMD_VALUE(x)) {
90 if (!IS_SIMD_VALUE(y)) return 1; // not equal
91 return %SimdEquals(x, y);
94 if (IS_SPEC_OBJECT(y)) return %_ObjectEquals(x, y) ? 0 : 1;
95 if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
97 y = %to_number_fun(y);
98 } else if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) {
99 return 1; // not equal
101 x = %to_primitive(x, NO_HINT);
107 // ECMA-262, section 11.8.5, page 53. The 'ncr' parameter is used as
108 // the result when either (or both) the operands are NaN.
109 function COMPARE(x, ncr) {
112 // Fast cases for string, numbers and undefined compares.
113 if (IS_STRING(this)) {
114 if (IS_STRING(x)) return %_StringCompare(this, x);
115 if (IS_UNDEFINED(x)) return ncr;
117 } else if (IS_NUMBER(this)) {
118 if (IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
119 if (IS_UNDEFINED(x)) return ncr;
121 } else if (IS_UNDEFINED(this)) {
122 if (!IS_UNDEFINED(x)) {
123 %to_primitive(x, NUMBER_HINT);
126 } else if (IS_UNDEFINED(x)) {
127 %to_primitive(this, NUMBER_HINT);
130 left = %to_primitive(this, NUMBER_HINT);
133 right = %to_primitive(x, NUMBER_HINT);
134 if (IS_STRING(left) && IS_STRING(right)) {
135 return %_StringCompare(left, right);
137 var left_number = %to_number_fun(left);
138 var right_number = %to_number_fun(right);
139 if (NUMBER_IS_NAN(left_number) || NUMBER_IS_NAN(right_number)) return ncr;
140 return %NumberCompare(left_number, right_number, ncr);
144 // Strong mode COMPARE throws if an implicit conversion would be performed
145 function COMPARE_STRONG(x, ncr) {
146 if (IS_STRING(this) && IS_STRING(x)) return %_StringCompare(this, x);
147 if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
149 throw %make_type_error(kStrongImplicitConversion);
154 /* -----------------------------------
155 - - - A r i t h m e t i c - - -
156 -----------------------------------
159 // Left operand (this) is already a string.
160 function STRING_ADD_LEFT(y) {
162 if (IS_STRING_WRAPPER(y) && %_IsStringWrapperSafeForDefaultValueOf(y)) {
166 ? %_NumberToString(y)
167 : %to_string_fun(%to_primitive(y, NO_HINT));
170 return %_StringAdd(this, y);
174 // Right operand (y) is already a string.
175 function STRING_ADD_RIGHT(y) {
178 if (IS_STRING_WRAPPER(x) && %_IsStringWrapperSafeForDefaultValueOf(x)) {
182 ? %_NumberToString(x)
183 : %to_string_fun(%to_primitive(x, NO_HINT));
186 return %_StringAdd(x, y);
190 /* -----------------------------
191 - - - H e l p e r s - - -
192 -----------------------------
195 function APPLY_PREPARE(args) {
198 // First check that the receiver is callable.
199 if (!IS_CALLABLE(this)) {
200 throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
204 // First check whether length is a positive Smi and args is an
205 // array. This is the fast case. If this fails, we do the slow case
206 // that takes care of more eventualities.
207 if (IS_ARRAY(args)) {
208 length = args.length;
209 if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
214 length = (args == null) ? 0 : TO_UINT32(args.length);
216 // We can handle any number of apply arguments if the stack is
217 // big enough, but sanity check the value to avoid overflow when
218 // multiplying with pointer size.
219 if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
221 // Make sure the arguments list has the right type.
222 if (args != null && !IS_SPEC_OBJECT(args)) {
223 throw %make_type_error(kWrongArgs, "Function.prototype.apply");
226 // Return the length which is the number of arguments to copy to the
227 // stack. It is guaranteed to be a small integer at this point.
232 function REFLECT_APPLY_PREPARE(args) {
235 // First check that the receiver is callable.
236 if (!IS_CALLABLE(this)) {
237 throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
241 // First check whether length is a positive Smi and args is an
242 // array. This is the fast case. If this fails, we do the slow case
243 // that takes care of more eventualities.
244 if (IS_ARRAY(args)) {
245 length = args.length;
246 if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
251 if (!IS_SPEC_OBJECT(args)) {
252 throw %make_type_error(kWrongArgs, "Reflect.apply");
255 length = %to_length_fun(args.length);
257 // We can handle any number of apply arguments if the stack is
258 // big enough, but sanity check the value to avoid overflow when
259 // multiplying with pointer size.
260 if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
262 // Return the length which is the number of arguments to copy to the
263 // stack. It is guaranteed to be a small integer at this point.
268 function REFLECT_CONSTRUCT_PREPARE(
271 var ctorOk = IS_CALLABLE(this) && %IsConstructor(this);
272 var newTargetOk = IS_CALLABLE(newTarget) && %IsConstructor(newTarget);
274 // First check whether length is a positive Smi and args is an
275 // array. This is the fast case. If this fails, we do the slow case
276 // that takes care of more eventualities.
277 if (IS_ARRAY(args)) {
278 length = args.length;
279 if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
280 ctorOk && newTargetOk) {
286 if (!IS_CALLABLE(this)) {
287 throw %make_type_error(kCalledNonCallable, %to_string_fun(this));
289 throw %make_type_error(kNotConstructor, %to_string_fun(this));
294 if (!IS_CALLABLE(newTarget)) {
295 throw %make_type_error(kCalledNonCallable, %to_string_fun(newTarget));
297 throw %make_type_error(kNotConstructor, %to_string_fun(newTarget));
301 if (!IS_SPEC_OBJECT(args)) {
302 throw %make_type_error(kWrongArgs, "Reflect.construct");
305 length = %to_length_fun(args.length);
307 // We can handle any number of apply arguments if the stack is
308 // big enough, but sanity check the value to avoid overflow when
309 // multiplying with pointer size.
310 if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
312 // Return the length which is the number of arguments to copy to the
313 // stack. It is guaranteed to be a small integer at this point.
318 function CONCAT_ITERABLE_TO_ARRAY(iterable) {
319 return %concat_iterable_to_array(this, iterable);
323 /* -------------------------------------
324 - - - C o n v e r s i o n s - - -
325 -------------------------------------
328 // ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
329 // (1) for number hint, and (2) for string hint.
330 function ToPrimitive(x, hint) {
331 if (!IS_SPEC_OBJECT(x)) return x;
332 if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
333 return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x);
337 // ECMA-262, section 9.2, page 30
338 function ToBoolean(x) {
339 if (IS_BOOLEAN(x)) return x;
340 if (IS_STRING(x)) return x.length != 0;
341 if (x == null) return false;
342 if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
347 // ECMA-262, section 9.3, page 31.
348 function ToNumber(x) {
349 if (IS_NUMBER(x)) return x;
351 return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
352 : %StringToNumber(x);
354 if (IS_BOOLEAN(x)) return x ? 1 : 0;
355 if (IS_UNDEFINED(x)) return NAN;
356 // Types that can't be converted to number are caught in DefaultNumber.
357 return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
360 function NonNumberToNumber(x) {
362 return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
363 : %StringToNumber(x);
365 if (IS_BOOLEAN(x)) return x ? 1 : 0;
366 if (IS_UNDEFINED(x)) return NAN;
367 // Types that can't be converted to number are caught in DefaultNumber.
368 return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
372 // ECMA-262, section 9.8, page 35.
373 function ToString(x) {
374 if (IS_STRING(x)) return x;
375 if (IS_NUMBER(x)) return %_NumberToString(x);
376 if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
377 if (IS_UNDEFINED(x)) return 'undefined';
378 // Types that can't be converted to string are caught in DefaultString.
379 return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
382 function NonStringToString(x) {
383 if (IS_NUMBER(x)) return %_NumberToString(x);
384 if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
385 if (IS_UNDEFINED(x)) return 'undefined';
386 // Types that can't be converted to string are caught in DefaultString.
387 return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
391 // ECMA-262, section 9.4, page 34.
392 function ToInteger(x) {
393 if (%_IsSmi(x)) return x;
394 return %NumberToInteger(ToNumber(x));
398 // ES6, draft 08-24-14, section 7.1.15
399 function ToLength(arg) {
400 arg = ToInteger(arg);
401 if (arg < 0) return 0;
402 return arg < GlobalNumber.MAX_SAFE_INTEGER ? arg
403 : GlobalNumber.MAX_SAFE_INTEGER;
408 function SameValue(x, y) {
409 if (typeof x != typeof y) return false;
411 if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
412 // x is +0 and y is -0 or vice versa.
413 if (x === 0 && y === 0 && %_IsMinusZero(x) != %_IsMinusZero(y)) {
417 if (IS_SIMD_VALUE(x)) return %SimdSameValue(x, y);
422 // ES6, section 7.2.4
423 function SameValueZero(x, y) {
424 if (typeof x != typeof y) return false;
426 if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
428 if (IS_SIMD_VALUE(x)) return %SimdSameValueZero(x, y);
433 function ConcatIterableToArray(target, iterable) {
434 var index = target.length;
435 for (var element of iterable) {
436 %AddElement(target, index++, element);
442 /* ---------------------------------
443 - - - U t i l i t i e s - - -
444 ---------------------------------
447 // Returns if the given x is a primitive value - not an object or a
449 function IsPrimitive(x) {
450 // Even though the type of null is "object", null is still
451 // considered a primitive value. IS_SPEC_OBJECT handles this correctly
452 // (i.e., it will return false if x is null).
453 return !IS_SPEC_OBJECT(x);
457 // ES6, draft 10-14-14, section 22.1.3.1.1
458 function IsConcatSpreadable(O) {
459 if (!IS_SPEC_OBJECT(O)) return false;
460 var spreadable = O[isConcatSpreadableSymbol];
461 if (IS_UNDEFINED(spreadable)) return IS_ARRAY(O);
462 return ToBoolean(spreadable);
466 // ECMA-262, section 8.6.2.6, page 28.
467 function DefaultNumber(x) {
468 var valueOf = x.valueOf;
469 if (IS_CALLABLE(valueOf)) {
470 var v = %_Call(valueOf, x);
471 if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber);
472 if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber);
473 if (IsPrimitive(v)) return v;
475 var toString = x.toString;
476 if (IS_CALLABLE(toString)) {
477 var s = %_Call(toString, x);
478 if (IsPrimitive(s)) return s;
480 throw MakeTypeError(kCannotConvertToPrimitive);
483 // ECMA-262, section 8.6.2.6, page 28.
484 function DefaultString(x) {
485 if (!IS_SYMBOL_WRAPPER(x)) {
486 if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString);
487 var toString = x.toString;
488 if (IS_CALLABLE(toString)) {
489 var s = %_Call(toString, x);
490 if (IsPrimitive(s)) return s;
493 var valueOf = x.valueOf;
494 if (IS_CALLABLE(valueOf)) {
495 var v = %_Call(valueOf, x);
496 if (IsPrimitive(v)) return v;
499 throw MakeTypeError(kCannotConvertToPrimitive);
502 function ToPositiveInteger(x, rangeErrorIndex) {
503 var i = TO_INTEGER_MAP_MINUS_ZERO(x);
504 if (i < 0) throw MakeRangeError(rangeErrorIndex);
508 //----------------------------------------------------------------------------
510 // NOTE: Setting the prototype for Array must take place as early as
511 // possible due to code generation for array literals. When
512 // generating code for a array literal a boilerplate array is created
513 // that is cloned when running the code. It is essential that the
514 // boilerplate gets the right prototype.
515 %FunctionSetPrototype(GlobalArray, new GlobalArray(0));
517 // ----------------------------------------------------------------------------
520 $defaultString = DefaultString;
521 $NaN = %GetRootNaN();
522 $nonNumberToNumber = NonNumberToNumber;
523 $nonStringToString = NonStringToString;
524 $sameValue = SameValue;
525 $sameValueZero = SameValueZero;
526 $toInteger = ToInteger;
527 $toLength = ToLength;
528 $toNumber = ToNumber;
529 $toPositiveInteger = ToPositiveInteger;
530 $toPrimitive = ToPrimitive;
531 $toString = ToString;
534 "apply_prepare_builtin", APPLY_PREPARE,
535 "compare_builtin", COMPARE,
536 "compare_strong_builtin", COMPARE_STRONG,
537 "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
538 "equals_builtin", EQUALS,
539 "reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE,
540 "reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE,
541 "string_add_left_builtin", STRING_ADD_LEFT,
542 "string_add_right_builtin", STRING_ADD_RIGHT,
546 "concat_iterable_to_array", ConcatIterableToArray,
547 "non_number_to_number", NonNumberToNumber,
548 "non_string_to_string", NonStringToString,
549 "to_integer_fun", ToInteger,
550 "to_length_fun", ToLength,
551 "to_number_fun", ToNumber,
552 "to_primitive", ToPrimitive,
553 "to_string_fun", ToString,
556 utils.Export(function(to) {
557 to.ToBoolean = ToBoolean;
558 to.ToLength = ToLength;
559 to.ToNumber = ToNumber;
560 to.ToPrimitive = ToPrimitive;
561 to.ToString = ToString;