1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 // This file relies on the fact that the following declarations have been made
30 // var $Object = global.Object;
31 // var $Boolean = global.Boolean;
32 // var $Number = global.Number;
33 // var $Function = global.Function;
34 // var $Array = global.Array;
37 // var $floor = MathFloor
39 var $isNaN = GlobalIsNaN;
40 var $isFinite = GlobalIsFinite;
42 // ----------------------------------------------------------------------------
44 // Helper function used to install functions on objects.
45 function InstallFunctions(object, attributes, functions) {
46 if (functions.length >= 8) {
47 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
49 for (var i = 0; i < functions.length; i += 2) {
50 var key = functions[i];
51 var f = functions[i + 1];
52 %FunctionSetName(f, key);
53 %FunctionRemovePrototype(f);
54 %SetProperty(object, key, f, attributes);
57 %ToFastProperties(object);
61 // Helper function to install a getter-only accessor property.
62 function InstallGetter(object, name, getter) {
63 %FunctionSetName(getter, name);
64 %FunctionRemovePrototype(getter);
65 %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
66 %SetNativeFlag(getter);
70 // Helper function to install a getter/setter accessor property.
71 function InstallGetterSetter(object, name, getter, setter) {
72 %FunctionSetName(getter, name);
73 %FunctionSetName(setter, name);
74 %FunctionRemovePrototype(getter);
75 %FunctionRemovePrototype(setter);
76 %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
77 %SetNativeFlag(getter);
78 %SetNativeFlag(setter);
82 // Helper function for installing constant properties on objects.
83 function InstallConstants(object, constants) {
84 if (constants.length >= 4) {
85 %OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1);
87 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
88 for (var i = 0; i < constants.length; i += 2) {
89 var name = constants[i];
90 var k = constants[i + 1];
91 %SetProperty(object, name, k, attributes);
93 %ToFastProperties(object);
97 // Prevents changes to the prototype of a built-in function.
98 // The "prototype" property of the function object is made non-configurable,
99 // and the prototype object is made non-extensible. The latter prevents
100 // changing the __proto__ property.
101 function SetUpLockedPrototype(constructor, fields, methods) {
102 %CheckIsBootstrapping();
103 var prototype = constructor.prototype;
104 // Install functions first, because this function is used to initialize
105 // PropertyDescriptor itself.
106 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
107 if (property_count >= 4) {
108 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
111 for (var i = 0; i < fields.length; i++) {
112 %SetProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE);
115 for (var i = 0; i < methods.length; i += 2) {
116 var key = methods[i];
117 var f = methods[i + 1];
118 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
121 %SetPrototype(prototype, null);
122 %ToFastProperties(prototype);
126 // ----------------------------------------------------------------------------
130 function GlobalIsNaN(number) {
131 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
132 return NUMBER_IS_NAN(number);
137 function GlobalIsFinite(number) {
138 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
139 return NUMBER_IS_FINITE(number);
143 // ECMA-262 - 15.1.2.2
144 function GlobalParseInt(string, radix) {
145 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
146 // Some people use parseInt instead of Math.floor. This
147 // optimization makes parseInt on a Smi 12 times faster (60ns
148 // vs 800ns). The following optimization makes parseInt on a
149 // non-Smi number 9 times faster (230ns vs 2070ns). Together
150 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
151 if (%_IsSmi(string)) return string;
152 if (IS_NUMBER(string) &&
153 ((0.01 < string && string < 1e9) ||
154 (-1e9 < string && string < -0.01))) {
158 string = TO_STRING_INLINE(string);
161 // The spec says ToString should be evaluated before ToInt32.
162 string = TO_STRING_INLINE(string);
163 radix = TO_INT32(radix);
164 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
169 if (%_HasCachedArrayIndex(string) &&
170 (radix == 0 || radix == 10)) {
171 return %_GetCachedArrayIndex(string);
173 return %StringParseInt(string, radix);
177 // ECMA-262 - 15.1.2.3
178 function GlobalParseFloat(string) {
179 string = TO_STRING_INLINE(string);
180 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
181 return %StringParseFloat(string);
185 function GlobalEval(x) {
186 if (!IS_STRING(x)) return x;
188 // For consistency with JSC we require the global object passed to
189 // eval to be the global object from which 'eval' originated. This
190 // is not mandated by the spec.
191 // We only throw if the global has been detached, since we need the
192 // receiver as this-value for the call.
193 if (!%IsAttachedGlobal(global)) {
194 throw new $EvalError('The "this" value passed to eval must ' +
195 'be the global object from which eval originated');
198 var global_receiver = %GlobalReceiver(global);
200 var f = %CompileString(x, false);
201 if (!IS_FUNCTION(f)) return f;
203 return %_CallFunction(global_receiver, f);
207 // ----------------------------------------------------------------------------
209 // Set up global object.
210 function SetUpGlobal() {
211 %CheckIsBootstrapping();
213 var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
215 // ECMA 262 - 15.1.1.1.
216 %SetProperty(global, "NaN", NAN, attributes);
218 // ECMA-262 - 15.1.1.2.
219 %SetProperty(global, "Infinity", INFINITY, attributes);
221 // ECMA-262 - 15.1.1.3.
222 %SetProperty(global, "undefined", UNDEFINED, attributes);
224 // Set up non-enumerable function on the global object.
225 InstallFunctions(global, DONT_ENUM, $Array(
226 "isNaN", GlobalIsNaN,
227 "isFinite", GlobalIsFinite,
228 "parseInt", GlobalParseInt,
229 "parseFloat", GlobalParseFloat,
237 // ----------------------------------------------------------------------------
240 // ECMA-262 - 15.2.4.2
241 function ObjectToString() {
242 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
243 if (IS_NULL(this)) return "[object Null]";
244 return "[object " + %_ClassOf(ToObject(this)) + "]";
248 // ECMA-262 - 15.2.4.3
249 function ObjectToLocaleString() {
250 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
251 return this.toString();
255 // ECMA-262 - 15.2.4.4
256 function ObjectValueOf() {
257 return ToObject(this);
261 // ECMA-262 - 15.2.4.5
262 function ObjectHasOwnProperty(V) {
263 if (%IsJSProxy(this)) {
264 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
265 if (IS_SYMBOL(V)) return false;
267 var handler = %GetHandler(this);
268 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
270 return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
274 // ECMA-262 - 15.2.4.6
275 function ObjectIsPrototypeOf(V) {
276 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
277 if (!IS_SPEC_OBJECT(V)) return false;
278 return %IsInPrototypeChain(this, V);
282 // ECMA-262 - 15.2.4.6
283 function ObjectPropertyIsEnumerable(V) {
285 if (%IsJSProxy(this)) {
286 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
287 if (IS_SYMBOL(V)) return false;
289 var desc = GetOwnProperty(this, P);
290 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
292 return %IsPropertyEnumerable(ToObject(this), P);
296 // Extensions for providing property getters and setters.
297 function ObjectDefineGetter(name, fun) {
299 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
300 receiver = %GlobalReceiver(global);
302 if (!IS_SPEC_FUNCTION(fun)) {
303 throw new $TypeError(
304 'Object.prototype.__defineGetter__: Expecting function');
306 var desc = new PropertyDescriptor();
308 desc.setEnumerable(true);
309 desc.setConfigurable(true);
310 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
314 function ObjectLookupGetter(name) {
316 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
317 receiver = %GlobalReceiver(global);
319 return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
323 function ObjectDefineSetter(name, fun) {
325 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
326 receiver = %GlobalReceiver(global);
328 if (!IS_SPEC_FUNCTION(fun)) {
329 throw new $TypeError(
330 'Object.prototype.__defineSetter__: Expecting function');
332 var desc = new PropertyDescriptor();
334 desc.setEnumerable(true);
335 desc.setConfigurable(true);
336 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
340 function ObjectLookupSetter(name) {
342 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
343 receiver = %GlobalReceiver(global);
345 return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
349 function ObjectKeys(obj) {
350 if (!IS_SPEC_OBJECT(obj)) {
351 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
353 if (%IsJSProxy(obj)) {
354 var handler = %GetHandler(obj);
355 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
356 return ToNameArray(names, "keys", false);
358 return %LocalKeys(obj);
363 function IsAccessorDescriptor(desc) {
364 if (IS_UNDEFINED(desc)) return false;
365 return desc.hasGetter() || desc.hasSetter();
370 function IsDataDescriptor(desc) {
371 if (IS_UNDEFINED(desc)) return false;
372 return desc.hasValue() || desc.hasWritable();
377 function IsGenericDescriptor(desc) {
378 if (IS_UNDEFINED(desc)) return false;
379 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
383 function IsInconsistentDescriptor(desc) {
384 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
389 function FromPropertyDescriptor(desc) {
390 if (IS_UNDEFINED(desc)) return desc;
392 if (IsDataDescriptor(desc)) {
393 return { value: desc.getValue(),
394 writable: desc.isWritable(),
395 enumerable: desc.isEnumerable(),
396 configurable: desc.isConfigurable() };
398 // Must be an AccessorDescriptor then. We never return a generic descriptor.
399 return { get: desc.getGet(),
401 enumerable: desc.isEnumerable(),
402 configurable: desc.isConfigurable() };
407 function FromGenericPropertyDescriptor(desc) {
408 if (IS_UNDEFINED(desc)) return desc;
409 var obj = new $Object();
411 if (desc.hasValue()) {
412 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
414 if (desc.hasWritable()) {
415 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
417 if (desc.hasGetter()) {
418 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
420 if (desc.hasSetter()) {
421 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
423 if (desc.hasEnumerable()) {
424 %IgnoreAttributesAndSetProperty(obj, "enumerable",
425 desc.isEnumerable(), NONE);
427 if (desc.hasConfigurable()) {
428 %IgnoreAttributesAndSetProperty(obj, "configurable",
429 desc.isConfigurable(), NONE);
436 function ToPropertyDescriptor(obj) {
437 if (!IS_SPEC_OBJECT(obj)) {
438 throw MakeTypeError("property_desc_object", [obj]);
440 var desc = new PropertyDescriptor();
442 if ("enumerable" in obj) {
443 desc.setEnumerable(ToBoolean(obj.enumerable));
446 if ("configurable" in obj) {
447 desc.setConfigurable(ToBoolean(obj.configurable));
450 if ("value" in obj) {
451 desc.setValue(obj.value);
454 if ("writable" in obj) {
455 desc.setWritable(ToBoolean(obj.writable));
460 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
461 throw MakeTypeError("getter_must_be_callable", [get]);
468 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
469 throw MakeTypeError("setter_must_be_callable", [set]);
474 if (IsInconsistentDescriptor(desc)) {
475 throw MakeTypeError("value_and_accessor", [obj]);
481 // For Harmony proxies.
482 function ToCompletePropertyDescriptor(obj) {
483 var desc = ToPropertyDescriptor(obj);
484 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
485 if (!desc.hasValue()) desc.setValue(UNDEFINED);
486 if (!desc.hasWritable()) desc.setWritable(false);
488 // Is accessor descriptor.
489 if (!desc.hasGetter()) desc.setGet(UNDEFINED);
490 if (!desc.hasSetter()) desc.setSet(UNDEFINED);
492 if (!desc.hasEnumerable()) desc.setEnumerable(false);
493 if (!desc.hasConfigurable()) desc.setConfigurable(false);
498 function PropertyDescriptor() {
499 // Initialize here so they are all in-object and have the same map.
500 // Default values from ES5 8.6.1.
501 this.value_ = UNDEFINED;
502 this.hasValue_ = false;
503 this.writable_ = false;
504 this.hasWritable_ = false;
505 this.enumerable_ = false;
506 this.hasEnumerable_ = false;
507 this.configurable_ = false;
508 this.hasConfigurable_ = false;
509 this.get_ = UNDEFINED;
510 this.hasGetter_ = false;
511 this.set_ = UNDEFINED;
512 this.hasSetter_ = false;
515 SetUpLockedPrototype(PropertyDescriptor, $Array(
529 "toString", function() {
530 return "[object PropertyDescriptor]";
532 "setValue", function(value) {
534 this.hasValue_ = true;
536 "getValue", function() {
539 "hasValue", function() {
540 return this.hasValue_;
542 "setEnumerable", function(enumerable) {
543 this.enumerable_ = enumerable;
544 this.hasEnumerable_ = true;
546 "isEnumerable", function () {
547 return this.enumerable_;
549 "hasEnumerable", function() {
550 return this.hasEnumerable_;
552 "setWritable", function(writable) {
553 this.writable_ = writable;
554 this.hasWritable_ = true;
556 "isWritable", function() {
557 return this.writable_;
559 "hasWritable", function() {
560 return this.hasWritable_;
562 "setConfigurable", function(configurable) {
563 this.configurable_ = configurable;
564 this.hasConfigurable_ = true;
566 "hasConfigurable", function() {
567 return this.hasConfigurable_;
569 "isConfigurable", function() {
570 return this.configurable_;
572 "setGet", function(get) {
574 this.hasGetter_ = true;
576 "getGet", function() {
579 "hasGetter", function() {
580 return this.hasGetter_;
582 "setSet", function(set) {
584 this.hasSetter_ = true;
586 "getSet", function() {
589 "hasSetter", function() {
590 return this.hasSetter_;
594 // Converts an array returned from Runtime_GetOwnProperty to an actual
595 // property descriptor. For a description of the array layout please
596 // see the runtime.cc file.
597 function ConvertDescriptorArrayToDescriptor(desc_array) {
598 if (desc_array === false) {
599 throw 'Internal error: invalid desc_array';
602 if (IS_UNDEFINED(desc_array)) {
606 var desc = new PropertyDescriptor();
607 // This is an accessor.
608 if (desc_array[IS_ACCESSOR_INDEX]) {
609 desc.setGet(desc_array[GETTER_INDEX]);
610 desc.setSet(desc_array[SETTER_INDEX]);
612 desc.setValue(desc_array[VALUE_INDEX]);
613 desc.setWritable(desc_array[WRITABLE_INDEX]);
615 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
616 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
622 // For Harmony proxies.
623 function GetTrap(handler, name, defaultTrap) {
624 var trap = handler[name];
625 if (IS_UNDEFINED(trap)) {
626 if (IS_UNDEFINED(defaultTrap)) {
627 throw MakeTypeError("handler_trap_missing", [handler, name]);
630 } else if (!IS_SPEC_FUNCTION(trap)) {
631 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
637 function CallTrap0(handler, name, defaultTrap) {
638 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
642 function CallTrap1(handler, name, defaultTrap, x) {
643 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
647 function CallTrap2(handler, name, defaultTrap, x, y) {
648 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
652 // ES5 section 8.12.1.
653 function GetOwnProperty(obj, v) {
655 if (%IsJSProxy(obj)) {
656 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
657 if (IS_SYMBOL(v)) return UNDEFINED;
659 var handler = %GetHandler(obj);
660 var descriptor = CallTrap1(
661 handler, "getOwnPropertyDescriptor", UNDEFINED, p);
662 if (IS_UNDEFINED(descriptor)) return descriptor;
663 var desc = ToCompletePropertyDescriptor(descriptor);
664 if (!desc.isConfigurable()) {
665 throw MakeTypeError("proxy_prop_not_configurable",
666 [handler, "getOwnPropertyDescriptor", p, descriptor]);
671 // GetOwnProperty returns an array indexed by the constants
672 // defined in macros.py.
673 // If p is not a property on obj undefined is returned.
674 var props = %GetOwnProperty(ToObject(obj), p);
676 // A false value here means that access checks failed.
677 if (props === false) return UNDEFINED;
679 return ConvertDescriptorArrayToDescriptor(props);
683 // ES5 section 8.12.7.
684 function Delete(obj, p, should_throw) {
685 var desc = GetOwnProperty(obj, p);
686 if (IS_UNDEFINED(desc)) return true;
687 if (desc.isConfigurable()) {
688 %DeleteProperty(obj, p, 0);
690 } else if (should_throw) {
691 throw MakeTypeError("define_disallowed", [p]);
699 function DefineProxyProperty(obj, p, attributes, should_throw) {
700 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
701 if (IS_SYMBOL(p)) return false;
703 var handler = %GetHandler(obj);
704 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
705 if (!ToBoolean(result)) {
707 throw MakeTypeError("handler_returned_false",
708 [handler, "defineProperty"]);
718 function DefineObjectProperty(obj, p, desc, should_throw) {
719 var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
720 // A false value here means that access checks failed.
721 if (current_or_access === false) return UNDEFINED;
723 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
724 var extensible = %IsExtensible(ToObject(obj));
726 // Error handling according to spec.
728 if (IS_UNDEFINED(current) && !extensible) {
730 throw MakeTypeError("define_disallowed", [p]);
736 if (!IS_UNDEFINED(current)) {
738 if ((IsGenericDescriptor(desc) ||
739 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
740 (!desc.hasEnumerable() ||
741 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
742 (!desc.hasConfigurable() ||
743 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
744 (!desc.hasWritable() ||
745 SameValue(desc.isWritable(), current.isWritable())) &&
747 SameValue(desc.getValue(), current.getValue())) &&
748 (!desc.hasGetter() ||
749 SameValue(desc.getGet(), current.getGet())) &&
750 (!desc.hasSetter() ||
751 SameValue(desc.getSet(), current.getSet()))) {
754 if (!current.isConfigurable()) {
756 if (desc.isConfigurable() ||
757 (desc.hasEnumerable() &&
758 desc.isEnumerable() != current.isEnumerable())) {
760 throw MakeTypeError("redefine_disallowed", [p]);
766 if (!IsGenericDescriptor(desc)) {
768 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
770 throw MakeTypeError("redefine_disallowed", [p]);
776 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
777 if (!current.isWritable() && desc.isWritable()) {
779 throw MakeTypeError("redefine_disallowed", [p]);
784 if (!current.isWritable() && desc.hasValue() &&
785 !SameValue(desc.getValue(), current.getValue())) {
787 throw MakeTypeError("redefine_disallowed", [p]);
794 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
795 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
797 throw MakeTypeError("redefine_disallowed", [p]);
802 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
804 throw MakeTypeError("redefine_disallowed", [p]);
814 // Send flags - enumerable and configurable are common - writable is
815 // only send to the data descriptor.
816 // Take special care if enumerable and configurable is not defined on
817 // desc (we need to preserve the existing values from current).
819 if (desc.hasEnumerable()) {
820 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
821 } else if (!IS_UNDEFINED(current)) {
822 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
827 if (desc.hasConfigurable()) {
828 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
829 } else if (!IS_UNDEFINED(current)) {
830 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
834 if (IsDataDescriptor(desc) ||
835 (IsGenericDescriptor(desc) &&
836 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
837 // There are 3 cases that lead here:
838 // Step 4a - defining a new data property.
839 // Steps 9b & 12 - replacing an existing accessor property with a data
841 // Step 12 - updating an existing data property with a data or generic
844 if (desc.hasWritable()) {
845 flag |= desc.isWritable() ? 0 : READ_ONLY;
846 } else if (!IS_UNDEFINED(current)) {
847 flag |= current.isWritable() ? 0 : READ_ONLY;
852 var value = UNDEFINED; // Default value is undefined.
853 if (desc.hasValue()) {
854 value = desc.getValue();
855 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
856 value = current.getValue();
859 %DefineOrRedefineDataProperty(obj, p, value, flag);
861 // There are 3 cases that lead here:
862 // Step 4b - defining a new accessor property.
863 // Steps 9c & 12 - replacing an existing data property with an accessor
865 // Step 12 - updating an existing accessor property with an accessor
867 var getter = desc.hasGetter() ? desc.getGet() : null;
868 var setter = desc.hasSetter() ? desc.getSet() : null;
869 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
875 // ES5 section 15.4.5.1.
876 function DefineArrayProperty(obj, p, desc, should_throw) {
877 // Note that the length of an array is not actually stored as part of the
878 // property, hence we use generated code throughout this function instead of
879 // DefineObjectProperty() to modify its value.
881 // Step 3 - Special handling for length property.
882 if (p === "length") {
883 var length = obj.length;
884 var old_length = length;
885 if (!desc.hasValue()) {
886 return DefineObjectProperty(obj, "length", desc, should_throw);
888 var new_length = ToUint32(desc.getValue());
889 if (new_length != ToNumber(desc.getValue())) {
890 throw new $RangeError('defineProperty() array length out of range');
892 var length_desc = GetOwnProperty(obj, "length");
893 if (new_length != length && !length_desc.isWritable()) {
895 throw MakeTypeError("redefine_disallowed", [p]);
902 var emit_splice = %IsObserved(obj) && new_length !== old_length;
905 BeginPerformSplice(obj);
907 if (new_length < old_length)
908 removed.length = old_length - new_length;
911 while (new_length < length--) {
912 var index = ToString(length);
914 var deletedDesc = GetOwnProperty(obj, index);
915 if (deletedDesc && deletedDesc.hasValue())
916 removed[length - new_length] = deletedDesc.getValue();
918 if (!Delete(obj, index, false)) {
919 new_length = length + 1;
924 // Make sure the below call to DefineObjectProperty() doesn't overwrite
925 // any magic "length" property by removing the value.
926 // TODO(mstarzinger): This hack should be removed once we have addressed the
927 // respective TODO in Runtime_DefineOrRedefineDataProperty.
928 // For the time being, we need a hack to prevent Object.observe from
929 // generating two change records.
930 obj.length = new_length;
931 desc.value_ = UNDEFINED;
932 desc.hasValue_ = false;
933 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
935 EndPerformSplice(obj);
936 EnqueueSpliceRecord(obj,
937 new_length < old_length ? new_length : old_length,
939 new_length > old_length ? new_length - old_length : 0);
943 throw MakeTypeError("redefine_disallowed", [p]);
951 // Step 4 - Special handling for array index.
952 var index = ToUint32(p);
953 var emit_splice = false;
954 if (ToString(index) == p && index != 4294967295) {
955 var length = obj.length;
956 if (index >= length && %IsObserved(obj)) {
958 BeginPerformSplice(obj);
961 var length_desc = GetOwnProperty(obj, "length");
962 if ((index >= length && !length_desc.isWritable()) ||
963 !DefineObjectProperty(obj, p, desc, true)) {
965 EndPerformSplice(obj);
967 throw MakeTypeError("define_disallowed", [p]);
972 if (index >= length) {
973 obj.length = index + 1;
976 EndPerformSplice(obj);
977 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
982 // Step 5 - Fallback to default implementation.
983 return DefineObjectProperty(obj, p, desc, should_throw);
987 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
988 function DefineOwnProperty(obj, p, desc, should_throw) {
989 if (%IsJSProxy(obj)) {
990 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
991 if (IS_SYMBOL(p)) return false;
993 var attributes = FromGenericPropertyDescriptor(desc);
994 return DefineProxyProperty(obj, p, attributes, should_throw);
995 } else if (IS_ARRAY(obj)) {
996 return DefineArrayProperty(obj, p, desc, should_throw);
998 return DefineObjectProperty(obj, p, desc, should_throw);
1003 // ES5 section 15.2.3.2.
1004 function ObjectGetPrototypeOf(obj) {
1005 if (!IS_SPEC_OBJECT(obj)) {
1006 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
1008 return %GetPrototype(obj);
1011 // ES6 section 19.1.2.19.
1012 function ObjectSetPrototypeOf(obj, proto) {
1013 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
1015 if (proto !== null && !IS_SPEC_OBJECT(proto)) {
1016 throw MakeTypeError("proto_object_or_null", [proto]);
1019 if (IS_SPEC_OBJECT(obj)) {
1020 %SetPrototype(obj, proto);
1027 // ES5 section 15.2.3.3
1028 function ObjectGetOwnPropertyDescriptor(obj, p) {
1029 if (!IS_SPEC_OBJECT(obj)) {
1030 throw MakeTypeError("called_on_non_object",
1031 ["Object.getOwnPropertyDescriptor"]);
1033 var desc = GetOwnProperty(obj, p);
1034 return FromPropertyDescriptor(desc);
1038 // For Harmony proxies
1039 function ToNameArray(obj, trap, includeSymbols) {
1040 if (!IS_SPEC_OBJECT(obj)) {
1041 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1043 var n = ToUint32(obj.length);
1044 var array = new $Array(n);
1046 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
1047 for (var index = 0; index < n; index++) {
1048 var s = ToName(obj[index]);
1049 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1050 if (IS_SYMBOL(s) && !includeSymbols) continue;
1051 if (%HasLocalProperty(names, s)) {
1052 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1058 array.length = realLength;
1063 function ObjectGetOwnPropertyKeys(obj, symbolsOnly) {
1064 var nameArrays = new InternalArray();
1065 var filter = symbolsOnly ?
1066 PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL :
1067 PROPERTY_ATTRIBUTES_SYMBOLIC;
1069 // Find all the indexed properties.
1071 // Only get the local element names if we want to include string keys.
1073 var localElementNames = %GetLocalElementNames(obj);
1074 for (var i = 0; i < localElementNames.length; ++i) {
1075 localElementNames[i] = %_NumberToString(localElementNames[i]);
1077 nameArrays.push(localElementNames);
1079 // Get names for indexed interceptor properties.
1080 var interceptorInfo = %GetInterceptorInfo(obj);
1081 if ((interceptorInfo & 1) != 0) {
1082 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1083 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1084 nameArrays.push(indexedInterceptorNames);
1089 // Find all the named properties.
1091 // Get the local property names.
1092 nameArrays.push(%GetLocalPropertyNames(obj, filter));
1094 // Get names for named interceptor properties if any.
1095 if ((interceptorInfo & 2) != 0) {
1096 var namedInterceptorNames =
1097 %GetNamedInterceptorPropertyNames(obj);
1098 if (!IS_UNDEFINED(namedInterceptorNames)) {
1099 nameArrays.push(namedInterceptorNames);
1104 %Apply(InternalArray.prototype.concat,
1105 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1107 // Property names are expected to be unique strings,
1108 // but interceptors can interfere with that assumption.
1109 if (interceptorInfo != 0) {
1110 var seenKeys = { __proto__: null };
1112 for (var i = 0; i < propertyNames.length; ++i) {
1113 var name = propertyNames[i];
1115 if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
1117 if (IS_SYMBOL(name)) continue;
1118 name = ToString(name);
1120 if (seenKeys[name]) continue;
1121 seenKeys[name] = true;
1122 propertyNames[j++] = name;
1124 propertyNames.length = j;
1127 return propertyNames;
1131 // ES5 section 15.2.3.4.
1132 function ObjectGetOwnPropertyNames(obj) {
1133 if (!IS_SPEC_OBJECT(obj)) {
1134 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
1136 // Special handling for proxies.
1137 if (%IsJSProxy(obj)) {
1138 var handler = %GetHandler(obj);
1139 var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1140 return ToNameArray(names, "getOwnPropertyNames", false);
1143 return ObjectGetOwnPropertyKeys(obj, false);
1147 // ES5 section 15.2.3.5.
1148 function ObjectCreate(proto, properties) {
1149 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1150 throw MakeTypeError("proto_object_or_null", [proto]);
1152 var obj = { __proto__: proto };
1153 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1158 // ES5 section 15.2.3.6.
1159 function ObjectDefineProperty(obj, p, attributes) {
1160 if (!IS_SPEC_OBJECT(obj)) {
1161 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1163 var name = ToName(p);
1164 if (%IsJSProxy(obj)) {
1165 // Clone the attributes object for protection.
1166 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1167 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1168 var attributesClone = { __proto__: null };
1169 for (var a in attributes) {
1170 attributesClone[a] = attributes[a];
1172 DefineProxyProperty(obj, name, attributesClone, true);
1173 // The following would implement the spec as in the current proposal,
1174 // but after recent comments on es-discuss, is most likely obsolete.
1176 var defineObj = FromGenericPropertyDescriptor(desc);
1177 var names = ObjectGetOwnPropertyNames(attributes);
1179 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1180 for (var i = 0; i < names.length; i++) {
1182 if (!(%HasLocalProperty(standardNames, N))) {
1183 var attr = GetOwnProperty(attributes, N);
1184 DefineOwnProperty(descObj, N, attr, true);
1187 // This is really confusing the types, but it is what the proxies spec
1188 // currently requires:
1192 var desc = ToPropertyDescriptor(attributes);
1193 DefineOwnProperty(obj, name, desc, true);
1199 function GetOwnEnumerablePropertyNames(properties) {
1200 var names = new InternalArray();
1201 for (var key in properties) {
1202 if (%HasLocalProperty(properties, key)) {
1210 // ES5 section 15.2.3.7.
1211 function ObjectDefineProperties(obj, properties) {
1212 if (!IS_SPEC_OBJECT(obj)) {
1213 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1215 var props = ToObject(properties);
1216 var names = GetOwnEnumerablePropertyNames(props);
1217 var descriptors = new InternalArray();
1218 for (var i = 0; i < names.length; i++) {
1219 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1221 for (var i = 0; i < names.length; i++) {
1222 DefineOwnProperty(obj, names[i], descriptors[i], true);
1229 function ProxyFix(obj) {
1230 var handler = %GetHandler(obj);
1231 var props = CallTrap0(handler, "fix", UNDEFINED);
1232 if (IS_UNDEFINED(props)) {
1233 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1236 if (%IsJSFunctionProxy(obj)) {
1237 var callTrap = %GetCallTrap(obj);
1238 var constructTrap = %GetConstructTrap(obj);
1239 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1240 %Fix(obj); // becomes a regular function
1241 %SetCode(obj, code);
1242 // TODO(rossberg): What about length and other properties? Not specified.
1243 // We just put in some half-reasonable defaults for now.
1244 var prototype = new $Object();
1245 $Object.defineProperty(prototype, "constructor",
1246 {value: obj, writable: true, enumerable: false, configurable: true});
1247 // TODO(v8:1530): defineProperty does not handle prototype and length.
1248 %FunctionSetPrototype(obj, prototype);
1253 ObjectDefineProperties(obj, props);
1257 // ES5 section 15.2.3.8.
1258 function ObjectSeal(obj) {
1259 if (!IS_SPEC_OBJECT(obj)) {
1260 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1262 if (%IsJSProxy(obj)) {
1265 var names = ObjectGetOwnPropertyNames(obj);
1266 for (var i = 0; i < names.length; i++) {
1267 var name = names[i];
1268 var desc = GetOwnProperty(obj, name);
1269 if (desc.isConfigurable()) {
1270 desc.setConfigurable(false);
1271 DefineOwnProperty(obj, name, desc, true);
1274 %PreventExtensions(obj);
1279 // ES5 section 15.2.3.9.
1280 function ObjectFreeze(obj) {
1281 if (!IS_SPEC_OBJECT(obj)) {
1282 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1284 var isProxy = %IsJSProxy(obj);
1285 if (isProxy || %HasNonStrictArgumentsElements(obj) || %IsObserved(obj)) {
1289 var names = ObjectGetOwnPropertyNames(obj);
1290 for (var i = 0; i < names.length; i++) {
1291 var name = names[i];
1292 var desc = GetOwnProperty(obj, name);
1293 if (desc.isWritable() || desc.isConfigurable()) {
1294 if (IsDataDescriptor(desc)) desc.setWritable(false);
1295 desc.setConfigurable(false);
1296 DefineOwnProperty(obj, name, desc, true);
1299 %PreventExtensions(obj);
1301 // TODO(adamk): Is it worth going to this fast path if the
1302 // object's properties are already in dictionary mode?
1309 // ES5 section 15.2.3.10
1310 function ObjectPreventExtension(obj) {
1311 if (!IS_SPEC_OBJECT(obj)) {
1312 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1314 if (%IsJSProxy(obj)) {
1317 %PreventExtensions(obj);
1322 // ES5 section 15.2.3.11
1323 function ObjectIsSealed(obj) {
1324 if (!IS_SPEC_OBJECT(obj)) {
1325 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1327 if (%IsJSProxy(obj)) {
1330 if (%IsExtensible(obj)) {
1333 var names = ObjectGetOwnPropertyNames(obj);
1334 for (var i = 0; i < names.length; i++) {
1335 var name = names[i];
1336 var desc = GetOwnProperty(obj, name);
1337 if (desc.isConfigurable()) return false;
1343 // ES5 section 15.2.3.12
1344 function ObjectIsFrozen(obj) {
1345 if (!IS_SPEC_OBJECT(obj)) {
1346 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1348 if (%IsJSProxy(obj)) {
1351 if (%IsExtensible(obj)) {
1354 var names = ObjectGetOwnPropertyNames(obj);
1355 for (var i = 0; i < names.length; i++) {
1356 var name = names[i];
1357 var desc = GetOwnProperty(obj, name);
1358 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1359 if (desc.isConfigurable()) return false;
1365 // ES5 section 15.2.3.13
1366 function ObjectIsExtensible(obj) {
1367 if (!IS_SPEC_OBJECT(obj)) {
1368 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1370 if (%IsJSProxy(obj)) {
1373 return %IsExtensible(obj);
1378 function ObjectIs(obj1, obj2) {
1379 if (obj1 === obj2) {
1380 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1382 return (obj1 !== obj1) && (obj2 !== obj2);
1387 // Harmony __proto__ getter.
1388 function ObjectGetProto() {
1389 return %GetPrototype(this);
1393 // Harmony __proto__ setter.
1394 function ObjectSetProto(obj) {
1395 return %SetPrototype(this, obj);
1399 function ObjectConstructor(x) {
1400 if (%_IsConstructCall()) {
1401 if (x == null) return this;
1404 if (x == null) return { };
1410 // ----------------------------------------------------------------------------
1413 function SetUpObject() {
1414 %CheckIsBootstrapping();
1416 %SetNativeFlag($Object);
1417 %SetCode($Object, ObjectConstructor);
1418 %SetExpectedNumberOfProperties($Object, 4);
1420 %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1422 // Set up non-enumerable functions on the Object.prototype object.
1423 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1424 "toString", ObjectToString,
1425 "toLocaleString", ObjectToLocaleString,
1426 "valueOf", ObjectValueOf,
1427 "hasOwnProperty", ObjectHasOwnProperty,
1428 "isPrototypeOf", ObjectIsPrototypeOf,
1429 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1430 "__defineGetter__", ObjectDefineGetter,
1431 "__lookupGetter__", ObjectLookupGetter,
1432 "__defineSetter__", ObjectDefineSetter,
1433 "__lookupSetter__", ObjectLookupSetter
1435 InstallGetterSetter($Object.prototype, "__proto__",
1436 ObjectGetProto, ObjectSetProto);
1438 // Set up non-enumerable functions in the Object object.
1439 InstallFunctions($Object, DONT_ENUM, $Array(
1441 "create", ObjectCreate,
1442 "defineProperty", ObjectDefineProperty,
1443 "defineProperties", ObjectDefineProperties,
1444 "freeze", ObjectFreeze,
1445 "getPrototypeOf", ObjectGetPrototypeOf,
1446 "setPrototypeOf", ObjectSetPrototypeOf,
1447 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1448 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1449 // getOwnPropertySymbols is added in symbol.js.
1451 "isExtensible", ObjectIsExtensible,
1452 "isFrozen", ObjectIsFrozen,
1453 "isSealed", ObjectIsSealed,
1454 "preventExtensions", ObjectPreventExtension,
1456 // deliverChangeRecords, getNotifier, observe and unobserve are added
1457 // in object-observe.js.
1464 // ----------------------------------------------------------------------------
1467 function BooleanConstructor(x) {
1468 if (%_IsConstructCall()) {
1469 %_SetValueOf(this, ToBoolean(x));
1471 return ToBoolean(x);
1476 function BooleanToString() {
1477 // NOTE: Both Boolean objects and values can enter here as
1478 // 'this'. This is not as dictated by ECMA-262.
1480 if (!IS_BOOLEAN(b)) {
1481 if (!IS_BOOLEAN_WRAPPER(b)) {
1482 throw new $TypeError('Boolean.prototype.toString is not generic');
1486 return b ? 'true' : 'false';
1490 function BooleanValueOf() {
1491 // NOTE: Both Boolean objects and values can enter here as
1492 // 'this'. This is not as dictated by ECMA-262.
1493 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1494 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1496 return %_ValueOf(this);
1500 // ----------------------------------------------------------------------------
1502 function SetUpBoolean () {
1503 %CheckIsBootstrapping();
1505 %SetCode($Boolean, BooleanConstructor);
1506 %FunctionSetPrototype($Boolean, new $Boolean(false));
1507 %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1509 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1510 "toString", BooleanToString,
1511 "valueOf", BooleanValueOf
1518 // ----------------------------------------------------------------------------
1521 function NumberConstructor(x) {
1522 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1523 if (%_IsConstructCall()) {
1524 %_SetValueOf(this, value);
1531 // ECMA-262 section 15.7.4.2.
1532 function NumberToString(radix) {
1533 // NOTE: Both Number objects and values can enter here as
1534 // 'this'. This is not as dictated by ECMA-262.
1536 if (!IS_NUMBER(this)) {
1537 if (!IS_NUMBER_WRAPPER(this)) {
1538 throw new $TypeError('Number.prototype.toString is not generic');
1540 // Get the value of this number in case it's an object.
1541 number = %_ValueOf(this);
1543 // Fast case: Convert number in radix 10.
1544 if (IS_UNDEFINED(radix) || radix === 10) {
1545 return %_NumberToString(number);
1548 // Convert the radix to an integer and check the range.
1549 radix = TO_INTEGER(radix);
1550 if (radix < 2 || radix > 36) {
1551 throw new $RangeError('toString() radix argument must be between 2 and 36');
1553 // Convert the number to a string in the given radix.
1554 return %NumberToRadixString(number, radix);
1558 // ECMA-262 section 15.7.4.3
1559 function NumberToLocaleString() {
1560 return %_CallFunction(this, NumberToString);
1564 // ECMA-262 section 15.7.4.4
1565 function NumberValueOf() {
1566 // NOTE: Both Number objects and values can enter here as
1567 // 'this'. This is not as dictated by ECMA-262.
1568 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1569 throw new $TypeError('Number.prototype.valueOf is not generic');
1571 return %_ValueOf(this);
1575 // ECMA-262 section 15.7.4.5
1576 function NumberToFixed(fractionDigits) {
1578 if (!IS_NUMBER(this)) {
1579 if (!IS_NUMBER_WRAPPER(this)) {
1580 throw MakeTypeError("incompatible_method_receiver",
1581 ["Number.prototype.toFixed", this]);
1583 // Get the value of this number in case it's an object.
1584 x = %_ValueOf(this);
1586 var f = TO_INTEGER(fractionDigits);
1588 if (f < 0 || f > 20) {
1589 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1592 if (NUMBER_IS_NAN(x)) return "NaN";
1593 if (x == INFINITY) return "Infinity";
1594 if (x == -INFINITY) return "-Infinity";
1596 return %NumberToFixed(x, f);
1600 // ECMA-262 section 15.7.4.6
1601 function NumberToExponential(fractionDigits) {
1603 if (!IS_NUMBER(this)) {
1604 if (!IS_NUMBER_WRAPPER(this)) {
1605 throw MakeTypeError("incompatible_method_receiver",
1606 ["Number.prototype.toExponential", this]);
1608 // Get the value of this number in case it's an object.
1609 x = %_ValueOf(this);
1611 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1613 if (NUMBER_IS_NAN(x)) return "NaN";
1614 if (x == INFINITY) return "Infinity";
1615 if (x == -INFINITY) return "-Infinity";
1617 if (IS_UNDEFINED(f)) {
1618 f = -1; // Signal for runtime function that f is not defined.
1619 } else if (f < 0 || f > 20) {
1620 throw new $RangeError("toExponential() argument must be between 0 and 20");
1622 return %NumberToExponential(x, f);
1626 // ECMA-262 section 15.7.4.7
1627 function NumberToPrecision(precision) {
1629 if (!IS_NUMBER(this)) {
1630 if (!IS_NUMBER_WRAPPER(this)) {
1631 throw MakeTypeError("incompatible_method_receiver",
1632 ["Number.prototype.toPrecision", this]);
1634 // Get the value of this number in case it's an object.
1635 x = %_ValueOf(this);
1637 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1638 var p = TO_INTEGER(precision);
1640 if (NUMBER_IS_NAN(x)) return "NaN";
1641 if (x == INFINITY) return "Infinity";
1642 if (x == -INFINITY) return "-Infinity";
1644 if (p < 1 || p > 21) {
1645 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1647 return %NumberToPrecision(x, p);
1651 // Harmony isFinite.
1652 function NumberIsFinite(number) {
1653 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1657 // Harmony isInteger
1658 function NumberIsInteger(number) {
1659 return NumberIsFinite(number) && TO_INTEGER(number) == number;
1664 function NumberIsNaN(number) {
1665 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1669 // Harmony isSafeInteger
1670 function NumberIsSafeInteger(number) {
1671 if (NumberIsFinite(number)) {
1672 var integral = TO_INTEGER(number);
1673 if (integral == number)
1674 return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
1680 // ----------------------------------------------------------------------------
1682 function SetUpNumber() {
1683 %CheckIsBootstrapping();
1685 %SetCode($Number, NumberConstructor);
1686 %FunctionSetPrototype($Number, new $Number(0));
1688 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1689 // Set up the constructor property on the Number prototype object.
1690 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1692 InstallConstants($Number, $Array(
1693 // ECMA-262 section 15.7.3.1.
1694 "MAX_VALUE", 1.7976931348623157e+308,
1695 // ECMA-262 section 15.7.3.2.
1696 "MIN_VALUE", 5e-324,
1697 // ECMA-262 section 15.7.3.3.
1699 // ECMA-262 section 15.7.3.4.
1700 "NEGATIVE_INFINITY", -INFINITY,
1701 // ECMA-262 section 15.7.3.5.
1702 "POSITIVE_INFINITY", INFINITY,
1704 // --- Harmony constants (no spec refs until settled.)
1706 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1707 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1708 "EPSILON", %_MathPow(2, -52)
1711 // Set up non-enumerable functions on the Number prototype object.
1712 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1713 "toString", NumberToString,
1714 "toLocaleString", NumberToLocaleString,
1715 "valueOf", NumberValueOf,
1716 "toFixed", NumberToFixed,
1717 "toExponential", NumberToExponential,
1718 "toPrecision", NumberToPrecision
1721 // Harmony Number constructor additions
1722 InstallFunctions($Number, DONT_ENUM, $Array(
1723 "isFinite", NumberIsFinite,
1724 "isInteger", NumberIsInteger,
1725 "isNaN", NumberIsNaN,
1726 "isSafeInteger", NumberIsSafeInteger,
1727 "parseInt", GlobalParseInt,
1728 "parseFloat", GlobalParseFloat
1735 // ----------------------------------------------------------------------------
1738 function FunctionSourceString(func) {
1739 while (%IsJSFunctionProxy(func)) {
1740 func = %GetCallTrap(func);
1743 if (!IS_FUNCTION(func)) {
1744 throw new $TypeError('Function.prototype.toString is not generic');
1747 var source = %FunctionGetSourceCode(func);
1748 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1749 var name = %FunctionGetName(func);
1751 // Mimic what KJS does.
1752 return 'function ' + name + '() { [native code] }';
1754 return 'function () { [native code] }';
1758 var name = %FunctionNameShouldPrintAsAnonymous(func)
1760 : %FunctionGetName(func);
1761 var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1762 return head + name + source;
1766 function FunctionToString() {
1767 return FunctionSourceString(this);
1772 function FunctionBind(this_arg) { // Length is 1.
1773 if (!IS_SPEC_FUNCTION(this)) {
1774 throw new $TypeError('Bind must be called on a function');
1776 var boundFunction = function () {
1777 // Poison .arguments and .caller, but is otherwise not detectable.
1779 // This function must not use any object literals (Object, Array, RegExp),
1780 // since the literals-array is being used to store the bound data.
1781 if (%_IsConstructCall()) {
1782 return %NewObjectFromBound(boundFunction);
1784 var bindings = %BoundFunctionGetBindings(boundFunction);
1786 var argc = %_ArgumentsLength();
1788 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1790 if (bindings.length === 2) {
1791 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1793 var bound_argc = bindings.length - 2;
1794 var argv = new InternalArray(bound_argc + argc);
1795 for (var i = 0; i < bound_argc; i++) {
1796 argv[i] = bindings[i + 2];
1798 for (var j = 0; j < argc; j++) {
1799 argv[i++] = %_Arguments(j);
1801 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1804 %FunctionRemovePrototype(boundFunction);
1806 if (%_ClassOf(this) == "Function") {
1807 // Function or FunctionProxy.
1808 var old_length = this.length;
1809 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1810 if ((typeof old_length === "number") &&
1811 ((old_length >>> 0) === old_length)) {
1812 var argc = %_ArgumentsLength();
1813 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1814 new_length = old_length - argc;
1815 if (new_length < 0) new_length = 0;
1818 // This runtime function finds any remaining arguments on the stack,
1819 // so we don't pass the arguments object.
1820 var result = %FunctionBindArguments(boundFunction, this,
1821 this_arg, new_length);
1823 // We already have caller and arguments properties on functions,
1824 // which are non-configurable. It therefore makes no sence to
1825 // try to redefine these as defined by the spec. The spec says
1826 // that bind should make these throw a TypeError if get or set
1827 // is called and make them non-enumerable and non-configurable.
1828 // To be consistent with our normal functions we leave this as it is.
1829 // TODO(lrn): Do set these to be thrower.
1834 function NewFunctionString(arguments, function_token) {
1835 var n = arguments.length;
1838 p = ToString(arguments[0]);
1839 for (var i = 1; i < n - 1; i++) {
1840 p += ',' + ToString(arguments[i]);
1842 // If the formal parameters string include ) - an illegal
1843 // character - it may make the combined function expression
1844 // compile. We avoid this problem by checking for this early on.
1845 if (%_CallFunction(p, ')', StringIndexOf) != -1) {
1846 throw MakeSyntaxError('paren_in_arg_string', []);
1848 // If the formal parameters include an unbalanced block comment, the
1849 // function must be rejected. Since JavaScript does not allow nested
1850 // comments we can include a trailing block comment to catch this.
1853 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1854 return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
1858 function FunctionConstructor(arg1) { // length == 1
1859 var source = NewFunctionString(arguments, 'function');
1860 var global_receiver = %GlobalReceiver(global);
1861 // Compile the string in the constructor and not a helper so that errors
1862 // appear to come from here.
1863 var f = %_CallFunction(global_receiver, %CompileString(source, true));
1864 %FunctionMarkNameShouldPrintAsAnonymous(f);
1869 // ----------------------------------------------------------------------------
1871 function SetUpFunction() {
1872 %CheckIsBootstrapping();
1874 %SetCode($Function, FunctionConstructor);
1875 %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1877 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1878 "bind", FunctionBind,
1879 "toString", FunctionToString
1886 //----------------------------------------------------------------------------
1888 // TODO(rossberg): very simple abstraction for generic microtask queue.
1889 // Eventually, we should move to a real event queue that allows to maintain
1890 // relative ordering of different kinds of tasks.
1892 RunMicrotasks.runners = new InternalArray;
1894 function RunMicrotasks() {
1895 while (%SetMicrotaskPending(false)) {
1896 for (var i in RunMicrotasks.runners) RunMicrotasks.runners[i]();