blob: 5185c620b30f636c64346baf827a5b6d95d23488 [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;
15var InternalArray = utils.InternalArray;
16var iteratorSymbol = utils.ImportNow("iterator_symbol");
17var MakeRangeError;
18var MakeSyntaxError;
19var MakeTypeError;
20var MathAbs;
21var NaN = %GetRootNaN();
22var ObjectToString = utils.ImportNow("object_to_string");
23var ObserveBeginPerformSplice;
24var ObserveEndPerformSplice;
25var ObserveEnqueueSpliceRecord;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
27
28utils.Import(function(from) {
29 MakeRangeError = from.MakeRangeError;
30 MakeSyntaxError = from.MakeSyntaxError;
31 MakeTypeError = from.MakeTypeError;
32 MathAbs = from.MathAbs;
33 ObserveBeginPerformSplice = from.ObserveBeginPerformSplice;
34 ObserveEndPerformSplice = from.ObserveEndPerformSplice;
35 ObserveEnqueueSpliceRecord = from.ObserveEnqueueSpliceRecord;
36});
37
38// ----------------------------------------------------------------------------
39
40
41// ES6 18.2.3 isNaN(number)
42function GlobalIsNaN(number) {
43 number = TO_NUMBER(number);
44 return NUMBER_IS_NAN(number);
45}
46
47
48// ES6 18.2.2 isFinite(number)
49function GlobalIsFinite(number) {
50 number = TO_NUMBER(number);
51 return NUMBER_IS_FINITE(number);
52}
53
54
55// ES6 18.2.5 parseInt(string, radix)
56function GlobalParseInt(string, radix) {
57 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
58 // Some people use parseInt instead of Math.floor. This
59 // optimization makes parseInt on a Smi 12 times faster (60ns
60 // vs 800ns). The following optimization makes parseInt on a
61 // non-Smi number 9 times faster (230ns vs 2070ns). Together
62 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
63 if (%_IsSmi(string)) return string;
64 if (IS_NUMBER(string) &&
65 ((0.01 < string && string < 1e9) ||
66 (-1e9 < string && string < -0.01))) {
67 // Truncate number.
68 return string | 0;
69 }
70 string = TO_STRING(string);
71 radix = radix | 0;
72 } else {
73 // The spec says ToString should be evaluated before ToInt32.
74 string = TO_STRING(string);
75 radix = TO_INT32(radix);
76 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
77 return NaN;
78 }
79 }
80
81 if (%_HasCachedArrayIndex(string) &&
82 (radix == 0 || radix == 10)) {
83 return %_GetCachedArrayIndex(string);
84 }
85 return %StringParseInt(string, radix);
86}
87
88
89// ES6 18.2.4 parseFloat(string)
90function GlobalParseFloat(string) {
91 // 1. Let inputString be ? ToString(string).
92 string = TO_STRING(string);
93 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
94 return %StringParseFloat(string);
95}
96
97
98// ----------------------------------------------------------------------------
99
100// Set up global object.
101var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
102
103utils.InstallConstants(global, [
104 // ES6 18.1.1
105 "Infinity", INFINITY,
106 // ES6 18.1.2
107 "NaN", NaN,
108 // ES6 18.1.3
109 "undefined", UNDEFINED,
110]);
111
112// Set up non-enumerable function on the global object.
113utils.InstallFunctions(global, DONT_ENUM, [
114 "isNaN", GlobalIsNaN,
115 "isFinite", GlobalIsFinite,
116 "parseInt", GlobalParseInt,
117 "parseFloat", GlobalParseFloat,
118]);
119
120
121// ----------------------------------------------------------------------------
122// Object
123
124// ES6 19.1.3.5 Object.prototype.toLocaleString([reserved1 [,reserved2]])
125function ObjectToLocaleString() {
126 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
127 return this.toString();
128}
129
130
131// ES6 19.1.3.7 Object.prototype.valueOf()
132function ObjectValueOf() {
133 return TO_OBJECT(this);
134}
135
136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V)
138function ObjectIsPrototypeOf(V) {
139 if (!IS_RECEIVER(V)) return false;
140 var O = TO_OBJECT(this);
141 return %HasInPrototypeChain(V, O);
142}
143
144
145// ES6 19.1.3.4
146function ObjectPropertyIsEnumerable(V) {
147 var P = TO_NAME(V);
148 return %PropertyIsEnumerable(TO_OBJECT(this), P);
149}
150
151
152// Extensions for providing property getters and setters.
153function ObjectDefineGetter(name, fun) {
154 var receiver = this;
155 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
156 receiver = %GlobalProxy(ObjectDefineGetter);
157 }
158 if (!IS_CALLABLE(fun)) {
159 throw MakeTypeError(kObjectGetterExpectingFunction);
160 }
161 var desc = new PropertyDescriptor();
162 desc.setGet(fun);
163 desc.setEnumerable(true);
164 desc.setConfigurable(true);
165 DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false);
166}
167
168
169function ObjectLookupGetter(name) {
170 var receiver = this;
171 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
172 receiver = %GlobalProxy(ObjectLookupGetter);
173 }
174 return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), GETTER);
175}
176
177
178function ObjectDefineSetter(name, fun) {
179 var receiver = this;
180 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
181 receiver = %GlobalProxy(ObjectDefineSetter);
182 }
183 if (!IS_CALLABLE(fun)) {
184 throw MakeTypeError(kObjectSetterExpectingFunction);
185 }
186 var desc = new PropertyDescriptor();
187 desc.setSet(fun);
188 desc.setEnumerable(true);
189 desc.setConfigurable(true);
190 DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false);
191}
192
193
194function ObjectLookupSetter(name) {
195 var receiver = this;
196 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
197 receiver = %GlobalProxy(ObjectLookupSetter);
198 }
199 return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), SETTER);
200}
201
202
203// ES6 6.2.4.1
204function IsAccessorDescriptor(desc) {
205 if (IS_UNDEFINED(desc)) return false;
206 return desc.hasGetter() || desc.hasSetter();
207}
208
209
210// ES6 6.2.4.2
211function IsDataDescriptor(desc) {
212 if (IS_UNDEFINED(desc)) return false;
213 return desc.hasValue() || desc.hasWritable();
214}
215
216
217// ES6 6.2.4.3
218function IsGenericDescriptor(desc) {
219 if (IS_UNDEFINED(desc)) return false;
220 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
221}
222
223
224function IsInconsistentDescriptor(desc) {
225 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
226}
227
228
229// Harmony Proxies
230function FromGenericPropertyDescriptor(desc) {
231 if (IS_UNDEFINED(desc)) return desc;
232 var obj = new GlobalObject();
233
234 if (desc.hasValue()) {
235 %AddNamedProperty(obj, "value", desc.getValue(), NONE);
236 }
237 if (desc.hasWritable()) {
238 %AddNamedProperty(obj, "writable", desc.isWritable(), NONE);
239 }
240 if (desc.hasGetter()) {
241 %AddNamedProperty(obj, "get", desc.getGet(), NONE);
242 }
243 if (desc.hasSetter()) {
244 %AddNamedProperty(obj, "set", desc.getSet(), NONE);
245 }
246 if (desc.hasEnumerable()) {
247 %AddNamedProperty(obj, "enumerable", desc.isEnumerable(), NONE);
248 }
249 if (desc.hasConfigurable()) {
250 %AddNamedProperty(obj, "configurable", desc.isConfigurable(), NONE);
251 }
252 return obj;
253}
254
255
256// ES6 6.2.4.5
257function ToPropertyDescriptor(obj) {
258 if (!IS_RECEIVER(obj)) throw MakeTypeError(kPropertyDescObject, obj);
259
260 var desc = new PropertyDescriptor();
261
262 if ("enumerable" in obj) {
263 desc.setEnumerable(TO_BOOLEAN(obj.enumerable));
264 }
265
266 if ("configurable" in obj) {
267 desc.setConfigurable(TO_BOOLEAN(obj.configurable));
268 }
269
270 if ("value" in obj) {
271 desc.setValue(obj.value);
272 }
273
274 if ("writable" in obj) {
275 desc.setWritable(TO_BOOLEAN(obj.writable));
276 }
277
278 if ("get" in obj) {
279 var get = obj.get;
280 if (!IS_UNDEFINED(get) && !IS_CALLABLE(get)) {
281 throw MakeTypeError(kObjectGetterCallable, get);
282 }
283 desc.setGet(get);
284 }
285
286 if ("set" in obj) {
287 var set = obj.set;
288 if (!IS_UNDEFINED(set) && !IS_CALLABLE(set)) {
289 throw MakeTypeError(kObjectSetterCallable, set);
290 }
291 desc.setSet(set);
292 }
293
294 if (IsInconsistentDescriptor(desc)) {
295 throw MakeTypeError(kValueAndAccessor, obj);
296 }
297 return desc;
298}
299
300// TODO(cbruni): remove once callers have been removed
301function ToCompletePropertyDescriptor(obj) {
302 var desc = ToPropertyDescriptor(obj);
303 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
304 if (!desc.hasValue()) desc.setValue(UNDEFINED);
305 if (!desc.hasWritable()) desc.setWritable(false);
306 } else {
307 // Is accessor descriptor.
308 if (!desc.hasGetter()) desc.setGet(UNDEFINED);
309 if (!desc.hasSetter()) desc.setSet(UNDEFINED);
310 }
311 if (!desc.hasEnumerable()) desc.setEnumerable(false);
312 if (!desc.hasConfigurable()) desc.setConfigurable(false);
313 return desc;
314}
315
316
317function PropertyDescriptor() {
318 // Initialize here so they are all in-object and have the same map.
319 // Default values from ES5 8.6.1.
320 this.value_ = UNDEFINED;
321 this.hasValue_ = false;
322 this.writable_ = false;
323 this.hasWritable_ = false;
324 this.enumerable_ = false;
325 this.hasEnumerable_ = false;
326 this.configurable_ = false;
327 this.hasConfigurable_ = false;
328 this.get_ = UNDEFINED;
329 this.hasGetter_ = false;
330 this.set_ = UNDEFINED;
331 this.hasSetter_ = false;
332}
333
334utils.SetUpLockedPrototype(PropertyDescriptor, [
335 "value_",
336 "hasValue_",
337 "writable_",
338 "hasWritable_",
339 "enumerable_",
340 "hasEnumerable_",
341 "configurable_",
342 "hasConfigurable_",
343 "get_",
344 "hasGetter_",
345 "set_",
346 "hasSetter_"
347], [
348 "toString", function PropertyDescriptor_ToString() {
349 return "[object PropertyDescriptor]";
350 },
351 "setValue", function PropertyDescriptor_SetValue(value) {
352 this.value_ = value;
353 this.hasValue_ = true;
354 },
355 "getValue", function PropertyDescriptor_GetValue() {
356 return this.value_;
357 },
358 "hasValue", function PropertyDescriptor_HasValue() {
359 return this.hasValue_;
360 },
361 "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) {
362 this.enumerable_ = enumerable;
363 this.hasEnumerable_ = true;
364 },
365 "isEnumerable", function PropertyDescriptor_IsEnumerable() {
366 return this.enumerable_;
367 },
368 "hasEnumerable", function PropertyDescriptor_HasEnumerable() {
369 return this.hasEnumerable_;
370 },
371 "setWritable", function PropertyDescriptor_SetWritable(writable) {
372 this.writable_ = writable;
373 this.hasWritable_ = true;
374 },
375 "isWritable", function PropertyDescriptor_IsWritable() {
376 return this.writable_;
377 },
378 "hasWritable", function PropertyDescriptor_HasWritable() {
379 return this.hasWritable_;
380 },
381 "setConfigurable",
382 function PropertyDescriptor_SetConfigurable(configurable) {
383 this.configurable_ = configurable;
384 this.hasConfigurable_ = true;
385 },
386 "hasConfigurable", function PropertyDescriptor_HasConfigurable() {
387 return this.hasConfigurable_;
388 },
389 "isConfigurable", function PropertyDescriptor_IsConfigurable() {
390 return this.configurable_;
391 },
392 "setGet", function PropertyDescriptor_SetGetter(get) {
393 this.get_ = get;
394 this.hasGetter_ = true;
395 },
396 "getGet", function PropertyDescriptor_GetGetter() {
397 return this.get_;
398 },
399 "hasGetter", function PropertyDescriptor_HasGetter() {
400 return this.hasGetter_;
401 },
402 "setSet", function PropertyDescriptor_SetSetter(set) {
403 this.set_ = set;
404 this.hasSetter_ = true;
405 },
406 "getSet", function PropertyDescriptor_GetSetter() {
407 return this.set_;
408 },
409 "hasSetter", function PropertyDescriptor_HasSetter() {
410 return this.hasSetter_;
411 }
412]);
413
414
415// Converts an array returned from Runtime_GetOwnProperty to an actual
416// property descriptor. For a description of the array layout please
417// see the runtime.cc file.
418function ConvertDescriptorArrayToDescriptor(desc_array) {
419 if (IS_UNDEFINED(desc_array)) {
420 return UNDEFINED;
421 }
422
423 var desc = new PropertyDescriptor();
424 // This is an accessor.
425 if (desc_array[IS_ACCESSOR_INDEX]) {
426 desc.setGet(desc_array[GETTER_INDEX]);
427 desc.setSet(desc_array[SETTER_INDEX]);
428 } else {
429 desc.setValue(desc_array[VALUE_INDEX]);
430 desc.setWritable(desc_array[WRITABLE_INDEX]);
431 }
432 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
433 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
434
435 return desc;
436}
437
438
439// For Harmony proxies.
440function GetTrap(handler, name, defaultTrap) {
441 var trap = handler[name];
442 if (IS_UNDEFINED(trap)) {
443 if (IS_UNDEFINED(defaultTrap)) {
444 throw MakeTypeError(kIllegalInvocation);
445 }
446 trap = defaultTrap;
447 } else if (!IS_CALLABLE(trap)) {
448 throw MakeTypeError(kIllegalInvocation);
449 }
450 return trap;
451}
452
453
454function CallTrap1(handler, name, defaultTrap, x) {
455 return %_Call(GetTrap(handler, name, defaultTrap), handler, x);
456}
457
458
459function CallTrap2(handler, name, defaultTrap, x, y) {
460 return %_Call(GetTrap(handler, name, defaultTrap), handler, x, y);
461}
462
463
464// ES5 section 8.12.1.
465// TODO(jkummerow): Deprecated. Migrate all callers to
466// ObjectGetOwnPropertyDescriptor and delete this.
467function GetOwnPropertyJS(obj, v) {
468 var p = TO_NAME(v);
469 if (IS_PROXY(obj)) {
470 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
471 if (IS_SYMBOL(v)) return UNDEFINED;
472
473 var handler = %JSProxyGetHandler(obj);
474 var descriptor = CallTrap1(
475 handler, "getOwnPropertyDescriptor", UNDEFINED, p);
476 if (IS_UNDEFINED(descriptor)) return descriptor;
477 var desc = ToCompletePropertyDescriptor(descriptor);
478 if (!desc.isConfigurable()) {
479 throw MakeTypeError(kIllegalInvocation);
480 }
481 return desc;
482 }
483
484 // GetOwnProperty returns an array indexed by the constants
485 // defined in macros.py.
486 // If p is not a property on obj undefined is returned.
487 var props = %GetOwnProperty_Legacy(TO_OBJECT(obj), p);
488
489 return ConvertDescriptorArrayToDescriptor(props);
490}
491
492
493// ES6 7.3.9
494function GetMethod(obj, p) {
495 var func = obj[p];
496 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED;
497 if (IS_CALLABLE(func)) return func;
498 throw MakeTypeError(kCalledNonCallable, typeof func);
499}
500
501
502// Harmony proxies.
503function DefineProxyProperty(obj, p, attributes, should_throw) {
504 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
505 if (IS_SYMBOL(p)) return false;
506
507 var handler = %JSProxyGetHandler(obj);
508 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
509 if (!result) {
510 if (should_throw) {
511 throw MakeTypeError(kIllegalInvocation);
512 } else {
513 return false;
514 }
515 }
516 return true;
517}
518
519
520// ES6 9.1.6 [[DefineOwnProperty]](P, Desc)
521function DefineObjectProperty(obj, p, desc, should_throw) {
522 var current_array = %GetOwnProperty_Legacy(obj, TO_NAME(p));
523 var current = ConvertDescriptorArrayToDescriptor(current_array);
524 var extensible = %object_is_extensible(obj);
525
526 if (IS_UNDEFINED(current) && !extensible) {
527 if (should_throw) {
528 throw MakeTypeError(kDefineDisallowed, p);
529 } else {
530 return false;
531 }
532 }
533
534 if (!IS_UNDEFINED(current)) {
535 if ((IsGenericDescriptor(desc) ||
536 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
537 (!desc.hasEnumerable() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100538 %SameValue(desc.isEnumerable(), current.isEnumerable())) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 (!desc.hasConfigurable() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100540 %SameValue(desc.isConfigurable(), current.isConfigurable())) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 (!desc.hasWritable() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100542 %SameValue(desc.isWritable(), current.isWritable())) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 (!desc.hasValue() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100544 %SameValue(desc.getValue(), current.getValue())) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 (!desc.hasGetter() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100546 %SameValue(desc.getGet(), current.getGet())) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 (!desc.hasSetter() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100548 %SameValue(desc.getSet(), current.getSet()))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 return true;
550 }
551 if (!current.isConfigurable()) {
552 // Step 7
553 if (desc.isConfigurable() ||
554 (desc.hasEnumerable() &&
555 desc.isEnumerable() != current.isEnumerable())) {
556 if (should_throw) {
557 throw MakeTypeError(kRedefineDisallowed, p);
558 } else {
559 return false;
560 }
561 }
562 // Step 8
563 if (!IsGenericDescriptor(desc)) {
564 // Step 9a
565 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
566 if (should_throw) {
567 throw MakeTypeError(kRedefineDisallowed, p);
568 } else {
569 return false;
570 }
571 }
572 // Step 10a
573 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
574 var currentIsWritable = current.isWritable();
575 if (currentIsWritable != desc.isWritable()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100576 if (!currentIsWritable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 if (should_throw) {
Ben Murdochda12d292016-06-02 14:46:10 +0100578 throw MakeTypeError(kRedefineDisallowed, p);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 } else {
580 return false;
581 }
582 }
583 }
584 if (!currentIsWritable && desc.hasValue() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100585 !%SameValue(desc.getValue(), current.getValue())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000586 if (should_throw) {
587 throw MakeTypeError(kRedefineDisallowed, p);
588 } else {
589 return false;
590 }
591 }
592 }
593 // Step 11
594 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
595 if (desc.hasSetter() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100596 !%SameValue(desc.getSet(), current.getSet())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 if (should_throw) {
598 throw MakeTypeError(kRedefineDisallowed, p);
599 } else {
600 return false;
601 }
602 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100603 if (desc.hasGetter() && !%SameValue(desc.getGet(),current.getGet())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 if (should_throw) {
605 throw MakeTypeError(kRedefineDisallowed, p);
606 } else {
607 return false;
608 }
609 }
610 }
611 }
612 }
613 }
614
615 // Send flags - enumerable and configurable are common - writable is
616 // only send to the data descriptor.
617 // Take special care if enumerable and configurable is not defined on
618 // desc (we need to preserve the existing values from current).
619 var flag = NONE;
620 if (desc.hasEnumerable()) {
621 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
622 } else if (!IS_UNDEFINED(current)) {
623 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
624 } else {
625 flag |= DONT_ENUM;
626 }
627
628 if (desc.hasConfigurable()) {
629 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
630 } else if (!IS_UNDEFINED(current)) {
631 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
632 } else
633 flag |= DONT_DELETE;
634
635 if (IsDataDescriptor(desc) ||
636 (IsGenericDescriptor(desc) &&
637 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
638 // There are 3 cases that lead here:
639 // Step 4a - defining a new data property.
640 // Steps 9b & 12 - replacing an existing accessor property with a data
641 // property.
642 // Step 12 - updating an existing data property with a data or generic
643 // descriptor.
644
645 if (desc.hasWritable()) {
646 flag |= desc.isWritable() ? 0 : READ_ONLY;
647 } else if (!IS_UNDEFINED(current)) {
648 flag |= current.isWritable() ? 0 : READ_ONLY;
649 } else {
650 flag |= READ_ONLY;
651 }
652
653 var value = UNDEFINED; // Default value is undefined.
654 if (desc.hasValue()) {
655 value = desc.getValue();
656 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
657 value = current.getValue();
658 }
659
660 %DefineDataPropertyUnchecked(obj, p, value, flag);
661 } else {
662 // There are 3 cases that lead here:
663 // Step 4b - defining a new accessor property.
664 // Steps 9c & 12 - replacing an existing data property with an accessor
665 // property.
666 // Step 12 - updating an existing accessor property with an accessor
667 // descriptor.
668 var getter = null;
669 if (desc.hasGetter()) {
670 getter = desc.getGet();
671 } else if (IsAccessorDescriptor(current) && current.hasGetter()) {
672 getter = current.getGet();
673 }
674 var setter = null;
675 if (desc.hasSetter()) {
676 setter = desc.getSet();
677 } else if (IsAccessorDescriptor(current) && current.hasSetter()) {
678 setter = current.getSet();
679 }
680 %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag);
681 }
682 return true;
683}
684
685
686// ES5 section 15.4.5.1.
687function DefineArrayProperty(obj, p, desc, should_throw) {
688 // Step 3 - Special handling for array index.
689 if (!IS_SYMBOL(p)) {
690 var index = TO_UINT32(p);
691 var emit_splice = false;
692 if (TO_STRING(index) == p && index != 4294967295) {
693 var length = obj.length;
694 if (index >= length && %IsObserved(obj)) {
695 emit_splice = true;
696 ObserveBeginPerformSplice(obj);
697 }
698
699 var length_desc = GetOwnPropertyJS(obj, "length");
700 if ((index >= length && !length_desc.isWritable()) ||
701 !DefineObjectProperty(obj, p, desc, true)) {
702 if (emit_splice)
703 ObserveEndPerformSplice(obj);
704 if (should_throw) {
705 throw MakeTypeError(kDefineDisallowed, p);
706 } else {
707 return false;
708 }
709 }
710 if (index >= length) {
711 obj.length = index + 1;
712 }
713 if (emit_splice) {
714 ObserveEndPerformSplice(obj);
715 ObserveEnqueueSpliceRecord(obj, length, [], index + 1 - length);
716 }
717 return true;
718 }
719 }
720
721 // Step 5 - Fallback to default implementation.
722 return DefineObjectProperty(obj, p, desc, should_throw);
723}
724
725
726// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
727function DefineOwnProperty(obj, p, desc, should_throw) {
728 if (IS_PROXY(obj)) {
729 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
730 if (IS_SYMBOL(p)) return false;
731
732 var attributes = FromGenericPropertyDescriptor(desc);
733 return DefineProxyProperty(obj, p, attributes, should_throw);
734 } else if (IS_ARRAY(obj)) {
735 return DefineArrayProperty(obj, p, desc, should_throw);
736 } else {
737 return DefineObjectProperty(obj, p, desc, should_throw);
738 }
739}
740
741
742// ES6 section 19.1.2.9
743function ObjectGetPrototypeOf(obj) {
744 return %_GetPrototype(TO_OBJECT(obj));
745}
746
747// ES6 section 19.1.2.18.
748function ObjectSetPrototypeOf(obj, proto) {
749 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
750
751 if (proto !== null && !IS_RECEIVER(proto)) {
752 throw MakeTypeError(kProtoObjectOrNull, proto);
753 }
754
755 if (IS_RECEIVER(obj)) {
756 %SetPrototype(obj, proto);
757 }
758
759 return obj;
760}
761
762
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763// ES5 section 15.2.3.6.
764function ObjectDefineProperty(obj, p, attributes) {
765 // The new pure-C++ implementation doesn't support O.o.
766 // TODO(jkummerow): Implement missing features and remove fallback path.
767 if (%IsObserved(obj)) {
768 if (!IS_RECEIVER(obj)) {
769 throw MakeTypeError(kCalledOnNonObject, "Object.defineProperty");
770 }
771 var name = TO_NAME(p);
772 var desc = ToPropertyDescriptor(attributes);
773 DefineOwnProperty(obj, name, desc, true);
774 return obj;
775 }
776 return %ObjectDefineProperty(obj, p, attributes);
777}
778
779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000780// ES5 section 15.2.3.7.
781function ObjectDefineProperties(obj, properties) {
782 // The new pure-C++ implementation doesn't support O.o.
783 // TODO(jkummerow): Implement missing features and remove fallback path.
784 if (%IsObserved(obj)) {
785 if (!IS_RECEIVER(obj)) {
786 throw MakeTypeError(kCalledOnNonObject, "Object.defineProperties");
787 }
788 var props = TO_OBJECT(properties);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100789 var names = %GetOwnPropertyKeys(props, PROPERTY_FILTER_ONLY_ENUMERABLE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 var descriptors = new InternalArray();
791 for (var i = 0; i < names.length; i++) {
792 descriptors.push(ToPropertyDescriptor(props[names[i]]));
793 }
794 for (var i = 0; i < names.length; i++) {
795 DefineOwnProperty(obj, names[i], descriptors[i], true);
796 }
797 return obj;
798 }
799 return %ObjectDefineProperties(obj, properties);
800}
801
802
803// ES6 B.2.2.1.1
804function ObjectGetProto() {
805 return %_GetPrototype(TO_OBJECT(this));
806}
807
808
809// ES6 B.2.2.1.2
810function ObjectSetProto(proto) {
811 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
812
813 if ((IS_RECEIVER(proto) || IS_NULL(proto)) && IS_RECEIVER(this)) {
814 %SetPrototype(this, proto);
815 }
816}
817
818
819// ES6 19.1.1.1
820function ObjectConstructor(x) {
821 if (GlobalObject != new.target && !IS_UNDEFINED(new.target)) {
822 return this;
823 }
824 if (IS_NULL(x) || IS_UNDEFINED(x)) return {};
825 return TO_OBJECT(x);
826}
827
828
829// ----------------------------------------------------------------------------
830// Object
831
832%SetNativeFlag(GlobalObject);
833%SetCode(GlobalObject, ObjectConstructor);
834
835%AddNamedProperty(GlobalObject.prototype, "constructor", GlobalObject,
836 DONT_ENUM);
837
838// Set up non-enumerable functions on the Object.prototype object.
839utils.InstallFunctions(GlobalObject.prototype, DONT_ENUM, [
840 "toString", ObjectToString,
841 "toLocaleString", ObjectToLocaleString,
842 "valueOf", ObjectValueOf,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843 "isPrototypeOf", ObjectIsPrototypeOf,
844 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
845 "__defineGetter__", ObjectDefineGetter,
846 "__lookupGetter__", ObjectLookupGetter,
847 "__defineSetter__", ObjectDefineSetter,
848 "__lookupSetter__", ObjectLookupSetter
849]);
850utils.InstallGetterSetter(GlobalObject.prototype, "__proto__", ObjectGetProto,
851 ObjectSetProto);
852
853// Set up non-enumerable functions in the Object object.
854utils.InstallFunctions(GlobalObject, DONT_ENUM, [
855 // assign is added in bootstrapper.cc.
856 // keys is added in bootstrapper.cc.
857 "defineProperty", ObjectDefineProperty,
858 "defineProperties", ObjectDefineProperties,
859 "getPrototypeOf", ObjectGetPrototypeOf,
860 "setPrototypeOf", ObjectSetPrototypeOf,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000861 // getOwnPropertySymbols is added in symbol.js.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100862 // is is added in bootstrapper.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 // deliverChangeRecords, getNotifier, observe and unobserve are added
864 // in object-observe.js.
865]);
866
867
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868
869// ----------------------------------------------------------------------------
870// Number
871
872// ES6 Number.prototype.toString([ radix ])
873function NumberToStringJS(radix) {
874 // NOTE: Both Number objects and values can enter here as
875 // 'this'. This is not as dictated by ECMA-262.
876 var number = this;
877 if (!IS_NUMBER(this)) {
878 if (!IS_NUMBER_WRAPPER(this)) {
879 throw MakeTypeError(kNotGeneric, 'Number.prototype.toString');
880 }
881 // Get the value of this number in case it's an object.
882 number = %_ValueOf(this);
883 }
884 // Fast case: Convert number in radix 10.
885 if (IS_UNDEFINED(radix) || radix === 10) {
886 return %_NumberToString(number);
887 }
888
889 // Convert the radix to an integer and check the range.
890 radix = TO_INTEGER(radix);
891 if (radix < 2 || radix > 36) throw MakeRangeError(kToRadixFormatRange);
892 // Convert the number to a string in the given radix.
893 return %NumberToRadixString(number, radix);
894}
895
896
897// ES6 20.1.3.4 Number.prototype.toLocaleString([reserved1 [, reserved2]])
898function NumberToLocaleString() {
899 return %_Call(NumberToStringJS, this);
900}
901
902
903// ES6 20.1.3.7 Number.prototype.valueOf()
904function NumberValueOf() {
905 // NOTE: Both Number objects and values can enter here as
906 // 'this'. This is not as dictated by ECMA-262.
907 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
908 throw MakeTypeError(kNotGeneric, 'Number.prototype.valueOf');
909 }
910 return %_ValueOf(this);
911}
912
913
914// ES6 20.1.3.3 Number.prototype.toFixed(fractionDigits)
915function NumberToFixedJS(fractionDigits) {
916 var x = this;
917 if (!IS_NUMBER(this)) {
918 if (!IS_NUMBER_WRAPPER(this)) {
919 throw MakeTypeError(kIncompatibleMethodReceiver,
920 "Number.prototype.toFixed", this);
921 }
922 // Get the value of this number in case it's an object.
923 x = %_ValueOf(this);
924 }
925 var f = TO_INTEGER(fractionDigits);
926
927 if (f < 0 || f > 20) {
928 throw MakeRangeError(kNumberFormatRange, "toFixed() digits");
929 }
930
931 if (NUMBER_IS_NAN(x)) return "NaN";
932 if (x == INFINITY) return "Infinity";
933 if (x == -INFINITY) return "-Infinity";
934
935 return %NumberToFixed(x, f);
936}
937
938
939// ES6 20.1.3.2 Number.prototype.toExponential(fractionDigits)
940function NumberToExponentialJS(fractionDigits) {
941 var x = this;
942 if (!IS_NUMBER(this)) {
943 if (!IS_NUMBER_WRAPPER(this)) {
944 throw MakeTypeError(kIncompatibleMethodReceiver,
945 "Number.prototype.toExponential", this);
946 }
947 // Get the value of this number in case it's an object.
948 x = %_ValueOf(this);
949 }
950 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
951
952 if (NUMBER_IS_NAN(x)) return "NaN";
953 if (x == INFINITY) return "Infinity";
954 if (x == -INFINITY) return "-Infinity";
955
956 if (IS_UNDEFINED(f)) {
957 f = -1; // Signal for runtime function that f is not defined.
958 } else if (f < 0 || f > 20) {
959 throw MakeRangeError(kNumberFormatRange, "toExponential()");
960 }
961 return %NumberToExponential(x, f);
962}
963
964
965// ES6 20.1.3.5 Number.prototype.toPrecision(precision)
966function NumberToPrecisionJS(precision) {
967 var x = this;
968 if (!IS_NUMBER(this)) {
969 if (!IS_NUMBER_WRAPPER(this)) {
970 throw MakeTypeError(kIncompatibleMethodReceiver,
971 "Number.prototype.toPrecision", this);
972 }
973 // Get the value of this number in case it's an object.
974 x = %_ValueOf(this);
975 }
976 if (IS_UNDEFINED(precision)) return TO_STRING(x);
977 var p = TO_INTEGER(precision);
978
979 if (NUMBER_IS_NAN(x)) return "NaN";
980 if (x == INFINITY) return "Infinity";
981 if (x == -INFINITY) return "-Infinity";
982
983 if (p < 1 || p > 21) {
984 throw MakeRangeError(kToPrecisionFormatRange);
985 }
986 return %NumberToPrecision(x, p);
987}
988
989
990// Harmony isFinite.
991function NumberIsFinite(number) {
992 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
993}
994
995
996// Harmony isInteger
997function NumberIsInteger(number) {
998 return NumberIsFinite(number) && TO_INTEGER(number) == number;
999}
1000
1001
1002// Harmony isNaN.
1003function NumberIsNaN(number) {
1004 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1005}
1006
1007
1008// Harmony isSafeInteger
1009function NumberIsSafeInteger(number) {
1010 if (NumberIsFinite(number)) {
1011 var integral = TO_INTEGER(number);
1012 if (integral == number) {
1013 return MathAbs(integral) <= kMaxSafeInteger;
1014 }
1015 }
1016 return false;
1017}
1018
1019
1020// ----------------------------------------------------------------------------
1021
1022%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0));
1023
1024%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8);
1025// Set up the constructor property on the Number prototype object.
1026%AddNamedProperty(GlobalNumber.prototype, "constructor", GlobalNumber,
1027 DONT_ENUM);
1028
1029utils.InstallConstants(GlobalNumber, [
1030 // ECMA-262 section 15.7.3.1.
1031 "MAX_VALUE", 1.7976931348623157e+308,
1032 // ECMA-262 section 15.7.3.2.
1033 "MIN_VALUE", 5e-324,
1034 // ECMA-262 section 15.7.3.3.
1035 "NaN", NaN,
1036 // ECMA-262 section 15.7.3.4.
1037 "NEGATIVE_INFINITY", -INFINITY,
1038 // ECMA-262 section 15.7.3.5.
1039 "POSITIVE_INFINITY", INFINITY,
1040
1041 // --- Harmony constants (no spec refs until settled.)
1042
1043 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1044 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1045 "EPSILON", %_MathPow(2, -52)
1046]);
1047
1048// Set up non-enumerable functions on the Number prototype object.
1049utils.InstallFunctions(GlobalNumber.prototype, DONT_ENUM, [
1050 "toString", NumberToStringJS,
1051 "toLocaleString", NumberToLocaleString,
1052 "valueOf", NumberValueOf,
1053 "toFixed", NumberToFixedJS,
1054 "toExponential", NumberToExponentialJS,
1055 "toPrecision", NumberToPrecisionJS
1056]);
1057
1058// Harmony Number constructor additions
1059utils.InstallFunctions(GlobalNumber, DONT_ENUM, [
1060 "isFinite", NumberIsFinite,
1061 "isInteger", NumberIsInteger,
1062 "isNaN", NumberIsNaN,
1063 "isSafeInteger", NumberIsSafeInteger,
1064 "parseInt", GlobalParseInt,
1065 "parseFloat", GlobalParseFloat
1066]);
1067
1068%SetForceInlineFlag(NumberIsNaN);
1069
1070
1071// ----------------------------------------------------------------------------
1072// Iterator related spec functions.
1073
1074// ES6 7.4.1 GetIterator(obj, method)
1075function GetIterator(obj, method) {
1076 if (IS_UNDEFINED(method)) {
1077 method = obj[iteratorSymbol];
1078 }
1079 if (!IS_CALLABLE(method)) {
1080 throw MakeTypeError(kNotIterable, obj);
1081 }
1082 var iterator = %_Call(method, obj);
1083 if (!IS_RECEIVER(iterator)) {
1084 throw MakeTypeError(kNotAnIterator, iterator);
1085 }
1086 return iterator;
1087}
1088
1089// ----------------------------------------------------------------------------
1090// Exports
1091
1092utils.Export(function(to) {
1093 to.GetIterator = GetIterator;
1094 to.GetMethod = GetMethod;
1095 to.IsFinite = GlobalIsFinite;
1096 to.IsNaN = GlobalIsNaN;
1097 to.NumberIsNaN = NumberIsNaN;
Ben Murdochda12d292016-06-02 14:46:10 +01001098 to.NumberIsInteger = NumberIsInteger;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099 to.ObjectDefineProperties = ObjectDefineProperties;
1100 to.ObjectDefineProperty = ObjectDefineProperty;
Ben Murdochda12d292016-06-02 14:46:10 +01001101 to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102});
1103
1104%InstallToContext([
1105 "object_value_of", ObjectValueOf,
1106]);
1107
1108})