1 // 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.
5 // This file relies on the fact that the following declarations have been made
7 // var $Object = global.Object;
8 // var $Boolean = global.Boolean;
9 // var $Number = global.Number;
10 // var $Function = global.Function;
11 // var $Array = global.Array;
13 var $isNaN = GlobalIsNaN;
14 var $isFinite = GlobalIsFinite;
16 // ----------------------------------------------------------------------------
18 // Helper function used to install functions on objects.
19 function InstallFunctions(object, attributes, functions) {
20 if (functions.length >= 8) {
21 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
23 for (var i = 0; i < functions.length; i += 2) {
24 var key = functions[i];
25 var f = functions[i + 1];
26 %FunctionSetName(f, key);
27 %FunctionRemovePrototype(f);
28 %AddNamedProperty(object, key, f, attributes);
31 %ToFastProperties(object);
35 function OverrideFunction(object, name, f) {
36 ObjectDefineProperty(object, name, { value: f,
40 %FunctionSetName(f, name);
41 %FunctionRemovePrototype(f);
46 // Helper function to install a getter-only accessor property.
47 function InstallGetter(object, name, getter) {
48 %FunctionSetName(getter, name);
49 %FunctionRemovePrototype(getter);
50 %DefineAccessorPropertyUnchecked(object, name, getter, null, DONT_ENUM);
51 %SetNativeFlag(getter);
55 // Helper function to install a getter/setter accessor property.
56 function InstallGetterSetter(object, name, getter, setter) {
57 %FunctionSetName(getter, name);
58 %FunctionSetName(setter, name);
59 %FunctionRemovePrototype(getter);
60 %FunctionRemovePrototype(setter);
61 %DefineAccessorPropertyUnchecked(object, name, getter, setter, DONT_ENUM);
62 %SetNativeFlag(getter);
63 %SetNativeFlag(setter);
67 // Helper function for installing constant properties on objects.
68 function InstallConstants(object, constants) {
69 if (constants.length >= 4) {
70 %OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1);
72 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
73 for (var i = 0; i < constants.length; i += 2) {
74 var name = constants[i];
75 var k = constants[i + 1];
76 %AddNamedProperty(object, name, k, attributes);
78 %ToFastProperties(object);
82 // Prevents changes to the prototype of a built-in function.
83 // The "prototype" property of the function object is made non-configurable,
84 // and the prototype object is made non-extensible. The latter prevents
85 // changing the __proto__ property.
86 function SetUpLockedPrototype(constructor, fields, methods) {
87 %CheckIsBootstrapping();
88 var prototype = constructor.prototype;
89 // Install functions first, because this function is used to initialize
90 // PropertyDescriptor itself.
91 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
92 if (property_count >= 4) {
93 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
96 for (var i = 0; i < fields.length; i++) {
97 %AddNamedProperty(prototype, fields[i],
98 UNDEFINED, DONT_ENUM | DONT_DELETE);
101 for (var i = 0; i < methods.length; i += 2) {
102 var key = methods[i];
103 var f = methods[i + 1];
104 %AddNamedProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
107 %InternalSetPrototype(prototype, null);
108 %ToFastProperties(prototype);
112 // ----------------------------------------------------------------------------
116 function GlobalIsNaN(number) {
117 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
118 return NUMBER_IS_NAN(number);
123 function GlobalIsFinite(number) {
124 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
125 return NUMBER_IS_FINITE(number);
129 // ECMA-262 - 15.1.2.2
130 function GlobalParseInt(string, radix) {
131 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
132 // Some people use parseInt instead of Math.floor. This
133 // optimization makes parseInt on a Smi 12 times faster (60ns
134 // vs 800ns). The following optimization makes parseInt on a
135 // non-Smi number 9 times faster (230ns vs 2070ns). Together
136 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
137 if (%_IsSmi(string)) return string;
138 if (IS_NUMBER(string) &&
139 ((0.01 < string && string < 1e9) ||
140 (-1e9 < string && string < -0.01))) {
144 string = TO_STRING_INLINE(string);
147 // The spec says ToString should be evaluated before ToInt32.
148 string = TO_STRING_INLINE(string);
149 radix = TO_INT32(radix);
150 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
155 if (%_HasCachedArrayIndex(string) &&
156 (radix == 0 || radix == 10)) {
157 return %_GetCachedArrayIndex(string);
159 return %StringParseInt(string, radix);
163 // ECMA-262 - 15.1.2.3
164 function GlobalParseFloat(string) {
165 string = TO_STRING_INLINE(string);
166 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
167 return %StringParseFloat(string);
171 function GlobalEval(x) {
172 if (!IS_STRING(x)) return x;
174 var global_proxy = %GlobalProxy(global);
176 var f = %CompileString(x, false, 0);
177 if (!IS_FUNCTION(f)) return f;
179 return %_CallFunction(global_proxy, f);
183 // ----------------------------------------------------------------------------
185 // Set up global object.
186 function SetUpGlobal() {
187 %CheckIsBootstrapping();
189 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
191 // ECMA 262 - 15.1.1.1.
192 %AddNamedProperty(global, "NaN", NAN, attributes);
194 // ECMA-262 - 15.1.1.2.
195 %AddNamedProperty(global, "Infinity", INFINITY, attributes);
197 // ECMA-262 - 15.1.1.3.
198 %AddNamedProperty(global, "undefined", UNDEFINED, attributes);
200 // Set up non-enumerable function on the global object.
201 InstallFunctions(global, DONT_ENUM, $Array(
202 "isNaN", GlobalIsNaN,
203 "isFinite", GlobalIsFinite,
204 "parseInt", GlobalParseInt,
205 "parseFloat", GlobalParseFloat,
213 // ----------------------------------------------------------------------------
216 var DefaultObjectToString = NoSideEffectsObjectToString;
217 // ECMA-262 - 15.2.4.2
218 function NoSideEffectsObjectToString() {
219 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
220 if (IS_NULL(this)) return "[object Null]";
221 return "[object " + %_ClassOf(TO_OBJECT_INLINE(this)) + "]";
225 // ECMA-262 - 15.2.4.3
226 function ObjectToLocaleString() {
227 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
228 return this.toString();
232 // ECMA-262 - 15.2.4.4
233 function ObjectValueOf() {
234 return TO_OBJECT_INLINE(this);
238 // ECMA-262 - 15.2.4.5
239 function ObjectHasOwnProperty(V) {
240 if (%_IsJSProxy(this)) {
241 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
242 if (IS_SYMBOL(V)) return false;
244 var handler = %GetHandler(this);
245 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
247 return %HasOwnProperty(TO_OBJECT_INLINE(this), ToName(V));
251 // ECMA-262 - 15.2.4.6
252 function ObjectIsPrototypeOf(V) {
253 if (!IS_SPEC_OBJECT(V)) return false;
254 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
255 return %IsInPrototypeChain(this, V);
259 // ECMA-262 - 15.2.4.6
260 function ObjectPropertyIsEnumerable(V) {
262 if (%_IsJSProxy(this)) {
263 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
264 if (IS_SYMBOL(V)) return false;
266 var desc = GetOwnPropertyJS(this, P);
267 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
269 return %IsPropertyEnumerable(TO_OBJECT_INLINE(this), P);
273 // Extensions for providing property getters and setters.
274 function ObjectDefineGetter(name, fun) {
276 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
277 receiver = %GlobalProxy(global);
279 if (!IS_SPEC_FUNCTION(fun)) {
280 throw new $TypeError(
281 'Object.prototype.__defineGetter__: Expecting function');
283 var desc = new PropertyDescriptor();
285 desc.setEnumerable(true);
286 desc.setConfigurable(true);
287 DefineOwnProperty(TO_OBJECT_INLINE(receiver), ToName(name), desc, false);
291 function ObjectLookupGetter(name) {
293 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
294 receiver = %GlobalProxy(global);
296 return %LookupAccessor(TO_OBJECT_INLINE(receiver), ToName(name), GETTER);
300 function ObjectDefineSetter(name, fun) {
302 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
303 receiver = %GlobalProxy(global);
305 if (!IS_SPEC_FUNCTION(fun)) {
306 throw new $TypeError(
307 'Object.prototype.__defineSetter__: Expecting function');
309 var desc = new PropertyDescriptor();
311 desc.setEnumerable(true);
312 desc.setConfigurable(true);
313 DefineOwnProperty(TO_OBJECT_INLINE(receiver), ToName(name), desc, false);
317 function ObjectLookupSetter(name) {
319 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
320 receiver = %GlobalProxy(global);
322 return %LookupAccessor(TO_OBJECT_INLINE(receiver), ToName(name), SETTER);
326 function ObjectKeys(obj) {
327 obj = TO_OBJECT_INLINE(obj);
328 if (%_IsJSProxy(obj)) {
329 var handler = %GetHandler(obj);
330 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
331 return ToNameArray(names, "keys", false);
333 return %OwnKeys(obj);
338 function IsAccessorDescriptor(desc) {
339 if (IS_UNDEFINED(desc)) return false;
340 return desc.hasGetter() || desc.hasSetter();
345 function IsDataDescriptor(desc) {
346 if (IS_UNDEFINED(desc)) return false;
347 return desc.hasValue() || desc.hasWritable();
352 function IsGenericDescriptor(desc) {
353 if (IS_UNDEFINED(desc)) return false;
354 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
358 function IsInconsistentDescriptor(desc) {
359 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
364 function FromPropertyDescriptor(desc) {
365 if (IS_UNDEFINED(desc)) return desc;
367 if (IsDataDescriptor(desc)) {
368 return { value: desc.getValue(),
369 writable: desc.isWritable(),
370 enumerable: desc.isEnumerable(),
371 configurable: desc.isConfigurable() };
373 // Must be an AccessorDescriptor then. We never return a generic descriptor.
374 return { get: desc.getGet(),
376 enumerable: desc.isEnumerable(),
377 configurable: desc.isConfigurable() };
382 function FromGenericPropertyDescriptor(desc) {
383 if (IS_UNDEFINED(desc)) return desc;
384 var obj = new $Object();
386 if (desc.hasValue()) {
387 %AddNamedProperty(obj, "value", desc.getValue(), NONE);
389 if (desc.hasWritable()) {
390 %AddNamedProperty(obj, "writable", desc.isWritable(), NONE);
392 if (desc.hasGetter()) {
393 %AddNamedProperty(obj, "get", desc.getGet(), NONE);
395 if (desc.hasSetter()) {
396 %AddNamedProperty(obj, "set", desc.getSet(), NONE);
398 if (desc.hasEnumerable()) {
399 %AddNamedProperty(obj, "enumerable", desc.isEnumerable(), NONE);
401 if (desc.hasConfigurable()) {
402 %AddNamedProperty(obj, "configurable", desc.isConfigurable(), NONE);
409 function ToPropertyDescriptor(obj) {
410 if (!IS_SPEC_OBJECT(obj)) {
411 throw MakeTypeError("property_desc_object", [obj]);
413 var desc = new PropertyDescriptor();
415 if ("enumerable" in obj) {
416 desc.setEnumerable(ToBoolean(obj.enumerable));
419 if ("configurable" in obj) {
420 desc.setConfigurable(ToBoolean(obj.configurable));
423 if ("value" in obj) {
424 desc.setValue(obj.value);
427 if ("writable" in obj) {
428 desc.setWritable(ToBoolean(obj.writable));
433 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
434 throw MakeTypeError("getter_must_be_callable", [get]);
441 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
442 throw MakeTypeError("setter_must_be_callable", [set]);
447 if (IsInconsistentDescriptor(desc)) {
448 throw MakeTypeError("value_and_accessor", [obj]);
454 // For Harmony proxies.
455 function ToCompletePropertyDescriptor(obj) {
456 var desc = ToPropertyDescriptor(obj);
457 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
458 if (!desc.hasValue()) desc.setValue(UNDEFINED);
459 if (!desc.hasWritable()) desc.setWritable(false);
461 // Is accessor descriptor.
462 if (!desc.hasGetter()) desc.setGet(UNDEFINED);
463 if (!desc.hasSetter()) desc.setSet(UNDEFINED);
465 if (!desc.hasEnumerable()) desc.setEnumerable(false);
466 if (!desc.hasConfigurable()) desc.setConfigurable(false);
471 function PropertyDescriptor() {
472 // Initialize here so they are all in-object and have the same map.
473 // Default values from ES5 8.6.1.
474 this.value_ = UNDEFINED;
475 this.hasValue_ = false;
476 this.writable_ = false;
477 this.hasWritable_ = false;
478 this.enumerable_ = false;
479 this.hasEnumerable_ = false;
480 this.configurable_ = false;
481 this.hasConfigurable_ = false;
482 this.get_ = UNDEFINED;
483 this.hasGetter_ = false;
484 this.set_ = UNDEFINED;
485 this.hasSetter_ = false;
488 SetUpLockedPrototype(PropertyDescriptor, $Array(
502 "toString", function PropertyDescriptor_ToString() {
503 return "[object PropertyDescriptor]";
505 "setValue", function PropertyDescriptor_SetValue(value) {
507 this.hasValue_ = true;
509 "getValue", function PropertyDescriptor_GetValue() {
512 "hasValue", function PropertyDescriptor_HasValue() {
513 return this.hasValue_;
515 "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) {
516 this.enumerable_ = enumerable;
517 this.hasEnumerable_ = true;
519 "isEnumerable", function PropertyDescriptor_IsEnumerable() {
520 return this.enumerable_;
522 "hasEnumerable", function PropertyDescriptor_HasEnumerable() {
523 return this.hasEnumerable_;
525 "setWritable", function PropertyDescriptor_SetWritable(writable) {
526 this.writable_ = writable;
527 this.hasWritable_ = true;
529 "isWritable", function PropertyDescriptor_IsWritable() {
530 return this.writable_;
532 "hasWritable", function PropertyDescriptor_HasWritable() {
533 return this.hasWritable_;
536 function PropertyDescriptor_SetConfigurable(configurable) {
537 this.configurable_ = configurable;
538 this.hasConfigurable_ = true;
540 "hasConfigurable", function PropertyDescriptor_HasConfigurable() {
541 return this.hasConfigurable_;
543 "isConfigurable", function PropertyDescriptor_IsConfigurable() {
544 return this.configurable_;
546 "setGet", function PropertyDescriptor_SetGetter(get) {
548 this.hasGetter_ = true;
550 "getGet", function PropertyDescriptor_GetGetter() {
553 "hasGetter", function PropertyDescriptor_HasGetter() {
554 return this.hasGetter_;
556 "setSet", function PropertyDescriptor_SetSetter(set) {
558 this.hasSetter_ = true;
560 "getSet", function PropertyDescriptor_GetSetter() {
563 "hasSetter", function PropertyDescriptor_HasSetter() {
564 return this.hasSetter_;
568 // Converts an array returned from Runtime_GetOwnProperty to an actual
569 // property descriptor. For a description of the array layout please
570 // see the runtime.cc file.
571 function ConvertDescriptorArrayToDescriptor(desc_array) {
572 if (IS_UNDEFINED(desc_array)) {
576 var desc = new PropertyDescriptor();
577 // This is an accessor.
578 if (desc_array[IS_ACCESSOR_INDEX]) {
579 desc.setGet(desc_array[GETTER_INDEX]);
580 desc.setSet(desc_array[SETTER_INDEX]);
582 desc.setValue(desc_array[VALUE_INDEX]);
583 desc.setWritable(desc_array[WRITABLE_INDEX]);
585 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
586 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
592 // For Harmony proxies.
593 function GetTrap(handler, name, defaultTrap) {
594 var trap = handler[name];
595 if (IS_UNDEFINED(trap)) {
596 if (IS_UNDEFINED(defaultTrap)) {
597 throw MakeTypeError("handler_trap_missing", [handler, name]);
600 } else if (!IS_SPEC_FUNCTION(trap)) {
601 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
607 function CallTrap0(handler, name, defaultTrap) {
608 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
612 function CallTrap1(handler, name, defaultTrap, x) {
613 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
617 function CallTrap2(handler, name, defaultTrap, x, y) {
618 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
622 // ES5 section 8.12.1.
623 function GetOwnPropertyJS(obj, v) {
625 if (%_IsJSProxy(obj)) {
626 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
627 if (IS_SYMBOL(v)) return UNDEFINED;
629 var handler = %GetHandler(obj);
630 var descriptor = CallTrap1(
631 handler, "getOwnPropertyDescriptor", UNDEFINED, p);
632 if (IS_UNDEFINED(descriptor)) return descriptor;
633 var desc = ToCompletePropertyDescriptor(descriptor);
634 if (!desc.isConfigurable()) {
635 throw MakeTypeError("proxy_prop_not_configurable",
636 [handler, "getOwnPropertyDescriptor", p, descriptor]);
641 // GetOwnProperty returns an array indexed by the constants
642 // defined in macros.py.
643 // If p is not a property on obj undefined is returned.
644 var props = %GetOwnProperty(TO_OBJECT_INLINE(obj), p);
646 return ConvertDescriptorArrayToDescriptor(props);
650 // ES5 section 8.12.7.
651 function Delete(obj, p, should_throw) {
652 var desc = GetOwnPropertyJS(obj, p);
653 if (IS_UNDEFINED(desc)) return true;
654 if (desc.isConfigurable()) {
655 %DeleteProperty(obj, p, 0);
657 } else if (should_throw) {
658 throw MakeTypeError("define_disallowed", [p]);
665 // ES6, draft 12-24-14, section 7.3.8
666 function GetMethod(obj, p) {
668 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED;
669 if (IS_SPEC_FUNCTION(func)) return func;
670 throw MakeTypeError('called_non_callable', [typeof func]);
675 function DefineProxyProperty(obj, p, attributes, should_throw) {
676 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
677 if (IS_SYMBOL(p)) return false;
679 var handler = %GetHandler(obj);
680 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
681 if (!ToBoolean(result)) {
683 throw MakeTypeError("handler_returned_false",
684 [handler, "defineProperty"]);
694 function DefineObjectProperty(obj, p, desc, should_throw) {
695 var current_array = %GetOwnProperty(obj, ToName(p));
696 var current = ConvertDescriptorArrayToDescriptor(current_array);
697 var extensible = %IsExtensible(obj);
699 // Error handling according to spec.
701 if (IS_UNDEFINED(current) && !extensible) {
703 throw MakeTypeError("define_disallowed", [p]);
709 if (!IS_UNDEFINED(current)) {
711 if ((IsGenericDescriptor(desc) ||
712 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
713 (!desc.hasEnumerable() ||
714 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
715 (!desc.hasConfigurable() ||
716 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
717 (!desc.hasWritable() ||
718 SameValue(desc.isWritable(), current.isWritable())) &&
720 SameValue(desc.getValue(), current.getValue())) &&
721 (!desc.hasGetter() ||
722 SameValue(desc.getGet(), current.getGet())) &&
723 (!desc.hasSetter() ||
724 SameValue(desc.getSet(), current.getSet()))) {
727 if (!current.isConfigurable()) {
729 if (desc.isConfigurable() ||
730 (desc.hasEnumerable() &&
731 desc.isEnumerable() != current.isEnumerable())) {
733 throw MakeTypeError("redefine_disallowed", [p]);
739 if (!IsGenericDescriptor(desc)) {
741 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
743 throw MakeTypeError("redefine_disallowed", [p]);
749 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
750 if (!current.isWritable() && desc.isWritable()) {
752 throw MakeTypeError("redefine_disallowed", [p]);
757 if (!current.isWritable() && desc.hasValue() &&
758 !SameValue(desc.getValue(), current.getValue())) {
760 throw MakeTypeError("redefine_disallowed", [p]);
767 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
768 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
770 throw MakeTypeError("redefine_disallowed", [p]);
775 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
777 throw MakeTypeError("redefine_disallowed", [p]);
787 // Send flags - enumerable and configurable are common - writable is
788 // only send to the data descriptor.
789 // Take special care if enumerable and configurable is not defined on
790 // desc (we need to preserve the existing values from current).
792 if (desc.hasEnumerable()) {
793 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
794 } else if (!IS_UNDEFINED(current)) {
795 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
800 if (desc.hasConfigurable()) {
801 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
802 } else if (!IS_UNDEFINED(current)) {
803 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
807 if (IsDataDescriptor(desc) ||
808 (IsGenericDescriptor(desc) &&
809 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
810 // There are 3 cases that lead here:
811 // Step 4a - defining a new data property.
812 // Steps 9b & 12 - replacing an existing accessor property with a data
814 // Step 12 - updating an existing data property with a data or generic
817 if (desc.hasWritable()) {
818 flag |= desc.isWritable() ? 0 : READ_ONLY;
819 } else if (!IS_UNDEFINED(current)) {
820 flag |= current.isWritable() ? 0 : READ_ONLY;
825 var value = UNDEFINED; // Default value is undefined.
826 if (desc.hasValue()) {
827 value = desc.getValue();
828 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
829 value = current.getValue();
832 %DefineDataPropertyUnchecked(obj, p, value, flag);
834 // There are 3 cases that lead here:
835 // Step 4b - defining a new accessor property.
836 // Steps 9c & 12 - replacing an existing data property with an accessor
838 // Step 12 - updating an existing accessor property with an accessor
841 if (desc.hasGetter()) {
842 getter = desc.getGet();
843 } else if (IsAccessorDescriptor(current) && current.hasGetter()) {
844 getter = current.getGet();
847 if (desc.hasSetter()) {
848 setter = desc.getSet();
849 } else if (IsAccessorDescriptor(current) && current.hasSetter()) {
850 setter = current.getSet();
852 %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag);
858 // ES5 section 15.4.5.1.
859 function DefineArrayProperty(obj, p, desc, should_throw) {
860 // Note that the length of an array is not actually stored as part of the
861 // property, hence we use generated code throughout this function instead of
862 // DefineObjectProperty() to modify its value.
864 // Step 3 - Special handling for length property.
865 if (p === "length") {
866 var length = obj.length;
867 var old_length = length;
868 if (!desc.hasValue()) {
869 return DefineObjectProperty(obj, "length", desc, should_throw);
871 var new_length = ToUint32(desc.getValue());
872 if (new_length != ToNumber(desc.getValue())) {
873 throw new $RangeError('defineProperty() array length out of range');
875 var length_desc = GetOwnPropertyJS(obj, "length");
876 if (new_length != length && !length_desc.isWritable()) {
878 throw MakeTypeError("redefine_disallowed", [p]);
885 var emit_splice = %IsObserved(obj) && new_length !== old_length;
888 BeginPerformSplice(obj);
890 if (new_length < old_length)
891 removed.length = old_length - new_length;
894 while (new_length < length--) {
895 var index = ToString(length);
897 var deletedDesc = GetOwnPropertyJS(obj, index);
898 if (deletedDesc && deletedDesc.hasValue())
899 removed[length - new_length] = deletedDesc.getValue();
901 if (!Delete(obj, index, false)) {
902 new_length = length + 1;
907 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
909 EndPerformSplice(obj);
910 EnqueueSpliceRecord(obj,
911 new_length < old_length ? new_length : old_length,
913 new_length > old_length ? new_length - old_length : 0);
917 throw MakeTypeError("redefine_disallowed", [p]);
925 // Step 4 - Special handling for array index.
927 var index = ToUint32(p);
928 var emit_splice = false;
929 if (ToString(index) == p && index != 4294967295) {
930 var length = obj.length;
931 if (index >= length && %IsObserved(obj)) {
933 BeginPerformSplice(obj);
936 var length_desc = GetOwnPropertyJS(obj, "length");
937 if ((index >= length && !length_desc.isWritable()) ||
938 !DefineObjectProperty(obj, p, desc, true)) {
940 EndPerformSplice(obj);
942 throw MakeTypeError("define_disallowed", [p]);
947 if (index >= length) {
948 obj.length = index + 1;
951 EndPerformSplice(obj);
952 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
958 // Step 5 - Fallback to default implementation.
959 return DefineObjectProperty(obj, p, desc, should_throw);
963 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
964 function DefineOwnProperty(obj, p, desc, should_throw) {
965 if (%_IsJSProxy(obj)) {
966 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
967 if (IS_SYMBOL(p)) return false;
969 var attributes = FromGenericPropertyDescriptor(desc);
970 return DefineProxyProperty(obj, p, attributes, should_throw);
971 } else if (IS_ARRAY(obj)) {
972 return DefineArrayProperty(obj, p, desc, should_throw);
974 return DefineObjectProperty(obj, p, desc, should_throw);
979 // ES5 section 15.2.3.2.
980 function ObjectGetPrototypeOf(obj) {
981 if (!IS_SPEC_OBJECT(obj)) {
982 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
984 return %_GetPrototype(obj);
987 // ES6 section 19.1.2.19.
988 function ObjectSetPrototypeOf(obj, proto) {
989 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
991 if (proto !== null && !IS_SPEC_OBJECT(proto)) {
992 throw MakeTypeError("proto_object_or_null", [proto]);
995 if (IS_SPEC_OBJECT(obj)) {
996 %SetPrototype(obj, proto);
1003 // ES5 section 15.2.3.3
1004 function ObjectGetOwnPropertyDescriptor(obj, p) {
1005 if (!IS_SPEC_OBJECT(obj)) {
1006 throw MakeTypeError("called_on_non_object",
1007 ["Object.getOwnPropertyDescriptor"]);
1009 var desc = GetOwnPropertyJS(obj, p);
1010 return FromPropertyDescriptor(desc);
1014 // For Harmony proxies
1015 function ToNameArray(obj, trap, includeSymbols) {
1016 if (!IS_SPEC_OBJECT(obj)) {
1017 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1019 var n = ToUint32(obj.length);
1020 var array = new $Array(n);
1022 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
1023 for (var index = 0; index < n; index++) {
1024 var s = ToName(obj[index]);
1025 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1026 if (IS_SYMBOL(s) && !includeSymbols) continue;
1027 if (%HasOwnProperty(names, s)) {
1028 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1034 array.length = realLength;
1039 function ObjectGetOwnPropertyKeys(obj, filter) {
1040 var nameArrays = new InternalArray();
1041 filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1042 var interceptorInfo = %GetInterceptorInfo(obj);
1044 // Find all the indexed properties.
1046 // Only get own element names if we want to include string keys.
1047 if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
1048 var ownElementNames = %GetOwnElementNames(obj);
1049 for (var i = 0; i < ownElementNames.length; ++i) {
1050 ownElementNames[i] = %_NumberToString(ownElementNames[i]);
1052 nameArrays.push(ownElementNames);
1053 // Get names for indexed interceptor properties.
1054 if ((interceptorInfo & 1) != 0) {
1055 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1056 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1057 nameArrays.push(indexedInterceptorNames);
1062 // Find all the named properties.
1064 // Get own property names.
1065 nameArrays.push(%GetOwnPropertyNames(obj, filter));
1067 // Get names for named interceptor properties if any.
1068 if ((interceptorInfo & 2) != 0) {
1069 var namedInterceptorNames =
1070 %GetNamedInterceptorPropertyNames(obj);
1071 if (!IS_UNDEFINED(namedInterceptorNames)) {
1072 nameArrays.push(namedInterceptorNames);
1077 %Apply(InternalArray.prototype.concat,
1078 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1080 // Property names are expected to be unique strings,
1081 // but interceptors can interfere with that assumption.
1082 if (interceptorInfo != 0) {
1083 var seenKeys = { __proto__: null };
1085 for (var i = 0; i < propertyNames.length; ++i) {
1086 var name = propertyNames[i];
1087 if (IS_SYMBOL(name)) {
1088 if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
1092 if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
1093 name = ToString(name);
1095 if (seenKeys[name]) continue;
1096 seenKeys[name] = true;
1097 propertyNames[j++] = name;
1099 propertyNames.length = j;
1102 return propertyNames;
1106 // ES5 section 15.2.3.4.
1107 function ObjectGetOwnPropertyNames(obj) {
1108 obj = TO_OBJECT_INLINE(obj);
1109 // Special handling for proxies.
1110 if (%_IsJSProxy(obj)) {
1111 var handler = %GetHandler(obj);
1112 var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1113 return ToNameArray(names, "getOwnPropertyNames", false);
1116 return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
1120 // ES5 section 15.2.3.5.
1121 function ObjectCreate(proto, properties) {
1122 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1123 throw MakeTypeError("proto_object_or_null", [proto]);
1126 %InternalSetPrototype(obj, proto);
1127 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1132 // ES5 section 15.2.3.6.
1133 function ObjectDefineProperty(obj, p, attributes) {
1134 if (!IS_SPEC_OBJECT(obj)) {
1135 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1137 var name = ToName(p);
1138 if (%_IsJSProxy(obj)) {
1139 // Clone the attributes object for protection.
1140 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1141 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1142 var attributesClone = { __proto__: null };
1143 for (var a in attributes) {
1144 attributesClone[a] = attributes[a];
1146 DefineProxyProperty(obj, name, attributesClone, true);
1147 // The following would implement the spec as in the current proposal,
1148 // but after recent comments on es-discuss, is most likely obsolete.
1150 var defineObj = FromGenericPropertyDescriptor(desc);
1151 var names = ObjectGetOwnPropertyNames(attributes);
1153 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1154 for (var i = 0; i < names.length; i++) {
1156 if (!(%HasOwnProperty(standardNames, N))) {
1157 var attr = GetOwnPropertyJS(attributes, N);
1158 DefineOwnProperty(descObj, N, attr, true);
1161 // This is really confusing the types, but it is what the proxies spec
1162 // currently requires:
1166 var desc = ToPropertyDescriptor(attributes);
1167 DefineOwnProperty(obj, name, desc, true);
1173 function GetOwnEnumerablePropertyNames(object) {
1174 var names = new InternalArray();
1175 for (var key in object) {
1176 if (%HasOwnProperty(object, key)) {
1181 var filter = PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1182 var symbols = %GetOwnPropertyNames(object, filter);
1183 for (var i = 0; i < symbols.length; ++i) {
1184 var symbol = symbols[i];
1185 if (IS_SYMBOL(symbol)) {
1186 var desc = ObjectGetOwnPropertyDescriptor(object, symbol);
1187 if (desc.enumerable) names.push(symbol);
1195 // ES5 section 15.2.3.7.
1196 function ObjectDefineProperties(obj, properties) {
1197 if (!IS_SPEC_OBJECT(obj)) {
1198 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1200 var props = TO_OBJECT_INLINE(properties);
1201 var names = GetOwnEnumerablePropertyNames(props);
1202 var descriptors = new InternalArray();
1203 for (var i = 0; i < names.length; i++) {
1204 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1206 for (var i = 0; i < names.length; i++) {
1207 DefineOwnProperty(obj, names[i], descriptors[i], true);
1214 function ProxyFix(obj) {
1215 var handler = %GetHandler(obj);
1216 var props = CallTrap0(handler, "fix", UNDEFINED);
1217 if (IS_UNDEFINED(props)) {
1218 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1221 if (%IsJSFunctionProxy(obj)) {
1222 var callTrap = %GetCallTrap(obj);
1223 var constructTrap = %GetConstructTrap(obj);
1224 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1225 %Fix(obj); // becomes a regular function
1226 %SetCode(obj, code);
1227 // TODO(rossberg): What about length and other properties? Not specified.
1228 // We just put in some half-reasonable defaults for now.
1229 var prototype = new $Object();
1230 $Object.defineProperty(prototype, "constructor",
1231 {value: obj, writable: true, enumerable: false, configurable: true});
1232 // TODO(v8:1530): defineProperty does not handle prototype and length.
1233 %FunctionSetPrototype(obj, prototype);
1238 ObjectDefineProperties(obj, props);
1242 // ES5 section 15.2.3.8.
1243 function ObjectSealJS(obj) {
1244 if (!IS_SPEC_OBJECT(obj)) {
1245 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1247 var isProxy = %_IsJSProxy(obj);
1248 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1252 var names = ObjectGetOwnPropertyNames(obj);
1253 for (var i = 0; i < names.length; i++) {
1254 var name = names[i];
1255 var desc = GetOwnPropertyJS(obj, name);
1256 if (desc.isConfigurable()) {
1257 desc.setConfigurable(false);
1258 DefineOwnProperty(obj, name, desc, true);
1261 %PreventExtensions(obj);
1263 // TODO(adamk): Is it worth going to this fast path if the
1264 // object's properties are already in dictionary mode?
1271 // ES5 section 15.2.3.9.
1272 function ObjectFreezeJS(obj) {
1273 if (!IS_SPEC_OBJECT(obj)) {
1274 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1276 var isProxy = %_IsJSProxy(obj);
1277 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1281 var names = ObjectGetOwnPropertyNames(obj);
1282 for (var i = 0; i < names.length; i++) {
1283 var name = names[i];
1284 var desc = GetOwnPropertyJS(obj, name);
1285 if (desc.isWritable() || desc.isConfigurable()) {
1286 if (IsDataDescriptor(desc)) desc.setWritable(false);
1287 desc.setConfigurable(false);
1288 DefineOwnProperty(obj, name, desc, true);
1291 %PreventExtensions(obj);
1293 // TODO(adamk): Is it worth going to this fast path if the
1294 // object's properties are already in dictionary mode?
1301 // ES5 section 15.2.3.10
1302 function ObjectPreventExtension(obj) {
1303 if (!IS_SPEC_OBJECT(obj)) {
1304 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1306 if (%_IsJSProxy(obj)) {
1309 %PreventExtensions(obj);
1314 // ES5 section 15.2.3.11
1315 function ObjectIsSealed(obj) {
1316 if (!IS_SPEC_OBJECT(obj)) {
1317 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1319 if (%_IsJSProxy(obj)) {
1322 if (%IsExtensible(obj)) {
1325 var names = ObjectGetOwnPropertyNames(obj);
1326 for (var i = 0; i < names.length; i++) {
1327 var name = names[i];
1328 var desc = GetOwnPropertyJS(obj, name);
1329 if (desc.isConfigurable()) {
1337 // ES5 section 15.2.3.12
1338 function ObjectIsFrozen(obj) {
1339 if (!IS_SPEC_OBJECT(obj)) {
1340 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1342 if (%_IsJSProxy(obj)) {
1345 if (%IsExtensible(obj)) {
1348 var names = ObjectGetOwnPropertyNames(obj);
1349 for (var i = 0; i < names.length; i++) {
1350 var name = names[i];
1351 var desc = GetOwnPropertyJS(obj, name);
1352 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1353 if (desc.isConfigurable()) return false;
1359 // ES5 section 15.2.3.13
1360 function ObjectIsExtensible(obj) {
1361 if (!IS_SPEC_OBJECT(obj)) {
1362 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1364 if (%_IsJSProxy(obj)) {
1367 return %IsExtensible(obj);
1371 // ECMA-262, Edition 6, section 19.1.2.10
1372 function ObjectIs(obj1, obj2) {
1373 return SameValue(obj1, obj2);
1377 // ECMA-262, Edition 6, section B.2.2.1.1
1378 function ObjectGetProto() {
1379 return %_GetPrototype(TO_OBJECT_INLINE(this));
1383 // ECMA-262, Edition 6, section B.2.2.1.2
1384 function ObjectSetProto(proto) {
1385 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1387 if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1388 %SetPrototype(this, proto);
1393 function ObjectConstructor(x) {
1394 if (%_IsConstructCall()) {
1395 if (x == null) return this;
1396 return TO_OBJECT_INLINE(x);
1398 if (x == null) return { };
1399 return TO_OBJECT_INLINE(x);
1404 // ----------------------------------------------------------------------------
1407 function SetUpObject() {
1408 %CheckIsBootstrapping();
1410 %SetNativeFlag($Object);
1411 %SetCode($Object, ObjectConstructor);
1413 %AddNamedProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1415 // Set up non-enumerable functions on the Object.prototype object.
1416 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1417 "toString", NoSideEffectsObjectToString,
1418 "toLocaleString", ObjectToLocaleString,
1419 "valueOf", ObjectValueOf,
1420 "hasOwnProperty", ObjectHasOwnProperty,
1421 "isPrototypeOf", ObjectIsPrototypeOf,
1422 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1423 "__defineGetter__", ObjectDefineGetter,
1424 "__lookupGetter__", ObjectLookupGetter,
1425 "__defineSetter__", ObjectDefineSetter,
1426 "__lookupSetter__", ObjectLookupSetter
1428 InstallGetterSetter($Object.prototype, "__proto__",
1429 ObjectGetProto, ObjectSetProto);
1431 // Set up non-enumerable functions in the Object object.
1432 InstallFunctions($Object, DONT_ENUM, $Array(
1434 "create", ObjectCreate,
1435 "defineProperty", ObjectDefineProperty,
1436 "defineProperties", ObjectDefineProperties,
1437 "freeze", ObjectFreezeJS,
1438 "getPrototypeOf", ObjectGetPrototypeOf,
1439 "setPrototypeOf", ObjectSetPrototypeOf,
1440 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1441 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1442 // getOwnPropertySymbols is added in symbol.js.
1444 "isExtensible", ObjectIsExtensible,
1445 "isFrozen", ObjectIsFrozen,
1446 "isSealed", ObjectIsSealed,
1447 "preventExtensions", ObjectPreventExtension,
1448 "seal", ObjectSealJS
1449 // deliverChangeRecords, getNotifier, observe and unobserve are added
1450 // in object-observe.js.
1457 // ----------------------------------------------------------------------------
1460 function BooleanConstructor(x) {
1461 if (%_IsConstructCall()) {
1462 %_SetValueOf(this, ToBoolean(x));
1464 return ToBoolean(x);
1469 function BooleanToString() {
1470 // NOTE: Both Boolean objects and values can enter here as
1471 // 'this'. This is not as dictated by ECMA-262.
1473 if (!IS_BOOLEAN(b)) {
1474 if (!IS_BOOLEAN_WRAPPER(b)) {
1475 throw new $TypeError('Boolean.prototype.toString is not generic');
1479 return b ? 'true' : 'false';
1483 function BooleanValueOf() {
1484 // NOTE: Both Boolean objects and values can enter here as
1485 // 'this'. This is not as dictated by ECMA-262.
1486 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1487 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1489 return %_ValueOf(this);
1493 // ----------------------------------------------------------------------------
1495 function SetUpBoolean () {
1496 %CheckIsBootstrapping();
1498 %SetCode($Boolean, BooleanConstructor);
1499 %FunctionSetPrototype($Boolean, new $Boolean(false));
1500 %AddNamedProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1502 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1503 "toString", BooleanToString,
1504 "valueOf", BooleanValueOf
1511 // ----------------------------------------------------------------------------
1514 function NumberConstructor(x) {
1515 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1516 if (%_IsConstructCall()) {
1517 %_SetValueOf(this, value);
1524 // ECMA-262 section 15.7.4.2.
1525 function NumberToStringJS(radix) {
1526 // NOTE: Both Number objects and values can enter here as
1527 // 'this'. This is not as dictated by ECMA-262.
1529 if (!IS_NUMBER(this)) {
1530 if (!IS_NUMBER_WRAPPER(this)) {
1531 throw new $TypeError('Number.prototype.toString is not generic');
1533 // Get the value of this number in case it's an object.
1534 number = %_ValueOf(this);
1536 // Fast case: Convert number in radix 10.
1537 if (IS_UNDEFINED(radix) || radix === 10) {
1538 return %_NumberToString(number);
1541 // Convert the radix to an integer and check the range.
1542 radix = TO_INTEGER(radix);
1543 if (radix < 2 || radix > 36) {
1544 throw new $RangeError('toString() radix argument must be between 2 and 36');
1546 // Convert the number to a string in the given radix.
1547 return %NumberToRadixString(number, radix);
1551 // ECMA-262 section 15.7.4.3
1552 function NumberToLocaleString() {
1553 return %_CallFunction(this, NumberToStringJS);
1557 // ECMA-262 section 15.7.4.4
1558 function NumberValueOf() {
1559 // NOTE: Both Number objects and values can enter here as
1560 // 'this'. This is not as dictated by ECMA-262.
1561 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1562 throw new $TypeError('Number.prototype.valueOf is not generic');
1564 return %_ValueOf(this);
1568 // ECMA-262 section 15.7.4.5
1569 function NumberToFixedJS(fractionDigits) {
1571 if (!IS_NUMBER(this)) {
1572 if (!IS_NUMBER_WRAPPER(this)) {
1573 throw MakeTypeError("incompatible_method_receiver",
1574 ["Number.prototype.toFixed", this]);
1576 // Get the value of this number in case it's an object.
1577 x = %_ValueOf(this);
1579 var f = TO_INTEGER(fractionDigits);
1581 if (f < 0 || f > 20) {
1582 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1585 if (NUMBER_IS_NAN(x)) return "NaN";
1586 if (x == INFINITY) return "Infinity";
1587 if (x == -INFINITY) return "-Infinity";
1589 return %NumberToFixed(x, f);
1593 // ECMA-262 section 15.7.4.6
1594 function NumberToExponentialJS(fractionDigits) {
1596 if (!IS_NUMBER(this)) {
1597 if (!IS_NUMBER_WRAPPER(this)) {
1598 throw MakeTypeError("incompatible_method_receiver",
1599 ["Number.prototype.toExponential", this]);
1601 // Get the value of this number in case it's an object.
1602 x = %_ValueOf(this);
1604 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1606 if (NUMBER_IS_NAN(x)) return "NaN";
1607 if (x == INFINITY) return "Infinity";
1608 if (x == -INFINITY) return "-Infinity";
1610 if (IS_UNDEFINED(f)) {
1611 f = -1; // Signal for runtime function that f is not defined.
1612 } else if (f < 0 || f > 20) {
1613 throw new $RangeError("toExponential() argument must be between 0 and 20");
1615 return %NumberToExponential(x, f);
1619 // ECMA-262 section 15.7.4.7
1620 function NumberToPrecisionJS(precision) {
1622 if (!IS_NUMBER(this)) {
1623 if (!IS_NUMBER_WRAPPER(this)) {
1624 throw MakeTypeError("incompatible_method_receiver",
1625 ["Number.prototype.toPrecision", this]);
1627 // Get the value of this number in case it's an object.
1628 x = %_ValueOf(this);
1630 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1631 var p = TO_INTEGER(precision);
1633 if (NUMBER_IS_NAN(x)) return "NaN";
1634 if (x == INFINITY) return "Infinity";
1635 if (x == -INFINITY) return "-Infinity";
1637 if (p < 1 || p > 21) {
1638 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1640 return %NumberToPrecision(x, p);
1644 // Harmony isFinite.
1645 function NumberIsFinite(number) {
1646 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1650 // Harmony isInteger
1651 function NumberIsInteger(number) {
1652 return NumberIsFinite(number) && TO_INTEGER(number) == number;
1657 function NumberIsNaN(number) {
1658 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1662 // Harmony isSafeInteger
1663 function NumberIsSafeInteger(number) {
1664 if (NumberIsFinite(number)) {
1665 var integral = TO_INTEGER(number);
1666 if (integral == number) return $abs(integral) <= $Number.MAX_SAFE_INTEGER;
1672 // ----------------------------------------------------------------------------
1674 function SetUpNumber() {
1675 %CheckIsBootstrapping();
1677 %SetCode($Number, NumberConstructor);
1678 %FunctionSetPrototype($Number, new $Number(0));
1680 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1681 // Set up the constructor property on the Number prototype object.
1682 %AddNamedProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1684 InstallConstants($Number, $Array(
1685 // ECMA-262 section 15.7.3.1.
1686 "MAX_VALUE", 1.7976931348623157e+308,
1687 // ECMA-262 section 15.7.3.2.
1688 "MIN_VALUE", 5e-324,
1689 // ECMA-262 section 15.7.3.3.
1691 // ECMA-262 section 15.7.3.4.
1692 "NEGATIVE_INFINITY", -INFINITY,
1693 // ECMA-262 section 15.7.3.5.
1694 "POSITIVE_INFINITY", INFINITY,
1696 // --- Harmony constants (no spec refs until settled.)
1698 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1699 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1700 "EPSILON", %_MathPow(2, -52)
1703 // Set up non-enumerable functions on the Number prototype object.
1704 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1705 "toString", NumberToStringJS,
1706 "toLocaleString", NumberToLocaleString,
1707 "valueOf", NumberValueOf,
1708 "toFixed", NumberToFixedJS,
1709 "toExponential", NumberToExponentialJS,
1710 "toPrecision", NumberToPrecisionJS
1713 // Harmony Number constructor additions
1714 InstallFunctions($Number, DONT_ENUM, $Array(
1715 "isFinite", NumberIsFinite,
1716 "isInteger", NumberIsInteger,
1717 "isNaN", NumberIsNaN,
1718 "isSafeInteger", NumberIsSafeInteger,
1719 "parseInt", GlobalParseInt,
1720 "parseFloat", GlobalParseFloat
1727 // ----------------------------------------------------------------------------
1730 function FunctionSourceString(func) {
1731 while (%IsJSFunctionProxy(func)) {
1732 func = %GetCallTrap(func);
1735 if (!IS_FUNCTION(func)) {
1736 throw new $TypeError('Function.prototype.toString is not generic');
1739 var classSource = %ClassGetSourceCode(func);
1740 if (IS_STRING(classSource)) {
1744 var source = %FunctionGetSourceCode(func);
1745 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1746 var name = %FunctionGetName(func);
1748 // Mimic what KJS does.
1749 return 'function ' + name + '() { [native code] }';
1751 return 'function () { [native code] }';
1755 if (%FunctionIsArrow(func)) {
1759 var name = %FunctionNameShouldPrintAsAnonymous(func)
1761 : %FunctionGetName(func);
1763 var isGenerator = %FunctionIsGenerator(func);
1764 var head = %FunctionIsConciseMethod(func)
1765 ? (isGenerator ? '*' : '')
1766 : (isGenerator ? 'function* ' : 'function ');
1767 return head + name + source;
1771 function FunctionToString() {
1772 return FunctionSourceString(this);
1777 function FunctionBind(this_arg) { // Length is 1.
1778 if (!IS_SPEC_FUNCTION(this)) {
1779 throw new $TypeError('Bind must be called on a function');
1781 var boundFunction = function () {
1782 // Poison .arguments and .caller, but is otherwise not detectable.
1784 // This function must not use any object literals (Object, Array, RegExp),
1785 // since the literals-array is being used to store the bound data.
1786 if (%_IsConstructCall()) {
1787 return %NewObjectFromBound(boundFunction);
1789 var bindings = %BoundFunctionGetBindings(boundFunction);
1791 var argc = %_ArgumentsLength();
1793 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1795 if (bindings.length === 2) {
1796 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1798 var bound_argc = bindings.length - 2;
1799 var argv = new InternalArray(bound_argc + argc);
1800 for (var i = 0; i < bound_argc; i++) {
1801 argv[i] = bindings[i + 2];
1803 for (var j = 0; j < argc; j++) {
1804 argv[i++] = %_Arguments(j);
1806 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1810 var old_length = this.length;
1811 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1812 if ((typeof old_length === "number") &&
1813 ((old_length >>> 0) === old_length)) {
1814 var argc = %_ArgumentsLength();
1815 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1816 new_length = old_length - argc;
1817 if (new_length < 0) new_length = 0;
1819 // This runtime function finds any remaining arguments on the stack,
1820 // so we don't pass the arguments object.
1821 var result = %FunctionBindArguments(boundFunction, this,
1822 this_arg, new_length);
1824 // We already have caller and arguments properties on functions,
1825 // which are non-configurable. It therefore makes no sence to
1826 // try to redefine these as defined by the spec. The spec says
1827 // that bind should make these throw a TypeError if get or set
1828 // is called and make them non-enumerable and non-configurable.
1829 // To be consistent with our normal functions we leave this as it is.
1830 // TODO(lrn): Do set these to be thrower.
1835 function NewFunctionFromString(arguments, function_token) {
1836 var n = arguments.length;
1839 p = ToString(arguments[0]);
1840 for (var i = 1; i < n - 1; i++) {
1841 p += ',' + ToString(arguments[i]);
1843 // If the formal parameters string include ) - an illegal
1844 // character - it may make the combined function expression
1845 // compile. We avoid this problem by checking for this early on.
1846 if (%_CallFunction(p, ')', $stringIndexOf) != -1) {
1847 throw MakeSyntaxError('paren_in_arg_string', []);
1849 // If the formal parameters include an unbalanced block comment, the
1850 // function must be rejected. Since JavaScript does not allow nested
1851 // comments we can include a trailing block comment to catch this.
1852 p += '\n\x2f**\x2f';
1854 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1855 var head = '(' + function_token + '(' + p + ') {\n';
1856 var src = head + body + '\n})';
1857 var global_proxy = %GlobalProxy(global);
1858 var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
1859 %FunctionMarkNameShouldPrintAsAnonymous(f);
1864 function FunctionConstructor(arg1) { // length == 1
1865 return NewFunctionFromString(arguments, 'function');
1869 // ----------------------------------------------------------------------------
1871 function SetUpFunction() {
1872 %CheckIsBootstrapping();
1874 %SetCode($Function, FunctionConstructor);
1875 %AddNamedProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1877 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1878 "bind", FunctionBind,
1879 "toString", FunctionToString
1886 // ----------------------------------------------------------------------------
1887 // Iterator related spec functions.
1889 // ES6 rev 33, 2015-02-12
1890 // 7.4.1 GetIterator ( obj, method )
1891 function GetIterator(obj, method) {
1892 if (IS_UNDEFINED(method)) {
1893 method = obj[symbolIterator];
1895 if (!IS_SPEC_FUNCTION(method)) {
1896 throw MakeTypeError('not_iterable', [obj]);
1898 var iterator = %_CallFunction(obj, method);
1899 if (!IS_SPEC_OBJECT(iterator)) {
1900 throw MakeTypeError('not_an_iterator', [iterator]);