e2eec4f17e9c61594c236846691d3047800657c6
[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 $toString;
25
26 var harmony_tolength = false;
27
28 (function(global, utils) {
29
30 %CheckIsBootstrapping();
31
32 var GlobalArray = global.Array;
33 var GlobalBoolean = global.Boolean;
34 var GlobalString = global.String;
35 var isConcatSpreadableSymbol =
36     utils.ImportNow("is_concat_spreadable_symbol");
37
38 // ----------------------------------------------------------------------------
39
40 /* -----------------------------
41    - - -   H e l p e r s   - - -
42    -----------------------------
43 */
44
45 function APPLY_PREPARE(args) {
46   var length;
47
48   // First check that the receiver is callable.
49   if (!IS_CALLABLE(this)) {
50     throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
51                            typeof this);
52   }
53
54   // First check whether length is a positive Smi and args is an
55   // array. This is the fast case. If this fails, we do the slow case
56   // that takes care of more eventualities.
57   if (IS_ARRAY(args)) {
58     length = args.length;
59     if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
60       return length;
61     }
62   }
63
64   length = (args == null) ? 0 : TO_UINT32(args.length);
65
66   // We can handle any number of apply arguments if the stack is
67   // big enough, but sanity check the value to avoid overflow when
68   // multiplying with pointer size.
69   if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
70
71   // Make sure the arguments list has the right type.
72   if (args != null && !IS_SPEC_OBJECT(args)) {
73     throw %make_type_error(kWrongArgs, "Function.prototype.apply");
74   }
75
76   // Return the length which is the number of arguments to copy to the
77   // stack. It is guaranteed to be a small integer at this point.
78   return length;
79 }
80
81
82 function REFLECT_APPLY_PREPARE(args) {
83   var length;
84
85   // First check that the receiver is callable.
86   if (!IS_CALLABLE(this)) {
87     throw %make_type_error(kApplyNonFunction, %to_string_fun(this),
88                            typeof this);
89   }
90
91   // First check whether length is a positive Smi and args is an
92   // array. This is the fast case. If this fails, we do the slow case
93   // that takes care of more eventualities.
94   if (IS_ARRAY(args)) {
95     length = args.length;
96     if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
97       return length;
98     }
99   }
100
101   if (!IS_SPEC_OBJECT(args)) {
102     throw %make_type_error(kWrongArgs, "Reflect.apply");
103   }
104
105   length = %to_length_fun(args.length);
106
107   // We can handle any number of apply arguments if the stack is
108   // big enough, but sanity check the value to avoid overflow when
109   // multiplying with pointer size.
110   if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
111
112   // Return the length which is the number of arguments to copy to the
113   // stack. It is guaranteed to be a small integer at this point.
114   return length;
115 }
116
117
118 function REFLECT_CONSTRUCT_PREPARE(
119     args, newTarget) {
120   var length;
121   var ctorOk = IS_CALLABLE(this) && %IsConstructor(this);
122   var newTargetOk = IS_CALLABLE(newTarget) && %IsConstructor(newTarget);
123
124   // First check whether length is a positive Smi and args is an
125   // array. This is the fast case. If this fails, we do the slow case
126   // that takes care of more eventualities.
127   if (IS_ARRAY(args)) {
128     length = args.length;
129     if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
130         ctorOk && newTargetOk) {
131       return length;
132     }
133   }
134
135   if (!ctorOk) {
136     if (!IS_CALLABLE(this)) {
137       throw %make_type_error(kCalledNonCallable, %to_string_fun(this));
138     } else {
139       throw %make_type_error(kNotConstructor, %to_string_fun(this));
140     }
141   }
142
143   if (!newTargetOk) {
144     if (!IS_CALLABLE(newTarget)) {
145       throw %make_type_error(kCalledNonCallable, %to_string_fun(newTarget));
146     } else {
147       throw %make_type_error(kNotConstructor, %to_string_fun(newTarget));
148     }
149   }
150
151   if (!IS_SPEC_OBJECT(args)) {
152     throw %make_type_error(kWrongArgs, "Reflect.construct");
153   }
154
155   length = %to_length_fun(args.length);
156
157   // We can handle any number of apply arguments if the stack is
158   // big enough, but sanity check the value to avoid overflow when
159   // multiplying with pointer size.
160   if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
161
162   // Return the length which is the number of arguments to copy to the
163   // stack. It is guaranteed to be a small integer at this point.
164   return length;
165 }
166
167
168 function CONCAT_ITERABLE_TO_ARRAY(iterable) {
169   return %concat_iterable_to_array(this, iterable);
170 };
171
172
173 /* -------------------------------------
174    - - -   C o n v e r s i o n s   - - -
175    -------------------------------------
176 */
177
178 // ECMA-262, section 9.2, page 30
179 function ToBoolean(x) {
180   if (IS_BOOLEAN(x)) return x;
181   if (IS_STRING(x)) return x.length != 0;
182   if (x == null) return false;
183   if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
184   return true;
185 }
186
187
188 // ECMA-262, section 9.3, page 31.
189 function ToNumber(x) {
190   if (IS_NUMBER(x)) return x;
191   if (IS_STRING(x)) {
192     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
193                                     : %StringToNumber(x);
194   }
195   if (IS_BOOLEAN(x)) return x ? 1 : 0;
196   if (IS_UNDEFINED(x)) return NAN;
197   // Types that can't be converted to number are caught in DefaultNumber.
198   return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
199 }
200
201 function NonNumberToNumber(x) {
202   if (IS_STRING(x)) {
203     return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
204                                     : %StringToNumber(x);
205   }
206   if (IS_BOOLEAN(x)) return x ? 1 : 0;
207   if (IS_UNDEFINED(x)) return NAN;
208   // Types that can't be converted to number are caught in DefaultNumber.
209   return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
210 }
211
212
213 // ECMA-262, section 9.8, page 35.
214 function ToString(x) {
215   if (IS_STRING(x)) return x;
216   if (IS_NUMBER(x)) return %_NumberToString(x);
217   if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
218   if (IS_UNDEFINED(x)) return 'undefined';
219   // Types that can't be converted to string are caught in DefaultString.
220   return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
221 }
222
223 function NonStringToString(x) {
224   if (IS_NUMBER(x)) return %_NumberToString(x);
225   if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
226   if (IS_UNDEFINED(x)) return 'undefined';
227   // Types that can't be converted to string are caught in DefaultString.
228   return (IS_NULL(x)) ? 'null' : ToString(DefaultString(x));
229 }
230
231
232 // ECMA-262, section 9.4, page 34.
233 function ToInteger(x) {
234   if (%_IsSmi(x)) return x;
235   return %NumberToInteger(ToNumber(x));
236 }
237
238
239 // ES6, draft 08-24-14, section 7.1.15
240 function ToLength(arg) {
241   arg = ToInteger(arg);
242   if (arg < 0) return 0;
243   return arg < kMaxSafeInteger ? arg : kMaxSafeInteger;
244 }
245
246
247 // ES5, section 9.12
248 function SameValue(x, y) {
249   if (typeof x != typeof y) return false;
250   if (IS_NUMBER(x)) {
251     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
252     // x is +0 and y is -0 or vice versa.
253     if (x === 0 && y === 0 && %_IsMinusZero(x) != %_IsMinusZero(y)) {
254       return false;
255     }
256   }
257   if (IS_SIMD_VALUE(x)) return %SimdSameValue(x, y);
258   return x === y;
259 }
260
261
262 // ES6, section 7.2.4
263 function SameValueZero(x, y) {
264   if (typeof x != typeof y) return false;
265   if (IS_NUMBER(x)) {
266     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
267   }
268   if (IS_SIMD_VALUE(x)) return %SimdSameValueZero(x, y);
269   return x === y;
270 }
271
272
273 function ConcatIterableToArray(target, iterable) {
274    var index = target.length;
275    for (var element of iterable) {
276      %AddElement(target, index++, element);
277    }
278    return target;
279 }
280
281
282 /* ---------------------------------
283    - - -   U t i l i t i e s   - - -
284    ---------------------------------
285 */
286
287 // Returns if the given x is a primitive value - not an object or a
288 // function.
289 function IsPrimitive(x) {
290   // Even though the type of null is "object", null is still
291   // considered a primitive value. IS_SPEC_OBJECT handles this correctly
292   // (i.e., it will return false if x is null).
293   return !IS_SPEC_OBJECT(x);
294 }
295
296
297 // ES6, draft 10-14-14, section 22.1.3.1.1
298 function IsConcatSpreadable(O) {
299   if (!IS_SPEC_OBJECT(O)) return false;
300   var spreadable = O[isConcatSpreadableSymbol];
301   if (IS_UNDEFINED(spreadable)) return IS_ARRAY(O);
302   return ToBoolean(spreadable);
303 }
304
305
306 // ECMA-262, section 8.6.2.6, page 28.
307 function DefaultNumber(x) {
308   var valueOf = x.valueOf;
309   if (IS_CALLABLE(valueOf)) {
310     var v = %_Call(valueOf, x);
311     if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber);
312     if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber);
313     if (IsPrimitive(v)) return v;
314   }
315   var toString = x.toString;
316   if (IS_CALLABLE(toString)) {
317     var s = %_Call(toString, x);
318     if (IsPrimitive(s)) return s;
319   }
320   throw MakeTypeError(kCannotConvertToPrimitive);
321 }
322
323 // ECMA-262, section 8.6.2.6, page 28.
324 function DefaultString(x) {
325   if (!IS_SYMBOL_WRAPPER(x)) {
326     if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString);
327     var toString = x.toString;
328     if (IS_CALLABLE(toString)) {
329       var s = %_Call(toString, x);
330       if (IsPrimitive(s)) return s;
331     }
332
333     var valueOf = x.valueOf;
334     if (IS_CALLABLE(valueOf)) {
335       var v = %_Call(valueOf, x);
336       if (IsPrimitive(v)) return v;
337     }
338   }
339   throw MakeTypeError(kCannotConvertToPrimitive);
340 }
341
342 function ToPositiveInteger(x, rangeErrorIndex) {
343   var i = TO_INTEGER_MAP_MINUS_ZERO(x);
344   if (i < 0) throw MakeRangeError(rangeErrorIndex);
345   return i;
346 }
347
348 //----------------------------------------------------------------------------
349
350 // NOTE: Setting the prototype for Array must take place as early as
351 // possible due to code generation for array literals.  When
352 // generating code for a array literal a boilerplate array is created
353 // that is cloned when running the code.  It is essential that the
354 // boilerplate gets the right prototype.
355 %FunctionSetPrototype(GlobalArray, new GlobalArray(0));
356
357 // ----------------------------------------------------------------------------
358 // Exports
359
360 $defaultString = DefaultString;
361 $NaN = %GetRootNaN();
362 $nonNumberToNumber = NonNumberToNumber;
363 $nonStringToString = NonStringToString;
364 $sameValue = SameValue;
365 $sameValueZero = SameValueZero;
366 $toInteger = ToInteger;
367 $toLength = ToLength;
368 $toNumber = ToNumber;
369 $toPositiveInteger = ToPositiveInteger;
370 $toString = ToString;
371
372 %InstallToContext([
373   "apply_prepare_builtin", APPLY_PREPARE,
374   "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
375   "reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE,
376   "reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE,
377 ]);
378
379 %InstallToContext([
380   "concat_iterable_to_array", ConcatIterableToArray,
381   "non_number_to_number", NonNumberToNumber,
382   "non_string_to_string", NonStringToString,
383   "to_integer_fun", ToInteger,
384   "to_length_fun", ToLength,
385   "to_number_fun", ToNumber,
386   "to_string_fun", ToString,
387 ]);
388
389 utils.Export(function(to) {
390   to.ToBoolean = ToBoolean;
391   to.ToLength = ToLength;
392   to.ToNumber = ToNumber;
393   to.ToString = ToString;
394 });
395
396 })