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]);
658 function DefineProxyProperty(obj, p, attributes, should_throw) {
659 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
660 if (IS_SYMBOL(p)) return false;
662 var handler = %GetHandler(obj);
663 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
664 if (!ToBoolean(result)) {
666 throw MakeTypeError("handler_returned_false",
667 [handler, "defineProperty"]);
677 function DefineObjectProperty(obj, p, desc, should_throw) {
678 var current_array = %GetOwnProperty(ToObject(obj), ToName(p));
679 var current = ConvertDescriptorArrayToDescriptor(current_array);
680 var extensible = %IsExtensible(ToObject(obj));
682 // Error handling according to spec.
684 if (IS_UNDEFINED(current) && !extensible) {
686 throw MakeTypeError("define_disallowed", [p]);
692 if (!IS_UNDEFINED(current)) {
694 if ((IsGenericDescriptor(desc) ||
695 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
696 (!desc.hasEnumerable() ||
697 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
698 (!desc.hasConfigurable() ||
699 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
700 (!desc.hasWritable() ||
701 SameValue(desc.isWritable(), current.isWritable())) &&
703 SameValue(desc.getValue(), current.getValue())) &&
704 (!desc.hasGetter() ||
705 SameValue(desc.getGet(), current.getGet())) &&
706 (!desc.hasSetter() ||
707 SameValue(desc.getSet(), current.getSet()))) {
710 if (!current.isConfigurable()) {
712 if (desc.isConfigurable() ||
713 (desc.hasEnumerable() &&
714 desc.isEnumerable() != current.isEnumerable())) {
716 throw MakeTypeError("redefine_disallowed", [p]);
722 if (!IsGenericDescriptor(desc)) {
724 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
726 throw MakeTypeError("redefine_disallowed", [p]);
732 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
733 if (!current.isWritable() && desc.isWritable()) {
735 throw MakeTypeError("redefine_disallowed", [p]);
740 if (!current.isWritable() && desc.hasValue() &&
741 !SameValue(desc.getValue(), current.getValue())) {
743 throw MakeTypeError("redefine_disallowed", [p]);
750 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
751 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
753 throw MakeTypeError("redefine_disallowed", [p]);
758 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
760 throw MakeTypeError("redefine_disallowed", [p]);
770 // Send flags - enumerable and configurable are common - writable is
771 // only send to the data descriptor.
772 // Take special care if enumerable and configurable is not defined on
773 // desc (we need to preserve the existing values from current).
775 if (desc.hasEnumerable()) {
776 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
777 } else if (!IS_UNDEFINED(current)) {
778 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
783 if (desc.hasConfigurable()) {
784 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
785 } else if (!IS_UNDEFINED(current)) {
786 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
790 if (IsDataDescriptor(desc) ||
791 (IsGenericDescriptor(desc) &&
792 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
793 // There are 3 cases that lead here:
794 // Step 4a - defining a new data property.
795 // Steps 9b & 12 - replacing an existing accessor property with a data
797 // Step 12 - updating an existing data property with a data or generic
800 if (desc.hasWritable()) {
801 flag |= desc.isWritable() ? 0 : READ_ONLY;
802 } else if (!IS_UNDEFINED(current)) {
803 flag |= current.isWritable() ? 0 : READ_ONLY;
808 var value = UNDEFINED; // Default value is undefined.
809 if (desc.hasValue()) {
810 value = desc.getValue();
811 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
812 value = current.getValue();
815 %DefineDataPropertyUnchecked(obj, p, value, flag);
817 // There are 3 cases that lead here:
818 // Step 4b - defining a new accessor property.
819 // Steps 9c & 12 - replacing an existing data property with an accessor
821 // Step 12 - updating an existing accessor property with an accessor
824 if (desc.hasGetter()) {
825 getter = desc.getGet();
826 } else if (IsAccessorDescriptor(current) && current.hasGetter()) {
827 getter = current.getGet();
830 if (desc.hasSetter()) {
831 setter = desc.getSet();
832 } else if (IsAccessorDescriptor(current) && current.hasSetter()) {
833 setter = current.getSet();
835 %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag);
841 // ES5 section 15.4.5.1.
842 function DefineArrayProperty(obj, p, desc, should_throw) {
843 // Note that the length of an array is not actually stored as part of the
844 // property, hence we use generated code throughout this function instead of
845 // DefineObjectProperty() to modify its value.
847 // Step 3 - Special handling for length property.
848 if (p === "length") {
849 var length = obj.length;
850 var old_length = length;
851 if (!desc.hasValue()) {
852 return DefineObjectProperty(obj, "length", desc, should_throw);
854 var new_length = ToUint32(desc.getValue());
855 if (new_length != ToNumber(desc.getValue())) {
856 throw new $RangeError('defineProperty() array length out of range');
858 var length_desc = GetOwnPropertyJS(obj, "length");
859 if (new_length != length && !length_desc.isWritable()) {
861 throw MakeTypeError("redefine_disallowed", [p]);
868 var emit_splice = %IsObserved(obj) && new_length !== old_length;
871 BeginPerformSplice(obj);
873 if (new_length < old_length)
874 removed.length = old_length - new_length;
877 while (new_length < length--) {
878 var index = ToString(length);
880 var deletedDesc = GetOwnPropertyJS(obj, index);
881 if (deletedDesc && deletedDesc.hasValue())
882 removed[length - new_length] = deletedDesc.getValue();
884 if (!Delete(obj, index, false)) {
885 new_length = length + 1;
890 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
892 EndPerformSplice(obj);
893 EnqueueSpliceRecord(obj,
894 new_length < old_length ? new_length : old_length,
896 new_length > old_length ? new_length - old_length : 0);
900 throw MakeTypeError("redefine_disallowed", [p]);
908 // Step 4 - Special handling for array index.
910 var index = ToUint32(p);
911 var emit_splice = false;
912 if (ToString(index) == p && index != 4294967295) {
913 var length = obj.length;
914 if (index >= length && %IsObserved(obj)) {
916 BeginPerformSplice(obj);
919 var length_desc = GetOwnPropertyJS(obj, "length");
920 if ((index >= length && !length_desc.isWritable()) ||
921 !DefineObjectProperty(obj, p, desc, true)) {
923 EndPerformSplice(obj);
925 throw MakeTypeError("define_disallowed", [p]);
930 if (index >= length) {
931 obj.length = index + 1;
934 EndPerformSplice(obj);
935 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
941 // Step 5 - Fallback to default implementation.
942 return DefineObjectProperty(obj, p, desc, should_throw);
946 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
947 function DefineOwnProperty(obj, p, desc, should_throw) {
948 if (%_IsJSProxy(obj)) {
949 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
950 if (IS_SYMBOL(p)) return false;
952 var attributes = FromGenericPropertyDescriptor(desc);
953 return DefineProxyProperty(obj, p, attributes, should_throw);
954 } else if (IS_ARRAY(obj)) {
955 return DefineArrayProperty(obj, p, desc, should_throw);
957 return DefineObjectProperty(obj, p, desc, should_throw);
962 // ES5 section 15.2.3.2.
963 function ObjectGetPrototypeOf(obj) {
964 if (!IS_SPEC_OBJECT(obj)) {
965 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
967 return %_GetPrototype(obj);
970 // ES6 section 19.1.2.19.
971 function ObjectSetPrototypeOf(obj, proto) {
972 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
974 if (proto !== null && !IS_SPEC_OBJECT(proto)) {
975 throw MakeTypeError("proto_object_or_null", [proto]);
978 if (IS_SPEC_OBJECT(obj)) {
979 %SetPrototype(obj, proto);
986 // ES5 section 15.2.3.3
987 function ObjectGetOwnPropertyDescriptor(obj, p) {
988 if (!IS_SPEC_OBJECT(obj)) {
989 throw MakeTypeError("called_on_non_object",
990 ["Object.getOwnPropertyDescriptor"]);
992 var desc = GetOwnPropertyJS(obj, p);
993 return FromPropertyDescriptor(desc);
997 // For Harmony proxies
998 function ToNameArray(obj, trap, includeSymbols) {
999 if (!IS_SPEC_OBJECT(obj)) {
1000 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1002 var n = ToUint32(obj.length);
1003 var array = new $Array(n);
1005 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
1006 for (var index = 0; index < n; index++) {
1007 var s = ToName(obj[index]);
1008 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1009 if (IS_SYMBOL(s) && !includeSymbols) continue;
1010 if (%HasOwnProperty(names, s)) {
1011 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1017 array.length = realLength;
1022 function ObjectGetOwnPropertyKeys(obj, filter) {
1023 var nameArrays = new InternalArray();
1024 filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1025 var interceptorInfo = %GetInterceptorInfo(obj);
1027 // Find all the indexed properties.
1029 // Only get own element names if we want to include string keys.
1030 if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
1031 var ownElementNames = %GetOwnElementNames(obj);
1032 for (var i = 0; i < ownElementNames.length; ++i) {
1033 ownElementNames[i] = %_NumberToString(ownElementNames[i]);
1035 nameArrays.push(ownElementNames);
1036 // Get names for indexed interceptor properties.
1037 if ((interceptorInfo & 1) != 0) {
1038 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1039 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1040 nameArrays.push(indexedInterceptorNames);
1045 // Find all the named properties.
1047 // Get own property names.
1048 nameArrays.push(%GetOwnPropertyNames(obj, filter));
1050 // Get names for named interceptor properties if any.
1051 if ((interceptorInfo & 2) != 0) {
1052 var namedInterceptorNames =
1053 %GetNamedInterceptorPropertyNames(obj);
1054 if (!IS_UNDEFINED(namedInterceptorNames)) {
1055 nameArrays.push(namedInterceptorNames);
1060 %Apply(InternalArray.prototype.concat,
1061 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1063 // Property names are expected to be unique strings,
1064 // but interceptors can interfere with that assumption.
1065 if (interceptorInfo != 0) {
1066 var seenKeys = { __proto__: null };
1068 for (var i = 0; i < propertyNames.length; ++i) {
1069 var name = propertyNames[i];
1070 if (IS_SYMBOL(name)) {
1071 if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
1075 if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
1076 name = ToString(name);
1078 if (seenKeys[name]) continue;
1079 seenKeys[name] = true;
1080 propertyNames[j++] = name;
1082 propertyNames.length = j;
1085 return propertyNames;
1089 // ES5 section 15.2.3.4.
1090 function ObjectGetOwnPropertyNames(obj) {
1091 obj = ToObject(obj);
1092 // Special handling for proxies.
1093 if (%_IsJSProxy(obj)) {
1094 var handler = %GetHandler(obj);
1095 var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1096 return ToNameArray(names, "getOwnPropertyNames", false);
1099 return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
1103 // ES5 section 15.2.3.5.
1104 function ObjectCreate(proto, properties) {
1105 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1106 throw MakeTypeError("proto_object_or_null", [proto]);
1109 %InternalSetPrototype(obj, proto);
1110 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1115 // ES5 section 15.2.3.6.
1116 function ObjectDefineProperty(obj, p, attributes) {
1117 if (!IS_SPEC_OBJECT(obj)) {
1118 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1120 var name = ToName(p);
1121 if (%_IsJSProxy(obj)) {
1122 // Clone the attributes object for protection.
1123 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1124 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1125 var attributesClone = { __proto__: null };
1126 for (var a in attributes) {
1127 attributesClone[a] = attributes[a];
1129 DefineProxyProperty(obj, name, attributesClone, true);
1130 // The following would implement the spec as in the current proposal,
1131 // but after recent comments on es-discuss, is most likely obsolete.
1133 var defineObj = FromGenericPropertyDescriptor(desc);
1134 var names = ObjectGetOwnPropertyNames(attributes);
1136 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1137 for (var i = 0; i < names.length; i++) {
1139 if (!(%HasOwnProperty(standardNames, N))) {
1140 var attr = GetOwnPropertyJS(attributes, N);
1141 DefineOwnProperty(descObj, N, attr, true);
1144 // This is really confusing the types, but it is what the proxies spec
1145 // currently requires:
1149 var desc = ToPropertyDescriptor(attributes);
1150 DefineOwnProperty(obj, name, desc, true);
1156 function GetOwnEnumerablePropertyNames(object) {
1157 var names = new InternalArray();
1158 for (var key in object) {
1159 if (%HasOwnProperty(object, key)) {
1164 var filter = PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1165 var symbols = %GetOwnPropertyNames(object, filter);
1166 for (var i = 0; i < symbols.length; ++i) {
1167 var symbol = symbols[i];
1168 if (IS_SYMBOL(symbol)) {
1169 var desc = ObjectGetOwnPropertyDescriptor(object, symbol);
1170 if (desc.enumerable) names.push(symbol);
1178 // ES5 section 15.2.3.7.
1179 function ObjectDefineProperties(obj, properties) {
1180 if (!IS_SPEC_OBJECT(obj)) {
1181 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1183 var props = ToObject(properties);
1184 var names = GetOwnEnumerablePropertyNames(props);
1185 var descriptors = new InternalArray();
1186 for (var i = 0; i < names.length; i++) {
1187 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1189 for (var i = 0; i < names.length; i++) {
1190 DefineOwnProperty(obj, names[i], descriptors[i], true);
1197 function ProxyFix(obj) {
1198 var handler = %GetHandler(obj);
1199 var props = CallTrap0(handler, "fix", UNDEFINED);
1200 if (IS_UNDEFINED(props)) {
1201 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1204 if (%IsJSFunctionProxy(obj)) {
1205 var callTrap = %GetCallTrap(obj);
1206 var constructTrap = %GetConstructTrap(obj);
1207 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1208 %Fix(obj); // becomes a regular function
1209 %SetCode(obj, code);
1210 // TODO(rossberg): What about length and other properties? Not specified.
1211 // We just put in some half-reasonable defaults for now.
1212 var prototype = new $Object();
1213 $Object.defineProperty(prototype, "constructor",
1214 {value: obj, writable: true, enumerable: false, configurable: true});
1215 // TODO(v8:1530): defineProperty does not handle prototype and length.
1216 %FunctionSetPrototype(obj, prototype);
1221 ObjectDefineProperties(obj, props);
1225 // ES5 section 15.2.3.8.
1226 function ObjectSealJS(obj) {
1227 if (!IS_SPEC_OBJECT(obj)) {
1228 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1230 var isProxy = %_IsJSProxy(obj);
1231 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1235 var names = ObjectGetOwnPropertyNames(obj);
1236 for (var i = 0; i < names.length; i++) {
1237 var name = names[i];
1238 var desc = GetOwnPropertyJS(obj, name);
1239 if (desc.isConfigurable()) {
1240 desc.setConfigurable(false);
1241 DefineOwnProperty(obj, name, desc, true);
1244 %PreventExtensions(obj);
1246 // TODO(adamk): Is it worth going to this fast path if the
1247 // object's properties are already in dictionary mode?
1254 // ES5 section 15.2.3.9.
1255 function ObjectFreezeJS(obj) {
1256 if (!IS_SPEC_OBJECT(obj)) {
1257 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1259 var isProxy = %_IsJSProxy(obj);
1260 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1264 var names = ObjectGetOwnPropertyNames(obj);
1265 for (var i = 0; i < names.length; i++) {
1266 var name = names[i];
1267 var desc = GetOwnPropertyJS(obj, name);
1268 if (desc.isWritable() || desc.isConfigurable()) {
1269 if (IsDataDescriptor(desc)) desc.setWritable(false);
1270 desc.setConfigurable(false);
1271 DefineOwnProperty(obj, name, desc, true);
1274 %PreventExtensions(obj);
1276 // TODO(adamk): Is it worth going to this fast path if the
1277 // object's properties are already in dictionary mode?
1284 // ES5 section 15.2.3.10
1285 function ObjectPreventExtension(obj) {
1286 if (!IS_SPEC_OBJECT(obj)) {
1287 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1289 if (%_IsJSProxy(obj)) {
1292 %PreventExtensions(obj);
1297 // ES5 section 15.2.3.11
1298 function ObjectIsSealed(obj) {
1299 if (!IS_SPEC_OBJECT(obj)) {
1300 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1302 if (%_IsJSProxy(obj)) {
1305 if (%IsExtensible(obj)) {
1308 var names = ObjectGetOwnPropertyNames(obj);
1309 for (var i = 0; i < names.length; i++) {
1310 var name = names[i];
1311 var desc = GetOwnPropertyJS(obj, name);
1312 if (desc.isConfigurable()) {
1320 // ES5 section 15.2.3.12
1321 function ObjectIsFrozen(obj) {
1322 if (!IS_SPEC_OBJECT(obj)) {
1323 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1325 if (%_IsJSProxy(obj)) {
1328 if (%IsExtensible(obj)) {
1331 var names = ObjectGetOwnPropertyNames(obj);
1332 for (var i = 0; i < names.length; i++) {
1333 var name = names[i];
1334 var desc = GetOwnPropertyJS(obj, name);
1335 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1336 if (desc.isConfigurable()) return false;
1342 // ES5 section 15.2.3.13
1343 function ObjectIsExtensible(obj) {
1344 if (!IS_SPEC_OBJECT(obj)) {
1345 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1347 if (%_IsJSProxy(obj)) {
1350 return %IsExtensible(obj);
1354 // ECMA-262, Edition 6, section 19.1.2.10
1355 function ObjectIs(obj1, obj2) {
1356 return SameValue(obj1, obj2);
1360 // ECMA-262, Edition 6, section B.2.2.1.1
1361 function ObjectGetProto() {
1362 return %_GetPrototype(ToObject(this));
1366 // ECMA-262, Edition 6, section B.2.2.1.2
1367 function ObjectSetProto(proto) {
1368 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1370 if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1371 %SetPrototype(this, proto);
1376 function ObjectConstructor(x) {
1377 if (%_IsConstructCall()) {
1378 if (x == null) return this;
1381 if (x == null) return { };
1387 // ----------------------------------------------------------------------------
1390 function SetUpObject() {
1391 %CheckIsBootstrapping();
1393 %SetNativeFlag($Object);
1394 %SetCode($Object, ObjectConstructor);
1396 %AddNamedProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1398 // Set up non-enumerable functions on the Object.prototype object.
1399 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1400 "toString", NoSideEffectsObjectToString,
1401 "toLocaleString", ObjectToLocaleString,
1402 "valueOf", ObjectValueOf,
1403 "hasOwnProperty", ObjectHasOwnProperty,
1404 "isPrototypeOf", ObjectIsPrototypeOf,
1405 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1406 "__defineGetter__", ObjectDefineGetter,
1407 "__lookupGetter__", ObjectLookupGetter,
1408 "__defineSetter__", ObjectDefineSetter,
1409 "__lookupSetter__", ObjectLookupSetter
1411 InstallGetterSetter($Object.prototype, "__proto__",
1412 ObjectGetProto, ObjectSetProto);
1414 // Set up non-enumerable functions in the Object object.
1415 InstallFunctions($Object, DONT_ENUM, $Array(
1417 "create", ObjectCreate,
1418 "defineProperty", ObjectDefineProperty,
1419 "defineProperties", ObjectDefineProperties,
1420 "freeze", ObjectFreezeJS,
1421 "getPrototypeOf", ObjectGetPrototypeOf,
1422 "setPrototypeOf", ObjectSetPrototypeOf,
1423 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1424 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1425 // getOwnPropertySymbols is added in symbol.js.
1427 "isExtensible", ObjectIsExtensible,
1428 "isFrozen", ObjectIsFrozen,
1429 "isSealed", ObjectIsSealed,
1430 "preventExtensions", ObjectPreventExtension,
1431 "seal", ObjectSealJS
1432 // deliverChangeRecords, getNotifier, observe and unobserve are added
1433 // in object-observe.js.
1440 // ----------------------------------------------------------------------------
1443 function BooleanConstructor(x) {
1444 if (%_IsConstructCall()) {
1445 %_SetValueOf(this, ToBoolean(x));
1447 return ToBoolean(x);
1452 function BooleanToString() {
1453 // NOTE: Both Boolean objects and values can enter here as
1454 // 'this'. This is not as dictated by ECMA-262.
1456 if (!IS_BOOLEAN(b)) {
1457 if (!IS_BOOLEAN_WRAPPER(b)) {
1458 throw new $TypeError('Boolean.prototype.toString is not generic');
1462 return b ? 'true' : 'false';
1466 function BooleanValueOf() {
1467 // NOTE: Both Boolean objects and values can enter here as
1468 // 'this'. This is not as dictated by ECMA-262.
1469 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1470 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1472 return %_ValueOf(this);
1476 // ----------------------------------------------------------------------------
1478 function SetUpBoolean () {
1479 %CheckIsBootstrapping();
1481 %SetCode($Boolean, BooleanConstructor);
1482 %FunctionSetPrototype($Boolean, new $Boolean(false));
1483 %AddNamedProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1485 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1486 "toString", BooleanToString,
1487 "valueOf", BooleanValueOf
1494 // ----------------------------------------------------------------------------
1497 function NumberConstructor(x) {
1498 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1499 if (%_IsConstructCall()) {
1500 %_SetValueOf(this, value);
1507 // ECMA-262 section 15.7.4.2.
1508 function NumberToString(radix) {
1509 // NOTE: Both Number objects and values can enter here as
1510 // 'this'. This is not as dictated by ECMA-262.
1512 if (!IS_NUMBER(this)) {
1513 if (!IS_NUMBER_WRAPPER(this)) {
1514 throw new $TypeError('Number.prototype.toString is not generic');
1516 // Get the value of this number in case it's an object.
1517 number = %_ValueOf(this);
1519 // Fast case: Convert number in radix 10.
1520 if (IS_UNDEFINED(radix) || radix === 10) {
1521 return %_NumberToString(number);
1524 // Convert the radix to an integer and check the range.
1525 radix = TO_INTEGER(radix);
1526 if (radix < 2 || radix > 36) {
1527 throw new $RangeError('toString() radix argument must be between 2 and 36');
1529 // Convert the number to a string in the given radix.
1530 return %NumberToRadixString(number, radix);
1534 // ECMA-262 section 15.7.4.3
1535 function NumberToLocaleString() {
1536 return %_CallFunction(this, NumberToString);
1540 // ECMA-262 section 15.7.4.4
1541 function NumberValueOf() {
1542 // NOTE: Both Number objects and values can enter here as
1543 // 'this'. This is not as dictated by ECMA-262.
1544 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1545 throw new $TypeError('Number.prototype.valueOf is not generic');
1547 return %_ValueOf(this);
1551 // ECMA-262 section 15.7.4.5
1552 function NumberToFixedJS(fractionDigits) {
1554 if (!IS_NUMBER(this)) {
1555 if (!IS_NUMBER_WRAPPER(this)) {
1556 throw MakeTypeError("incompatible_method_receiver",
1557 ["Number.prototype.toFixed", this]);
1559 // Get the value of this number in case it's an object.
1560 x = %_ValueOf(this);
1562 var f = TO_INTEGER(fractionDigits);
1564 if (f < 0 || f > 20) {
1565 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1568 if (NUMBER_IS_NAN(x)) return "NaN";
1569 if (x == INFINITY) return "Infinity";
1570 if (x == -INFINITY) return "-Infinity";
1572 return %NumberToFixed(x, f);
1576 // ECMA-262 section 15.7.4.6
1577 function NumberToExponentialJS(fractionDigits) {
1579 if (!IS_NUMBER(this)) {
1580 if (!IS_NUMBER_WRAPPER(this)) {
1581 throw MakeTypeError("incompatible_method_receiver",
1582 ["Number.prototype.toExponential", this]);
1584 // Get the value of this number in case it's an object.
1585 x = %_ValueOf(this);
1587 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1589 if (NUMBER_IS_NAN(x)) return "NaN";
1590 if (x == INFINITY) return "Infinity";
1591 if (x == -INFINITY) return "-Infinity";
1593 if (IS_UNDEFINED(f)) {
1594 f = -1; // Signal for runtime function that f is not defined.
1595 } else if (f < 0 || f > 20) {
1596 throw new $RangeError("toExponential() argument must be between 0 and 20");
1598 return %NumberToExponential(x, f);
1602 // ECMA-262 section 15.7.4.7
1603 function NumberToPrecisionJS(precision) {
1605 if (!IS_NUMBER(this)) {
1606 if (!IS_NUMBER_WRAPPER(this)) {
1607 throw MakeTypeError("incompatible_method_receiver",
1608 ["Number.prototype.toPrecision", this]);
1610 // Get the value of this number in case it's an object.
1611 x = %_ValueOf(this);
1613 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1614 var p = TO_INTEGER(precision);
1616 if (NUMBER_IS_NAN(x)) return "NaN";
1617 if (x == INFINITY) return "Infinity";
1618 if (x == -INFINITY) return "-Infinity";
1620 if (p < 1 || p > 21) {
1621 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1623 return %NumberToPrecision(x, p);
1627 // Harmony isFinite.
1628 function NumberIsFinite(number) {
1629 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1633 // Harmony isInteger
1634 function NumberIsInteger(number) {
1635 return NumberIsFinite(number) && TO_INTEGER(number) == number;
1640 function NumberIsNaN(number) {
1641 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1645 // Harmony isSafeInteger
1646 function NumberIsSafeInteger(number) {
1647 if (NumberIsFinite(number)) {
1648 var integral = TO_INTEGER(number);
1649 if (integral == number)
1650 return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
1656 // ----------------------------------------------------------------------------
1658 function SetUpNumber() {
1659 %CheckIsBootstrapping();
1661 %SetCode($Number, NumberConstructor);
1662 %FunctionSetPrototype($Number, new $Number(0));
1664 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1665 // Set up the constructor property on the Number prototype object.
1666 %AddNamedProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1668 InstallConstants($Number, $Array(
1669 // ECMA-262 section 15.7.3.1.
1670 "MAX_VALUE", 1.7976931348623157e+308,
1671 // ECMA-262 section 15.7.3.2.
1672 "MIN_VALUE", 5e-324,
1673 // ECMA-262 section 15.7.3.3.
1675 // ECMA-262 section 15.7.3.4.
1676 "NEGATIVE_INFINITY", -INFINITY,
1677 // ECMA-262 section 15.7.3.5.
1678 "POSITIVE_INFINITY", INFINITY,
1680 // --- Harmony constants (no spec refs until settled.)
1682 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1683 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1684 "EPSILON", %_MathPow(2, -52)
1687 // Set up non-enumerable functions on the Number prototype object.
1688 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1689 "toString", NumberToString,
1690 "toLocaleString", NumberToLocaleString,
1691 "valueOf", NumberValueOf,
1692 "toFixed", NumberToFixedJS,
1693 "toExponential", NumberToExponentialJS,
1694 "toPrecision", NumberToPrecisionJS
1697 // Harmony Number constructor additions
1698 InstallFunctions($Number, DONT_ENUM, $Array(
1699 "isFinite", NumberIsFinite,
1700 "isInteger", NumberIsInteger,
1701 "isNaN", NumberIsNaN,
1702 "isSafeInteger", NumberIsSafeInteger,
1703 "parseInt", GlobalParseInt,
1704 "parseFloat", GlobalParseFloat
1711 // ----------------------------------------------------------------------------
1714 function FunctionSourceString(func) {
1715 while (%IsJSFunctionProxy(func)) {
1716 func = %GetCallTrap(func);
1719 if (!IS_FUNCTION(func)) {
1720 throw new $TypeError('Function.prototype.toString is not generic');
1723 var classSource = %ClassGetSourceCode(func);
1724 if (IS_STRING(classSource)) {
1728 var source = %FunctionGetSourceCode(func);
1729 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1730 var name = %FunctionGetName(func);
1732 // Mimic what KJS does.
1733 return 'function ' + name + '() { [native code] }';
1735 return 'function () { [native code] }';
1739 if (%FunctionIsArrow(func)) {
1743 var name = %FunctionNameShouldPrintAsAnonymous(func)
1745 : %FunctionGetName(func);
1747 var isGenerator = %FunctionIsGenerator(func);
1748 var head = %FunctionIsConciseMethod(func)
1749 ? (isGenerator ? '*' : '')
1750 : (isGenerator ? 'function* ' : 'function ');
1751 return head + name + source;
1755 function FunctionToString() {
1756 return FunctionSourceString(this);
1761 function FunctionBind(this_arg) { // Length is 1.
1762 if (!IS_SPEC_FUNCTION(this)) {
1763 throw new $TypeError('Bind must be called on a function');
1765 var boundFunction = function () {
1766 // Poison .arguments and .caller, but is otherwise not detectable.
1768 // This function must not use any object literals (Object, Array, RegExp),
1769 // since the literals-array is being used to store the bound data.
1770 if (%_IsConstructCall()) {
1771 return %NewObjectFromBound(boundFunction);
1773 var bindings = %BoundFunctionGetBindings(boundFunction);
1775 var argc = %_ArgumentsLength();
1777 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1779 if (bindings.length === 2) {
1780 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1782 var bound_argc = bindings.length - 2;
1783 var argv = new InternalArray(bound_argc + argc);
1784 for (var i = 0; i < bound_argc; i++) {
1785 argv[i] = bindings[i + 2];
1787 for (var j = 0; j < argc; j++) {
1788 argv[i++] = %_Arguments(j);
1790 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1794 var old_length = this.length;
1795 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1796 if ((typeof old_length === "number") &&
1797 ((old_length >>> 0) === old_length)) {
1798 var argc = %_ArgumentsLength();
1799 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1800 new_length = old_length - argc;
1801 if (new_length < 0) new_length = 0;
1803 // This runtime function finds any remaining arguments on the stack,
1804 // so we don't pass the arguments object.
1805 var result = %FunctionBindArguments(boundFunction, this,
1806 this_arg, new_length);
1808 // We already have caller and arguments properties on functions,
1809 // which are non-configurable. It therefore makes no sence to
1810 // try to redefine these as defined by the spec. The spec says
1811 // that bind should make these throw a TypeError if get or set
1812 // is called and make them non-enumerable and non-configurable.
1813 // To be consistent with our normal functions we leave this as it is.
1814 // TODO(lrn): Do set these to be thrower.
1819 function NewFunctionFromString(arguments, function_token) {
1820 var n = arguments.length;
1823 p = ToString(arguments[0]);
1824 for (var i = 1; i < n - 1; i++) {
1825 p += ',' + ToString(arguments[i]);
1827 // If the formal parameters string include ) - an illegal
1828 // character - it may make the combined function expression
1829 // compile. We avoid this problem by checking for this early on.
1830 if (%_CallFunction(p, ')', StringIndexOfJS) != -1) {
1831 throw MakeSyntaxError('paren_in_arg_string', []);
1833 // If the formal parameters include an unbalanced block comment, the
1834 // function must be rejected. Since JavaScript does not allow nested
1835 // comments we can include a trailing block comment to catch this.
1836 p += '\n\x2f**\x2f';
1838 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1839 var head = '(' + function_token + '(' + p + ') {\n';
1840 var src = head + body + '\n})';
1841 var global_proxy = %GlobalProxy(global);
1842 var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
1843 %FunctionMarkNameShouldPrintAsAnonymous(f);
1848 function FunctionConstructor(arg1) { // length == 1
1849 return NewFunctionFromString(arguments, 'function');
1853 // ----------------------------------------------------------------------------
1855 function SetUpFunction() {
1856 %CheckIsBootstrapping();
1858 %SetCode($Function, FunctionConstructor);
1859 %AddNamedProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1861 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1862 "bind", FunctionBind,
1863 "toString", FunctionToString
1870 // ----------------------------------------------------------------------------
1871 // Iterator related spec functions.
1873 // ES6 rev 26, 2014-07-18
1874 // 7.4.1 CheckIterable ( obj )
1875 function ToIterable(obj) {
1876 if (!IS_SPEC_OBJECT(obj)) {
1879 return obj[symbolIterator];
1883 // ES6 rev 26, 2014-07-18
1884 // 7.4.2 GetIterator ( obj, method )
1885 function GetIterator(obj, method) {
1886 if (IS_UNDEFINED(method)) {
1887 method = ToIterable(obj);
1889 if (!IS_SPEC_FUNCTION(method)) {
1890 throw MakeTypeError('not_iterable', [obj]);
1892 var iterator = %_CallFunction(obj, method);
1893 if (!IS_SPEC_OBJECT(iterator)) {
1894 throw MakeTypeError('not_an_iterator', [iterator]);