749feb68a8e390b827e7be7ec347990a4ea712dc
[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 function STACK_OVERFLOW(length) {
324   throw %make_range_error(kStackOverflow);
325 }
326
327
328 /* -------------------------------------
329    - - -   C o n v e r s i o n s   - - -
330    -------------------------------------
331 */
332
333 // ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
334 // (1) for number hint, and (2) for string hint.
335 function ToPrimitive(x, hint) {
336   if (!IS_SPEC_OBJECT(x)) return x;
337   if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
338   return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x);
339 }
340
341
342 // ECMA-262, section 9.2, page 30
343 function ToBoolean(x) {
344   if (IS_BOOLEAN(x)) return x;
345   if (IS_STRING(x)) return x.length != 0;
346   if (x == null) return false;
347   if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
348   return true;
349 }
350
351
352 // ECMA-262, section 9.3, page 31.
353 function ToNumber(x) {
354   if (IS_NUMBER(x)) return x;
355   if (IS_STRING(x)) {
356     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
357                                     : %StringToNumber(x);
358   }
359   if (IS_BOOLEAN(x)) return x ? 1 : 0;
360   if (IS_UNDEFINED(x)) return NAN;
361   // Types that can't be converted to number are caught in DefaultNumber.
362   return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
363 }
364
365 function NonNumberToNumber(x) {
366   if (IS_STRING(x)) {
367     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
368                                     : %StringToNumber(x);
369   }
370   if (IS_BOOLEAN(x)) return x ? 1 : 0;
371   if (IS_UNDEFINED(x)) return NAN;
372   // Types that can't be converted to number are caught in DefaultNumber.
373   return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
374 }
375
376
377 // ECMA-262, section 9.8, page 35.
378 function ToString(x) {
379   if (IS_STRING(x)) return x;
380   if (IS_NUMBER(x)) return %_NumberToString(x);
381   if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
382   if (IS_UNDEFINED(x)) return 'undefined';
383   // Types that can't be converted to string are caught in DefaultString.
384   return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
385 }
386
387 function NonStringToString(x) {
388   if (IS_NUMBER(x)) return %_NumberToString(x);
389   if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
390   if (IS_UNDEFINED(x)) return 'undefined';
391   // Types that can't be converted to string are caught in DefaultString.
392   return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
393 }
394
395
396 // ECMA-262, section 9.4, page 34.
397 function ToInteger(x) {
398   if (%_IsSmi(x)) return x;
399   return %NumberToInteger(ToNumber(x));
400 }
401
402
403 // ES6, draft 08-24-14, section 7.1.15
404 function ToLength(arg) {
405   arg = ToInteger(arg);
406   if (arg < 0) return 0;
407   return arg < GlobalNumber.MAX_SAFE_INTEGER ? arg
408                                              : GlobalNumber.MAX_SAFE_INTEGER;
409 }
410
411
412 // ES5, section 9.12
413 function SameValue(x, y) {
414   if (typeof x != typeof y) return false;
415   if (IS_NUMBER(x)) {
416     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
417     // x is +0 and y is -0 or vice versa.
418     if (x === 0 && y === 0 && %_IsMinusZero(x) != %_IsMinusZero(y)) {
419       return false;
420     }
421   }
422   if (IS_SIMD_VALUE(x)) return %SimdSameValue(x, y);
423   return x === y;
424 }
425
426
427 // ES6, section 7.2.4
428 function SameValueZero(x, y) {
429   if (typeof x != typeof y) return false;
430   if (IS_NUMBER(x)) {
431     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
432   }
433   if (IS_SIMD_VALUE(x)) return %SimdSameValueZero(x, y);
434   return x === y;
435 }
436
437
438 function ConcatIterableToArray(target, iterable) {
439    var index = target.length;
440    for (var element of iterable) {
441      %AddElement(target, index++, element);
442    }
443    return target;
444 }
445
446
447 /* ---------------------------------
448    - - -   U t i l i t i e s   - - -
449    ---------------------------------
450 */
451
452 // Returns if the given x is a primitive value - not an object or a
453 // function.
454 function IsPrimitive(x) {
455   // Even though the type of null is "object", null is still
456   // considered a primitive value. IS_SPEC_OBJECT handles this correctly
457   // (i.e., it will return false if x is null).
458   return !IS_SPEC_OBJECT(x);
459 }
460
461
462 // ES6, draft 10-14-14, section 22.1.3.1.1
463 function IsConcatSpreadable(O) {
464   if (!IS_SPEC_OBJECT(O)) return false;
465   var spreadable = O[isConcatSpreadableSymbol];
466   if (IS_UNDEFINED(spreadable)) return IS_ARRAY(O);
467   return ToBoolean(spreadable);
468 }
469
470
471 // ECMA-262, section 8.6.2.6, page 28.
472 function DefaultNumber(x) {
473   var valueOf = x.valueOf;
474   if (IS_CALLABLE(valueOf)) {
475     var v = %_Call(valueOf, x);
476     if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber);
477     if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber);
478     if (IsPrimitive(v)) return v;
479   }
480   var toString = x.toString;
481   if (IS_CALLABLE(toString)) {
482     var s = %_Call(toString, x);
483     if (IsPrimitive(s)) return s;
484   }
485   throw MakeTypeError(kCannotConvertToPrimitive);
486 }
487
488 // ECMA-262, section 8.6.2.6, page 28.
489 function DefaultString(x) {
490   if (!IS_SYMBOL_WRAPPER(x)) {
491     if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString);
492     var toString = x.toString;
493     if (IS_CALLABLE(toString)) {
494       var s = %_Call(toString, x);
495       if (IsPrimitive(s)) return s;
496     }
497
498     var valueOf = x.valueOf;
499     if (IS_CALLABLE(valueOf)) {
500       var v = %_Call(valueOf, x);
501       if (IsPrimitive(v)) return v;
502     }
503   }
504   throw MakeTypeError(kCannotConvertToPrimitive);
505 }
506
507 function ToPositiveInteger(x, rangeErrorIndex) {
508   var i = TO_INTEGER_MAP_MINUS_ZERO(x);
509   if (i < 0) throw MakeRangeError(rangeErrorIndex);
510   return i;
511 }
512
513 //----------------------------------------------------------------------------
514
515 // NOTE: Setting the prototype for Array must take place as early as
516 // possible due to code generation for array literals.  When
517 // generating code for a array literal a boilerplate array is created
518 // that is cloned when running the code.  It is essential that the
519 // boilerplate gets the right prototype.
520 %FunctionSetPrototype(GlobalArray, new GlobalArray(0));
521
522 // ----------------------------------------------------------------------------
523 // Exports
524
525 $defaultString = DefaultString;
526 $NaN = %GetRootNaN();
527 $nonNumberToNumber = NonNumberToNumber;
528 $nonStringToString = NonStringToString;
529 $sameValue = SameValue;
530 $sameValueZero = SameValueZero;
531 $toInteger = ToInteger;
532 $toLength = ToLength;
533 $toNumber = ToNumber;
534 $toPositiveInteger = ToPositiveInteger;
535 $toPrimitive = ToPrimitive;
536 $toString = ToString;
537
538 %InstallToContext([
539   "apply_prepare_builtin", APPLY_PREPARE,
540   "compare_builtin", COMPARE,
541   "compare_strong_builtin", COMPARE_STRONG,
542   "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
543   "equals_builtin", EQUALS,
544   "reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE,
545   "reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE,
546   "stack_overflow_builtin", STACK_OVERFLOW,
547   "string_add_left_builtin", STRING_ADD_LEFT,
548   "string_add_right_builtin", STRING_ADD_RIGHT,
549 ]);
550
551 %InstallToContext([
552   "concat_iterable_to_array", ConcatIterableToArray,
553   "non_number_to_number", NonNumberToNumber,
554   "non_string_to_string", NonStringToString,
555   "to_integer_fun", ToInteger,
556   "to_length_fun", ToLength,
557   "to_number_fun", ToNumber,
558   "to_primitive", ToPrimitive,
559   "to_string_fun", ToString,
560 ]);
561
562 utils.Export(function(to) {
563   to.ToBoolean = ToBoolean;
564   to.ToLength = ToLength;
565   to.ToNumber = ToNumber;
566   to.ToPrimitive = ToPrimitive;
567   to.ToString = ToString;
568 });
569
570 })