Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / v8natives.js
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.
4
5 // This file relies on the fact that the following declarations have been made
6 // in runtime.js:
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;
12 //
13 // in math.js:
14 // var $floor = MathFloor
15
16 var $isNaN = GlobalIsNaN;
17 var $isFinite = GlobalIsFinite;
18
19 // ----------------------------------------------------------------------------
20
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);
25   }
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);
32     %SetNativeFlag(f);
33   }
34   %ToFastProperties(object);
35 }
36
37
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);
44 }
45
46
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);
56 }
57
58
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);
63   }
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);
69   }
70   %ToFastProperties(object);
71 }
72
73
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);
86   }
87   if (fields) {
88     for (var i = 0; i < fields.length; i++) {
89       %SetProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE);
90     }
91   }
92   for (var i = 0; i < methods.length; i += 2) {
93     var key = methods[i];
94     var f = methods[i + 1];
95     %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
96     %SetNativeFlag(f);
97   }
98   %SetPrototype(prototype, null);
99   %ToFastProperties(prototype);
100 }
101
102
103 // ----------------------------------------------------------------------------
104
105
106 // ECMA 262 - 15.1.4
107 function GlobalIsNaN(number) {
108   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
109   return NUMBER_IS_NAN(number);
110 }
111
112
113 // ECMA 262 - 15.1.5
114 function GlobalIsFinite(number) {
115   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
116   return NUMBER_IS_FINITE(number);
117 }
118
119
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))) {
132       // Truncate number.
133       return string | 0;
134     }
135     string = TO_STRING_INLINE(string);
136     radix = radix | 0;
137   } else {
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))) {
142       return NAN;
143     }
144   }
145
146   if (%_HasCachedArrayIndex(string) &&
147       (radix == 0 || radix == 10)) {
148     return %_GetCachedArrayIndex(string);
149   }
150   return %StringParseInt(string, radix);
151 }
152
153
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);
159 }
160
161
162 function GlobalEval(x) {
163   if (!IS_STRING(x)) return x;
164
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');
173   }
174
175   var global_receiver = %GlobalReceiver(global);
176
177   var f = %CompileString(x, false);
178   if (!IS_FUNCTION(f)) return f;
179
180   return %_CallFunction(global_receiver, f);
181 }
182
183
184 // ----------------------------------------------------------------------------
185
186 // Set up global object.
187 function SetUpGlobal() {
188   %CheckIsBootstrapping();
189
190   var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
191
192   // ECMA 262 - 15.1.1.1.
193   %SetProperty(global, "NaN", NAN, attributes);
194
195   // ECMA-262 - 15.1.1.2.
196   %SetProperty(global, "Infinity", INFINITY, attributes);
197
198   // ECMA-262 - 15.1.1.3.
199   %SetProperty(global, "undefined", UNDEFINED, attributes);
200
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,
207     "eval", GlobalEval
208   ));
209 }
210
211 SetUpGlobal();
212
213
214 // ----------------------------------------------------------------------------
215 // Object
216
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)) + "]";
222 }
223
224
225 // ECMA-262 - 15.2.4.3
226 function ObjectToLocaleString() {
227   CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
228   return this.toString();
229 }
230
231
232 // ECMA-262 - 15.2.4.4
233 function ObjectValueOf() {
234   return ToObject(this);
235 }
236
237
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;
243
244     var handler = %GetHandler(this);
245     return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
246   }
247   return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
248 }
249
250
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);
256 }
257
258
259 // ECMA-262 - 15.2.4.6
260 function ObjectPropertyIsEnumerable(V) {
261   var P = ToName(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;
265
266     var desc = GetOwnProperty(this, P);
267     return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
268   }
269   return %IsPropertyEnumerable(ToObject(this), P);
270 }
271
272
273 // Extensions for providing property getters and setters.
274 function ObjectDefineGetter(name, fun) {
275   var receiver = this;
276   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
277     receiver = %GlobalReceiver(global);
278   }
279   if (!IS_SPEC_FUNCTION(fun)) {
280     throw new $TypeError(
281         'Object.prototype.__defineGetter__: Expecting function');
282   }
283   var desc = new PropertyDescriptor();
284   desc.setGet(fun);
285   desc.setEnumerable(true);
286   desc.setConfigurable(true);
287   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
288 }
289
290
291 function ObjectLookupGetter(name) {
292   var receiver = this;
293   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
294     receiver = %GlobalReceiver(global);
295   }
296   return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
297 }
298
299
300 function ObjectDefineSetter(name, fun) {
301   var receiver = this;
302   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
303     receiver = %GlobalReceiver(global);
304   }
305   if (!IS_SPEC_FUNCTION(fun)) {
306     throw new $TypeError(
307         'Object.prototype.__defineSetter__: Expecting function');
308   }
309   var desc = new PropertyDescriptor();
310   desc.setSet(fun);
311   desc.setEnumerable(true);
312   desc.setConfigurable(true);
313   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
314 }
315
316
317 function ObjectLookupSetter(name) {
318   var receiver = this;
319   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
320     receiver = %GlobalReceiver(global);
321   }
322   return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
323 }
324
325
326 function ObjectKeys(obj) {
327   if (!IS_SPEC_OBJECT(obj)) {
328     throw MakeTypeError("called_on_non_object", ["Object.keys"]);
329   }
330   if (%IsJSProxy(obj)) {
331     var handler = %GetHandler(obj);
332     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
333     return ToNameArray(names, "keys", false);
334   }
335   return %LocalKeys(obj);
336 }
337
338
339 // ES5 8.10.1.
340 function IsAccessorDescriptor(desc) {
341   if (IS_UNDEFINED(desc)) return false;
342   return desc.hasGetter() || desc.hasSetter();
343 }
344
345
346 // ES5 8.10.2.
347 function IsDataDescriptor(desc) {
348   if (IS_UNDEFINED(desc)) return false;
349   return desc.hasValue() || desc.hasWritable();
350 }
351
352
353 // ES5 8.10.3.
354 function IsGenericDescriptor(desc) {
355   if (IS_UNDEFINED(desc)) return false;
356   return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
357 }
358
359
360 function IsInconsistentDescriptor(desc) {
361   return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
362 }
363
364
365 // ES5 8.10.4
366 function FromPropertyDescriptor(desc) {
367   if (IS_UNDEFINED(desc)) return desc;
368
369   if (IsDataDescriptor(desc)) {
370     return { value: desc.getValue(),
371              writable: desc.isWritable(),
372              enumerable: desc.isEnumerable(),
373              configurable: desc.isConfigurable() };
374   }
375   // Must be an AccessorDescriptor then. We never return a generic descriptor.
376   return { get: desc.getGet(),
377            set: desc.getSet(),
378            enumerable: desc.isEnumerable(),
379            configurable: desc.isConfigurable() };
380 }
381
382
383 // Harmony Proxies
384 function FromGenericPropertyDescriptor(desc) {
385   if (IS_UNDEFINED(desc)) return desc;
386   var obj = new $Object();
387
388   if (desc.hasValue()) {
389     %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
390   }
391   if (desc.hasWritable()) {
392     %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
393   }
394   if (desc.hasGetter()) {
395     %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
396   }
397   if (desc.hasSetter()) {
398     %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
399   }
400   if (desc.hasEnumerable()) {
401     %IgnoreAttributesAndSetProperty(obj, "enumerable",
402                                     desc.isEnumerable(), NONE);
403   }
404   if (desc.hasConfigurable()) {
405     %IgnoreAttributesAndSetProperty(obj, "configurable",
406                                     desc.isConfigurable(), NONE);
407   }
408   return obj;
409 }
410
411
412 // ES5 8.10.5.
413 function ToPropertyDescriptor(obj) {
414   if (!IS_SPEC_OBJECT(obj)) {
415     throw MakeTypeError("property_desc_object", [obj]);
416   }
417   var desc = new PropertyDescriptor();
418
419   if ("enumerable" in obj) {
420     desc.setEnumerable(ToBoolean(obj.enumerable));
421   }
422
423   if ("configurable" in obj) {
424     desc.setConfigurable(ToBoolean(obj.configurable));
425   }
426
427   if ("value" in obj) {
428     desc.setValue(obj.value);
429   }
430
431   if ("writable" in obj) {
432     desc.setWritable(ToBoolean(obj.writable));
433   }
434
435   if ("get" in obj) {
436     var get = obj.get;
437     if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
438       throw MakeTypeError("getter_must_be_callable", [get]);
439     }
440     desc.setGet(get);
441   }
442
443   if ("set" in obj) {
444     var set = obj.set;
445     if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
446       throw MakeTypeError("setter_must_be_callable", [set]);
447     }
448     desc.setSet(set);
449   }
450
451   if (IsInconsistentDescriptor(desc)) {
452     throw MakeTypeError("value_and_accessor", [obj]);
453   }
454   return desc;
455 }
456
457
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);
464   } else {
465     // Is accessor descriptor.
466     if (!desc.hasGetter()) desc.setGet(UNDEFINED);
467     if (!desc.hasSetter()) desc.setSet(UNDEFINED);
468   }
469   if (!desc.hasEnumerable()) desc.setEnumerable(false);
470   if (!desc.hasConfigurable()) desc.setConfigurable(false);
471   return desc;
472 }
473
474
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;
490 }
491
492 SetUpLockedPrototype(PropertyDescriptor, $Array(
493     "value_",
494     "hasValue_",
495     "writable_",
496     "hasWritable_",
497     "enumerable_",
498     "hasEnumerable_",
499     "configurable_",
500     "hasConfigurable_",
501     "get_",
502     "hasGetter_",
503     "set_",
504     "hasSetter_"
505   ), $Array(
506     "toString", function() {
507       return "[object PropertyDescriptor]";
508     },
509     "setValue", function(value) {
510       this.value_ = value;
511       this.hasValue_ = true;
512     },
513     "getValue", function() {
514       return this.value_;
515     },
516     "hasValue", function() {
517       return this.hasValue_;
518     },
519     "setEnumerable", function(enumerable) {
520       this.enumerable_ = enumerable;
521         this.hasEnumerable_ = true;
522     },
523     "isEnumerable", function () {
524       return this.enumerable_;
525     },
526     "hasEnumerable", function() {
527       return this.hasEnumerable_;
528     },
529     "setWritable", function(writable) {
530       this.writable_ = writable;
531       this.hasWritable_ = true;
532     },
533     "isWritable", function() {
534       return this.writable_;
535     },
536     "hasWritable", function() {
537       return this.hasWritable_;
538     },
539     "setConfigurable", function(configurable) {
540       this.configurable_ = configurable;
541       this.hasConfigurable_ = true;
542     },
543     "hasConfigurable", function() {
544       return this.hasConfigurable_;
545     },
546     "isConfigurable", function() {
547       return this.configurable_;
548     },
549     "setGet", function(get) {
550       this.get_ = get;
551         this.hasGetter_ = true;
552     },
553     "getGet", function() {
554       return this.get_;
555     },
556     "hasGetter", function() {
557       return this.hasGetter_;
558     },
559     "setSet", function(set) {
560       this.set_ = set;
561       this.hasSetter_ = true;
562     },
563     "getSet", function() {
564       return this.set_;
565     },
566     "hasSetter", function() {
567       return this.hasSetter_;
568   }));
569
570
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';
577   }
578
579   if (IS_UNDEFINED(desc_array)) {
580     return UNDEFINED;
581   }
582
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]);
588   } else {
589     desc.setValue(desc_array[VALUE_INDEX]);
590     desc.setWritable(desc_array[WRITABLE_INDEX]);
591   }
592   desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
593   desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
594
595   return desc;
596 }
597
598
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]);
605     }
606     trap = defaultTrap;
607   } else if (!IS_SPEC_FUNCTION(trap)) {
608     throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
609   }
610   return trap;
611 }
612
613
614 function CallTrap0(handler, name, defaultTrap) {
615   return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
616 }
617
618
619 function CallTrap1(handler, name, defaultTrap, x) {
620   return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
621 }
622
623
624 function CallTrap2(handler, name, defaultTrap, x, y) {
625   return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
626 }
627
628
629 // ES5 section 8.12.1.
630 function GetOwnProperty(obj, v) {
631   var p = ToName(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;
635
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]);
644     }
645     return desc;
646   }
647
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);
652
653   // A false value here means that access checks failed.
654   if (props === false) return UNDEFINED;
655
656   return ConvertDescriptorArrayToDescriptor(props);
657 }
658
659
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);
666     return true;
667   } else if (should_throw) {
668     throw MakeTypeError("define_disallowed", [p]);
669   } else {
670     return;
671   }
672 }
673
674
675 // Harmony proxies.
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;
679
680   var handler = %GetHandler(obj);
681   var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
682   if (!ToBoolean(result)) {
683     if (should_throw) {
684       throw MakeTypeError("handler_returned_false",
685                           [handler, "defineProperty"]);
686     } else {
687       return false;
688     }
689   }
690   return true;
691 }
692
693
694 // ES5 8.12.9.
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;
699
700   var current = ConvertDescriptorArrayToDescriptor(current_or_access);
701   var extensible = %IsExtensible(ToObject(obj));
702
703   // Error handling according to spec.
704   // Step 3
705   if (IS_UNDEFINED(current) && !extensible) {
706     if (should_throw) {
707       throw MakeTypeError("define_disallowed", [p]);
708     } else {
709       return false;
710     }
711   }
712
713   if (!IS_UNDEFINED(current)) {
714     // Step 5 and 6
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())) &&
723         (!desc.hasValue() ||
724          SameValue(desc.getValue(), current.getValue())) &&
725         (!desc.hasGetter() ||
726          SameValue(desc.getGet(), current.getGet())) &&
727         (!desc.hasSetter() ||
728          SameValue(desc.getSet(), current.getSet()))) {
729       return true;
730     }
731     if (!current.isConfigurable()) {
732       // Step 7
733       if (desc.isConfigurable() ||
734           (desc.hasEnumerable() &&
735            desc.isEnumerable() != current.isEnumerable())) {
736         if (should_throw) {
737           throw MakeTypeError("redefine_disallowed", [p]);
738         } else {
739           return false;
740         }
741       }
742       // Step 8
743       if (!IsGenericDescriptor(desc)) {
744         // Step 9a
745         if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
746           if (should_throw) {
747             throw MakeTypeError("redefine_disallowed", [p]);
748           } else {
749             return false;
750           }
751         }
752         // Step 10a
753         if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
754           if (!current.isWritable() && desc.isWritable()) {
755             if (should_throw) {
756               throw MakeTypeError("redefine_disallowed", [p]);
757             } else {
758               return false;
759             }
760           }
761           if (!current.isWritable() && desc.hasValue() &&
762               !SameValue(desc.getValue(), current.getValue())) {
763             if (should_throw) {
764               throw MakeTypeError("redefine_disallowed", [p]);
765             } else {
766               return false;
767             }
768           }
769         }
770         // Step 11
771         if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
772           if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
773             if (should_throw) {
774               throw MakeTypeError("redefine_disallowed", [p]);
775             } else {
776               return false;
777             }
778           }
779           if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
780             if (should_throw) {
781               throw MakeTypeError("redefine_disallowed", [p]);
782             } else {
783               return false;
784             }
785           }
786         }
787       }
788     }
789   }
790
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).
795   var flag = NONE;
796   if (desc.hasEnumerable()) {
797     flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
798   } else if (!IS_UNDEFINED(current)) {
799     flag |= current.isEnumerable() ? 0 : DONT_ENUM;
800   } else {
801     flag |= DONT_ENUM;
802   }
803
804   if (desc.hasConfigurable()) {
805     flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
806   } else if (!IS_UNDEFINED(current)) {
807     flag |= current.isConfigurable() ? 0 : DONT_DELETE;
808   } else
809     flag |= DONT_DELETE;
810
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
817     //                 property.
818     // Step 12 - updating an existing data property with a data or generic
819     //           descriptor.
820
821     if (desc.hasWritable()) {
822       flag |= desc.isWritable() ? 0 : READ_ONLY;
823     } else if (!IS_UNDEFINED(current)) {
824       flag |= current.isWritable() ? 0 : READ_ONLY;
825     } else {
826       flag |= READ_ONLY;
827     }
828
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();
834     }
835
836     %DefineOrRedefineDataProperty(obj, p, value, flag);
837   } else {
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
841     //                 property.
842     // Step 12 - updating an existing accessor property with an accessor
843     //           descriptor.
844     var getter = desc.hasGetter() ? desc.getGet() : null;
845     var setter = desc.hasSetter() ? desc.getSet() : null;
846     %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
847   }
848   return true;
849 }
850
851
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.
857
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);
864     }
865     var new_length = ToUint32(desc.getValue());
866     if (new_length != ToNumber(desc.getValue())) {
867       throw new $RangeError('defineProperty() array length out of range');
868     }
869     var length_desc = GetOwnProperty(obj, "length");
870     if (new_length != length && !length_desc.isWritable()) {
871       if (should_throw) {
872         throw MakeTypeError("redefine_disallowed", [p]);
873       } else {
874         return false;
875       }
876     }
877     var threw = false;
878
879     var emit_splice = %IsObserved(obj) && new_length !== old_length;
880     var removed;
881     if (emit_splice) {
882       BeginPerformSplice(obj);
883       removed = [];
884       if (new_length < old_length)
885         removed.length = old_length - new_length;
886     }
887
888     while (new_length < length--) {
889       var index = ToString(length);
890       if (emit_splice) {
891         var deletedDesc = GetOwnProperty(obj, index);
892         if (deletedDesc && deletedDesc.hasValue())
893           removed[length - new_length] = deletedDesc.getValue();
894       }
895       if (!Delete(obj, index, false)) {
896         new_length = length + 1;
897         threw = true;
898         break;
899       }
900     }
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;
911     if (emit_splice) {
912       EndPerformSplice(obj);
913       EnqueueSpliceRecord(obj,
914           new_length < old_length ? new_length : old_length,
915           removed,
916           new_length > old_length ? new_length - old_length : 0);
917     }
918     if (threw) {
919       if (should_throw) {
920         throw MakeTypeError("redefine_disallowed", [p]);
921       } else {
922         return false;
923       }
924     }
925     return true;
926   }
927
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)) {
934       emit_splice = true;
935       BeginPerformSplice(obj);
936     }
937
938     var length_desc = GetOwnProperty(obj, "length");
939     if ((index >= length && !length_desc.isWritable()) ||
940         !DefineObjectProperty(obj, p, desc, true)) {
941       if (emit_splice)
942         EndPerformSplice(obj);
943       if (should_throw) {
944         throw MakeTypeError("define_disallowed", [p]);
945       } else {
946         return false;
947       }
948     }
949     if (index >= length) {
950       obj.length = index + 1;
951     }
952     if (emit_splice) {
953       EndPerformSplice(obj);
954       EnqueueSpliceRecord(obj, length, [], index + 1 - length);
955     }
956     return true;
957   }
958
959   // Step 5 - Fallback to default implementation.
960   return DefineObjectProperty(obj, p, desc, should_throw);
961 }
962
963
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;
969
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);
974   } else {
975     return DefineObjectProperty(obj, p, desc, should_throw);
976   }
977 }
978
979
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"]);
984   }
985   return %GetPrototype(obj);
986 }
987
988 // ES6 section 19.1.2.19.
989 function ObjectSetPrototypeOf(obj, proto) {
990   CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
991
992   if (proto !== null && !IS_SPEC_OBJECT(proto)) {
993     throw MakeTypeError("proto_object_or_null", [proto]);
994   }
995
996   if (IS_SPEC_OBJECT(obj)) {
997     %SetPrototype(obj, proto);
998   }
999
1000   return obj;
1001 }
1002
1003
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"]);
1009   }
1010   var desc = GetOwnProperty(obj, p);
1011   return FromPropertyDescriptor(desc);
1012 }
1013
1014
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]);
1019   }
1020   var n = ToUint32(obj.length);
1021   var array = new $Array(n);
1022   var realLength = 0;
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]);
1030     }
1031     array[index] = s;
1032     ++realLength;
1033     names[s] = 0;
1034   }
1035   array.length = realLength;
1036   return array;
1037 }
1038
1039
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;
1045
1046   // Find all the indexed properties.
1047
1048   // Only get the local element names if we want to include string keys.
1049   if (!symbolsOnly) {
1050     var localElementNames = %GetLocalElementNames(obj);
1051     for (var i = 0; i < localElementNames.length; ++i) {
1052       localElementNames[i] = %_NumberToString(localElementNames[i]);
1053     }
1054     nameArrays.push(localElementNames);
1055
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);
1062       }
1063     }
1064   }
1065
1066   // Find all the named properties.
1067
1068   // Get the local property names.
1069   nameArrays.push(%GetLocalPropertyNames(obj, filter));
1070
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);
1077     }
1078   }
1079
1080   var propertyNames =
1081       %Apply(InternalArray.prototype.concat,
1082              nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1083
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 };
1088     var j = 0;
1089     for (var i = 0; i < propertyNames.length; ++i) {
1090       var name = propertyNames[i];
1091       if (symbolsOnly) {
1092         if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
1093       } else {
1094         if (IS_SYMBOL(name)) continue;
1095         name = ToString(name);
1096       }
1097       if (seenKeys[name]) continue;
1098       seenKeys[name] = true;
1099       propertyNames[j++] = name;
1100     }
1101     propertyNames.length = j;
1102   }
1103
1104   return propertyNames;
1105 }
1106
1107
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"]);
1112   }
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);
1118   }
1119
1120   return ObjectGetOwnPropertyKeys(obj, false);
1121 }
1122
1123
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]);
1128   }
1129   var obj = { __proto__: proto };
1130   if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1131   return obj;
1132 }
1133
1134
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"]);
1139   }
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];
1148     }
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.
1152     /*
1153     var defineObj = FromGenericPropertyDescriptor(desc);
1154     var names = ObjectGetOwnPropertyNames(attributes);
1155     var standardNames =
1156       {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1157     for (var i = 0; i < names.length; i++) {
1158       var N = names[i];
1159       if (!(%HasLocalProperty(standardNames, N))) {
1160         var attr = GetOwnProperty(attributes, N);
1161         DefineOwnProperty(descObj, N, attr, true);
1162       }
1163     }
1164     // This is really confusing the types, but it is what the proxies spec
1165     // currently requires:
1166     desc = descObj;
1167     */
1168   } else {
1169     var desc = ToPropertyDescriptor(attributes);
1170     DefineOwnProperty(obj, name, desc, true);
1171   }
1172   return obj;
1173 }
1174
1175
1176 function GetOwnEnumerablePropertyNames(properties) {
1177   var names = new InternalArray();
1178   for (var key in properties) {
1179     if (%HasLocalProperty(properties, key)) {
1180       names.push(key);
1181     }
1182   }
1183   return names;
1184 }
1185
1186
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"]);
1191   }
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]]));
1197   }
1198   for (var i = 0; i < names.length; i++) {
1199     DefineOwnProperty(obj, names[i], descriptors[i], true);
1200   }
1201   return obj;
1202 }
1203
1204
1205 // Harmony proxies.
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"]);
1211   }
1212
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);
1226     obj.length = 0;
1227   } else {
1228     %Fix(obj);
1229   }
1230   ObjectDefineProperties(obj, props);
1231 }
1232
1233
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"]);
1238   }
1239   if (%IsJSProxy(obj)) {
1240     ProxyFix(obj);
1241   }
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);
1249     }
1250   }
1251   %PreventExtensions(obj);
1252   return obj;
1253 }
1254
1255
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"]);
1260   }
1261   var isProxy = %IsJSProxy(obj);
1262   if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1263     if (isProxy) {
1264       ProxyFix(obj);
1265     }
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);
1274       }
1275     }
1276     %PreventExtensions(obj);
1277   } else {
1278     // TODO(adamk): Is it worth going to this fast path if the
1279     // object's properties are already in dictionary mode?
1280     %ObjectFreeze(obj);
1281   }
1282   return obj;
1283 }
1284
1285
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"]);
1290   }
1291   if (%IsJSProxy(obj)) {
1292     ProxyFix(obj);
1293   }
1294   %PreventExtensions(obj);
1295   return obj;
1296 }
1297
1298
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"]);
1303   }
1304   if (%IsJSProxy(obj)) {
1305     return false;
1306   }
1307   if (%IsExtensible(obj)) {
1308     return false;
1309   }
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;
1315   }
1316   return true;
1317 }
1318
1319
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"]);
1324   }
1325   if (%IsJSProxy(obj)) {
1326     return false;
1327   }
1328   if (%IsExtensible(obj)) {
1329     return false;
1330   }
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;
1337   }
1338   return true;
1339 }
1340
1341
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"]);
1346   }
1347   if (%IsJSProxy(obj)) {
1348     return true;
1349   }
1350   return %IsExtensible(obj);
1351 }
1352
1353
1354 // Harmony egal.
1355 function ObjectIs(obj1, obj2) {
1356   if (obj1 === obj2) {
1357     return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1358   } else {
1359     return (obj1 !== obj1) && (obj2 !== obj2);
1360   }
1361 }
1362
1363
1364 // ECMA-262, Edition 6, section B.2.2.1.1
1365 function ObjectGetProto() {
1366   return %GetPrototype(ToObject(this));
1367 }
1368
1369
1370 // ECMA-262, Edition 6, section B.2.2.1.2
1371 function ObjectSetProto(proto) {
1372   CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1373
1374   if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1375     %SetPrototype(this, proto);
1376   }
1377 }
1378
1379
1380 function ObjectConstructor(x) {
1381   if (%_IsConstructCall()) {
1382     if (x == null) return this;
1383     return ToObject(x);
1384   } else {
1385     if (x == null) return { };
1386     return ToObject(x);
1387   }
1388 }
1389
1390
1391 // ----------------------------------------------------------------------------
1392 // Object
1393
1394 function SetUpObject() {
1395   %CheckIsBootstrapping();
1396
1397   %SetNativeFlag($Object);
1398   %SetCode($Object, ObjectConstructor);
1399   %SetExpectedNumberOfProperties($Object, 4);
1400
1401   %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1402
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
1415   ));
1416   InstallGetterSetter($Object.prototype, "__proto__",
1417                       ObjectGetProto, ObjectSetProto);
1418
1419   // Set up non-enumerable functions in the Object object.
1420   InstallFunctions($Object, DONT_ENUM, $Array(
1421     "keys", ObjectKeys,
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.
1431     "is", ObjectIs,
1432     "isExtensible", ObjectIsExtensible,
1433     "isFrozen", ObjectIsFrozen,
1434     "isSealed", ObjectIsSealed,
1435     "preventExtensions", ObjectPreventExtension,
1436     "seal", ObjectSeal
1437     // deliverChangeRecords, getNotifier, observe and unobserve are added
1438     // in object-observe.js.
1439   ));
1440 }
1441
1442 SetUpObject();
1443
1444
1445 // ----------------------------------------------------------------------------
1446 // Boolean
1447
1448 function BooleanConstructor(x) {
1449   if (%_IsConstructCall()) {
1450     %_SetValueOf(this, ToBoolean(x));
1451   } else {
1452     return ToBoolean(x);
1453   }
1454 }
1455
1456
1457 function BooleanToString() {
1458   // NOTE: Both Boolean objects and values can enter here as
1459   // 'this'. This is not as dictated by ECMA-262.
1460   var b = this;
1461   if (!IS_BOOLEAN(b)) {
1462     if (!IS_BOOLEAN_WRAPPER(b)) {
1463       throw new $TypeError('Boolean.prototype.toString is not generic');
1464     }
1465     b = %_ValueOf(b);
1466   }
1467   return b ? 'true' : 'false';
1468 }
1469
1470
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');
1476   }
1477   return %_ValueOf(this);
1478 }
1479
1480
1481 // ----------------------------------------------------------------------------
1482
1483 function SetUpBoolean () {
1484   %CheckIsBootstrapping();
1485
1486   %SetCode($Boolean, BooleanConstructor);
1487   %FunctionSetPrototype($Boolean, new $Boolean(false));
1488   %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1489
1490   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1491     "toString", BooleanToString,
1492     "valueOf", BooleanValueOf
1493   ));
1494 }
1495
1496 SetUpBoolean();
1497
1498
1499 // ----------------------------------------------------------------------------
1500 // Number
1501
1502 function NumberConstructor(x) {
1503   var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1504   if (%_IsConstructCall()) {
1505     %_SetValueOf(this, value);
1506   } else {
1507     return value;
1508   }
1509 }
1510
1511
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.
1516   var number = this;
1517   if (!IS_NUMBER(this)) {
1518     if (!IS_NUMBER_WRAPPER(this)) {
1519       throw new $TypeError('Number.prototype.toString is not generic');
1520     }
1521     // Get the value of this number in case it's an object.
1522     number = %_ValueOf(this);
1523   }
1524   // Fast case: Convert number in radix 10.
1525   if (IS_UNDEFINED(radix) || radix === 10) {
1526     return %_NumberToString(number);
1527   }
1528
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');
1533   }
1534   // Convert the number to a string in the given radix.
1535   return %NumberToRadixString(number, radix);
1536 }
1537
1538
1539 // ECMA-262 section 15.7.4.3
1540 function NumberToLocaleString() {
1541   return %_CallFunction(this, NumberToString);
1542 }
1543
1544
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');
1551   }
1552   return %_ValueOf(this);
1553 }
1554
1555
1556 // ECMA-262 section 15.7.4.5
1557 function NumberToFixed(fractionDigits) {
1558   var x = this;
1559   if (!IS_NUMBER(this)) {
1560     if (!IS_NUMBER_WRAPPER(this)) {
1561       throw MakeTypeError("incompatible_method_receiver",
1562                           ["Number.prototype.toFixed", this]);
1563     }
1564     // Get the value of this number in case it's an object.
1565     x = %_ValueOf(this);
1566   }
1567   var f = TO_INTEGER(fractionDigits);
1568
1569   if (f < 0 || f > 20) {
1570     throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1571   }
1572
1573   if (NUMBER_IS_NAN(x)) return "NaN";
1574   if (x == INFINITY) return "Infinity";
1575   if (x == -INFINITY) return "-Infinity";
1576
1577   return %NumberToFixed(x, f);
1578 }
1579
1580
1581 // ECMA-262 section 15.7.4.6
1582 function NumberToExponential(fractionDigits) {
1583   var x = this;
1584   if (!IS_NUMBER(this)) {
1585     if (!IS_NUMBER_WRAPPER(this)) {
1586       throw MakeTypeError("incompatible_method_receiver",
1587                           ["Number.prototype.toExponential", this]);
1588     }
1589     // Get the value of this number in case it's an object.
1590     x = %_ValueOf(this);
1591   }
1592   var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1593
1594   if (NUMBER_IS_NAN(x)) return "NaN";
1595   if (x == INFINITY) return "Infinity";
1596   if (x == -INFINITY) return "-Infinity";
1597
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");
1602   }
1603   return %NumberToExponential(x, f);
1604 }
1605
1606
1607 // ECMA-262 section 15.7.4.7
1608 function NumberToPrecision(precision) {
1609   var x = this;
1610   if (!IS_NUMBER(this)) {
1611     if (!IS_NUMBER_WRAPPER(this)) {
1612       throw MakeTypeError("incompatible_method_receiver",
1613                           ["Number.prototype.toPrecision", this]);
1614     }
1615     // Get the value of this number in case it's an object.
1616     x = %_ValueOf(this);
1617   }
1618   if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1619   var p = TO_INTEGER(precision);
1620
1621   if (NUMBER_IS_NAN(x)) return "NaN";
1622   if (x == INFINITY) return "Infinity";
1623   if (x == -INFINITY) return "-Infinity";
1624
1625   if (p < 1 || p > 21) {
1626     throw new $RangeError("toPrecision() argument must be between 1 and 21");
1627   }
1628   return %NumberToPrecision(x, p);
1629 }
1630
1631
1632 // Harmony isFinite.
1633 function NumberIsFinite(number) {
1634   return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1635 }
1636
1637
1638 // Harmony isInteger
1639 function NumberIsInteger(number) {
1640   return NumberIsFinite(number) && TO_INTEGER(number) == number;
1641 }
1642
1643
1644 // Harmony isNaN.
1645 function NumberIsNaN(number) {
1646   return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1647 }
1648
1649
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;
1656   }
1657   return false;
1658 }
1659
1660
1661 // ----------------------------------------------------------------------------
1662
1663 function SetUpNumber() {
1664   %CheckIsBootstrapping();
1665
1666   %SetCode($Number, NumberConstructor);
1667   %FunctionSetPrototype($Number, new $Number(0));
1668
1669   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1670   // Set up the constructor property on the Number prototype object.
1671   %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1672
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.
1679       "NaN", NAN,
1680       // ECMA-262 section 15.7.3.4.
1681       "NEGATIVE_INFINITY", -INFINITY,
1682       // ECMA-262 section 15.7.3.5.
1683       "POSITIVE_INFINITY", INFINITY,
1684
1685       // --- Harmony constants (no spec refs until settled.)
1686
1687       "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1688       "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1689       "EPSILON", %_MathPow(2, -52)
1690   ));
1691
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
1700   ));
1701
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
1710   ));
1711 }
1712
1713 SetUpNumber();
1714
1715
1716 // ----------------------------------------------------------------------------
1717 // Function
1718
1719 function FunctionSourceString(func) {
1720   while (%IsJSFunctionProxy(func)) {
1721     func = %GetCallTrap(func);
1722   }
1723
1724   if (!IS_FUNCTION(func)) {
1725     throw new $TypeError('Function.prototype.toString is not generic');
1726   }
1727
1728   var source = %FunctionGetSourceCode(func);
1729   if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1730     var name = %FunctionGetName(func);
1731     if (name) {
1732       // Mimic what KJS does.
1733       return 'function ' + name + '() { [native code] }';
1734     } else {
1735       return 'function () { [native code] }';
1736     }
1737   }
1738
1739   var name = %FunctionNameShouldPrintAsAnonymous(func)
1740       ? 'anonymous'
1741       : %FunctionGetName(func);
1742   var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1743   return head + name + source;
1744 }
1745
1746
1747 function FunctionToString() {
1748   return FunctionSourceString(this);
1749 }
1750
1751
1752 // ES5 15.3.4.5
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');
1756   }
1757   var boundFunction = function () {
1758     // Poison .arguments and .caller, but is otherwise not detectable.
1759     "use strict";
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);
1764     }
1765     var bindings = %BoundFunctionGetBindings(boundFunction);
1766
1767     var argc = %_ArgumentsLength();
1768     if (argc == 0) {
1769       return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1770     }
1771     if (bindings.length === 2) {
1772       return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1773     }
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];
1778     }
1779     for (var j = 0; j < argc; j++) {
1780       argv[i++] = %_Arguments(j);
1781     }
1782     return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1783   };
1784
1785   %FunctionRemovePrototype(boundFunction);
1786   var new_length = 0;
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;
1797     }
1798   }
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);
1803
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.
1811   return result;
1812 }
1813
1814
1815 function NewFunctionString(arguments, function_token) {
1816   var n = arguments.length;
1817   var p = '';
1818   if (n > 1) {
1819     p = ToString(arguments[0]);
1820     for (var i = 1; i < n - 1; i++) {
1821       p += ',' + ToString(arguments[i]);
1822     }
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', []);
1828     }
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.
1832     p += '\n/' + '**/';
1833   }
1834   var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1835   return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
1836 }
1837
1838
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);
1846   return f;
1847 }
1848
1849
1850 // ----------------------------------------------------------------------------
1851
1852 function SetUpFunction() {
1853   %CheckIsBootstrapping();
1854
1855   %SetCode($Function, FunctionConstructor);
1856   %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1857
1858   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1859     "bind", FunctionBind,
1860     "toString", FunctionToString
1861   ));
1862 }
1863
1864 SetUpFunction();
1865
1866
1867 //----------------------------------------------------------------------------
1868
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.
1872
1873 function RunMicrotasks() {
1874   while (%SetMicrotaskPending(false)) {
1875     var microtaskState = %GetMicrotaskState();
1876     if (IS_UNDEFINED(microtaskState.queue))
1877       return;
1878
1879     var microtasks = microtaskState.queue;
1880     microtaskState.queue = null;
1881
1882     for (var i = 0; i < microtasks.length; i++) {
1883       microtasks[i]();
1884     }
1885   }
1886 }
1887
1888 function EnqueueMicrotask(fn) {
1889   var microtaskState = %GetMicrotaskState();
1890   if (IS_UNDEFINED(microtaskState.queue) || IS_NULL(microtaskState.queue)) {
1891     microtaskState.queue = new InternalArray;
1892   }
1893   microtaskState.queue.push(fn);
1894   %SetMicrotaskPending(true);
1895 }