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