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