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;
14 // var $floor = MathFloor
16 var $isNaN = GlobalIsNaN;
17 var $isFinite = GlobalIsFinite;
19 // ----------------------------------------------------------------------------
21 // Helper function used to install functions on objects.
22 function InstallFunctions(object, attributes, functions) {
23 if (functions.length >= 8) {
24 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
26 for (var i = 0; i < functions.length; i += 2) {
27 var key = functions[i];
28 var f = functions[i + 1];
29 %FunctionSetName(f, key);
30 %FunctionRemovePrototype(f);
31 %AddNamedProperty(object, key, f, attributes);
34 %ToFastProperties(object);
38 // Helper function to install a getter-only accessor property.
39 function InstallGetter(object, name, getter) {
40 %FunctionSetName(getter, name);
41 %FunctionRemovePrototype(getter);
42 %DefineAccessorPropertyUnchecked(object, name, getter, null, DONT_ENUM);
43 %SetNativeFlag(getter);
47 // Helper function to install a getter/setter accessor property.
48 function InstallGetterSetter(object, name, getter, setter) {
49 %FunctionSetName(getter, name);
50 %FunctionSetName(setter, name);
51 %FunctionRemovePrototype(getter);
52 %FunctionRemovePrototype(setter);
53 %DefineAccessorPropertyUnchecked(object, name, getter, setter, DONT_ENUM);
54 %SetNativeFlag(getter);
55 %SetNativeFlag(setter);
59 // Helper function for installing constant properties on objects.
60 function InstallConstants(object, constants) {
61 if (constants.length >= 4) {
62 %OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1);
64 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
65 for (var i = 0; i < constants.length; i += 2) {
66 var name = constants[i];
67 var k = constants[i + 1];
68 %AddNamedProperty(object, name, k, attributes);
70 %ToFastProperties(object);
74 // Prevents changes to the prototype of a built-in function.
75 // The "prototype" property of the function object is made non-configurable,
76 // and the prototype object is made non-extensible. The latter prevents
77 // changing the __proto__ property.
78 function SetUpLockedPrototype(constructor, fields, methods) {
79 %CheckIsBootstrapping();
80 var prototype = constructor.prototype;
81 // Install functions first, because this function is used to initialize
82 // PropertyDescriptor itself.
83 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
84 if (property_count >= 4) {
85 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
88 for (var i = 0; i < fields.length; i++) {
89 %AddNamedProperty(prototype, fields[i],
90 UNDEFINED, DONT_ENUM | DONT_DELETE);
93 for (var i = 0; i < methods.length; i += 2) {
95 var f = methods[i + 1];
96 %AddNamedProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
99 %InternalSetPrototype(prototype, null);
100 %ToFastProperties(prototype);
104 // ----------------------------------------------------------------------------
108 function GlobalIsNaN(number) {
109 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
110 return NUMBER_IS_NAN(number);
115 function GlobalIsFinite(number) {
116 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
117 return NUMBER_IS_FINITE(number);
121 // ECMA-262 - 15.1.2.2
122 function GlobalParseInt(string, radix) {
123 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
124 // Some people use parseInt instead of Math.floor. This
125 // optimization makes parseInt on a Smi 12 times faster (60ns
126 // vs 800ns). The following optimization makes parseInt on a
127 // non-Smi number 9 times faster (230ns vs 2070ns). Together
128 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
129 if (%_IsSmi(string)) return string;
130 if (IS_NUMBER(string) &&
131 ((0.01 < string && string < 1e9) ||
132 (-1e9 < string && string < -0.01))) {
136 string = TO_STRING_INLINE(string);
139 // The spec says ToString should be evaluated before ToInt32.
140 string = TO_STRING_INLINE(string);
141 radix = TO_INT32(radix);
142 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
147 if (%_HasCachedArrayIndex(string) &&
148 (radix == 0 || radix == 10)) {
149 return %_GetCachedArrayIndex(string);
151 return %StringParseInt(string, radix);
155 // ECMA-262 - 15.1.2.3
156 function GlobalParseFloat(string) {
157 string = TO_STRING_INLINE(string);
158 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
159 return %StringParseFloat(string);
163 function GlobalEval(x) {
164 if (!IS_STRING(x)) return x;
166 var global_proxy = %GlobalProxy(global);
168 var f = %CompileString(x, false, 0);
169 if (!IS_FUNCTION(f)) return f;
171 return %_CallFunction(global_proxy, f);
175 // ----------------------------------------------------------------------------
177 // Set up global object.
178 function SetUpGlobal() {
179 %CheckIsBootstrapping();
181 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
183 // ECMA 262 - 15.1.1.1.
184 %AddNamedProperty(global, "NaN", NAN, attributes);
186 // ECMA-262 - 15.1.1.2.
187 %AddNamedProperty(global, "Infinity", INFINITY, attributes);
189 // ECMA-262 - 15.1.1.3.
190 %AddNamedProperty(global, "undefined", UNDEFINED, attributes);
192 // Set up non-enumerable function on the global object.
193 InstallFunctions(global, DONT_ENUM, $Array(
194 "isNaN", GlobalIsNaN,
195 "isFinite", GlobalIsFinite,
196 "parseInt", GlobalParseInt,
197 "parseFloat", GlobalParseFloat,
205 // ----------------------------------------------------------------------------
208 var DefaultObjectToString = NoSideEffectsObjectToString;
209 // ECMA-262 - 15.2.4.2
210 function NoSideEffectsObjectToString() {
211 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
212 if (IS_NULL(this)) return "[object Null]";
213 return "[object " + %_ClassOf(ToObject(this)) + "]";
217 // ECMA-262 - 15.2.4.3
218 function ObjectToLocaleString() {
219 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
220 return this.toString();
224 // ECMA-262 - 15.2.4.4
225 function ObjectValueOf() {
226 return ToObject(this);
230 // ECMA-262 - 15.2.4.5
231 function ObjectHasOwnProperty(V) {
232 if (%_IsJSProxy(this)) {
233 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
234 if (IS_SYMBOL(V)) return false;
236 var handler = %GetHandler(this);
237 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
239 return %HasOwnProperty(TO_OBJECT_INLINE(this), ToName(V));
243 // ECMA-262 - 15.2.4.6
244 function ObjectIsPrototypeOf(V) {
245 if (!IS_SPEC_OBJECT(V)) return false;
246 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
247 return %IsInPrototypeChain(this, V);
251 // ECMA-262 - 15.2.4.6
252 function ObjectPropertyIsEnumerable(V) {
254 if (%_IsJSProxy(this)) {
255 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
256 if (IS_SYMBOL(V)) return false;
258 var desc = GetOwnPropertyJS(this, P);
259 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
261 return %IsPropertyEnumerable(ToObject(this), P);
265 // Extensions for providing property getters and setters.
266 function ObjectDefineGetter(name, fun) {
268 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
269 receiver = %GlobalProxy(global);
271 if (!IS_SPEC_FUNCTION(fun)) {
272 throw new $TypeError(
273 'Object.prototype.__defineGetter__: Expecting function');
275 var desc = new PropertyDescriptor();
277 desc.setEnumerable(true);
278 desc.setConfigurable(true);
279 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
283 function ObjectLookupGetter(name) {
285 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
286 receiver = %GlobalProxy(global);
288 return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
292 function ObjectDefineSetter(name, fun) {
294 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
295 receiver = %GlobalProxy(global);
297 if (!IS_SPEC_FUNCTION(fun)) {
298 throw new $TypeError(
299 'Object.prototype.__defineSetter__: Expecting function');
301 var desc = new PropertyDescriptor();
303 desc.setEnumerable(true);
304 desc.setConfigurable(true);
305 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
309 function ObjectLookupSetter(name) {
311 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
312 receiver = %GlobalProxy(global);
314 return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
318 function ObjectKeys(obj) {
320 if (%_IsJSProxy(obj)) {
321 var handler = %GetHandler(obj);
322 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
323 return ToNameArray(names, "keys", false);
325 return %OwnKeys(obj);
330 function IsAccessorDescriptor(desc) {
331 if (IS_UNDEFINED(desc)) return false;
332 return desc.hasGetter() || desc.hasSetter();
337 function IsDataDescriptor(desc) {
338 if (IS_UNDEFINED(desc)) return false;
339 return desc.hasValue() || desc.hasWritable();
344 function IsGenericDescriptor(desc) {
345 if (IS_UNDEFINED(desc)) return false;
346 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
350 function IsInconsistentDescriptor(desc) {
351 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
356 function FromPropertyDescriptor(desc) {
357 if (IS_UNDEFINED(desc)) return desc;
359 if (IsDataDescriptor(desc)) {
360 return { value: desc.getValue(),
361 writable: desc.isWritable(),
362 enumerable: desc.isEnumerable(),
363 configurable: desc.isConfigurable() };
365 // Must be an AccessorDescriptor then. We never return a generic descriptor.
366 return { get: desc.getGet(),
368 enumerable: desc.isEnumerable(),
369 configurable: desc.isConfigurable() };
374 function FromGenericPropertyDescriptor(desc) {
375 if (IS_UNDEFINED(desc)) return desc;
376 var obj = new $Object();
378 if (desc.hasValue()) {
379 %AddNamedProperty(obj, "value", desc.getValue(), NONE);
381 if (desc.hasWritable()) {
382 %AddNamedProperty(obj, "writable", desc.isWritable(), NONE);
384 if (desc.hasGetter()) {
385 %AddNamedProperty(obj, "get", desc.getGet(), NONE);
387 if (desc.hasSetter()) {
388 %AddNamedProperty(obj, "set", desc.getSet(), NONE);
390 if (desc.hasEnumerable()) {
391 %AddNamedProperty(obj, "enumerable", desc.isEnumerable(), NONE);
393 if (desc.hasConfigurable()) {
394 %AddNamedProperty(obj, "configurable", desc.isConfigurable(), NONE);
401 function ToPropertyDescriptor(obj) {
402 if (!IS_SPEC_OBJECT(obj)) {
403 throw MakeTypeError("property_desc_object", [obj]);
405 var desc = new PropertyDescriptor();
407 if ("enumerable" in obj) {
408 desc.setEnumerable(ToBoolean(obj.enumerable));
411 if ("configurable" in obj) {
412 desc.setConfigurable(ToBoolean(obj.configurable));
415 if ("value" in obj) {
416 desc.setValue(obj.value);
419 if ("writable" in obj) {
420 desc.setWritable(ToBoolean(obj.writable));
425 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
426 throw MakeTypeError("getter_must_be_callable", [get]);
433 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
434 throw MakeTypeError("setter_must_be_callable", [set]);
439 if (IsInconsistentDescriptor(desc)) {
440 throw MakeTypeError("value_and_accessor", [obj]);
446 // For Harmony proxies.
447 function ToCompletePropertyDescriptor(obj) {
448 var desc = ToPropertyDescriptor(obj);
449 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
450 if (!desc.hasValue()) desc.setValue(UNDEFINED);
451 if (!desc.hasWritable()) desc.setWritable(false);
453 // Is accessor descriptor.
454 if (!desc.hasGetter()) desc.setGet(UNDEFINED);
455 if (!desc.hasSetter()) desc.setSet(UNDEFINED);
457 if (!desc.hasEnumerable()) desc.setEnumerable(false);
458 if (!desc.hasConfigurable()) desc.setConfigurable(false);
463 function PropertyDescriptor() {
464 // Initialize here so they are all in-object and have the same map.
465 // Default values from ES5 8.6.1.
466 this.value_ = UNDEFINED;
467 this.hasValue_ = false;
468 this.writable_ = false;
469 this.hasWritable_ = false;
470 this.enumerable_ = false;
471 this.hasEnumerable_ = false;
472 this.configurable_ = false;
473 this.hasConfigurable_ = false;
474 this.get_ = UNDEFINED;
475 this.hasGetter_ = false;
476 this.set_ = UNDEFINED;
477 this.hasSetter_ = false;
480 SetUpLockedPrototype(PropertyDescriptor, $Array(
494 "toString", function PropertyDescriptor_ToString() {
495 return "[object PropertyDescriptor]";
497 "setValue", function PropertyDescriptor_SetValue(value) {
499 this.hasValue_ = true;
501 "getValue", function PropertyDescriptor_GetValue() {
504 "hasValue", function PropertyDescriptor_HasValue() {
505 return this.hasValue_;
507 "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) {
508 this.enumerable_ = enumerable;
509 this.hasEnumerable_ = true;
511 "isEnumerable", function PropertyDescriptor_IsEnumerable() {
512 return this.enumerable_;
514 "hasEnumerable", function PropertyDescriptor_HasEnumerable() {
515 return this.hasEnumerable_;
517 "setWritable", function PropertyDescriptor_SetWritable(writable) {
518 this.writable_ = writable;
519 this.hasWritable_ = true;
521 "isWritable", function PropertyDescriptor_IsWritable() {
522 return this.writable_;
524 "hasWritable", function PropertyDescriptor_HasWritable() {
525 return this.hasWritable_;
528 function PropertyDescriptor_SetConfigurable(configurable) {
529 this.configurable_ = configurable;
530 this.hasConfigurable_ = true;
532 "hasConfigurable", function PropertyDescriptor_HasConfigurable() {
533 return this.hasConfigurable_;
535 "isConfigurable", function PropertyDescriptor_IsConfigurable() {
536 return this.configurable_;
538 "setGet", function PropertyDescriptor_SetGetter(get) {
540 this.hasGetter_ = true;
542 "getGet", function PropertyDescriptor_GetGetter() {
545 "hasGetter", function PropertyDescriptor_HasGetter() {
546 return this.hasGetter_;
548 "setSet", function PropertyDescriptor_SetSetter(set) {
550 this.hasSetter_ = true;
552 "getSet", function PropertyDescriptor_GetSetter() {
555 "hasSetter", function PropertyDescriptor_HasSetter() {
556 return this.hasSetter_;
560 // Converts an array returned from Runtime_GetOwnProperty to an actual
561 // property descriptor. For a description of the array layout please
562 // see the runtime.cc file.
563 function ConvertDescriptorArrayToDescriptor(desc_array) {
564 if (IS_UNDEFINED(desc_array)) {
568 var desc = new PropertyDescriptor();
569 // This is an accessor.
570 if (desc_array[IS_ACCESSOR_INDEX]) {
571 desc.setGet(desc_array[GETTER_INDEX]);
572 desc.setSet(desc_array[SETTER_INDEX]);
574 desc.setValue(desc_array[VALUE_INDEX]);
575 desc.setWritable(desc_array[WRITABLE_INDEX]);
577 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
578 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
584 // For Harmony proxies.
585 function GetTrap(handler, name, defaultTrap) {
586 var trap = handler[name];
587 if (IS_UNDEFINED(trap)) {
588 if (IS_UNDEFINED(defaultTrap)) {
589 throw MakeTypeError("handler_trap_missing", [handler, name]);
592 } else if (!IS_SPEC_FUNCTION(trap)) {
593 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
599 function CallTrap0(handler, name, defaultTrap) {
600 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
604 function CallTrap1(handler, name, defaultTrap, x) {
605 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
609 function CallTrap2(handler, name, defaultTrap, x, y) {
610 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
614 // ES5 section 8.12.1.
615 function GetOwnPropertyJS(obj, v) {
617 if (%_IsJSProxy(obj)) {
618 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
619 if (IS_SYMBOL(v)) return UNDEFINED;
621 var handler = %GetHandler(obj);
622 var descriptor = CallTrap1(
623 handler, "getOwnPropertyDescriptor", UNDEFINED, p);
624 if (IS_UNDEFINED(descriptor)) return descriptor;
625 var desc = ToCompletePropertyDescriptor(descriptor);
626 if (!desc.isConfigurable()) {
627 throw MakeTypeError("proxy_prop_not_configurable",
628 [handler, "getOwnPropertyDescriptor", p, descriptor]);
633 // GetOwnProperty returns an array indexed by the constants
634 // defined in macros.py.
635 // If p is not a property on obj undefined is returned.
636 var props = %GetOwnProperty(ToObject(obj), p);
638 return ConvertDescriptorArrayToDescriptor(props);
642 // ES5 section 8.12.7.
643 function Delete(obj, p, should_throw) {
644 var desc = GetOwnPropertyJS(obj, p);
645 if (IS_UNDEFINED(desc)) return true;
646 if (desc.isConfigurable()) {
647 %DeleteProperty(obj, p, 0);
649 } else if (should_throw) {
650 throw MakeTypeError("define_disallowed", [p]);
657 // ES6, draft 12-24-14, section 7.3.8
658 function GetMethod(obj, p) {
660 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED;
661 if (IS_SPEC_FUNCTION(func)) return func;
662 throw MakeTypeError('called_non_callable', [typeof func]);
667 function DefineProxyProperty(obj, p, attributes, should_throw) {
668 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
669 if (IS_SYMBOL(p)) return false;
671 var handler = %GetHandler(obj);
672 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
673 if (!ToBoolean(result)) {
675 throw MakeTypeError("handler_returned_false",
676 [handler, "defineProperty"]);
686 function DefineObjectProperty(obj, p, desc, should_throw) {
687 var current_array = %GetOwnProperty(ToObject(obj), ToName(p));
688 var current = ConvertDescriptorArrayToDescriptor(current_array);
689 var extensible = %IsExtensible(ToObject(obj));
691 // Error handling according to spec.
693 if (IS_UNDEFINED(current) && !extensible) {
695 throw MakeTypeError("define_disallowed", [p]);
701 if (!IS_UNDEFINED(current)) {
703 if ((IsGenericDescriptor(desc) ||
704 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
705 (!desc.hasEnumerable() ||
706 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
707 (!desc.hasConfigurable() ||
708 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
709 (!desc.hasWritable() ||
710 SameValue(desc.isWritable(), current.isWritable())) &&
712 SameValue(desc.getValue(), current.getValue())) &&
713 (!desc.hasGetter() ||
714 SameValue(desc.getGet(), current.getGet())) &&
715 (!desc.hasSetter() ||
716 SameValue(desc.getSet(), current.getSet()))) {
719 if (!current.isConfigurable()) {
721 if (desc.isConfigurable() ||
722 (desc.hasEnumerable() &&
723 desc.isEnumerable() != current.isEnumerable())) {
725 throw MakeTypeError("redefine_disallowed", [p]);
731 if (!IsGenericDescriptor(desc)) {
733 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
735 throw MakeTypeError("redefine_disallowed", [p]);
741 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
742 if (!current.isWritable() && desc.isWritable()) {
744 throw MakeTypeError("redefine_disallowed", [p]);
749 if (!current.isWritable() && desc.hasValue() &&
750 !SameValue(desc.getValue(), current.getValue())) {
752 throw MakeTypeError("redefine_disallowed", [p]);
759 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
760 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
762 throw MakeTypeError("redefine_disallowed", [p]);
767 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
769 throw MakeTypeError("redefine_disallowed", [p]);
779 // Send flags - enumerable and configurable are common - writable is
780 // only send to the data descriptor.
781 // Take special care if enumerable and configurable is not defined on
782 // desc (we need to preserve the existing values from current).
784 if (desc.hasEnumerable()) {
785 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
786 } else if (!IS_UNDEFINED(current)) {
787 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
792 if (desc.hasConfigurable()) {
793 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
794 } else if (!IS_UNDEFINED(current)) {
795 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
799 if (IsDataDescriptor(desc) ||
800 (IsGenericDescriptor(desc) &&
801 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
802 // There are 3 cases that lead here:
803 // Step 4a - defining a new data property.
804 // Steps 9b & 12 - replacing an existing accessor property with a data
806 // Step 12 - updating an existing data property with a data or generic
809 if (desc.hasWritable()) {
810 flag |= desc.isWritable() ? 0 : READ_ONLY;
811 } else if (!IS_UNDEFINED(current)) {
812 flag |= current.isWritable() ? 0 : READ_ONLY;
817 var value = UNDEFINED; // Default value is undefined.
818 if (desc.hasValue()) {
819 value = desc.getValue();
820 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
821 value = current.getValue();
824 %DefineDataPropertyUnchecked(obj, p, value, flag);
826 // There are 3 cases that lead here:
827 // Step 4b - defining a new accessor property.
828 // Steps 9c & 12 - replacing an existing data property with an accessor
830 // Step 12 - updating an existing accessor property with an accessor
833 if (desc.hasGetter()) {
834 getter = desc.getGet();
835 } else if (IsAccessorDescriptor(current) && current.hasGetter()) {
836 getter = current.getGet();
839 if (desc.hasSetter()) {
840 setter = desc.getSet();
841 } else if (IsAccessorDescriptor(current) && current.hasSetter()) {
842 setter = current.getSet();
844 %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag);
850 // ES5 section 15.4.5.1.
851 function DefineArrayProperty(obj, p, desc, should_throw) {
852 // Note that the length of an array is not actually stored as part of the
853 // property, hence we use generated code throughout this function instead of
854 // DefineObjectProperty() to modify its value.
856 // Step 3 - Special handling for length property.
857 if (p === "length") {
858 var length = obj.length;
859 var old_length = length;
860 if (!desc.hasValue()) {
861 return DefineObjectProperty(obj, "length", desc, should_throw);
863 var new_length = ToUint32(desc.getValue());
864 if (new_length != ToNumber(desc.getValue())) {
865 throw new $RangeError('defineProperty() array length out of range');
867 var length_desc = GetOwnPropertyJS(obj, "length");
868 if (new_length != length && !length_desc.isWritable()) {
870 throw MakeTypeError("redefine_disallowed", [p]);
877 var emit_splice = %IsObserved(obj) && new_length !== old_length;
880 BeginPerformSplice(obj);
882 if (new_length < old_length)
883 removed.length = old_length - new_length;
886 while (new_length < length--) {
887 var index = ToString(length);
889 var deletedDesc = GetOwnPropertyJS(obj, index);
890 if (deletedDesc && deletedDesc.hasValue())
891 removed[length - new_length] = deletedDesc.getValue();
893 if (!Delete(obj, index, false)) {
894 new_length = length + 1;
899 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
901 EndPerformSplice(obj);
902 EnqueueSpliceRecord(obj,
903 new_length < old_length ? new_length : old_length,
905 new_length > old_length ? new_length - old_length : 0);
909 throw MakeTypeError("redefine_disallowed", [p]);
917 // Step 4 - Special handling for array index.
919 var index = ToUint32(p);
920 var emit_splice = false;
921 if (ToString(index) == p && index != 4294967295) {
922 var length = obj.length;
923 if (index >= length && %IsObserved(obj)) {
925 BeginPerformSplice(obj);
928 var length_desc = GetOwnPropertyJS(obj, "length");
929 if ((index >= length && !length_desc.isWritable()) ||
930 !DefineObjectProperty(obj, p, desc, true)) {
932 EndPerformSplice(obj);
934 throw MakeTypeError("define_disallowed", [p]);
939 if (index >= length) {
940 obj.length = index + 1;
943 EndPerformSplice(obj);
944 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
950 // Step 5 - Fallback to default implementation.
951 return DefineObjectProperty(obj, p, desc, should_throw);
955 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
956 function DefineOwnProperty(obj, p, desc, should_throw) {
957 if (%_IsJSProxy(obj)) {
958 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
959 if (IS_SYMBOL(p)) return false;
961 var attributes = FromGenericPropertyDescriptor(desc);
962 return DefineProxyProperty(obj, p, attributes, should_throw);
963 } else if (IS_ARRAY(obj)) {
964 return DefineArrayProperty(obj, p, desc, should_throw);
966 return DefineObjectProperty(obj, p, desc, should_throw);
971 // ES5 section 15.2.3.2.
972 function ObjectGetPrototypeOf(obj) {
973 if (!IS_SPEC_OBJECT(obj)) {
974 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
976 return %_GetPrototype(obj);
979 // ES6 section 19.1.2.19.
980 function ObjectSetPrototypeOf(obj, proto) {
981 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
983 if (proto !== null && !IS_SPEC_OBJECT(proto)) {
984 throw MakeTypeError("proto_object_or_null", [proto]);
987 if (IS_SPEC_OBJECT(obj)) {
988 %SetPrototype(obj, proto);
995 // ES5 section 15.2.3.3
996 function ObjectGetOwnPropertyDescriptor(obj, p) {
997 if (!IS_SPEC_OBJECT(obj)) {
998 throw MakeTypeError("called_on_non_object",
999 ["Object.getOwnPropertyDescriptor"]);
1001 var desc = GetOwnPropertyJS(obj, p);
1002 return FromPropertyDescriptor(desc);
1006 // For Harmony proxies
1007 function ToNameArray(obj, trap, includeSymbols) {
1008 if (!IS_SPEC_OBJECT(obj)) {
1009 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1011 var n = ToUint32(obj.length);
1012 var array = new $Array(n);
1014 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
1015 for (var index = 0; index < n; index++) {
1016 var s = ToName(obj[index]);
1017 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1018 if (IS_SYMBOL(s) && !includeSymbols) continue;
1019 if (%HasOwnProperty(names, s)) {
1020 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1026 array.length = realLength;
1031 function ObjectGetOwnPropertyKeys(obj, filter) {
1032 var nameArrays = new InternalArray();
1033 filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1034 var interceptorInfo = %GetInterceptorInfo(obj);
1036 // Find all the indexed properties.
1038 // Only get own element names if we want to include string keys.
1039 if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
1040 var ownElementNames = %GetOwnElementNames(obj);
1041 for (var i = 0; i < ownElementNames.length; ++i) {
1042 ownElementNames[i] = %_NumberToString(ownElementNames[i]);
1044 nameArrays.push(ownElementNames);
1045 // Get names for indexed interceptor properties.
1046 if ((interceptorInfo & 1) != 0) {
1047 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1048 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1049 nameArrays.push(indexedInterceptorNames);
1054 // Find all the named properties.
1056 // Get own property names.
1057 nameArrays.push(%GetOwnPropertyNames(obj, filter));
1059 // Get names for named interceptor properties if any.
1060 if ((interceptorInfo & 2) != 0) {
1061 var namedInterceptorNames =
1062 %GetNamedInterceptorPropertyNames(obj);
1063 if (!IS_UNDEFINED(namedInterceptorNames)) {
1064 nameArrays.push(namedInterceptorNames);
1069 %Apply(InternalArray.prototype.concat,
1070 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1072 // Property names are expected to be unique strings,
1073 // but interceptors can interfere with that assumption.
1074 if (interceptorInfo != 0) {
1075 var seenKeys = { __proto__: null };
1077 for (var i = 0; i < propertyNames.length; ++i) {
1078 var name = propertyNames[i];
1079 if (IS_SYMBOL(name)) {
1080 if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
1084 if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
1085 name = ToString(name);
1087 if (seenKeys[name]) continue;
1088 seenKeys[name] = true;
1089 propertyNames[j++] = name;
1091 propertyNames.length = j;
1094 return propertyNames;
1098 // ES5 section 15.2.3.4.
1099 function ObjectGetOwnPropertyNames(obj) {
1100 obj = ToObject(obj);
1101 // Special handling for proxies.
1102 if (%_IsJSProxy(obj)) {
1103 var handler = %GetHandler(obj);
1104 var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1105 return ToNameArray(names, "getOwnPropertyNames", false);
1108 return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
1112 // ES5 section 15.2.3.5.
1113 function ObjectCreate(proto, properties) {
1114 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1115 throw MakeTypeError("proto_object_or_null", [proto]);
1118 %InternalSetPrototype(obj, proto);
1119 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1124 // ES5 section 15.2.3.6.
1125 function ObjectDefineProperty(obj, p, attributes) {
1126 if (!IS_SPEC_OBJECT(obj)) {
1127 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1129 var name = ToName(p);
1130 if (%_IsJSProxy(obj)) {
1131 // Clone the attributes object for protection.
1132 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1133 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1134 var attributesClone = { __proto__: null };
1135 for (var a in attributes) {
1136 attributesClone[a] = attributes[a];
1138 DefineProxyProperty(obj, name, attributesClone, true);
1139 // The following would implement the spec as in the current proposal,
1140 // but after recent comments on es-discuss, is most likely obsolete.
1142 var defineObj = FromGenericPropertyDescriptor(desc);
1143 var names = ObjectGetOwnPropertyNames(attributes);
1145 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1146 for (var i = 0; i < names.length; i++) {
1148 if (!(%HasOwnProperty(standardNames, N))) {
1149 var attr = GetOwnPropertyJS(attributes, N);
1150 DefineOwnProperty(descObj, N, attr, true);
1153 // This is really confusing the types, but it is what the proxies spec
1154 // currently requires:
1158 var desc = ToPropertyDescriptor(attributes);
1159 DefineOwnProperty(obj, name, desc, true);
1165 function GetOwnEnumerablePropertyNames(object) {
1166 var names = new InternalArray();
1167 for (var key in object) {
1168 if (%HasOwnProperty(object, key)) {
1173 var filter = PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1174 var symbols = %GetOwnPropertyNames(object, filter);
1175 for (var i = 0; i < symbols.length; ++i) {
1176 var symbol = symbols[i];
1177 if (IS_SYMBOL(symbol)) {
1178 var desc = ObjectGetOwnPropertyDescriptor(object, symbol);
1179 if (desc.enumerable) names.push(symbol);
1187 // ES5 section 15.2.3.7.
1188 function ObjectDefineProperties(obj, properties) {
1189 if (!IS_SPEC_OBJECT(obj)) {
1190 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1192 var props = ToObject(properties);
1193 var names = GetOwnEnumerablePropertyNames(props);
1194 var descriptors = new InternalArray();
1195 for (var i = 0; i < names.length; i++) {
1196 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1198 for (var i = 0; i < names.length; i++) {
1199 DefineOwnProperty(obj, names[i], descriptors[i], true);
1206 function ProxyFix(obj) {
1207 var handler = %GetHandler(obj);
1208 var props = CallTrap0(handler, "fix", UNDEFINED);
1209 if (IS_UNDEFINED(props)) {
1210 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1213 if (%IsJSFunctionProxy(obj)) {
1214 var callTrap = %GetCallTrap(obj);
1215 var constructTrap = %GetConstructTrap(obj);
1216 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1217 %Fix(obj); // becomes a regular function
1218 %SetCode(obj, code);
1219 // TODO(rossberg): What about length and other properties? Not specified.
1220 // We just put in some half-reasonable defaults for now.
1221 var prototype = new $Object();
1222 $Object.defineProperty(prototype, "constructor",
1223 {value: obj, writable: true, enumerable: false, configurable: true});
1224 // TODO(v8:1530): defineProperty does not handle prototype and length.
1225 %FunctionSetPrototype(obj, prototype);
1230 ObjectDefineProperties(obj, props);
1234 // ES5 section 15.2.3.8.
1235 function ObjectSealJS(obj) {
1236 if (!IS_SPEC_OBJECT(obj)) {
1237 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1239 var isProxy = %_IsJSProxy(obj);
1240 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1244 var names = ObjectGetOwnPropertyNames(obj);
1245 for (var i = 0; i < names.length; i++) {
1246 var name = names[i];
1247 var desc = GetOwnPropertyJS(obj, name);
1248 if (desc.isConfigurable()) {
1249 desc.setConfigurable(false);
1250 DefineOwnProperty(obj, name, desc, true);
1253 %PreventExtensions(obj);
1255 // TODO(adamk): Is it worth going to this fast path if the
1256 // object's properties are already in dictionary mode?
1263 // ES5 section 15.2.3.9.
1264 function ObjectFreezeJS(obj) {
1265 if (!IS_SPEC_OBJECT(obj)) {
1266 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1268 var isProxy = %_IsJSProxy(obj);
1269 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1273 var names = ObjectGetOwnPropertyNames(obj);
1274 for (var i = 0; i < names.length; i++) {
1275 var name = names[i];
1276 var desc = GetOwnPropertyJS(obj, name);
1277 if (desc.isWritable() || desc.isConfigurable()) {
1278 if (IsDataDescriptor(desc)) desc.setWritable(false);
1279 desc.setConfigurable(false);
1280 DefineOwnProperty(obj, name, desc, true);
1283 %PreventExtensions(obj);
1285 // TODO(adamk): Is it worth going to this fast path if the
1286 // object's properties are already in dictionary mode?
1293 // ES5 section 15.2.3.10
1294 function ObjectPreventExtension(obj) {
1295 if (!IS_SPEC_OBJECT(obj)) {
1296 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1298 if (%_IsJSProxy(obj)) {
1301 %PreventExtensions(obj);
1306 // ES5 section 15.2.3.11
1307 function ObjectIsSealed(obj) {
1308 if (!IS_SPEC_OBJECT(obj)) {
1309 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1311 if (%_IsJSProxy(obj)) {
1314 if (%IsExtensible(obj)) {
1317 var names = ObjectGetOwnPropertyNames(obj);
1318 for (var i = 0; i < names.length; i++) {
1319 var name = names[i];
1320 var desc = GetOwnPropertyJS(obj, name);
1321 if (desc.isConfigurable()) {
1329 // ES5 section 15.2.3.12
1330 function ObjectIsFrozen(obj) {
1331 if (!IS_SPEC_OBJECT(obj)) {
1332 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1334 if (%_IsJSProxy(obj)) {
1337 if (%IsExtensible(obj)) {
1340 var names = ObjectGetOwnPropertyNames(obj);
1341 for (var i = 0; i < names.length; i++) {
1342 var name = names[i];
1343 var desc = GetOwnPropertyJS(obj, name);
1344 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1345 if (desc.isConfigurable()) return false;
1351 // ES5 section 15.2.3.13
1352 function ObjectIsExtensible(obj) {
1353 if (!IS_SPEC_OBJECT(obj)) {
1354 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1356 if (%_IsJSProxy(obj)) {
1359 return %IsExtensible(obj);
1363 // ECMA-262, Edition 6, section 19.1.2.10
1364 function ObjectIs(obj1, obj2) {
1365 return SameValue(obj1, obj2);
1369 // ECMA-262, Edition 6, section B.2.2.1.1
1370 function ObjectGetProto() {
1371 return %_GetPrototype(ToObject(this));
1375 // ECMA-262, Edition 6, section B.2.2.1.2
1376 function ObjectSetProto(proto) {
1377 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1379 if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1380 %SetPrototype(this, proto);
1385 function ObjectConstructor(x) {
1386 if (%_IsConstructCall()) {
1387 if (x == null) return this;
1390 if (x == null) return { };
1396 // ----------------------------------------------------------------------------
1399 function SetUpObject() {
1400 %CheckIsBootstrapping();
1402 %SetNativeFlag($Object);
1403 %SetCode($Object, ObjectConstructor);
1405 %AddNamedProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1407 // Set up non-enumerable functions on the Object.prototype object.
1408 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1409 "toString", NoSideEffectsObjectToString,
1410 "toLocaleString", ObjectToLocaleString,
1411 "valueOf", ObjectValueOf,
1412 "hasOwnProperty", ObjectHasOwnProperty,
1413 "isPrototypeOf", ObjectIsPrototypeOf,
1414 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1415 "__defineGetter__", ObjectDefineGetter,
1416 "__lookupGetter__", ObjectLookupGetter,
1417 "__defineSetter__", ObjectDefineSetter,
1418 "__lookupSetter__", ObjectLookupSetter
1420 InstallGetterSetter($Object.prototype, "__proto__",
1421 ObjectGetProto, ObjectSetProto);
1423 // Set up non-enumerable functions in the Object object.
1424 InstallFunctions($Object, DONT_ENUM, $Array(
1426 "create", ObjectCreate,
1427 "defineProperty", ObjectDefineProperty,
1428 "defineProperties", ObjectDefineProperties,
1429 "freeze", ObjectFreezeJS,
1430 "getPrototypeOf", ObjectGetPrototypeOf,
1431 "setPrototypeOf", ObjectSetPrototypeOf,
1432 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1433 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1434 // getOwnPropertySymbols is added in symbol.js.
1436 "isExtensible", ObjectIsExtensible,
1437 "isFrozen", ObjectIsFrozen,
1438 "isSealed", ObjectIsSealed,
1439 "preventExtensions", ObjectPreventExtension,
1440 "seal", ObjectSealJS
1441 // deliverChangeRecords, getNotifier, observe and unobserve are added
1442 // in object-observe.js.
1449 // ----------------------------------------------------------------------------
1452 function BooleanConstructor(x) {
1453 if (%_IsConstructCall()) {
1454 %_SetValueOf(this, ToBoolean(x));
1456 return ToBoolean(x);
1461 function BooleanToString() {
1462 // NOTE: Both Boolean objects and values can enter here as
1463 // 'this'. This is not as dictated by ECMA-262.
1465 if (!IS_BOOLEAN(b)) {
1466 if (!IS_BOOLEAN_WRAPPER(b)) {
1467 throw new $TypeError('Boolean.prototype.toString is not generic');
1471 return b ? 'true' : 'false';
1475 function BooleanValueOf() {
1476 // NOTE: Both Boolean objects and values can enter here as
1477 // 'this'. This is not as dictated by ECMA-262.
1478 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1479 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1481 return %_ValueOf(this);
1485 // ----------------------------------------------------------------------------
1487 function SetUpBoolean () {
1488 %CheckIsBootstrapping();
1490 %SetCode($Boolean, BooleanConstructor);
1491 %FunctionSetPrototype($Boolean, new $Boolean(false));
1492 %AddNamedProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1494 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1495 "toString", BooleanToString,
1496 "valueOf", BooleanValueOf
1503 // ----------------------------------------------------------------------------
1506 function NumberConstructor(x) {
1507 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1508 if (%_IsConstructCall()) {
1509 %_SetValueOf(this, value);
1516 // ECMA-262 section 15.7.4.2.
1517 function NumberToString(radix) {
1518 // NOTE: Both Number objects and values can enter here as
1519 // 'this'. This is not as dictated by ECMA-262.
1521 if (!IS_NUMBER(this)) {
1522 if (!IS_NUMBER_WRAPPER(this)) {
1523 throw new $TypeError('Number.prototype.toString is not generic');
1525 // Get the value of this number in case it's an object.
1526 number = %_ValueOf(this);
1528 // Fast case: Convert number in radix 10.
1529 if (IS_UNDEFINED(radix) || radix === 10) {
1530 return %_NumberToString(number);
1533 // Convert the radix to an integer and check the range.
1534 radix = TO_INTEGER(radix);
1535 if (radix < 2 || radix > 36) {
1536 throw new $RangeError('toString() radix argument must be between 2 and 36');
1538 // Convert the number to a string in the given radix.
1539 return %NumberToRadixString(number, radix);
1543 // ECMA-262 section 15.7.4.3
1544 function NumberToLocaleString() {
1545 return %_CallFunction(this, NumberToString);
1549 // ECMA-262 section 15.7.4.4
1550 function NumberValueOf() {
1551 // NOTE: Both Number objects and values can enter here as
1552 // 'this'. This is not as dictated by ECMA-262.
1553 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1554 throw new $TypeError('Number.prototype.valueOf is not generic');
1556 return %_ValueOf(this);
1560 // ECMA-262 section 15.7.4.5
1561 function NumberToFixedJS(fractionDigits) {
1563 if (!IS_NUMBER(this)) {
1564 if (!IS_NUMBER_WRAPPER(this)) {
1565 throw MakeTypeError("incompatible_method_receiver",
1566 ["Number.prototype.toFixed", this]);
1568 // Get the value of this number in case it's an object.
1569 x = %_ValueOf(this);
1571 var f = TO_INTEGER(fractionDigits);
1573 if (f < 0 || f > 20) {
1574 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1577 if (NUMBER_IS_NAN(x)) return "NaN";
1578 if (x == INFINITY) return "Infinity";
1579 if (x == -INFINITY) return "-Infinity";
1581 return %NumberToFixed(x, f);
1585 // ECMA-262 section 15.7.4.6
1586 function NumberToExponentialJS(fractionDigits) {
1588 if (!IS_NUMBER(this)) {
1589 if (!IS_NUMBER_WRAPPER(this)) {
1590 throw MakeTypeError("incompatible_method_receiver",
1591 ["Number.prototype.toExponential", this]);
1593 // Get the value of this number in case it's an object.
1594 x = %_ValueOf(this);
1596 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1598 if (NUMBER_IS_NAN(x)) return "NaN";
1599 if (x == INFINITY) return "Infinity";
1600 if (x == -INFINITY) return "-Infinity";
1602 if (IS_UNDEFINED(f)) {
1603 f = -1; // Signal for runtime function that f is not defined.
1604 } else if (f < 0 || f > 20) {
1605 throw new $RangeError("toExponential() argument must be between 0 and 20");
1607 return %NumberToExponential(x, f);
1611 // ECMA-262 section 15.7.4.7
1612 function NumberToPrecisionJS(precision) {
1614 if (!IS_NUMBER(this)) {
1615 if (!IS_NUMBER_WRAPPER(this)) {
1616 throw MakeTypeError("incompatible_method_receiver",
1617 ["Number.prototype.toPrecision", this]);
1619 // Get the value of this number in case it's an object.
1620 x = %_ValueOf(this);
1622 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1623 var p = TO_INTEGER(precision);
1625 if (NUMBER_IS_NAN(x)) return "NaN";
1626 if (x == INFINITY) return "Infinity";
1627 if (x == -INFINITY) return "-Infinity";
1629 if (p < 1 || p > 21) {
1630 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1632 return %NumberToPrecision(x, p);
1636 // Harmony isFinite.
1637 function NumberIsFinite(number) {
1638 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1642 // Harmony isInteger
1643 function NumberIsInteger(number) {
1644 return NumberIsFinite(number) && TO_INTEGER(number) == number;
1649 function NumberIsNaN(number) {
1650 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1654 // Harmony isSafeInteger
1655 function NumberIsSafeInteger(number) {
1656 if (NumberIsFinite(number)) {
1657 var integral = TO_INTEGER(number);
1658 if (integral == number)
1659 return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
1665 // ----------------------------------------------------------------------------
1667 function SetUpNumber() {
1668 %CheckIsBootstrapping();
1670 %SetCode($Number, NumberConstructor);
1671 %FunctionSetPrototype($Number, new $Number(0));
1673 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1674 // Set up the constructor property on the Number prototype object.
1675 %AddNamedProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1677 InstallConstants($Number, $Array(
1678 // ECMA-262 section 15.7.3.1.
1679 "MAX_VALUE", 1.7976931348623157e+308,
1680 // ECMA-262 section 15.7.3.2.
1681 "MIN_VALUE", 5e-324,
1682 // ECMA-262 section 15.7.3.3.
1684 // ECMA-262 section 15.7.3.4.
1685 "NEGATIVE_INFINITY", -INFINITY,
1686 // ECMA-262 section 15.7.3.5.
1687 "POSITIVE_INFINITY", INFINITY,
1689 // --- Harmony constants (no spec refs until settled.)
1691 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1692 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1693 "EPSILON", %_MathPow(2, -52)
1696 // Set up non-enumerable functions on the Number prototype object.
1697 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1698 "toString", NumberToString,
1699 "toLocaleString", NumberToLocaleString,
1700 "valueOf", NumberValueOf,
1701 "toFixed", NumberToFixedJS,
1702 "toExponential", NumberToExponentialJS,
1703 "toPrecision", NumberToPrecisionJS
1706 // Harmony Number constructor additions
1707 InstallFunctions($Number, DONT_ENUM, $Array(
1708 "isFinite", NumberIsFinite,
1709 "isInteger", NumberIsInteger,
1710 "isNaN", NumberIsNaN,
1711 "isSafeInteger", NumberIsSafeInteger,
1712 "parseInt", GlobalParseInt,
1713 "parseFloat", GlobalParseFloat
1720 // ----------------------------------------------------------------------------
1723 function FunctionSourceString(func) {
1724 while (%IsJSFunctionProxy(func)) {
1725 func = %GetCallTrap(func);
1728 if (!IS_FUNCTION(func)) {
1729 throw new $TypeError('Function.prototype.toString is not generic');
1732 var classSource = %ClassGetSourceCode(func);
1733 if (IS_STRING(classSource)) {
1737 var source = %FunctionGetSourceCode(func);
1738 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1739 var name = %FunctionGetName(func);
1741 // Mimic what KJS does.
1742 return 'function ' + name + '() { [native code] }';
1744 return 'function () { [native code] }';
1748 if (%FunctionIsArrow(func)) {
1752 var name = %FunctionNameShouldPrintAsAnonymous(func)
1754 : %FunctionGetName(func);
1756 var isGenerator = %FunctionIsGenerator(func);
1757 var head = %FunctionIsConciseMethod(func)
1758 ? (isGenerator ? '*' : '')
1759 : (isGenerator ? 'function* ' : 'function ');
1760 return head + name + source;
1764 function FunctionToString() {
1765 return FunctionSourceString(this);
1770 function FunctionBind(this_arg) { // Length is 1.
1771 if (!IS_SPEC_FUNCTION(this)) {
1772 throw new $TypeError('Bind must be called on a function');
1774 var boundFunction = function () {
1775 // Poison .arguments and .caller, but is otherwise not detectable.
1777 // This function must not use any object literals (Object, Array, RegExp),
1778 // since the literals-array is being used to store the bound data.
1779 if (%_IsConstructCall()) {
1780 return %NewObjectFromBound(boundFunction);
1782 var bindings = %BoundFunctionGetBindings(boundFunction);
1784 var argc = %_ArgumentsLength();
1786 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1788 if (bindings.length === 2) {
1789 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1791 var bound_argc = bindings.length - 2;
1792 var argv = new InternalArray(bound_argc + argc);
1793 for (var i = 0; i < bound_argc; i++) {
1794 argv[i] = bindings[i + 2];
1796 for (var j = 0; j < argc; j++) {
1797 argv[i++] = %_Arguments(j);
1799 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1803 var old_length = this.length;
1804 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1805 if ((typeof old_length === "number") &&
1806 ((old_length >>> 0) === old_length)) {
1807 var argc = %_ArgumentsLength();
1808 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1809 new_length = old_length - argc;
1810 if (new_length < 0) new_length = 0;
1812 // This runtime function finds any remaining arguments on the stack,
1813 // so we don't pass the arguments object.
1814 var result = %FunctionBindArguments(boundFunction, this,
1815 this_arg, new_length);
1817 // We already have caller and arguments properties on functions,
1818 // which are non-configurable. It therefore makes no sence to
1819 // try to redefine these as defined by the spec. The spec says
1820 // that bind should make these throw a TypeError if get or set
1821 // is called and make them non-enumerable and non-configurable.
1822 // To be consistent with our normal functions we leave this as it is.
1823 // TODO(lrn): Do set these to be thrower.
1828 function NewFunctionFromString(arguments, function_token) {
1829 var n = arguments.length;
1832 p = ToString(arguments[0]);
1833 for (var i = 1; i < n - 1; i++) {
1834 p += ',' + ToString(arguments[i]);
1836 // If the formal parameters string include ) - an illegal
1837 // character - it may make the combined function expression
1838 // compile. We avoid this problem by checking for this early on.
1839 if (%_CallFunction(p, ')', StringIndexOfJS) != -1) {
1840 throw MakeSyntaxError('paren_in_arg_string', []);
1842 // If the formal parameters include an unbalanced block comment, the
1843 // function must be rejected. Since JavaScript does not allow nested
1844 // comments we can include a trailing block comment to catch this.
1845 p += '\n\x2f**\x2f';
1847 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1848 var head = '(' + function_token + '(' + p + ') {\n';
1849 var src = head + body + '\n})';
1850 var global_proxy = %GlobalProxy(global);
1851 var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
1852 %FunctionMarkNameShouldPrintAsAnonymous(f);
1857 function FunctionConstructor(arg1) { // length == 1
1858 return NewFunctionFromString(arguments, 'function');
1862 // ----------------------------------------------------------------------------
1864 function SetUpFunction() {
1865 %CheckIsBootstrapping();
1867 %SetCode($Function, FunctionConstructor);
1868 %AddNamedProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1870 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1871 "bind", FunctionBind,
1872 "toString", FunctionToString
1879 // ----------------------------------------------------------------------------
1880 // Iterator related spec functions.
1882 // ES6 rev 26, 2014-07-18
1883 // 7.4.1 CheckIterable ( obj )
1884 function ToIterable(obj) {
1885 if (!IS_SPEC_OBJECT(obj)) {
1888 return obj[symbolIterator];
1892 // ES6 rev 26, 2014-07-18
1893 // 7.4.2 GetIterator ( obj, method )
1894 function GetIterator(obj, method) {
1895 if (IS_UNDEFINED(method)) {
1896 method = ToIterable(obj);
1898 if (!IS_SPEC_FUNCTION(method)) {
1899 throw MakeTypeError('not_iterable', [obj]);
1901 var iterator = %_CallFunction(obj, method);
1902 if (!IS_SPEC_OBJECT(iterator)) {
1903 throw MakeTypeError('not_an_iterator', [iterator]);