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 %SetProperty(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 %DefineOrRedefineAccessorProperty(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 %DefineOrRedefineAccessorProperty(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 %SetProperty(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 %SetProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE);
92 for (var i = 0; i < methods.length; i += 2) {
94 var f = methods[i + 1];
95 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
98 %SetPrototype(prototype, null);
99 %ToFastProperties(prototype);
103 // ----------------------------------------------------------------------------
107 function GlobalIsNaN(number) {
108 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
109 return NUMBER_IS_NAN(number);
114 function GlobalIsFinite(number) {
115 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
116 return NUMBER_IS_FINITE(number);
120 // ECMA-262 - 15.1.2.2
121 function GlobalParseInt(string, radix) {
122 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
123 // Some people use parseInt instead of Math.floor. This
124 // optimization makes parseInt on a Smi 12 times faster (60ns
125 // vs 800ns). The following optimization makes parseInt on a
126 // non-Smi number 9 times faster (230ns vs 2070ns). Together
127 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
128 if (%_IsSmi(string)) return string;
129 if (IS_NUMBER(string) &&
130 ((0.01 < string && string < 1e9) ||
131 (-1e9 < string && string < -0.01))) {
135 string = TO_STRING_INLINE(string);
138 // The spec says ToString should be evaluated before ToInt32.
139 string = TO_STRING_INLINE(string);
140 radix = TO_INT32(radix);
141 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
146 if (%_HasCachedArrayIndex(string) &&
147 (radix == 0 || radix == 10)) {
148 return %_GetCachedArrayIndex(string);
150 return %StringParseInt(string, radix);
154 // ECMA-262 - 15.1.2.3
155 function GlobalParseFloat(string) {
156 string = TO_STRING_INLINE(string);
157 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
158 return %StringParseFloat(string);
162 function GlobalEval(x) {
163 if (!IS_STRING(x)) return x;
165 // For consistency with JSC we require the global object passed to
166 // eval to be the global object from which 'eval' originated. This
167 // is not mandated by the spec.
168 // We only throw if the global has been detached, since we need the
169 // receiver as this-value for the call.
170 if (!%IsAttachedGlobal(global)) {
171 throw new $EvalError('The "this" value passed to eval must ' +
172 'be the global object from which eval originated');
175 var global_receiver = %GlobalReceiver(global);
177 var f = %CompileString(x, false);
178 if (!IS_FUNCTION(f)) return f;
180 return %_CallFunction(global_receiver, f);
184 // ----------------------------------------------------------------------------
186 // Set up global object.
187 function SetUpGlobal() {
188 %CheckIsBootstrapping();
190 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
192 // ECMA 262 - 15.1.1.1.
193 %SetProperty(global, "NaN", NAN, attributes);
195 // ECMA-262 - 15.1.1.2.
196 %SetProperty(global, "Infinity", INFINITY, attributes);
198 // ECMA-262 - 15.1.1.3.
199 %SetProperty(global, "undefined", UNDEFINED, attributes);
201 // Set up non-enumerable function on the global object.
202 InstallFunctions(global, DONT_ENUM, $Array(
203 "isNaN", GlobalIsNaN,
204 "isFinite", GlobalIsFinite,
205 "parseInt", GlobalParseInt,
206 "parseFloat", GlobalParseFloat,
214 // ----------------------------------------------------------------------------
217 // ECMA-262 - 15.2.4.2
218 function ObjectToString() {
219 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
220 if (IS_NULL(this)) return "[object Null]";
221 return "[object " + %_ClassOf(ToObject(this)) + "]";
225 // ECMA-262 - 15.2.4.3
226 function ObjectToLocaleString() {
227 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
228 return this.toString();
232 // ECMA-262 - 15.2.4.4
233 function ObjectValueOf() {
234 return ToObject(this);
238 // ECMA-262 - 15.2.4.5
239 function ObjectHasOwnProperty(V) {
240 if (%IsJSProxy(this)) {
241 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
242 if (IS_SYMBOL(V)) return false;
244 var handler = %GetHandler(this);
245 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
247 return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
251 // ECMA-262 - 15.2.4.6
252 function ObjectIsPrototypeOf(V) {
253 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
254 if (!IS_SPEC_OBJECT(V)) return false;
255 return %IsInPrototypeChain(this, V);
259 // ECMA-262 - 15.2.4.6
260 function ObjectPropertyIsEnumerable(V) {
262 if (%IsJSProxy(this)) {
263 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
264 if (IS_SYMBOL(V)) return false;
266 var desc = GetOwnProperty(this, P);
267 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
269 return %IsPropertyEnumerable(ToObject(this), P);
273 // Extensions for providing property getters and setters.
274 function ObjectDefineGetter(name, fun) {
276 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
277 receiver = %GlobalReceiver(global);
279 if (!IS_SPEC_FUNCTION(fun)) {
280 throw new $TypeError(
281 'Object.prototype.__defineGetter__: Expecting function');
283 var desc = new PropertyDescriptor();
285 desc.setEnumerable(true);
286 desc.setConfigurable(true);
287 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
291 function ObjectLookupGetter(name) {
293 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
294 receiver = %GlobalReceiver(global);
296 return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
300 function ObjectDefineSetter(name, fun) {
302 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
303 receiver = %GlobalReceiver(global);
305 if (!IS_SPEC_FUNCTION(fun)) {
306 throw new $TypeError(
307 'Object.prototype.__defineSetter__: Expecting function');
309 var desc = new PropertyDescriptor();
311 desc.setEnumerable(true);
312 desc.setConfigurable(true);
313 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
317 function ObjectLookupSetter(name) {
319 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
320 receiver = %GlobalReceiver(global);
322 return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
326 function ObjectKeys(obj) {
327 if (!IS_SPEC_OBJECT(obj)) {
328 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
330 if (%IsJSProxy(obj)) {
331 var handler = %GetHandler(obj);
332 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
333 return ToNameArray(names, "keys", false);
335 return %LocalKeys(obj);
340 function IsAccessorDescriptor(desc) {
341 if (IS_UNDEFINED(desc)) return false;
342 return desc.hasGetter() || desc.hasSetter();
347 function IsDataDescriptor(desc) {
348 if (IS_UNDEFINED(desc)) return false;
349 return desc.hasValue() || desc.hasWritable();
354 function IsGenericDescriptor(desc) {
355 if (IS_UNDEFINED(desc)) return false;
356 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
360 function IsInconsistentDescriptor(desc) {
361 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
366 function FromPropertyDescriptor(desc) {
367 if (IS_UNDEFINED(desc)) return desc;
369 if (IsDataDescriptor(desc)) {
370 return { value: desc.getValue(),
371 writable: desc.isWritable(),
372 enumerable: desc.isEnumerable(),
373 configurable: desc.isConfigurable() };
375 // Must be an AccessorDescriptor then. We never return a generic descriptor.
376 return { get: desc.getGet(),
378 enumerable: desc.isEnumerable(),
379 configurable: desc.isConfigurable() };
384 function FromGenericPropertyDescriptor(desc) {
385 if (IS_UNDEFINED(desc)) return desc;
386 var obj = new $Object();
388 if (desc.hasValue()) {
389 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
391 if (desc.hasWritable()) {
392 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
394 if (desc.hasGetter()) {
395 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
397 if (desc.hasSetter()) {
398 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
400 if (desc.hasEnumerable()) {
401 %IgnoreAttributesAndSetProperty(obj, "enumerable",
402 desc.isEnumerable(), NONE);
404 if (desc.hasConfigurable()) {
405 %IgnoreAttributesAndSetProperty(obj, "configurable",
406 desc.isConfigurable(), NONE);
413 function ToPropertyDescriptor(obj) {
414 if (!IS_SPEC_OBJECT(obj)) {
415 throw MakeTypeError("property_desc_object", [obj]);
417 var desc = new PropertyDescriptor();
419 if ("enumerable" in obj) {
420 desc.setEnumerable(ToBoolean(obj.enumerable));
423 if ("configurable" in obj) {
424 desc.setConfigurable(ToBoolean(obj.configurable));
427 if ("value" in obj) {
428 desc.setValue(obj.value);
431 if ("writable" in obj) {
432 desc.setWritable(ToBoolean(obj.writable));
437 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
438 throw MakeTypeError("getter_must_be_callable", [get]);
445 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
446 throw MakeTypeError("setter_must_be_callable", [set]);
451 if (IsInconsistentDescriptor(desc)) {
452 throw MakeTypeError("value_and_accessor", [obj]);
458 // For Harmony proxies.
459 function ToCompletePropertyDescriptor(obj) {
460 var desc = ToPropertyDescriptor(obj);
461 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
462 if (!desc.hasValue()) desc.setValue(UNDEFINED);
463 if (!desc.hasWritable()) desc.setWritable(false);
465 // Is accessor descriptor.
466 if (!desc.hasGetter()) desc.setGet(UNDEFINED);
467 if (!desc.hasSetter()) desc.setSet(UNDEFINED);
469 if (!desc.hasEnumerable()) desc.setEnumerable(false);
470 if (!desc.hasConfigurable()) desc.setConfigurable(false);
475 function PropertyDescriptor() {
476 // Initialize here so they are all in-object and have the same map.
477 // Default values from ES5 8.6.1.
478 this.value_ = UNDEFINED;
479 this.hasValue_ = false;
480 this.writable_ = false;
481 this.hasWritable_ = false;
482 this.enumerable_ = false;
483 this.hasEnumerable_ = false;
484 this.configurable_ = false;
485 this.hasConfigurable_ = false;
486 this.get_ = UNDEFINED;
487 this.hasGetter_ = false;
488 this.set_ = UNDEFINED;
489 this.hasSetter_ = false;
492 SetUpLockedPrototype(PropertyDescriptor, $Array(
506 "toString", function() {
507 return "[object PropertyDescriptor]";
509 "setValue", function(value) {
511 this.hasValue_ = true;
513 "getValue", function() {
516 "hasValue", function() {
517 return this.hasValue_;
519 "setEnumerable", function(enumerable) {
520 this.enumerable_ = enumerable;
521 this.hasEnumerable_ = true;
523 "isEnumerable", function () {
524 return this.enumerable_;
526 "hasEnumerable", function() {
527 return this.hasEnumerable_;
529 "setWritable", function(writable) {
530 this.writable_ = writable;
531 this.hasWritable_ = true;
533 "isWritable", function() {
534 return this.writable_;
536 "hasWritable", function() {
537 return this.hasWritable_;
539 "setConfigurable", function(configurable) {
540 this.configurable_ = configurable;
541 this.hasConfigurable_ = true;
543 "hasConfigurable", function() {
544 return this.hasConfigurable_;
546 "isConfigurable", function() {
547 return this.configurable_;
549 "setGet", function(get) {
551 this.hasGetter_ = true;
553 "getGet", function() {
556 "hasGetter", function() {
557 return this.hasGetter_;
559 "setSet", function(set) {
561 this.hasSetter_ = true;
563 "getSet", function() {
566 "hasSetter", function() {
567 return this.hasSetter_;
571 // Converts an array returned from Runtime_GetOwnProperty to an actual
572 // property descriptor. For a description of the array layout please
573 // see the runtime.cc file.
574 function ConvertDescriptorArrayToDescriptor(desc_array) {
575 if (desc_array === false) {
576 throw 'Internal error: invalid desc_array';
579 if (IS_UNDEFINED(desc_array)) {
583 var desc = new PropertyDescriptor();
584 // This is an accessor.
585 if (desc_array[IS_ACCESSOR_INDEX]) {
586 desc.setGet(desc_array[GETTER_INDEX]);
587 desc.setSet(desc_array[SETTER_INDEX]);
589 desc.setValue(desc_array[VALUE_INDEX]);
590 desc.setWritable(desc_array[WRITABLE_INDEX]);
592 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
593 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
599 // For Harmony proxies.
600 function GetTrap(handler, name, defaultTrap) {
601 var trap = handler[name];
602 if (IS_UNDEFINED(trap)) {
603 if (IS_UNDEFINED(defaultTrap)) {
604 throw MakeTypeError("handler_trap_missing", [handler, name]);
607 } else if (!IS_SPEC_FUNCTION(trap)) {
608 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
614 function CallTrap0(handler, name, defaultTrap) {
615 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
619 function CallTrap1(handler, name, defaultTrap, x) {
620 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
624 function CallTrap2(handler, name, defaultTrap, x, y) {
625 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
629 // ES5 section 8.12.1.
630 function GetOwnProperty(obj, v) {
632 if (%IsJSProxy(obj)) {
633 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
634 if (IS_SYMBOL(v)) return UNDEFINED;
636 var handler = %GetHandler(obj);
637 var descriptor = CallTrap1(
638 handler, "getOwnPropertyDescriptor", UNDEFINED, p);
639 if (IS_UNDEFINED(descriptor)) return descriptor;
640 var desc = ToCompletePropertyDescriptor(descriptor);
641 if (!desc.isConfigurable()) {
642 throw MakeTypeError("proxy_prop_not_configurable",
643 [handler, "getOwnPropertyDescriptor", p, descriptor]);
648 // GetOwnProperty returns an array indexed by the constants
649 // defined in macros.py.
650 // If p is not a property on obj undefined is returned.
651 var props = %GetOwnProperty(ToObject(obj), p);
653 // A false value here means that access checks failed.
654 if (props === false) return UNDEFINED;
656 return ConvertDescriptorArrayToDescriptor(props);
660 // ES5 section 8.12.7.
661 function Delete(obj, p, should_throw) {
662 var desc = GetOwnProperty(obj, p);
663 if (IS_UNDEFINED(desc)) return true;
664 if (desc.isConfigurable()) {
665 %DeleteProperty(obj, p, 0);
667 } else if (should_throw) {
668 throw MakeTypeError("define_disallowed", [p]);
676 function DefineProxyProperty(obj, p, attributes, should_throw) {
677 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
678 if (IS_SYMBOL(p)) return false;
680 var handler = %GetHandler(obj);
681 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
682 if (!ToBoolean(result)) {
684 throw MakeTypeError("handler_returned_false",
685 [handler, "defineProperty"]);
695 function DefineObjectProperty(obj, p, desc, should_throw) {
696 var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
697 // A false value here means that access checks failed.
698 if (current_or_access === false) return UNDEFINED;
700 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
701 var extensible = %IsExtensible(ToObject(obj));
703 // Error handling according to spec.
705 if (IS_UNDEFINED(current) && !extensible) {
707 throw MakeTypeError("define_disallowed", [p]);
713 if (!IS_UNDEFINED(current)) {
715 if ((IsGenericDescriptor(desc) ||
716 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
717 (!desc.hasEnumerable() ||
718 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
719 (!desc.hasConfigurable() ||
720 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
721 (!desc.hasWritable() ||
722 SameValue(desc.isWritable(), current.isWritable())) &&
724 SameValue(desc.getValue(), current.getValue())) &&
725 (!desc.hasGetter() ||
726 SameValue(desc.getGet(), current.getGet())) &&
727 (!desc.hasSetter() ||
728 SameValue(desc.getSet(), current.getSet()))) {
731 if (!current.isConfigurable()) {
733 if (desc.isConfigurable() ||
734 (desc.hasEnumerable() &&
735 desc.isEnumerable() != current.isEnumerable())) {
737 throw MakeTypeError("redefine_disallowed", [p]);
743 if (!IsGenericDescriptor(desc)) {
745 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
747 throw MakeTypeError("redefine_disallowed", [p]);
753 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
754 if (!current.isWritable() && desc.isWritable()) {
756 throw MakeTypeError("redefine_disallowed", [p]);
761 if (!current.isWritable() && desc.hasValue() &&
762 !SameValue(desc.getValue(), current.getValue())) {
764 throw MakeTypeError("redefine_disallowed", [p]);
771 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
772 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
774 throw MakeTypeError("redefine_disallowed", [p]);
779 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
781 throw MakeTypeError("redefine_disallowed", [p]);
791 // Send flags - enumerable and configurable are common - writable is
792 // only send to the data descriptor.
793 // Take special care if enumerable and configurable is not defined on
794 // desc (we need to preserve the existing values from current).
796 if (desc.hasEnumerable()) {
797 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
798 } else if (!IS_UNDEFINED(current)) {
799 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
804 if (desc.hasConfigurable()) {
805 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
806 } else if (!IS_UNDEFINED(current)) {
807 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
811 if (IsDataDescriptor(desc) ||
812 (IsGenericDescriptor(desc) &&
813 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
814 // There are 3 cases that lead here:
815 // Step 4a - defining a new data property.
816 // Steps 9b & 12 - replacing an existing accessor property with a data
818 // Step 12 - updating an existing data property with a data or generic
821 if (desc.hasWritable()) {
822 flag |= desc.isWritable() ? 0 : READ_ONLY;
823 } else if (!IS_UNDEFINED(current)) {
824 flag |= current.isWritable() ? 0 : READ_ONLY;
829 var value = UNDEFINED; // Default value is undefined.
830 if (desc.hasValue()) {
831 value = desc.getValue();
832 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
833 value = current.getValue();
836 %DefineOrRedefineDataProperty(obj, p, value, flag);
838 // There are 3 cases that lead here:
839 // Step 4b - defining a new accessor property.
840 // Steps 9c & 12 - replacing an existing data property with an accessor
842 // Step 12 - updating an existing accessor property with an accessor
844 var getter = desc.hasGetter() ? desc.getGet() : null;
845 var setter = desc.hasSetter() ? desc.getSet() : null;
846 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
852 // ES5 section 15.4.5.1.
853 function DefineArrayProperty(obj, p, desc, should_throw) {
854 // Note that the length of an array is not actually stored as part of the
855 // property, hence we use generated code throughout this function instead of
856 // DefineObjectProperty() to modify its value.
858 // Step 3 - Special handling for length property.
859 if (p === "length") {
860 var length = obj.length;
861 var old_length = length;
862 if (!desc.hasValue()) {
863 return DefineObjectProperty(obj, "length", desc, should_throw);
865 var new_length = ToUint32(desc.getValue());
866 if (new_length != ToNumber(desc.getValue())) {
867 throw new $RangeError('defineProperty() array length out of range');
869 var length_desc = GetOwnProperty(obj, "length");
870 if (new_length != length && !length_desc.isWritable()) {
872 throw MakeTypeError("redefine_disallowed", [p]);
879 var emit_splice = %IsObserved(obj) && new_length !== old_length;
882 BeginPerformSplice(obj);
884 if (new_length < old_length)
885 removed.length = old_length - new_length;
888 while (new_length < length--) {
889 var index = ToString(length);
891 var deletedDesc = GetOwnProperty(obj, index);
892 if (deletedDesc && deletedDesc.hasValue())
893 removed[length - new_length] = deletedDesc.getValue();
895 if (!Delete(obj, index, false)) {
896 new_length = length + 1;
901 // Make sure the below call to DefineObjectProperty() doesn't overwrite
902 // any magic "length" property by removing the value.
903 // TODO(mstarzinger): This hack should be removed once we have addressed the
904 // respective TODO in Runtime_DefineOrRedefineDataProperty.
905 // For the time being, we need a hack to prevent Object.observe from
906 // generating two change records.
907 obj.length = new_length;
908 desc.value_ = UNDEFINED;
909 desc.hasValue_ = false;
910 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
912 EndPerformSplice(obj);
913 EnqueueSpliceRecord(obj,
914 new_length < old_length ? new_length : old_length,
916 new_length > old_length ? new_length - old_length : 0);
920 throw MakeTypeError("redefine_disallowed", [p]);
928 // Step 4 - Special handling for array index.
929 var index = ToUint32(p);
930 var emit_splice = false;
931 if (ToString(index) == p && index != 4294967295) {
932 var length = obj.length;
933 if (index >= length && %IsObserved(obj)) {
935 BeginPerformSplice(obj);
938 var length_desc = GetOwnProperty(obj, "length");
939 if ((index >= length && !length_desc.isWritable()) ||
940 !DefineObjectProperty(obj, p, desc, true)) {
942 EndPerformSplice(obj);
944 throw MakeTypeError("define_disallowed", [p]);
949 if (index >= length) {
950 obj.length = index + 1;
953 EndPerformSplice(obj);
954 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
959 // Step 5 - Fallback to default implementation.
960 return DefineObjectProperty(obj, p, desc, should_throw);
964 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
965 function DefineOwnProperty(obj, p, desc, should_throw) {
966 if (%IsJSProxy(obj)) {
967 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
968 if (IS_SYMBOL(p)) return false;
970 var attributes = FromGenericPropertyDescriptor(desc);
971 return DefineProxyProperty(obj, p, attributes, should_throw);
972 } else if (IS_ARRAY(obj)) {
973 return DefineArrayProperty(obj, p, desc, should_throw);
975 return DefineObjectProperty(obj, p, desc, should_throw);
980 // ES5 section 15.2.3.2.
981 function ObjectGetPrototypeOf(obj) {
982 if (!IS_SPEC_OBJECT(obj)) {
983 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
985 return %GetPrototype(obj);
988 // ES6 section 19.1.2.19.
989 function ObjectSetPrototypeOf(obj, proto) {
990 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
992 if (proto !== null && !IS_SPEC_OBJECT(proto)) {
993 throw MakeTypeError("proto_object_or_null", [proto]);
996 if (IS_SPEC_OBJECT(obj)) {
997 %SetPrototype(obj, proto);
1004 // ES5 section 15.2.3.3
1005 function ObjectGetOwnPropertyDescriptor(obj, p) {
1006 if (!IS_SPEC_OBJECT(obj)) {
1007 throw MakeTypeError("called_on_non_object",
1008 ["Object.getOwnPropertyDescriptor"]);
1010 var desc = GetOwnProperty(obj, p);
1011 return FromPropertyDescriptor(desc);
1015 // For Harmony proxies
1016 function ToNameArray(obj, trap, includeSymbols) {
1017 if (!IS_SPEC_OBJECT(obj)) {
1018 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1020 var n = ToUint32(obj.length);
1021 var array = new $Array(n);
1023 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
1024 for (var index = 0; index < n; index++) {
1025 var s = ToName(obj[index]);
1026 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1027 if (IS_SYMBOL(s) && !includeSymbols) continue;
1028 if (%HasLocalProperty(names, s)) {
1029 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1035 array.length = realLength;
1040 function ObjectGetOwnPropertyKeys(obj, symbolsOnly) {
1041 var nameArrays = new InternalArray();
1042 var filter = symbolsOnly ?
1043 PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL :
1044 PROPERTY_ATTRIBUTES_SYMBOLIC;
1046 // Find all the indexed properties.
1048 // Only get the local element names if we want to include string keys.
1050 var localElementNames = %GetLocalElementNames(obj);
1051 for (var i = 0; i < localElementNames.length; ++i) {
1052 localElementNames[i] = %_NumberToString(localElementNames[i]);
1054 nameArrays.push(localElementNames);
1056 // Get names for indexed interceptor properties.
1057 var interceptorInfo = %GetInterceptorInfo(obj);
1058 if ((interceptorInfo & 1) != 0) {
1059 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1060 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1061 nameArrays.push(indexedInterceptorNames);
1066 // Find all the named properties.
1068 // Get the local property names.
1069 nameArrays.push(%GetLocalPropertyNames(obj, filter));
1071 // Get names for named interceptor properties if any.
1072 if ((interceptorInfo & 2) != 0) {
1073 var namedInterceptorNames =
1074 %GetNamedInterceptorPropertyNames(obj);
1075 if (!IS_UNDEFINED(namedInterceptorNames)) {
1076 nameArrays.push(namedInterceptorNames);
1081 %Apply(InternalArray.prototype.concat,
1082 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1084 // Property names are expected to be unique strings,
1085 // but interceptors can interfere with that assumption.
1086 if (interceptorInfo != 0) {
1087 var seenKeys = { __proto__: null };
1089 for (var i = 0; i < propertyNames.length; ++i) {
1090 var name = propertyNames[i];
1092 if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
1094 if (IS_SYMBOL(name)) continue;
1095 name = ToString(name);
1097 if (seenKeys[name]) continue;
1098 seenKeys[name] = true;
1099 propertyNames[j++] = name;
1101 propertyNames.length = j;
1104 return propertyNames;
1108 // ES5 section 15.2.3.4.
1109 function ObjectGetOwnPropertyNames(obj) {
1110 if (!IS_SPEC_OBJECT(obj)) {
1111 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
1113 // Special handling for proxies.
1114 if (%IsJSProxy(obj)) {
1115 var handler = %GetHandler(obj);
1116 var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1117 return ToNameArray(names, "getOwnPropertyNames", false);
1120 return ObjectGetOwnPropertyKeys(obj, false);
1124 // ES5 section 15.2.3.5.
1125 function ObjectCreate(proto, properties) {
1126 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1127 throw MakeTypeError("proto_object_or_null", [proto]);
1129 var obj = { __proto__: proto };
1130 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1135 // ES5 section 15.2.3.6.
1136 function ObjectDefineProperty(obj, p, attributes) {
1137 if (!IS_SPEC_OBJECT(obj)) {
1138 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1140 var name = ToName(p);
1141 if (%IsJSProxy(obj)) {
1142 // Clone the attributes object for protection.
1143 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1144 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1145 var attributesClone = { __proto__: null };
1146 for (var a in attributes) {
1147 attributesClone[a] = attributes[a];
1149 DefineProxyProperty(obj, name, attributesClone, true);
1150 // The following would implement the spec as in the current proposal,
1151 // but after recent comments on es-discuss, is most likely obsolete.
1153 var defineObj = FromGenericPropertyDescriptor(desc);
1154 var names = ObjectGetOwnPropertyNames(attributes);
1156 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1157 for (var i = 0; i < names.length; i++) {
1159 if (!(%HasLocalProperty(standardNames, N))) {
1160 var attr = GetOwnProperty(attributes, N);
1161 DefineOwnProperty(descObj, N, attr, true);
1164 // This is really confusing the types, but it is what the proxies spec
1165 // currently requires:
1169 var desc = ToPropertyDescriptor(attributes);
1170 DefineOwnProperty(obj, name, desc, true);
1176 function GetOwnEnumerablePropertyNames(properties) {
1177 var names = new InternalArray();
1178 for (var key in properties) {
1179 if (%HasLocalProperty(properties, key)) {
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 ObjectSeal(obj) {
1236 if (!IS_SPEC_OBJECT(obj)) {
1237 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1239 if (%IsJSProxy(obj)) {
1242 var names = ObjectGetOwnPropertyNames(obj);
1243 for (var i = 0; i < names.length; i++) {
1244 var name = names[i];
1245 var desc = GetOwnProperty(obj, name);
1246 if (desc.isConfigurable()) {
1247 desc.setConfigurable(false);
1248 DefineOwnProperty(obj, name, desc, true);
1251 %PreventExtensions(obj);
1256 // ES5 section 15.2.3.9.
1257 function ObjectFreeze(obj) {
1258 if (!IS_SPEC_OBJECT(obj)) {
1259 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1261 var isProxy = %IsJSProxy(obj);
1262 if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1266 var names = ObjectGetOwnPropertyNames(obj);
1267 for (var i = 0; i < names.length; i++) {
1268 var name = names[i];
1269 var desc = GetOwnProperty(obj, name);
1270 if (desc.isWritable() || desc.isConfigurable()) {
1271 if (IsDataDescriptor(desc)) desc.setWritable(false);
1272 desc.setConfigurable(false);
1273 DefineOwnProperty(obj, name, desc, true);
1276 %PreventExtensions(obj);
1278 // TODO(adamk): Is it worth going to this fast path if the
1279 // object's properties are already in dictionary mode?
1286 // ES5 section 15.2.3.10
1287 function ObjectPreventExtension(obj) {
1288 if (!IS_SPEC_OBJECT(obj)) {
1289 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1291 if (%IsJSProxy(obj)) {
1294 %PreventExtensions(obj);
1299 // ES5 section 15.2.3.11
1300 function ObjectIsSealed(obj) {
1301 if (!IS_SPEC_OBJECT(obj)) {
1302 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1304 if (%IsJSProxy(obj)) {
1307 if (%IsExtensible(obj)) {
1310 var names = ObjectGetOwnPropertyNames(obj);
1311 for (var i = 0; i < names.length; i++) {
1312 var name = names[i];
1313 var desc = GetOwnProperty(obj, name);
1314 if (desc.isConfigurable()) return false;
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 = GetOwnProperty(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);
1355 function ObjectIs(obj1, obj2) {
1356 if (obj1 === obj2) {
1357 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1359 return (obj1 !== obj1) && (obj2 !== obj2);
1364 // ECMA-262, Edition 6, section B.2.2.1.1
1365 function ObjectGetProto() {
1366 return %GetPrototype(ToObject(this));
1370 // ECMA-262, Edition 6, section B.2.2.1.2
1371 function ObjectSetProto(proto) {
1372 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1374 if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1375 %SetPrototype(this, proto);
1380 function ObjectConstructor(x) {
1381 if (%_IsConstructCall()) {
1382 if (x == null) return this;
1385 if (x == null) return { };
1391 // ----------------------------------------------------------------------------
1394 function SetUpObject() {
1395 %CheckIsBootstrapping();
1397 %SetNativeFlag($Object);
1398 %SetCode($Object, ObjectConstructor);
1399 %SetExpectedNumberOfProperties($Object, 4);
1401 %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1403 // Set up non-enumerable functions on the Object.prototype object.
1404 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1405 "toString", ObjectToString,
1406 "toLocaleString", ObjectToLocaleString,
1407 "valueOf", ObjectValueOf,
1408 "hasOwnProperty", ObjectHasOwnProperty,
1409 "isPrototypeOf", ObjectIsPrototypeOf,
1410 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1411 "__defineGetter__", ObjectDefineGetter,
1412 "__lookupGetter__", ObjectLookupGetter,
1413 "__defineSetter__", ObjectDefineSetter,
1414 "__lookupSetter__", ObjectLookupSetter
1416 InstallGetterSetter($Object.prototype, "__proto__",
1417 ObjectGetProto, ObjectSetProto);
1419 // Set up non-enumerable functions in the Object object.
1420 InstallFunctions($Object, DONT_ENUM, $Array(
1422 "create", ObjectCreate,
1423 "defineProperty", ObjectDefineProperty,
1424 "defineProperties", ObjectDefineProperties,
1425 "freeze", ObjectFreeze,
1426 "getPrototypeOf", ObjectGetPrototypeOf,
1427 "setPrototypeOf", ObjectSetPrototypeOf,
1428 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1429 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1430 // getOwnPropertySymbols is added in symbol.js.
1432 "isExtensible", ObjectIsExtensible,
1433 "isFrozen", ObjectIsFrozen,
1434 "isSealed", ObjectIsSealed,
1435 "preventExtensions", ObjectPreventExtension,
1437 // deliverChangeRecords, getNotifier, observe and unobserve are added
1438 // in object-observe.js.
1445 // ----------------------------------------------------------------------------
1448 function BooleanConstructor(x) {
1449 if (%_IsConstructCall()) {
1450 %_SetValueOf(this, ToBoolean(x));
1452 return ToBoolean(x);
1457 function BooleanToString() {
1458 // NOTE: Both Boolean objects and values can enter here as
1459 // 'this'. This is not as dictated by ECMA-262.
1461 if (!IS_BOOLEAN(b)) {
1462 if (!IS_BOOLEAN_WRAPPER(b)) {
1463 throw new $TypeError('Boolean.prototype.toString is not generic');
1467 return b ? 'true' : 'false';
1471 function BooleanValueOf() {
1472 // NOTE: Both Boolean objects and values can enter here as
1473 // 'this'. This is not as dictated by ECMA-262.
1474 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1475 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1477 return %_ValueOf(this);
1481 // ----------------------------------------------------------------------------
1483 function SetUpBoolean () {
1484 %CheckIsBootstrapping();
1486 %SetCode($Boolean, BooleanConstructor);
1487 %FunctionSetPrototype($Boolean, new $Boolean(false));
1488 %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1490 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1491 "toString", BooleanToString,
1492 "valueOf", BooleanValueOf
1499 // ----------------------------------------------------------------------------
1502 function NumberConstructor(x) {
1503 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1504 if (%_IsConstructCall()) {
1505 %_SetValueOf(this, value);
1512 // ECMA-262 section 15.7.4.2.
1513 function NumberToString(radix) {
1514 // NOTE: Both Number objects and values can enter here as
1515 // 'this'. This is not as dictated by ECMA-262.
1517 if (!IS_NUMBER(this)) {
1518 if (!IS_NUMBER_WRAPPER(this)) {
1519 throw new $TypeError('Number.prototype.toString is not generic');
1521 // Get the value of this number in case it's an object.
1522 number = %_ValueOf(this);
1524 // Fast case: Convert number in radix 10.
1525 if (IS_UNDEFINED(radix) || radix === 10) {
1526 return %_NumberToString(number);
1529 // Convert the radix to an integer and check the range.
1530 radix = TO_INTEGER(radix);
1531 if (radix < 2 || radix > 36) {
1532 throw new $RangeError('toString() radix argument must be between 2 and 36');
1534 // Convert the number to a string in the given radix.
1535 return %NumberToRadixString(number, radix);
1539 // ECMA-262 section 15.7.4.3
1540 function NumberToLocaleString() {
1541 return %_CallFunction(this, NumberToString);
1545 // ECMA-262 section 15.7.4.4
1546 function NumberValueOf() {
1547 // NOTE: Both Number objects and values can enter here as
1548 // 'this'. This is not as dictated by ECMA-262.
1549 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1550 throw new $TypeError('Number.prototype.valueOf is not generic');
1552 return %_ValueOf(this);
1556 // ECMA-262 section 15.7.4.5
1557 function NumberToFixed(fractionDigits) {
1559 if (!IS_NUMBER(this)) {
1560 if (!IS_NUMBER_WRAPPER(this)) {
1561 throw MakeTypeError("incompatible_method_receiver",
1562 ["Number.prototype.toFixed", this]);
1564 // Get the value of this number in case it's an object.
1565 x = %_ValueOf(this);
1567 var f = TO_INTEGER(fractionDigits);
1569 if (f < 0 || f > 20) {
1570 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1573 if (NUMBER_IS_NAN(x)) return "NaN";
1574 if (x == INFINITY) return "Infinity";
1575 if (x == -INFINITY) return "-Infinity";
1577 return %NumberToFixed(x, f);
1581 // ECMA-262 section 15.7.4.6
1582 function NumberToExponential(fractionDigits) {
1584 if (!IS_NUMBER(this)) {
1585 if (!IS_NUMBER_WRAPPER(this)) {
1586 throw MakeTypeError("incompatible_method_receiver",
1587 ["Number.prototype.toExponential", this]);
1589 // Get the value of this number in case it's an object.
1590 x = %_ValueOf(this);
1592 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1594 if (NUMBER_IS_NAN(x)) return "NaN";
1595 if (x == INFINITY) return "Infinity";
1596 if (x == -INFINITY) return "-Infinity";
1598 if (IS_UNDEFINED(f)) {
1599 f = -1; // Signal for runtime function that f is not defined.
1600 } else if (f < 0 || f > 20) {
1601 throw new $RangeError("toExponential() argument must be between 0 and 20");
1603 return %NumberToExponential(x, f);
1607 // ECMA-262 section 15.7.4.7
1608 function NumberToPrecision(precision) {
1610 if (!IS_NUMBER(this)) {
1611 if (!IS_NUMBER_WRAPPER(this)) {
1612 throw MakeTypeError("incompatible_method_receiver",
1613 ["Number.prototype.toPrecision", this]);
1615 // Get the value of this number in case it's an object.
1616 x = %_ValueOf(this);
1618 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1619 var p = TO_INTEGER(precision);
1621 if (NUMBER_IS_NAN(x)) return "NaN";
1622 if (x == INFINITY) return "Infinity";
1623 if (x == -INFINITY) return "-Infinity";
1625 if (p < 1 || p > 21) {
1626 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1628 return %NumberToPrecision(x, p);
1632 // Harmony isFinite.
1633 function NumberIsFinite(number) {
1634 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1638 // Harmony isInteger
1639 function NumberIsInteger(number) {
1640 return NumberIsFinite(number) && TO_INTEGER(number) == number;
1645 function NumberIsNaN(number) {
1646 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1650 // Harmony isSafeInteger
1651 function NumberIsSafeInteger(number) {
1652 if (NumberIsFinite(number)) {
1653 var integral = TO_INTEGER(number);
1654 if (integral == number)
1655 return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
1661 // ----------------------------------------------------------------------------
1663 function SetUpNumber() {
1664 %CheckIsBootstrapping();
1666 %SetCode($Number, NumberConstructor);
1667 %FunctionSetPrototype($Number, new $Number(0));
1669 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1670 // Set up the constructor property on the Number prototype object.
1671 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1673 InstallConstants($Number, $Array(
1674 // ECMA-262 section 15.7.3.1.
1675 "MAX_VALUE", 1.7976931348623157e+308,
1676 // ECMA-262 section 15.7.3.2.
1677 "MIN_VALUE", 5e-324,
1678 // ECMA-262 section 15.7.3.3.
1680 // ECMA-262 section 15.7.3.4.
1681 "NEGATIVE_INFINITY", -INFINITY,
1682 // ECMA-262 section 15.7.3.5.
1683 "POSITIVE_INFINITY", INFINITY,
1685 // --- Harmony constants (no spec refs until settled.)
1687 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1688 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1689 "EPSILON", %_MathPow(2, -52)
1692 // Set up non-enumerable functions on the Number prototype object.
1693 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1694 "toString", NumberToString,
1695 "toLocaleString", NumberToLocaleString,
1696 "valueOf", NumberValueOf,
1697 "toFixed", NumberToFixed,
1698 "toExponential", NumberToExponential,
1699 "toPrecision", NumberToPrecision
1702 // Harmony Number constructor additions
1703 InstallFunctions($Number, DONT_ENUM, $Array(
1704 "isFinite", NumberIsFinite,
1705 "isInteger", NumberIsInteger,
1706 "isNaN", NumberIsNaN,
1707 "isSafeInteger", NumberIsSafeInteger,
1708 "parseInt", GlobalParseInt,
1709 "parseFloat", GlobalParseFloat
1716 // ----------------------------------------------------------------------------
1719 function FunctionSourceString(func) {
1720 while (%IsJSFunctionProxy(func)) {
1721 func = %GetCallTrap(func);
1724 if (!IS_FUNCTION(func)) {
1725 throw new $TypeError('Function.prototype.toString is not generic');
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 var name = %FunctionNameShouldPrintAsAnonymous(func)
1741 : %FunctionGetName(func);
1742 var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1743 return head + name + source;
1747 function FunctionToString() {
1748 return FunctionSourceString(this);
1753 function FunctionBind(this_arg) { // Length is 1.
1754 if (!IS_SPEC_FUNCTION(this)) {
1755 throw new $TypeError('Bind must be called on a function');
1757 var boundFunction = function () {
1758 // Poison .arguments and .caller, but is otherwise not detectable.
1760 // This function must not use any object literals (Object, Array, RegExp),
1761 // since the literals-array is being used to store the bound data.
1762 if (%_IsConstructCall()) {
1763 return %NewObjectFromBound(boundFunction);
1765 var bindings = %BoundFunctionGetBindings(boundFunction);
1767 var argc = %_ArgumentsLength();
1769 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1771 if (bindings.length === 2) {
1772 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1774 var bound_argc = bindings.length - 2;
1775 var argv = new InternalArray(bound_argc + argc);
1776 for (var i = 0; i < bound_argc; i++) {
1777 argv[i] = bindings[i + 2];
1779 for (var j = 0; j < argc; j++) {
1780 argv[i++] = %_Arguments(j);
1782 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1785 %FunctionRemovePrototype(boundFunction);
1787 if (%_ClassOf(this) == "Function") {
1788 // Function or FunctionProxy.
1789 var old_length = this.length;
1790 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1791 if ((typeof old_length === "number") &&
1792 ((old_length >>> 0) === old_length)) {
1793 var argc = %_ArgumentsLength();
1794 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1795 new_length = old_length - argc;
1796 if (new_length < 0) new_length = 0;
1799 // This runtime function finds any remaining arguments on the stack,
1800 // so we don't pass the arguments object.
1801 var result = %FunctionBindArguments(boundFunction, this,
1802 this_arg, new_length);
1804 // We already have caller and arguments properties on functions,
1805 // which are non-configurable. It therefore makes no sence to
1806 // try to redefine these as defined by the spec. The spec says
1807 // that bind should make these throw a TypeError if get or set
1808 // is called and make them non-enumerable and non-configurable.
1809 // To be consistent with our normal functions we leave this as it is.
1810 // TODO(lrn): Do set these to be thrower.
1815 function NewFunctionString(arguments, function_token) {
1816 var n = arguments.length;
1819 p = ToString(arguments[0]);
1820 for (var i = 1; i < n - 1; i++) {
1821 p += ',' + ToString(arguments[i]);
1823 // If the formal parameters string include ) - an illegal
1824 // character - it may make the combined function expression
1825 // compile. We avoid this problem by checking for this early on.
1826 if (%_CallFunction(p, ')', StringIndexOf) != -1) {
1827 throw MakeSyntaxError('paren_in_arg_string', []);
1829 // If the formal parameters include an unbalanced block comment, the
1830 // function must be rejected. Since JavaScript does not allow nested
1831 // comments we can include a trailing block comment to catch this.
1834 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1835 return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
1839 function FunctionConstructor(arg1) { // length == 1
1840 var source = NewFunctionString(arguments, 'function');
1841 var global_receiver = %GlobalReceiver(global);
1842 // Compile the string in the constructor and not a helper so that errors
1843 // appear to come from here.
1844 var f = %_CallFunction(global_receiver, %CompileString(source, true));
1845 %FunctionMarkNameShouldPrintAsAnonymous(f);
1850 // ----------------------------------------------------------------------------
1852 function SetUpFunction() {
1853 %CheckIsBootstrapping();
1855 %SetCode($Function, FunctionConstructor);
1856 %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1858 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1859 "bind", FunctionBind,
1860 "toString", FunctionToString
1867 //----------------------------------------------------------------------------
1869 // TODO(rossberg): very simple abstraction for generic microtask queue.
1870 // Eventually, we should move to a real event queue that allows to maintain
1871 // relative ordering of different kinds of tasks.
1873 function RunMicrotasks() {
1874 while (%SetMicrotaskPending(false)) {
1875 var microtaskState = %GetMicrotaskState();
1876 if (IS_UNDEFINED(microtaskState.queue))
1879 var microtasks = microtaskState.queue;
1880 microtaskState.queue = null;
1882 for (var i = 0; i < microtasks.length; i++) {
1888 function EnqueueMicrotask(fn) {
1889 var microtaskState = %GetMicrotaskState();
1890 if (IS_UNDEFINED(microtaskState.queue) || IS_NULL(microtaskState.queue)) {
1891 microtaskState.queue = new InternalArray;
1893 microtaskState.queue.push(fn);
1894 %SetMicrotaskPending(true);