blob: 9e437a3f028f1ab59586d92f1824b21692fd237b [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 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(function(global, utils) {
6
7%CheckIsBootstrapping();
8
9// ----------------------------------------------------------------------------
10// Imports
11
12var GlobalArray = global.Array;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013var GlobalNumber = global.Number;
14var GlobalObject = global.Object;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015var iteratorSymbol = utils.ImportNow("iterator_symbol");
16var MakeRangeError;
17var MakeSyntaxError;
18var MakeTypeError;
19var MathAbs;
20var NaN = %GetRootNaN();
21var ObjectToString = utils.ImportNow("object_to_string");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
23
24utils.Import(function(from) {
25 MakeRangeError = from.MakeRangeError;
26 MakeSyntaxError = from.MakeSyntaxError;
27 MakeTypeError = from.MakeTypeError;
28 MathAbs = from.MathAbs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029});
30
31// ----------------------------------------------------------------------------
32
33
34// ES6 18.2.3 isNaN(number)
35function GlobalIsNaN(number) {
36 number = TO_NUMBER(number);
37 return NUMBER_IS_NAN(number);
38}
39
40
41// ES6 18.2.2 isFinite(number)
42function GlobalIsFinite(number) {
43 number = TO_NUMBER(number);
44 return NUMBER_IS_FINITE(number);
45}
46
47
48// ES6 18.2.5 parseInt(string, radix)
49function GlobalParseInt(string, radix) {
50 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
51 // Some people use parseInt instead of Math.floor. This
52 // optimization makes parseInt on a Smi 12 times faster (60ns
53 // vs 800ns). The following optimization makes parseInt on a
54 // non-Smi number 9 times faster (230ns vs 2070ns). Together
55 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
56 if (%_IsSmi(string)) return string;
57 if (IS_NUMBER(string) &&
58 ((0.01 < string && string < 1e9) ||
59 (-1e9 < string && string < -0.01))) {
60 // Truncate number.
61 return string | 0;
62 }
63 string = TO_STRING(string);
64 radix = radix | 0;
65 } else {
66 // The spec says ToString should be evaluated before ToInt32.
67 string = TO_STRING(string);
68 radix = TO_INT32(radix);
69 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
70 return NaN;
71 }
72 }
73
74 if (%_HasCachedArrayIndex(string) &&
75 (radix == 0 || radix == 10)) {
76 return %_GetCachedArrayIndex(string);
77 }
78 return %StringParseInt(string, radix);
79}
80
81
82// ES6 18.2.4 parseFloat(string)
83function GlobalParseFloat(string) {
84 // 1. Let inputString be ? ToString(string).
85 string = TO_STRING(string);
86 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
87 return %StringParseFloat(string);
88}
89
90
91// ----------------------------------------------------------------------------
92
93// Set up global object.
94var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
95
96utils.InstallConstants(global, [
97 // ES6 18.1.1
98 "Infinity", INFINITY,
99 // ES6 18.1.2
100 "NaN", NaN,
101 // ES6 18.1.3
102 "undefined", UNDEFINED,
103]);
104
105// Set up non-enumerable function on the global object.
106utils.InstallFunctions(global, DONT_ENUM, [
107 "isNaN", GlobalIsNaN,
108 "isFinite", GlobalIsFinite,
109 "parseInt", GlobalParseInt,
110 "parseFloat", GlobalParseFloat,
111]);
112
113
114// ----------------------------------------------------------------------------
115// Object
116
117// ES6 19.1.3.5 Object.prototype.toLocaleString([reserved1 [,reserved2]])
118function ObjectToLocaleString() {
119 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
120 return this.toString();
121}
122
123
124// ES6 19.1.3.7 Object.prototype.valueOf()
125function ObjectValueOf() {
126 return TO_OBJECT(this);
127}
128
129
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V)
131function ObjectIsPrototypeOf(V) {
132 if (!IS_RECEIVER(V)) return false;
133 var O = TO_OBJECT(this);
134 return %HasInPrototypeChain(V, O);
135}
136
137
138// ES6 19.1.3.4
139function ObjectPropertyIsEnumerable(V) {
140 var P = TO_NAME(V);
141 return %PropertyIsEnumerable(TO_OBJECT(this), P);
142}
143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144// ES6 7.3.9
145function GetMethod(obj, p) {
146 var func = obj[p];
147 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED;
148 if (IS_CALLABLE(func)) return func;
149 throw MakeTypeError(kCalledNonCallable, typeof func);
150}
151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152// ES6 section 19.1.2.18.
153function ObjectSetPrototypeOf(obj, proto) {
154 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
155
156 if (proto !== null && !IS_RECEIVER(proto)) {
157 throw MakeTypeError(kProtoObjectOrNull, proto);
158 }
159
160 if (IS_RECEIVER(obj)) {
161 %SetPrototype(obj, proto);
162 }
163
164 return obj;
165}
166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167// ES6 B.2.2.1.1
168function ObjectGetProto() {
Ben Murdochc5610432016-08-08 18:44:38 +0100169 return %object_get_prototype_of(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170}
171
172
173// ES6 B.2.2.1.2
174function ObjectSetProto(proto) {
175 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
176
177 if ((IS_RECEIVER(proto) || IS_NULL(proto)) && IS_RECEIVER(this)) {
178 %SetPrototype(this, proto);
179 }
180}
181
182
183// ES6 19.1.1.1
184function ObjectConstructor(x) {
185 if (GlobalObject != new.target && !IS_UNDEFINED(new.target)) {
186 return this;
187 }
188 if (IS_NULL(x) || IS_UNDEFINED(x)) return {};
189 return TO_OBJECT(x);
190}
191
192
193// ----------------------------------------------------------------------------
194// Object
195
196%SetNativeFlag(GlobalObject);
197%SetCode(GlobalObject, ObjectConstructor);
198
199%AddNamedProperty(GlobalObject.prototype, "constructor", GlobalObject,
200 DONT_ENUM);
201
202// Set up non-enumerable functions on the Object.prototype object.
203utils.InstallFunctions(GlobalObject.prototype, DONT_ENUM, [
204 "toString", ObjectToString,
205 "toLocaleString", ObjectToLocaleString,
206 "valueOf", ObjectValueOf,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 "isPrototypeOf", ObjectIsPrototypeOf,
208 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
Ben Murdochc5610432016-08-08 18:44:38 +0100209 // __defineGetter__ is added in bootstrapper.cc.
210 // __lookupGetter__ is added in bootstrapper.cc.
211 // __defineSetter__ is added in bootstrapper.cc.
212 // __lookupSetter__ is added in bootstrapper.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213]);
Ben Murdochc5610432016-08-08 18:44:38 +0100214utils.InstallGetterSetter(
215 GlobalObject.prototype, "__proto__", ObjectGetProto, ObjectSetProto);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216
217// Set up non-enumerable functions in the Object object.
218utils.InstallFunctions(GlobalObject, DONT_ENUM, [
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 "setPrototypeOf", ObjectSetPrototypeOf,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 // getOwnPropertySymbols is added in symbol.js.
Ben Murdochc5610432016-08-08 18:44:38 +0100221 // Others are added in bootstrapper.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222]);
223
224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225
226// ----------------------------------------------------------------------------
227// Number
228
229// ES6 Number.prototype.toString([ radix ])
230function NumberToStringJS(radix) {
231 // NOTE: Both Number objects and values can enter here as
232 // 'this'. This is not as dictated by ECMA-262.
233 var number = this;
234 if (!IS_NUMBER(this)) {
235 if (!IS_NUMBER_WRAPPER(this)) {
236 throw MakeTypeError(kNotGeneric, 'Number.prototype.toString');
237 }
238 // Get the value of this number in case it's an object.
239 number = %_ValueOf(this);
240 }
241 // Fast case: Convert number in radix 10.
242 if (IS_UNDEFINED(radix) || radix === 10) {
243 return %_NumberToString(number);
244 }
245
246 // Convert the radix to an integer and check the range.
247 radix = TO_INTEGER(radix);
248 if (radix < 2 || radix > 36) throw MakeRangeError(kToRadixFormatRange);
249 // Convert the number to a string in the given radix.
250 return %NumberToRadixString(number, radix);
251}
252
253
254// ES6 20.1.3.4 Number.prototype.toLocaleString([reserved1 [, reserved2]])
255function NumberToLocaleString() {
256 return %_Call(NumberToStringJS, this);
257}
258
259
260// ES6 20.1.3.7 Number.prototype.valueOf()
261function NumberValueOf() {
262 // NOTE: Both Number objects and values can enter here as
263 // 'this'. This is not as dictated by ECMA-262.
264 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
265 throw MakeTypeError(kNotGeneric, 'Number.prototype.valueOf');
266 }
267 return %_ValueOf(this);
268}
269
270
271// ES6 20.1.3.3 Number.prototype.toFixed(fractionDigits)
272function NumberToFixedJS(fractionDigits) {
273 var x = this;
274 if (!IS_NUMBER(this)) {
275 if (!IS_NUMBER_WRAPPER(this)) {
276 throw MakeTypeError(kIncompatibleMethodReceiver,
277 "Number.prototype.toFixed", this);
278 }
279 // Get the value of this number in case it's an object.
280 x = %_ValueOf(this);
281 }
282 var f = TO_INTEGER(fractionDigits);
283
284 if (f < 0 || f > 20) {
285 throw MakeRangeError(kNumberFormatRange, "toFixed() digits");
286 }
287
288 if (NUMBER_IS_NAN(x)) return "NaN";
289 if (x == INFINITY) return "Infinity";
290 if (x == -INFINITY) return "-Infinity";
291
292 return %NumberToFixed(x, f);
293}
294
295
296// ES6 20.1.3.2 Number.prototype.toExponential(fractionDigits)
297function NumberToExponentialJS(fractionDigits) {
298 var x = this;
299 if (!IS_NUMBER(this)) {
300 if (!IS_NUMBER_WRAPPER(this)) {
301 throw MakeTypeError(kIncompatibleMethodReceiver,
302 "Number.prototype.toExponential", this);
303 }
304 // Get the value of this number in case it's an object.
305 x = %_ValueOf(this);
306 }
307 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
308
309 if (NUMBER_IS_NAN(x)) return "NaN";
310 if (x == INFINITY) return "Infinity";
311 if (x == -INFINITY) return "-Infinity";
312
313 if (IS_UNDEFINED(f)) {
314 f = -1; // Signal for runtime function that f is not defined.
315 } else if (f < 0 || f > 20) {
316 throw MakeRangeError(kNumberFormatRange, "toExponential()");
317 }
318 return %NumberToExponential(x, f);
319}
320
321
322// ES6 20.1.3.5 Number.prototype.toPrecision(precision)
323function NumberToPrecisionJS(precision) {
324 var x = this;
325 if (!IS_NUMBER(this)) {
326 if (!IS_NUMBER_WRAPPER(this)) {
327 throw MakeTypeError(kIncompatibleMethodReceiver,
328 "Number.prototype.toPrecision", this);
329 }
330 // Get the value of this number in case it's an object.
331 x = %_ValueOf(this);
332 }
333 if (IS_UNDEFINED(precision)) return TO_STRING(x);
334 var p = TO_INTEGER(precision);
335
336 if (NUMBER_IS_NAN(x)) return "NaN";
337 if (x == INFINITY) return "Infinity";
338 if (x == -INFINITY) return "-Infinity";
339
340 if (p < 1 || p > 21) {
341 throw MakeRangeError(kToPrecisionFormatRange);
342 }
343 return %NumberToPrecision(x, p);
344}
345
346
347// Harmony isFinite.
348function NumberIsFinite(number) {
349 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
350}
351
352
353// Harmony isInteger
354function NumberIsInteger(number) {
355 return NumberIsFinite(number) && TO_INTEGER(number) == number;
356}
357
358
359// Harmony isNaN.
360function NumberIsNaN(number) {
361 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
362}
363
364
365// Harmony isSafeInteger
366function NumberIsSafeInteger(number) {
367 if (NumberIsFinite(number)) {
368 var integral = TO_INTEGER(number);
369 if (integral == number) {
370 return MathAbs(integral) <= kMaxSafeInteger;
371 }
372 }
373 return false;
374}
375
376
377// ----------------------------------------------------------------------------
378
379%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0));
380
381%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8);
382// Set up the constructor property on the Number prototype object.
383%AddNamedProperty(GlobalNumber.prototype, "constructor", GlobalNumber,
384 DONT_ENUM);
385
386utils.InstallConstants(GlobalNumber, [
387 // ECMA-262 section 15.7.3.1.
388 "MAX_VALUE", 1.7976931348623157e+308,
389 // ECMA-262 section 15.7.3.2.
390 "MIN_VALUE", 5e-324,
391 // ECMA-262 section 15.7.3.3.
392 "NaN", NaN,
393 // ECMA-262 section 15.7.3.4.
394 "NEGATIVE_INFINITY", -INFINITY,
395 // ECMA-262 section 15.7.3.5.
396 "POSITIVE_INFINITY", INFINITY,
397
398 // --- Harmony constants (no spec refs until settled.)
399
400 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
401 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
402 "EPSILON", %_MathPow(2, -52)
403]);
404
405// Set up non-enumerable functions on the Number prototype object.
406utils.InstallFunctions(GlobalNumber.prototype, DONT_ENUM, [
407 "toString", NumberToStringJS,
408 "toLocaleString", NumberToLocaleString,
409 "valueOf", NumberValueOf,
410 "toFixed", NumberToFixedJS,
411 "toExponential", NumberToExponentialJS,
412 "toPrecision", NumberToPrecisionJS
413]);
414
415// Harmony Number constructor additions
416utils.InstallFunctions(GlobalNumber, DONT_ENUM, [
417 "isFinite", NumberIsFinite,
418 "isInteger", NumberIsInteger,
419 "isNaN", NumberIsNaN,
420 "isSafeInteger", NumberIsSafeInteger,
421 "parseInt", GlobalParseInt,
422 "parseFloat", GlobalParseFloat
423]);
424
425%SetForceInlineFlag(NumberIsNaN);
426
427
428// ----------------------------------------------------------------------------
429// Iterator related spec functions.
430
431// ES6 7.4.1 GetIterator(obj, method)
432function GetIterator(obj, method) {
433 if (IS_UNDEFINED(method)) {
434 method = obj[iteratorSymbol];
435 }
436 if (!IS_CALLABLE(method)) {
437 throw MakeTypeError(kNotIterable, obj);
438 }
439 var iterator = %_Call(method, obj);
440 if (!IS_RECEIVER(iterator)) {
441 throw MakeTypeError(kNotAnIterator, iterator);
442 }
443 return iterator;
444}
445
446// ----------------------------------------------------------------------------
447// Exports
448
449utils.Export(function(to) {
450 to.GetIterator = GetIterator;
451 to.GetMethod = GetMethod;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 to.IsNaN = GlobalIsNaN;
453 to.NumberIsNaN = NumberIsNaN;
Ben Murdochda12d292016-06-02 14:46:10 +0100454 to.NumberIsInteger = NumberIsInteger;
Ben Murdochda12d292016-06-02 14:46:10 +0100455 to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456});
457
458%InstallToContext([
459 "object_value_of", ObjectValueOf,
460]);
461
462})