[builtins] Remove the weird STACK_OVERFLOW builtin.
[platform/upstream/v8.git] / src / runtime.js
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.
4
5 // This files contains runtime support implemented in JavaScript.
6
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'.
10
11
12 // The following declarations are shared with other native JS files.
13 // They are all declared at this one spot to avoid redeclaration errors.
14 var $defaultString;
15 var $NaN;
16 var $nonNumberToNumber;
17 var $nonStringToString;
18 var $sameValue;
19 var $sameValueZero;
20 var $toInteger;
21 var $toLength;
22 var $toNumber;
23 var $toPositiveInteger;
24 var $toPrimitive;
25 var $toString;
26
27 (function(global, utils) {
28
29 %CheckIsBootstrapping();
30
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");
37
38 // ----------------------------------------------------------------------------
39
40 /* -----------------------------------
41 - - -   C o m p a r i s o n   - - -
42 -----------------------------------
43 */
44
45 // ECMA-262 Section 11.9.3.
46 function EQUALS(y) {
47   if (IS_STRING(this) && IS_STRING(y)) return %StringEquals(this, y);
48   var x = this;
49
50   while (true) {
51     if (IS_NUMBER(x)) {
52       while (true) {
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
57           // String or boolean.
58           return %NumberEquals(x, %to_number_fun(y));
59         }
60         y = %to_primitive(y, NO_HINT);
61       }
62     } else if (IS_STRING(x)) {
63       while (true) {
64         if (IS_STRING(y)) return %StringEquals(x, y);
65         if (IS_NUMBER(y)) return %NumberEquals(%to_number_fun(x), y);
66         if (IS_BOOLEAN(y)) {
67           return %NumberEquals(%to_number_fun(x), %to_number_fun(y));
68         }
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);
72       }
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);
80       if (IS_STRING(y)) {
81         return %NumberEquals(%to_number_fun(x), %to_number_fun(y));
82       }
83       if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) return 1;  // not equal
84       // y is object.
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);
92     } else {
93       // x is an object.
94       if (IS_SPEC_OBJECT(y)) return %_ObjectEquals(x, y) ? 0 : 1;
95       if (IS_NULL_OR_UNDEFINED(y)) return 1;  // not equal
96       if (IS_BOOLEAN(y)) {
97         y = %to_number_fun(y);
98       } else if (IS_SYMBOL(y) || IS_SIMD_VALUE(y)) {
99         return 1;  // not equal
100       }
101       x = %to_primitive(x, NO_HINT);
102     }
103   }
104 }
105
106
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) {
110   var left;
111   var right;
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;
116     left = this;
117   } else if (IS_NUMBER(this)) {
118     if (IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
119     if (IS_UNDEFINED(x)) return ncr;
120     left = this;
121   } else if (IS_UNDEFINED(this)) {
122     if (!IS_UNDEFINED(x)) {
123       %to_primitive(x, NUMBER_HINT);
124     }
125     return ncr;
126   } else if (IS_UNDEFINED(x)) {
127     %to_primitive(this, NUMBER_HINT);
128     return ncr;
129   } else {
130     left = %to_primitive(this, NUMBER_HINT);
131   }
132
133   right = %to_primitive(x, NUMBER_HINT);
134   if (IS_STRING(left) && IS_STRING(right)) {
135     return %_StringCompare(left, right);
136   } else {
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);
141   }
142 }
143
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);
148
149   throw %make_type_error(kStrongImplicitConversion);
150 }
151
152
153
154 /* -----------------------------------
155    - - -   A r i t h m e t i c   - - -
156    -----------------------------------
157 */
158
159 // Left operand (this) is already a string.
160 function STRING_ADD_LEFT(y) {
161   if (!IS_STRING(y)) {
162     if (IS_STRING_WRAPPER(y) && %_IsStringWrapperSafeForDefaultValueOf(y)) {
163       y = %_ValueOf(y);
164     } else {
165       y = IS_NUMBER(y)
166           ? %_NumberToString(y)
167           : %to_string_fun(%to_primitive(y, NO_HINT));
168     }
169   }
170   return %_StringAdd(this, y);
171 }
172
173
174 // Right operand (y) is already a string.
175 function STRING_ADD_RIGHT(y) {
176   var x = this;
177   if (!IS_STRING(x)) {
178     if (IS_STRING_WRAPPER(x) && %_IsStringWrapperSafeForDefaultValueOf(x)) {
179       x = %_ValueOf(x);
180     } else {
181       x = IS_NUMBER(x)
182           ? %_NumberToString(x)
183           : %to_string_fun(%to_primitive(x, NO_HINT));
184     }
185   }
186   return %_StringAdd(x, y);
187 }
188
189
190 /* -----------------------------
191    - - -   H e l p e r s   - - -
192    -----------------------------
193 */
194
195 function APPLY_PREPARE(args) {
196   var length;
197
198   // First check that the receiver is callable.
199   if (!IS_CALLABLE(this)) {
200     throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
201                            typeof this);
202   }
203
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) {
210       return length;
211     }
212   }
213
214   length = (args == null) ? 0 : TO_UINT32(args.length);
215
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);
220
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");
224   }
225
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.
228   return length;
229 }
230
231
232 function REFLECT_APPLY_PREPARE(args) {
233   var length;
234
235   // First check that the receiver is callable.
236   if (!IS_CALLABLE(this)) {
237     throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
238                            typeof this);
239   }
240
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) {
247       return length;
248     }
249   }
250
251   if (!IS_SPEC_OBJECT(args)) {
252     throw %make_type_error(kWrongArgs, "Reflect.apply");
253   }
254
255   length = %to_length_fun(args.length);
256
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);
261
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.
264   return length;
265 }
266
267
268 function REFLECT_CONSTRUCT_PREPARE(
269     args, newTarget) {
270   var length;
271   var ctorOk = IS_CALLABLE(this) && %IsConstructor(this);
272   var newTargetOk = IS_CALLABLE(newTarget) && %IsConstructor(newTarget);
273
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) {
281       return length;
282     }
283   }
284
285   if (!ctorOk) {
286     if (!IS_CALLABLE(this)) {
287       throw %make_type_error(kCalledNonCallable, %to_string_fun(this));
288     } else {
289       throw %make_type_error(kNotConstructor, %to_string_fun(this));
290     }
291   }
292
293   if (!newTargetOk) {
294     if (!IS_CALLABLE(newTarget)) {
295       throw %make_type_error(kCalledNonCallable, %to_string_fun(newTarget));
296     } else {
297       throw %make_type_error(kNotConstructor, %to_string_fun(newTarget));
298     }
299   }
300
301   if (!IS_SPEC_OBJECT(args)) {
302     throw %make_type_error(kWrongArgs, "Reflect.construct");
303   }
304
305   length = %to_length_fun(args.length);
306
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);
311
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.
314   return length;
315 }
316
317
318 function CONCAT_ITERABLE_TO_ARRAY(iterable) {
319   return %concat_iterable_to_array(this, iterable);
320 };
321
322
323 /* -------------------------------------
324    - - -   C o n v e r s i o n s   - - -
325    -------------------------------------
326 */
327
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);
334 }
335
336
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));
343   return true;
344 }
345
346
347 // ECMA-262, section 9.3, page 31.
348 function ToNumber(x) {
349   if (IS_NUMBER(x)) return x;
350   if (IS_STRING(x)) {
351     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
352                                     : %StringToNumber(x);
353   }
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));
358 }
359
360 function NonNumberToNumber(x) {
361   if (IS_STRING(x)) {
362     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
363                                     : %StringToNumber(x);
364   }
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));
369 }
370
371
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));
380 }
381
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));
388 }
389
390
391 // ECMA-262, section 9.4, page 34.
392 function ToInteger(x) {
393   if (%_IsSmi(x)) return x;
394   return %NumberToInteger(ToNumber(x));
395 }
396
397
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;
404 }
405
406
407 // ES5, section 9.12
408 function SameValue(x, y) {
409   if (typeof x != typeof y) return false;
410   if (IS_NUMBER(x)) {
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)) {
414       return false;
415     }
416   }
417   if (IS_SIMD_VALUE(x)) return %SimdSameValue(x, y);
418   return x === y;
419 }
420
421
422 // ES6, section 7.2.4
423 function SameValueZero(x, y) {
424   if (typeof x != typeof y) return false;
425   if (IS_NUMBER(x)) {
426     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
427   }
428   if (IS_SIMD_VALUE(x)) return %SimdSameValueZero(x, y);
429   return x === y;
430 }
431
432
433 function ConcatIterableToArray(target, iterable) {
434    var index = target.length;
435    for (var element of iterable) {
436      %AddElement(target, index++, element);
437    }
438    return target;
439 }
440
441
442 /* ---------------------------------
443    - - -   U t i l i t i e s   - - -
444    ---------------------------------
445 */
446
447 // Returns if the given x is a primitive value - not an object or a
448 // function.
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);
454 }
455
456
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);
463 }
464
465
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;
474   }
475   var toString = x.toString;
476   if (IS_CALLABLE(toString)) {
477     var s = %_Call(toString, x);
478     if (IsPrimitive(s)) return s;
479   }
480   throw MakeTypeError(kCannotConvertToPrimitive);
481 }
482
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;
491     }
492
493     var valueOf = x.valueOf;
494     if (IS_CALLABLE(valueOf)) {
495       var v = %_Call(valueOf, x);
496       if (IsPrimitive(v)) return v;
497     }
498   }
499   throw MakeTypeError(kCannotConvertToPrimitive);
500 }
501
502 function ToPositiveInteger(x, rangeErrorIndex) {
503   var i = TO_INTEGER_MAP_MINUS_ZERO(x);
504   if (i < 0) throw MakeRangeError(rangeErrorIndex);
505   return i;
506 }
507
508 //----------------------------------------------------------------------------
509
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));
516
517 // ----------------------------------------------------------------------------
518 // Exports
519
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;
532
533 %InstallToContext([
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,
543 ]);
544
545 %InstallToContext([
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,
554 ]);
555
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;
562 });
563
564 })