deps: upgrade v8 to 3.31.74.1
[platform/upstream/nodejs.git] / deps / 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     %AddNamedProperty(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   %DefineAccessorPropertyUnchecked(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   %DefineAccessorPropertyUnchecked(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     %AddNamedProperty(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       %AddNamedProperty(prototype, fields[i],
90                         UNDEFINED, DONT_ENUM | DONT_DELETE);
91     }
92   }
93   for (var i = 0; i < methods.length; i += 2) {
94     var key = methods[i];
95     var f = methods[i + 1];
96     %AddNamedProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
97     %SetNativeFlag(f);
98   }
99   %InternalSetPrototype(prototype, null);
100   %ToFastProperties(prototype);
101 }
102
103
104 // ----------------------------------------------------------------------------
105
106
107 // ECMA 262 - 15.1.4
108 function GlobalIsNaN(number) {
109   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
110   return NUMBER_IS_NAN(number);
111 }
112
113
114 // ECMA 262 - 15.1.5
115 function GlobalIsFinite(number) {
116   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
117   return NUMBER_IS_FINITE(number);
118 }
119
120
121 // ECMA-262 - 15.1.2.2
122 function GlobalParseInt(string, radix) {
123   if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
124     // Some people use parseInt instead of Math.floor.  This
125     // optimization makes parseInt on a Smi 12 times faster (60ns
126     // vs 800ns).  The following optimization makes parseInt on a
127     // non-Smi number 9 times faster (230ns vs 2070ns).  Together
128     // they make parseInt on a string 1.4% slower (274ns vs 270ns).
129     if (%_IsSmi(string)) return string;
130     if (IS_NUMBER(string) &&
131         ((0.01 < string && string < 1e9) ||
132             (-1e9 < string && string < -0.01))) {
133       // Truncate number.
134       return string | 0;
135     }
136     string = TO_STRING_INLINE(string);
137     radix = radix | 0;
138   } else {
139     // The spec says ToString should be evaluated before ToInt32.
140     string = TO_STRING_INLINE(string);
141     radix = TO_INT32(radix);
142     if (!(radix == 0 || (2 <= radix && radix <= 36))) {
143       return NAN;
144     }
145   }
146
147   if (%_HasCachedArrayIndex(string) &&
148       (radix == 0 || radix == 10)) {
149     return %_GetCachedArrayIndex(string);
150   }
151   return %StringParseInt(string, radix);
152 }
153
154
155 // ECMA-262 - 15.1.2.3
156 function GlobalParseFloat(string) {
157   string = TO_STRING_INLINE(string);
158   if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
159   return %StringParseFloat(string);
160 }
161
162
163 function GlobalEval(x) {
164   if (!IS_STRING(x)) return x;
165
166   var global_proxy = %GlobalProxy(global);
167
168   var f = %CompileString(x, false, 0);
169   if (!IS_FUNCTION(f)) return f;
170
171   return %_CallFunction(global_proxy, f);
172 }
173
174
175 // ----------------------------------------------------------------------------
176
177 // Set up global object.
178 function SetUpGlobal() {
179   %CheckIsBootstrapping();
180
181   var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
182
183   // ECMA 262 - 15.1.1.1.
184   %AddNamedProperty(global, "NaN", NAN, attributes);
185
186   // ECMA-262 - 15.1.1.2.
187   %AddNamedProperty(global, "Infinity", INFINITY, attributes);
188
189   // ECMA-262 - 15.1.1.3.
190   %AddNamedProperty(global, "undefined", UNDEFINED, attributes);
191
192   // Set up non-enumerable function on the global object.
193   InstallFunctions(global, DONT_ENUM, $Array(
194     "isNaN", GlobalIsNaN,
195     "isFinite", GlobalIsFinite,
196     "parseInt", GlobalParseInt,
197     "parseFloat", GlobalParseFloat,
198     "eval", GlobalEval
199   ));
200 }
201
202 SetUpGlobal();
203
204
205 // ----------------------------------------------------------------------------
206 // Object
207
208 var DefaultObjectToString = NoSideEffectsObjectToString;
209 // ECMA-262 - 15.2.4.2
210 function NoSideEffectsObjectToString() {
211   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
212   if (IS_NULL(this)) return "[object Null]";
213   return "[object " + %_ClassOf(ToObject(this)) + "]";
214 }
215
216
217 // ECMA-262 - 15.2.4.3
218 function ObjectToLocaleString() {
219   CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString");
220   return this.toString();
221 }
222
223
224 // ECMA-262 - 15.2.4.4
225 function ObjectValueOf() {
226   return ToObject(this);
227 }
228
229
230 // ECMA-262 - 15.2.4.5
231 function ObjectHasOwnProperty(V) {
232   if (%_IsJSProxy(this)) {
233     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
234     if (IS_SYMBOL(V)) return false;
235
236     var handler = %GetHandler(this);
237     return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
238   }
239   return %HasOwnProperty(TO_OBJECT_INLINE(this), ToName(V));
240 }
241
242
243 // ECMA-262 - 15.2.4.6
244 function ObjectIsPrototypeOf(V) {
245   if (!IS_SPEC_OBJECT(V)) return false;
246   CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
247   return %IsInPrototypeChain(this, V);
248 }
249
250
251 // ECMA-262 - 15.2.4.6
252 function ObjectPropertyIsEnumerable(V) {
253   var P = ToName(V);
254   if (%_IsJSProxy(this)) {
255     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
256     if (IS_SYMBOL(V)) return false;
257
258     var desc = GetOwnPropertyJS(this, P);
259     return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
260   }
261   return %IsPropertyEnumerable(ToObject(this), P);
262 }
263
264
265 // Extensions for providing property getters and setters.
266 function ObjectDefineGetter(name, fun) {
267   var receiver = this;
268   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
269     receiver = %GlobalProxy(global);
270   }
271   if (!IS_SPEC_FUNCTION(fun)) {
272     throw new $TypeError(
273         'Object.prototype.__defineGetter__: Expecting function');
274   }
275   var desc = new PropertyDescriptor();
276   desc.setGet(fun);
277   desc.setEnumerable(true);
278   desc.setConfigurable(true);
279   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
280 }
281
282
283 function ObjectLookupGetter(name) {
284   var receiver = this;
285   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
286     receiver = %GlobalProxy(global);
287   }
288   return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
289 }
290
291
292 function ObjectDefineSetter(name, fun) {
293   var receiver = this;
294   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
295     receiver = %GlobalProxy(global);
296   }
297   if (!IS_SPEC_FUNCTION(fun)) {
298     throw new $TypeError(
299         'Object.prototype.__defineSetter__: Expecting function');
300   }
301   var desc = new PropertyDescriptor();
302   desc.setSet(fun);
303   desc.setEnumerable(true);
304   desc.setConfigurable(true);
305   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
306 }
307
308
309 function ObjectLookupSetter(name) {
310   var receiver = this;
311   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
312     receiver = %GlobalProxy(global);
313   }
314   return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
315 }
316
317
318 function ObjectKeys(obj) {
319   obj = ToObject(obj);
320   if (%_IsJSProxy(obj)) {
321     var handler = %GetHandler(obj);
322     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
323     return ToNameArray(names, "keys", false);
324   }
325   return %OwnKeys(obj);
326 }
327
328
329 // ES5 8.10.1.
330 function IsAccessorDescriptor(desc) {
331   if (IS_UNDEFINED(desc)) return false;
332   return desc.hasGetter() || desc.hasSetter();
333 }
334
335
336 // ES5 8.10.2.
337 function IsDataDescriptor(desc) {
338   if (IS_UNDEFINED(desc)) return false;
339   return desc.hasValue() || desc.hasWritable();
340 }
341
342
343 // ES5 8.10.3.
344 function IsGenericDescriptor(desc) {
345   if (IS_UNDEFINED(desc)) return false;
346   return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
347 }
348
349
350 function IsInconsistentDescriptor(desc) {
351   return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
352 }
353
354
355 // ES5 8.10.4
356 function FromPropertyDescriptor(desc) {
357   if (IS_UNDEFINED(desc)) return desc;
358
359   if (IsDataDescriptor(desc)) {
360     return { value: desc.getValue(),
361              writable: desc.isWritable(),
362              enumerable: desc.isEnumerable(),
363              configurable: desc.isConfigurable() };
364   }
365   // Must be an AccessorDescriptor then. We never return a generic descriptor.
366   return { get: desc.getGet(),
367            set: desc.getSet(),
368            enumerable: desc.isEnumerable(),
369            configurable: desc.isConfigurable() };
370 }
371
372
373 // Harmony Proxies
374 function FromGenericPropertyDescriptor(desc) {
375   if (IS_UNDEFINED(desc)) return desc;
376   var obj = new $Object();
377
378   if (desc.hasValue()) {
379     %AddNamedProperty(obj, "value", desc.getValue(), NONE);
380   }
381   if (desc.hasWritable()) {
382     %AddNamedProperty(obj, "writable", desc.isWritable(), NONE);
383   }
384   if (desc.hasGetter()) {
385     %AddNamedProperty(obj, "get", desc.getGet(), NONE);
386   }
387   if (desc.hasSetter()) {
388     %AddNamedProperty(obj, "set", desc.getSet(), NONE);
389   }
390   if (desc.hasEnumerable()) {
391     %AddNamedProperty(obj, "enumerable", desc.isEnumerable(), NONE);
392   }
393   if (desc.hasConfigurable()) {
394     %AddNamedProperty(obj, "configurable", desc.isConfigurable(), NONE);
395   }
396   return obj;
397 }
398
399
400 // ES5 8.10.5.
401 function ToPropertyDescriptor(obj) {
402   if (!IS_SPEC_OBJECT(obj)) {
403     throw MakeTypeError("property_desc_object", [obj]);
404   }
405   var desc = new PropertyDescriptor();
406
407   if ("enumerable" in obj) {
408     desc.setEnumerable(ToBoolean(obj.enumerable));
409   }
410
411   if ("configurable" in obj) {
412     desc.setConfigurable(ToBoolean(obj.configurable));
413   }
414
415   if ("value" in obj) {
416     desc.setValue(obj.value);
417   }
418
419   if ("writable" in obj) {
420     desc.setWritable(ToBoolean(obj.writable));
421   }
422
423   if ("get" in obj) {
424     var get = obj.get;
425     if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
426       throw MakeTypeError("getter_must_be_callable", [get]);
427     }
428     desc.setGet(get);
429   }
430
431   if ("set" in obj) {
432     var set = obj.set;
433     if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
434       throw MakeTypeError("setter_must_be_callable", [set]);
435     }
436     desc.setSet(set);
437   }
438
439   if (IsInconsistentDescriptor(desc)) {
440     throw MakeTypeError("value_and_accessor", [obj]);
441   }
442   return desc;
443 }
444
445
446 // For Harmony proxies.
447 function ToCompletePropertyDescriptor(obj) {
448   var desc = ToPropertyDescriptor(obj);
449   if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
450     if (!desc.hasValue()) desc.setValue(UNDEFINED);
451     if (!desc.hasWritable()) desc.setWritable(false);
452   } else {
453     // Is accessor descriptor.
454     if (!desc.hasGetter()) desc.setGet(UNDEFINED);
455     if (!desc.hasSetter()) desc.setSet(UNDEFINED);
456   }
457   if (!desc.hasEnumerable()) desc.setEnumerable(false);
458   if (!desc.hasConfigurable()) desc.setConfigurable(false);
459   return desc;
460 }
461
462
463 function PropertyDescriptor() {
464   // Initialize here so they are all in-object and have the same map.
465   // Default values from ES5 8.6.1.
466   this.value_ = UNDEFINED;
467   this.hasValue_ = false;
468   this.writable_ = false;
469   this.hasWritable_ = false;
470   this.enumerable_ = false;
471   this.hasEnumerable_ = false;
472   this.configurable_ = false;
473   this.hasConfigurable_ = false;
474   this.get_ = UNDEFINED;
475   this.hasGetter_ = false;
476   this.set_ = UNDEFINED;
477   this.hasSetter_ = false;
478 }
479
480 SetUpLockedPrototype(PropertyDescriptor, $Array(
481     "value_",
482     "hasValue_",
483     "writable_",
484     "hasWritable_",
485     "enumerable_",
486     "hasEnumerable_",
487     "configurable_",
488     "hasConfigurable_",
489     "get_",
490     "hasGetter_",
491     "set_",
492     "hasSetter_"
493   ), $Array(
494     "toString", function PropertyDescriptor_ToString() {
495       return "[object PropertyDescriptor]";
496     },
497     "setValue", function PropertyDescriptor_SetValue(value) {
498       this.value_ = value;
499       this.hasValue_ = true;
500     },
501     "getValue", function PropertyDescriptor_GetValue() {
502       return this.value_;
503     },
504     "hasValue", function PropertyDescriptor_HasValue() {
505       return this.hasValue_;
506     },
507     "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) {
508       this.enumerable_ = enumerable;
509         this.hasEnumerable_ = true;
510     },
511     "isEnumerable", function PropertyDescriptor_IsEnumerable() {
512       return this.enumerable_;
513     },
514     "hasEnumerable", function PropertyDescriptor_HasEnumerable() {
515       return this.hasEnumerable_;
516     },
517     "setWritable", function PropertyDescriptor_SetWritable(writable) {
518       this.writable_ = writable;
519       this.hasWritable_ = true;
520     },
521     "isWritable", function PropertyDescriptor_IsWritable() {
522       return this.writable_;
523     },
524     "hasWritable", function PropertyDescriptor_HasWritable() {
525       return this.hasWritable_;
526     },
527     "setConfigurable",
528     function PropertyDescriptor_SetConfigurable(configurable) {
529       this.configurable_ = configurable;
530       this.hasConfigurable_ = true;
531     },
532     "hasConfigurable", function PropertyDescriptor_HasConfigurable() {
533       return this.hasConfigurable_;
534     },
535     "isConfigurable", function PropertyDescriptor_IsConfigurable() {
536       return this.configurable_;
537     },
538     "setGet", function PropertyDescriptor_SetGetter(get) {
539       this.get_ = get;
540       this.hasGetter_ = true;
541     },
542     "getGet", function PropertyDescriptor_GetGetter() {
543       return this.get_;
544     },
545     "hasGetter", function PropertyDescriptor_HasGetter() {
546       return this.hasGetter_;
547     },
548     "setSet", function PropertyDescriptor_SetSetter(set) {
549       this.set_ = set;
550       this.hasSetter_ = true;
551     },
552     "getSet", function PropertyDescriptor_GetSetter() {
553       return this.set_;
554     },
555     "hasSetter", function PropertyDescriptor_HasSetter() {
556       return this.hasSetter_;
557   }));
558
559
560 // Converts an array returned from Runtime_GetOwnProperty to an actual
561 // property descriptor. For a description of the array layout please
562 // see the runtime.cc file.
563 function ConvertDescriptorArrayToDescriptor(desc_array) {
564   if (IS_UNDEFINED(desc_array)) {
565     return UNDEFINED;
566   }
567
568   var desc = new PropertyDescriptor();
569   // This is an accessor.
570   if (desc_array[IS_ACCESSOR_INDEX]) {
571     desc.setGet(desc_array[GETTER_INDEX]);
572     desc.setSet(desc_array[SETTER_INDEX]);
573   } else {
574     desc.setValue(desc_array[VALUE_INDEX]);
575     desc.setWritable(desc_array[WRITABLE_INDEX]);
576   }
577   desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
578   desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
579
580   return desc;
581 }
582
583
584 // For Harmony proxies.
585 function GetTrap(handler, name, defaultTrap) {
586   var trap = handler[name];
587   if (IS_UNDEFINED(trap)) {
588     if (IS_UNDEFINED(defaultTrap)) {
589       throw MakeTypeError("handler_trap_missing", [handler, name]);
590     }
591     trap = defaultTrap;
592   } else if (!IS_SPEC_FUNCTION(trap)) {
593     throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
594   }
595   return trap;
596 }
597
598
599 function CallTrap0(handler, name, defaultTrap) {
600   return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
601 }
602
603
604 function CallTrap1(handler, name, defaultTrap, x) {
605   return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
606 }
607
608
609 function CallTrap2(handler, name, defaultTrap, x, y) {
610   return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
611 }
612
613
614 // ES5 section 8.12.1.
615 function GetOwnPropertyJS(obj, v) {
616   var p = ToName(v);
617   if (%_IsJSProxy(obj)) {
618     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
619     if (IS_SYMBOL(v)) return UNDEFINED;
620
621     var handler = %GetHandler(obj);
622     var descriptor = CallTrap1(
623                          handler, "getOwnPropertyDescriptor", UNDEFINED, p);
624     if (IS_UNDEFINED(descriptor)) return descriptor;
625     var desc = ToCompletePropertyDescriptor(descriptor);
626     if (!desc.isConfigurable()) {
627       throw MakeTypeError("proxy_prop_not_configurable",
628                           [handler, "getOwnPropertyDescriptor", p, descriptor]);
629     }
630     return desc;
631   }
632
633   // GetOwnProperty returns an array indexed by the constants
634   // defined in macros.py.
635   // If p is not a property on obj undefined is returned.
636   var props = %GetOwnProperty(ToObject(obj), p);
637
638   return ConvertDescriptorArrayToDescriptor(props);
639 }
640
641
642 // ES5 section 8.12.7.
643 function Delete(obj, p, should_throw) {
644   var desc = GetOwnPropertyJS(obj, p);
645   if (IS_UNDEFINED(desc)) return true;
646   if (desc.isConfigurable()) {
647     %DeleteProperty(obj, p, 0);
648     return true;
649   } else if (should_throw) {
650     throw MakeTypeError("define_disallowed", [p]);
651   } else {
652     return;
653   }
654 }
655
656
657 // Harmony proxies.
658 function DefineProxyProperty(obj, p, attributes, should_throw) {
659   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
660   if (IS_SYMBOL(p)) return false;
661
662   var handler = %GetHandler(obj);
663   var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
664   if (!ToBoolean(result)) {
665     if (should_throw) {
666       throw MakeTypeError("handler_returned_false",
667                           [handler, "defineProperty"]);
668     } else {
669       return false;
670     }
671   }
672   return true;
673 }
674
675
676 // ES5 8.12.9.
677 function DefineObjectProperty(obj, p, desc, should_throw) {
678   var current_array = %GetOwnProperty(ToObject(obj), ToName(p));
679   var current = ConvertDescriptorArrayToDescriptor(current_array);
680   var extensible = %IsExtensible(ToObject(obj));
681
682   // Error handling according to spec.
683   // Step 3
684   if (IS_UNDEFINED(current) && !extensible) {
685     if (should_throw) {
686       throw MakeTypeError("define_disallowed", [p]);
687     } else {
688       return false;
689     }
690   }
691
692   if (!IS_UNDEFINED(current)) {
693     // Step 5 and 6
694     if ((IsGenericDescriptor(desc) ||
695          IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
696         (!desc.hasEnumerable() ||
697          SameValue(desc.isEnumerable(), current.isEnumerable())) &&
698         (!desc.hasConfigurable() ||
699          SameValue(desc.isConfigurable(), current.isConfigurable())) &&
700         (!desc.hasWritable() ||
701          SameValue(desc.isWritable(), current.isWritable())) &&
702         (!desc.hasValue() ||
703          SameValue(desc.getValue(), current.getValue())) &&
704         (!desc.hasGetter() ||
705          SameValue(desc.getGet(), current.getGet())) &&
706         (!desc.hasSetter() ||
707          SameValue(desc.getSet(), current.getSet()))) {
708       return true;
709     }
710     if (!current.isConfigurable()) {
711       // Step 7
712       if (desc.isConfigurable() ||
713           (desc.hasEnumerable() &&
714            desc.isEnumerable() != current.isEnumerable())) {
715         if (should_throw) {
716           throw MakeTypeError("redefine_disallowed", [p]);
717         } else {
718           return false;
719         }
720       }
721       // Step 8
722       if (!IsGenericDescriptor(desc)) {
723         // Step 9a
724         if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
725           if (should_throw) {
726             throw MakeTypeError("redefine_disallowed", [p]);
727           } else {
728             return false;
729           }
730         }
731         // Step 10a
732         if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
733           if (!current.isWritable() && desc.isWritable()) {
734             if (should_throw) {
735               throw MakeTypeError("redefine_disallowed", [p]);
736             } else {
737               return false;
738             }
739           }
740           if (!current.isWritable() && desc.hasValue() &&
741               !SameValue(desc.getValue(), current.getValue())) {
742             if (should_throw) {
743               throw MakeTypeError("redefine_disallowed", [p]);
744             } else {
745               return false;
746             }
747           }
748         }
749         // Step 11
750         if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
751           if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
752             if (should_throw) {
753               throw MakeTypeError("redefine_disallowed", [p]);
754             } else {
755               return false;
756             }
757           }
758           if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
759             if (should_throw) {
760               throw MakeTypeError("redefine_disallowed", [p]);
761             } else {
762               return false;
763             }
764           }
765         }
766       }
767     }
768   }
769
770   // Send flags - enumerable and configurable are common - writable is
771   // only send to the data descriptor.
772   // Take special care if enumerable and configurable is not defined on
773   // desc (we need to preserve the existing values from current).
774   var flag = NONE;
775   if (desc.hasEnumerable()) {
776     flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
777   } else if (!IS_UNDEFINED(current)) {
778     flag |= current.isEnumerable() ? 0 : DONT_ENUM;
779   } else {
780     flag |= DONT_ENUM;
781   }
782
783   if (desc.hasConfigurable()) {
784     flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
785   } else if (!IS_UNDEFINED(current)) {
786     flag |= current.isConfigurable() ? 0 : DONT_DELETE;
787   } else
788     flag |= DONT_DELETE;
789
790   if (IsDataDescriptor(desc) ||
791       (IsGenericDescriptor(desc) &&
792        (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
793     // There are 3 cases that lead here:
794     // Step 4a - defining a new data property.
795     // Steps 9b & 12 - replacing an existing accessor property with a data
796     //                 property.
797     // Step 12 - updating an existing data property with a data or generic
798     //           descriptor.
799
800     if (desc.hasWritable()) {
801       flag |= desc.isWritable() ? 0 : READ_ONLY;
802     } else if (!IS_UNDEFINED(current)) {
803       flag |= current.isWritable() ? 0 : READ_ONLY;
804     } else {
805       flag |= READ_ONLY;
806     }
807
808     var value = UNDEFINED;  // Default value is undefined.
809     if (desc.hasValue()) {
810       value = desc.getValue();
811     } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
812       value = current.getValue();
813     }
814
815     %DefineDataPropertyUnchecked(obj, p, value, flag);
816   } else {
817     // There are 3 cases that lead here:
818     // Step 4b - defining a new accessor property.
819     // Steps 9c & 12 - replacing an existing data property with an accessor
820     //                 property.
821     // Step 12 - updating an existing accessor property with an accessor
822     //           descriptor.
823     var getter = null;
824     if (desc.hasGetter()) {
825       getter = desc.getGet();
826     } else if (IsAccessorDescriptor(current) && current.hasGetter()) {
827       getter = current.getGet();
828     }
829     var setter = null;
830     if (desc.hasSetter()) {
831       setter = desc.getSet();
832     } else if (IsAccessorDescriptor(current) && current.hasSetter()) {
833       setter = current.getSet();
834     }
835     %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag);
836   }
837   return true;
838 }
839
840
841 // ES5 section 15.4.5.1.
842 function DefineArrayProperty(obj, p, desc, should_throw) {
843   // Note that the length of an array is not actually stored as part of the
844   // property, hence we use generated code throughout this function instead of
845   // DefineObjectProperty() to modify its value.
846
847   // Step 3 - Special handling for length property.
848   if (p === "length") {
849     var length = obj.length;
850     var old_length = length;
851     if (!desc.hasValue()) {
852       return DefineObjectProperty(obj, "length", desc, should_throw);
853     }
854     var new_length = ToUint32(desc.getValue());
855     if (new_length != ToNumber(desc.getValue())) {
856       throw new $RangeError('defineProperty() array length out of range');
857     }
858     var length_desc = GetOwnPropertyJS(obj, "length");
859     if (new_length != length && !length_desc.isWritable()) {
860       if (should_throw) {
861         throw MakeTypeError("redefine_disallowed", [p]);
862       } else {
863         return false;
864       }
865     }
866     var threw = false;
867
868     var emit_splice = %IsObserved(obj) && new_length !== old_length;
869     var removed;
870     if (emit_splice) {
871       BeginPerformSplice(obj);
872       removed = [];
873       if (new_length < old_length)
874         removed.length = old_length - new_length;
875     }
876
877     while (new_length < length--) {
878       var index = ToString(length);
879       if (emit_splice) {
880         var deletedDesc = GetOwnPropertyJS(obj, index);
881         if (deletedDesc && deletedDesc.hasValue())
882           removed[length - new_length] = deletedDesc.getValue();
883       }
884       if (!Delete(obj, index, false)) {
885         new_length = length + 1;
886         threw = true;
887         break;
888       }
889     }
890     threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
891     if (emit_splice) {
892       EndPerformSplice(obj);
893       EnqueueSpliceRecord(obj,
894           new_length < old_length ? new_length : old_length,
895           removed,
896           new_length > old_length ? new_length - old_length : 0);
897     }
898     if (threw) {
899       if (should_throw) {
900         throw MakeTypeError("redefine_disallowed", [p]);
901       } else {
902         return false;
903       }
904     }
905     return true;
906   }
907
908   // Step 4 - Special handling for array index.
909   if (!IS_SYMBOL(p)) {
910     var index = ToUint32(p);
911     var emit_splice = false;
912     if (ToString(index) == p && index != 4294967295) {
913       var length = obj.length;
914       if (index >= length && %IsObserved(obj)) {
915         emit_splice = true;
916         BeginPerformSplice(obj);
917       }
918
919       var length_desc = GetOwnPropertyJS(obj, "length");
920       if ((index >= length && !length_desc.isWritable()) ||
921           !DefineObjectProperty(obj, p, desc, true)) {
922         if (emit_splice)
923           EndPerformSplice(obj);
924         if (should_throw) {
925           throw MakeTypeError("define_disallowed", [p]);
926         } else {
927           return false;
928         }
929       }
930       if (index >= length) {
931         obj.length = index + 1;
932       }
933       if (emit_splice) {
934         EndPerformSplice(obj);
935         EnqueueSpliceRecord(obj, length, [], index + 1 - length);
936       }
937       return true;
938     }
939   }
940
941   // Step 5 - Fallback to default implementation.
942   return DefineObjectProperty(obj, p, desc, should_throw);
943 }
944
945
946 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
947 function DefineOwnProperty(obj, p, desc, should_throw) {
948   if (%_IsJSProxy(obj)) {
949     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
950     if (IS_SYMBOL(p)) return false;
951
952     var attributes = FromGenericPropertyDescriptor(desc);
953     return DefineProxyProperty(obj, p, attributes, should_throw);
954   } else if (IS_ARRAY(obj)) {
955     return DefineArrayProperty(obj, p, desc, should_throw);
956   } else {
957     return DefineObjectProperty(obj, p, desc, should_throw);
958   }
959 }
960
961
962 // ES5 section 15.2.3.2.
963 function ObjectGetPrototypeOf(obj) {
964   if (!IS_SPEC_OBJECT(obj)) {
965     throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
966   }
967   return %_GetPrototype(obj);
968 }
969
970 // ES6 section 19.1.2.19.
971 function ObjectSetPrototypeOf(obj, proto) {
972   CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
973
974   if (proto !== null && !IS_SPEC_OBJECT(proto)) {
975     throw MakeTypeError("proto_object_or_null", [proto]);
976   }
977
978   if (IS_SPEC_OBJECT(obj)) {
979     %SetPrototype(obj, proto);
980   }
981
982   return obj;
983 }
984
985
986 // ES5 section 15.2.3.3
987 function ObjectGetOwnPropertyDescriptor(obj, p) {
988   if (!IS_SPEC_OBJECT(obj)) {
989     throw MakeTypeError("called_on_non_object",
990                         ["Object.getOwnPropertyDescriptor"]);
991   }
992   var desc = GetOwnPropertyJS(obj, p);
993   return FromPropertyDescriptor(desc);
994 }
995
996
997 // For Harmony proxies
998 function ToNameArray(obj, trap, includeSymbols) {
999   if (!IS_SPEC_OBJECT(obj)) {
1000     throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1001   }
1002   var n = ToUint32(obj.length);
1003   var array = new $Array(n);
1004   var realLength = 0;
1005   var names = { __proto__: null };  // TODO(rossberg): use sets once ready.
1006   for (var index = 0; index < n; index++) {
1007     var s = ToName(obj[index]);
1008     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1009     if (IS_SYMBOL(s) && !includeSymbols) continue;
1010     if (%HasOwnProperty(names, s)) {
1011       throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1012     }
1013     array[index] = s;
1014     ++realLength;
1015     names[s] = 0;
1016   }
1017   array.length = realLength;
1018   return array;
1019 }
1020
1021
1022 function ObjectGetOwnPropertyKeys(obj, filter) {
1023   var nameArrays = new InternalArray();
1024   filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1025   var interceptorInfo = %GetInterceptorInfo(obj);
1026
1027   // Find all the indexed properties.
1028
1029   // Only get own element names if we want to include string keys.
1030   if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
1031     var ownElementNames = %GetOwnElementNames(obj);
1032     for (var i = 0; i < ownElementNames.length; ++i) {
1033       ownElementNames[i] = %_NumberToString(ownElementNames[i]);
1034     }
1035     nameArrays.push(ownElementNames);
1036     // Get names for indexed interceptor properties.
1037     if ((interceptorInfo & 1) != 0) {
1038       var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1039       if (!IS_UNDEFINED(indexedInterceptorNames)) {
1040         nameArrays.push(indexedInterceptorNames);
1041       }
1042     }
1043   }
1044
1045   // Find all the named properties.
1046
1047   // Get own property names.
1048   nameArrays.push(%GetOwnPropertyNames(obj, filter));
1049
1050   // Get names for named interceptor properties if any.
1051   if ((interceptorInfo & 2) != 0) {
1052     var namedInterceptorNames =
1053         %GetNamedInterceptorPropertyNames(obj);
1054     if (!IS_UNDEFINED(namedInterceptorNames)) {
1055       nameArrays.push(namedInterceptorNames);
1056     }
1057   }
1058
1059   var propertyNames =
1060       %Apply(InternalArray.prototype.concat,
1061              nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1062
1063   // Property names are expected to be unique strings,
1064   // but interceptors can interfere with that assumption.
1065   if (interceptorInfo != 0) {
1066     var seenKeys = { __proto__: null };
1067     var j = 0;
1068     for (var i = 0; i < propertyNames.length; ++i) {
1069       var name = propertyNames[i];
1070       if (IS_SYMBOL(name)) {
1071         if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
1072           continue;
1073         }
1074       } else {
1075         if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
1076         name = ToString(name);
1077       }
1078       if (seenKeys[name]) continue;
1079       seenKeys[name] = true;
1080       propertyNames[j++] = name;
1081     }
1082     propertyNames.length = j;
1083   }
1084
1085   return propertyNames;
1086 }
1087
1088
1089 // ES5 section 15.2.3.4.
1090 function ObjectGetOwnPropertyNames(obj) {
1091   obj = ToObject(obj);
1092   // Special handling for proxies.
1093   if (%_IsJSProxy(obj)) {
1094     var handler = %GetHandler(obj);
1095     var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1096     return ToNameArray(names, "getOwnPropertyNames", false);
1097   }
1098
1099   return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
1100 }
1101
1102
1103 // ES5 section 15.2.3.5.
1104 function ObjectCreate(proto, properties) {
1105   if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1106     throw MakeTypeError("proto_object_or_null", [proto]);
1107   }
1108   var obj = {};
1109   %InternalSetPrototype(obj, proto);
1110   if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1111   return obj;
1112 }
1113
1114
1115 // ES5 section 15.2.3.6.
1116 function ObjectDefineProperty(obj, p, attributes) {
1117   if (!IS_SPEC_OBJECT(obj)) {
1118     throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1119   }
1120   var name = ToName(p);
1121   if (%_IsJSProxy(obj)) {
1122     // Clone the attributes object for protection.
1123     // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1124     // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1125     var attributesClone = { __proto__: null };
1126     for (var a in attributes) {
1127       attributesClone[a] = attributes[a];
1128     }
1129     DefineProxyProperty(obj, name, attributesClone, true);
1130     // The following would implement the spec as in the current proposal,
1131     // but after recent comments on es-discuss, is most likely obsolete.
1132     /*
1133     var defineObj = FromGenericPropertyDescriptor(desc);
1134     var names = ObjectGetOwnPropertyNames(attributes);
1135     var standardNames =
1136       {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1137     for (var i = 0; i < names.length; i++) {
1138       var N = names[i];
1139       if (!(%HasOwnProperty(standardNames, N))) {
1140         var attr = GetOwnPropertyJS(attributes, N);
1141         DefineOwnProperty(descObj, N, attr, true);
1142       }
1143     }
1144     // This is really confusing the types, but it is what the proxies spec
1145     // currently requires:
1146     desc = descObj;
1147     */
1148   } else {
1149     var desc = ToPropertyDescriptor(attributes);
1150     DefineOwnProperty(obj, name, desc, true);
1151   }
1152   return obj;
1153 }
1154
1155
1156 function GetOwnEnumerablePropertyNames(object) {
1157   var names = new InternalArray();
1158   for (var key in object) {
1159     if (%HasOwnProperty(object, key)) {
1160       names.push(key);
1161     }
1162   }
1163
1164   var filter = PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
1165   var symbols = %GetOwnPropertyNames(object, filter);
1166   for (var i = 0; i < symbols.length; ++i) {
1167     var symbol = symbols[i];
1168     if (IS_SYMBOL(symbol)) {
1169       var desc = ObjectGetOwnPropertyDescriptor(object, symbol);
1170       if (desc.enumerable) names.push(symbol);
1171     }
1172   }
1173
1174   return names;
1175 }
1176
1177
1178 // ES5 section 15.2.3.7.
1179 function ObjectDefineProperties(obj, properties) {
1180   if (!IS_SPEC_OBJECT(obj)) {
1181     throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1182   }
1183   var props = ToObject(properties);
1184   var names = GetOwnEnumerablePropertyNames(props);
1185   var descriptors = new InternalArray();
1186   for (var i = 0; i < names.length; i++) {
1187     descriptors.push(ToPropertyDescriptor(props[names[i]]));
1188   }
1189   for (var i = 0; i < names.length; i++) {
1190     DefineOwnProperty(obj, names[i], descriptors[i], true);
1191   }
1192   return obj;
1193 }
1194
1195
1196 // Harmony proxies.
1197 function ProxyFix(obj) {
1198   var handler = %GetHandler(obj);
1199   var props = CallTrap0(handler, "fix", UNDEFINED);
1200   if (IS_UNDEFINED(props)) {
1201     throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1202   }
1203
1204   if (%IsJSFunctionProxy(obj)) {
1205     var callTrap = %GetCallTrap(obj);
1206     var constructTrap = %GetConstructTrap(obj);
1207     var code = DelegateCallAndConstruct(callTrap, constructTrap);
1208     %Fix(obj);  // becomes a regular function
1209     %SetCode(obj, code);
1210     // TODO(rossberg): What about length and other properties? Not specified.
1211     // We just put in some half-reasonable defaults for now.
1212     var prototype = new $Object();
1213     $Object.defineProperty(prototype, "constructor",
1214       {value: obj, writable: true, enumerable: false, configurable: true});
1215     // TODO(v8:1530): defineProperty does not handle prototype and length.
1216     %FunctionSetPrototype(obj, prototype);
1217     obj.length = 0;
1218   } else {
1219     %Fix(obj);
1220   }
1221   ObjectDefineProperties(obj, props);
1222 }
1223
1224
1225 // ES5 section 15.2.3.8.
1226 function ObjectSealJS(obj) {
1227   if (!IS_SPEC_OBJECT(obj)) {
1228     throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1229   }
1230   var isProxy = %_IsJSProxy(obj);
1231   if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1232     if (isProxy) {
1233       ProxyFix(obj);
1234     }
1235     var names = ObjectGetOwnPropertyNames(obj);
1236     for (var i = 0; i < names.length; i++) {
1237       var name = names[i];
1238       var desc = GetOwnPropertyJS(obj, name);
1239       if (desc.isConfigurable()) {
1240         desc.setConfigurable(false);
1241         DefineOwnProperty(obj, name, desc, true);
1242       }
1243     }
1244     %PreventExtensions(obj);
1245   } else {
1246     // TODO(adamk): Is it worth going to this fast path if the
1247     // object's properties are already in dictionary mode?
1248     %ObjectSeal(obj);
1249   }
1250   return obj;
1251 }
1252
1253
1254 // ES5 section 15.2.3.9.
1255 function ObjectFreezeJS(obj) {
1256   if (!IS_SPEC_OBJECT(obj)) {
1257     throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1258   }
1259   var isProxy = %_IsJSProxy(obj);
1260   if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
1261     if (isProxy) {
1262       ProxyFix(obj);
1263     }
1264     var names = ObjectGetOwnPropertyNames(obj);
1265     for (var i = 0; i < names.length; i++) {
1266       var name = names[i];
1267       var desc = GetOwnPropertyJS(obj, name);
1268       if (desc.isWritable() || desc.isConfigurable()) {
1269         if (IsDataDescriptor(desc)) desc.setWritable(false);
1270         desc.setConfigurable(false);
1271         DefineOwnProperty(obj, name, desc, true);
1272       }
1273     }
1274     %PreventExtensions(obj);
1275   } else {
1276     // TODO(adamk): Is it worth going to this fast path if the
1277     // object's properties are already in dictionary mode?
1278     %ObjectFreeze(obj);
1279   }
1280   return obj;
1281 }
1282
1283
1284 // ES5 section 15.2.3.10
1285 function ObjectPreventExtension(obj) {
1286   if (!IS_SPEC_OBJECT(obj)) {
1287     throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1288   }
1289   if (%_IsJSProxy(obj)) {
1290     ProxyFix(obj);
1291   }
1292   %PreventExtensions(obj);
1293   return obj;
1294 }
1295
1296
1297 // ES5 section 15.2.3.11
1298 function ObjectIsSealed(obj) {
1299   if (!IS_SPEC_OBJECT(obj)) {
1300     throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1301   }
1302   if (%_IsJSProxy(obj)) {
1303     return false;
1304   }
1305   if (%IsExtensible(obj)) {
1306     return false;
1307   }
1308   var names = ObjectGetOwnPropertyNames(obj);
1309   for (var i = 0; i < names.length; i++) {
1310     var name = names[i];
1311     var desc = GetOwnPropertyJS(obj, name);
1312     if (desc.isConfigurable()) {
1313       return false;
1314     }
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 = GetOwnPropertyJS(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 // ECMA-262, Edition 6, section 19.1.2.10
1355 function ObjectIs(obj1, obj2) {
1356   return SameValue(obj1, obj2);
1357 }
1358
1359
1360 // ECMA-262, Edition 6, section B.2.2.1.1
1361 function ObjectGetProto() {
1362   return %_GetPrototype(ToObject(this));
1363 }
1364
1365
1366 // ECMA-262, Edition 6, section B.2.2.1.2
1367 function ObjectSetProto(proto) {
1368   CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__");
1369
1370   if ((IS_SPEC_OBJECT(proto) || IS_NULL(proto)) && IS_SPEC_OBJECT(this)) {
1371     %SetPrototype(this, proto);
1372   }
1373 }
1374
1375
1376 function ObjectConstructor(x) {
1377   if (%_IsConstructCall()) {
1378     if (x == null) return this;
1379     return ToObject(x);
1380   } else {
1381     if (x == null) return { };
1382     return ToObject(x);
1383   }
1384 }
1385
1386
1387 // ----------------------------------------------------------------------------
1388 // Object
1389
1390 function SetUpObject() {
1391   %CheckIsBootstrapping();
1392
1393   %SetNativeFlag($Object);
1394   %SetCode($Object, ObjectConstructor);
1395
1396   %AddNamedProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1397
1398   // Set up non-enumerable functions on the Object.prototype object.
1399   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1400     "toString", NoSideEffectsObjectToString,
1401     "toLocaleString", ObjectToLocaleString,
1402     "valueOf", ObjectValueOf,
1403     "hasOwnProperty", ObjectHasOwnProperty,
1404     "isPrototypeOf", ObjectIsPrototypeOf,
1405     "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1406     "__defineGetter__", ObjectDefineGetter,
1407     "__lookupGetter__", ObjectLookupGetter,
1408     "__defineSetter__", ObjectDefineSetter,
1409     "__lookupSetter__", ObjectLookupSetter
1410   ));
1411   InstallGetterSetter($Object.prototype, "__proto__",
1412                       ObjectGetProto, ObjectSetProto);
1413
1414   // Set up non-enumerable functions in the Object object.
1415   InstallFunctions($Object, DONT_ENUM, $Array(
1416     "keys", ObjectKeys,
1417     "create", ObjectCreate,
1418     "defineProperty", ObjectDefineProperty,
1419     "defineProperties", ObjectDefineProperties,
1420     "freeze", ObjectFreezeJS,
1421     "getPrototypeOf", ObjectGetPrototypeOf,
1422     "setPrototypeOf", ObjectSetPrototypeOf,
1423     "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1424     "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1425     // getOwnPropertySymbols is added in symbol.js.
1426     "is", ObjectIs,
1427     "isExtensible", ObjectIsExtensible,
1428     "isFrozen", ObjectIsFrozen,
1429     "isSealed", ObjectIsSealed,
1430     "preventExtensions", ObjectPreventExtension,
1431     "seal", ObjectSealJS
1432     // deliverChangeRecords, getNotifier, observe and unobserve are added
1433     // in object-observe.js.
1434   ));
1435 }
1436
1437 SetUpObject();
1438
1439
1440 // ----------------------------------------------------------------------------
1441 // Boolean
1442
1443 function BooleanConstructor(x) {
1444   if (%_IsConstructCall()) {
1445     %_SetValueOf(this, ToBoolean(x));
1446   } else {
1447     return ToBoolean(x);
1448   }
1449 }
1450
1451
1452 function BooleanToString() {
1453   // NOTE: Both Boolean objects and values can enter here as
1454   // 'this'. This is not as dictated by ECMA-262.
1455   var b = this;
1456   if (!IS_BOOLEAN(b)) {
1457     if (!IS_BOOLEAN_WRAPPER(b)) {
1458       throw new $TypeError('Boolean.prototype.toString is not generic');
1459     }
1460     b = %_ValueOf(b);
1461   }
1462   return b ? 'true' : 'false';
1463 }
1464
1465
1466 function BooleanValueOf() {
1467   // NOTE: Both Boolean objects and values can enter here as
1468   // 'this'. This is not as dictated by ECMA-262.
1469   if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1470     throw new $TypeError('Boolean.prototype.valueOf is not generic');
1471   }
1472   return %_ValueOf(this);
1473 }
1474
1475
1476 // ----------------------------------------------------------------------------
1477
1478 function SetUpBoolean () {
1479   %CheckIsBootstrapping();
1480
1481   %SetCode($Boolean, BooleanConstructor);
1482   %FunctionSetPrototype($Boolean, new $Boolean(false));
1483   %AddNamedProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1484
1485   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1486     "toString", BooleanToString,
1487     "valueOf", BooleanValueOf
1488   ));
1489 }
1490
1491 SetUpBoolean();
1492
1493
1494 // ----------------------------------------------------------------------------
1495 // Number
1496
1497 function NumberConstructor(x) {
1498   var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1499   if (%_IsConstructCall()) {
1500     %_SetValueOf(this, value);
1501   } else {
1502     return value;
1503   }
1504 }
1505
1506
1507 // ECMA-262 section 15.7.4.2.
1508 function NumberToString(radix) {
1509   // NOTE: Both Number objects and values can enter here as
1510   // 'this'. This is not as dictated by ECMA-262.
1511   var number = this;
1512   if (!IS_NUMBER(this)) {
1513     if (!IS_NUMBER_WRAPPER(this)) {
1514       throw new $TypeError('Number.prototype.toString is not generic');
1515     }
1516     // Get the value of this number in case it's an object.
1517     number = %_ValueOf(this);
1518   }
1519   // Fast case: Convert number in radix 10.
1520   if (IS_UNDEFINED(radix) || radix === 10) {
1521     return %_NumberToString(number);
1522   }
1523
1524   // Convert the radix to an integer and check the range.
1525   radix = TO_INTEGER(radix);
1526   if (radix < 2 || radix > 36) {
1527     throw new $RangeError('toString() radix argument must be between 2 and 36');
1528   }
1529   // Convert the number to a string in the given radix.
1530   return %NumberToRadixString(number, radix);
1531 }
1532
1533
1534 // ECMA-262 section 15.7.4.3
1535 function NumberToLocaleString() {
1536   return %_CallFunction(this, NumberToString);
1537 }
1538
1539
1540 // ECMA-262 section 15.7.4.4
1541 function NumberValueOf() {
1542   // NOTE: Both Number objects and values can enter here as
1543   // 'this'. This is not as dictated by ECMA-262.
1544   if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1545     throw new $TypeError('Number.prototype.valueOf is not generic');
1546   }
1547   return %_ValueOf(this);
1548 }
1549
1550
1551 // ECMA-262 section 15.7.4.5
1552 function NumberToFixedJS(fractionDigits) {
1553   var x = this;
1554   if (!IS_NUMBER(this)) {
1555     if (!IS_NUMBER_WRAPPER(this)) {
1556       throw MakeTypeError("incompatible_method_receiver",
1557                           ["Number.prototype.toFixed", this]);
1558     }
1559     // Get the value of this number in case it's an object.
1560     x = %_ValueOf(this);
1561   }
1562   var f = TO_INTEGER(fractionDigits);
1563
1564   if (f < 0 || f > 20) {
1565     throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1566   }
1567
1568   if (NUMBER_IS_NAN(x)) return "NaN";
1569   if (x == INFINITY) return "Infinity";
1570   if (x == -INFINITY) return "-Infinity";
1571
1572   return %NumberToFixed(x, f);
1573 }
1574
1575
1576 // ECMA-262 section 15.7.4.6
1577 function NumberToExponentialJS(fractionDigits) {
1578   var x = this;
1579   if (!IS_NUMBER(this)) {
1580     if (!IS_NUMBER_WRAPPER(this)) {
1581       throw MakeTypeError("incompatible_method_receiver",
1582                           ["Number.prototype.toExponential", this]);
1583     }
1584     // Get the value of this number in case it's an object.
1585     x = %_ValueOf(this);
1586   }
1587   var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1588
1589   if (NUMBER_IS_NAN(x)) return "NaN";
1590   if (x == INFINITY) return "Infinity";
1591   if (x == -INFINITY) return "-Infinity";
1592
1593   if (IS_UNDEFINED(f)) {
1594     f = -1;  // Signal for runtime function that f is not defined.
1595   } else if (f < 0 || f > 20) {
1596     throw new $RangeError("toExponential() argument must be between 0 and 20");
1597   }
1598   return %NumberToExponential(x, f);
1599 }
1600
1601
1602 // ECMA-262 section 15.7.4.7
1603 function NumberToPrecisionJS(precision) {
1604   var x = this;
1605   if (!IS_NUMBER(this)) {
1606     if (!IS_NUMBER_WRAPPER(this)) {
1607       throw MakeTypeError("incompatible_method_receiver",
1608                           ["Number.prototype.toPrecision", this]);
1609     }
1610     // Get the value of this number in case it's an object.
1611     x = %_ValueOf(this);
1612   }
1613   if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1614   var p = TO_INTEGER(precision);
1615
1616   if (NUMBER_IS_NAN(x)) return "NaN";
1617   if (x == INFINITY) return "Infinity";
1618   if (x == -INFINITY) return "-Infinity";
1619
1620   if (p < 1 || p > 21) {
1621     throw new $RangeError("toPrecision() argument must be between 1 and 21");
1622   }
1623   return %NumberToPrecision(x, p);
1624 }
1625
1626
1627 // Harmony isFinite.
1628 function NumberIsFinite(number) {
1629   return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1630 }
1631
1632
1633 // Harmony isInteger
1634 function NumberIsInteger(number) {
1635   return NumberIsFinite(number) && TO_INTEGER(number) == number;
1636 }
1637
1638
1639 // Harmony isNaN.
1640 function NumberIsNaN(number) {
1641   return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1642 }
1643
1644
1645 // Harmony isSafeInteger
1646 function NumberIsSafeInteger(number) {
1647   if (NumberIsFinite(number)) {
1648     var integral = TO_INTEGER(number);
1649     if (integral == number)
1650       return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
1651   }
1652   return false;
1653 }
1654
1655
1656 // ----------------------------------------------------------------------------
1657
1658 function SetUpNumber() {
1659   %CheckIsBootstrapping();
1660
1661   %SetCode($Number, NumberConstructor);
1662   %FunctionSetPrototype($Number, new $Number(0));
1663
1664   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1665   // Set up the constructor property on the Number prototype object.
1666   %AddNamedProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1667
1668   InstallConstants($Number, $Array(
1669       // ECMA-262 section 15.7.3.1.
1670       "MAX_VALUE", 1.7976931348623157e+308,
1671       // ECMA-262 section 15.7.3.2.
1672       "MIN_VALUE", 5e-324,
1673       // ECMA-262 section 15.7.3.3.
1674       "NaN", NAN,
1675       // ECMA-262 section 15.7.3.4.
1676       "NEGATIVE_INFINITY", -INFINITY,
1677       // ECMA-262 section 15.7.3.5.
1678       "POSITIVE_INFINITY", INFINITY,
1679
1680       // --- Harmony constants (no spec refs until settled.)
1681
1682       "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
1683       "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
1684       "EPSILON", %_MathPow(2, -52)
1685   ));
1686
1687   // Set up non-enumerable functions on the Number prototype object.
1688   InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1689     "toString", NumberToString,
1690     "toLocaleString", NumberToLocaleString,
1691     "valueOf", NumberValueOf,
1692     "toFixed", NumberToFixedJS,
1693     "toExponential", NumberToExponentialJS,
1694     "toPrecision", NumberToPrecisionJS
1695   ));
1696
1697   // Harmony Number constructor additions
1698   InstallFunctions($Number, DONT_ENUM, $Array(
1699     "isFinite", NumberIsFinite,
1700     "isInteger", NumberIsInteger,
1701     "isNaN", NumberIsNaN,
1702     "isSafeInteger", NumberIsSafeInteger,
1703     "parseInt", GlobalParseInt,
1704     "parseFloat", GlobalParseFloat
1705   ));
1706 }
1707
1708 SetUpNumber();
1709
1710
1711 // ----------------------------------------------------------------------------
1712 // Function
1713
1714 function FunctionSourceString(func) {
1715   while (%IsJSFunctionProxy(func)) {
1716     func = %GetCallTrap(func);
1717   }
1718
1719   if (!IS_FUNCTION(func)) {
1720     throw new $TypeError('Function.prototype.toString is not generic');
1721   }
1722
1723   var classSource = %ClassGetSourceCode(func);
1724   if (IS_STRING(classSource)) {
1725     return classSource;
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   if (%FunctionIsArrow(func)) {
1740     return source;
1741   }
1742
1743   var name = %FunctionNameShouldPrintAsAnonymous(func)
1744       ? 'anonymous'
1745       : %FunctionGetName(func);
1746
1747   var isGenerator = %FunctionIsGenerator(func);
1748   var head = %FunctionIsConciseMethod(func)
1749       ? (isGenerator ? '*' : '')
1750       : (isGenerator ? 'function* ' : 'function ');
1751   return head + name + source;
1752 }
1753
1754
1755 function FunctionToString() {
1756   return FunctionSourceString(this);
1757 }
1758
1759
1760 // ES5 15.3.4.5
1761 function FunctionBind(this_arg) { // Length is 1.
1762   if (!IS_SPEC_FUNCTION(this)) {
1763     throw new $TypeError('Bind must be called on a function');
1764   }
1765   var boundFunction = function () {
1766     // Poison .arguments and .caller, but is otherwise not detectable.
1767     "use strict";
1768     // This function must not use any object literals (Object, Array, RegExp),
1769     // since the literals-array is being used to store the bound data.
1770     if (%_IsConstructCall()) {
1771       return %NewObjectFromBound(boundFunction);
1772     }
1773     var bindings = %BoundFunctionGetBindings(boundFunction);
1774
1775     var argc = %_ArgumentsLength();
1776     if (argc == 0) {
1777       return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1778     }
1779     if (bindings.length === 2) {
1780       return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1781     }
1782     var bound_argc = bindings.length - 2;
1783     var argv = new InternalArray(bound_argc + argc);
1784     for (var i = 0; i < bound_argc; i++) {
1785       argv[i] = bindings[i + 2];
1786     }
1787     for (var j = 0; j < argc; j++) {
1788       argv[i++] = %_Arguments(j);
1789     }
1790     return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1791   };
1792
1793   var new_length = 0;
1794   var old_length = this.length;
1795   // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1796   if ((typeof old_length === "number") &&
1797       ((old_length >>> 0) === old_length)) {
1798     var argc = %_ArgumentsLength();
1799     if (argc > 0) argc--;  // Don't count the thisArg as parameter.
1800     new_length = old_length - argc;
1801     if (new_length < 0) new_length = 0;
1802   }
1803   // This runtime function finds any remaining arguments on the stack,
1804   // so we don't pass the arguments object.
1805   var result = %FunctionBindArguments(boundFunction, this,
1806                                       this_arg, new_length);
1807
1808   // We already have caller and arguments properties on functions,
1809   // which are non-configurable. It therefore makes no sence to
1810   // try to redefine these as defined by the spec. The spec says
1811   // that bind should make these throw a TypeError if get or set
1812   // is called and make them non-enumerable and non-configurable.
1813   // To be consistent with our normal functions we leave this as it is.
1814   // TODO(lrn): Do set these to be thrower.
1815   return result;
1816 }
1817
1818
1819 function NewFunctionFromString(arguments, function_token) {
1820   var n = arguments.length;
1821   var p = '';
1822   if (n > 1) {
1823     p = ToString(arguments[0]);
1824     for (var i = 1; i < n - 1; i++) {
1825       p += ',' + ToString(arguments[i]);
1826     }
1827     // If the formal parameters string include ) - an illegal
1828     // character - it may make the combined function expression
1829     // compile. We avoid this problem by checking for this early on.
1830     if (%_CallFunction(p, ')', StringIndexOfJS) != -1) {
1831       throw MakeSyntaxError('paren_in_arg_string', []);
1832     }
1833     // If the formal parameters include an unbalanced block comment, the
1834     // function must be rejected. Since JavaScript does not allow nested
1835     // comments we can include a trailing block comment to catch this.
1836     p += '\n\x2f**\x2f';
1837   }
1838   var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1839   var head = '(' + function_token + '(' + p + ') {\n';
1840   var src = head + body + '\n})';
1841   var global_proxy = %GlobalProxy(global);
1842   var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
1843   %FunctionMarkNameShouldPrintAsAnonymous(f);
1844   return f;
1845 }
1846
1847
1848 function FunctionConstructor(arg1) {  // length == 1
1849   return NewFunctionFromString(arguments, 'function');
1850 }
1851
1852
1853 // ----------------------------------------------------------------------------
1854
1855 function SetUpFunction() {
1856   %CheckIsBootstrapping();
1857
1858   %SetCode($Function, FunctionConstructor);
1859   %AddNamedProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1860
1861   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1862     "bind", FunctionBind,
1863     "toString", FunctionToString
1864   ));
1865 }
1866
1867 SetUpFunction();
1868
1869
1870 // ----------------------------------------------------------------------------
1871 // Iterator related spec functions.
1872
1873 // ES6 rev 26, 2014-07-18
1874 // 7.4.1 CheckIterable ( obj )
1875 function ToIterable(obj) {
1876   if (!IS_SPEC_OBJECT(obj)) {
1877     return UNDEFINED;
1878   }
1879   return obj[symbolIterator];
1880 }
1881
1882
1883 // ES6 rev 26, 2014-07-18
1884 // 7.4.2 GetIterator ( obj, method )
1885 function GetIterator(obj, method) {
1886   if (IS_UNDEFINED(method)) {
1887     method = ToIterable(obj);
1888   }
1889   if (!IS_SPEC_FUNCTION(method)) {
1890     throw MakeTypeError('not_iterable', [obj]);
1891   }
1892   var iterator = %_CallFunction(obj, method);
1893   if (!IS_SPEC_OBJECT(iterator)) {
1894     throw MakeTypeError('not_an_iterator', [iterator]);
1895   }
1896   return iterator;
1897 }