1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// This file relies on the fact that the following declarations have been made
29//
30// in runtime.js:
31// var $Object = global.Object;
32// var $Boolean = global.Boolean;
33// var $Number = global.Number;
34// var $Function = global.Function;
35// var $Array = global.Array;
36// var $NaN = 0/0;
37//
38// in math.js:
39// var $floor = MathFloor
40
41var $isNaN = GlobalIsNaN;
42var $isFinite = GlobalIsFinite;
43
44// ----------------------------------------------------------------------------
45
46
47// Helper function used to install functions on objects.
48function InstallFunctions(object, attributes, functions) {
49  if (functions.length >= 8) {
50    %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
51  }
52  for (var i = 0; i < functions.length; i += 2) {
53    var key = functions[i];
54    var f = functions[i + 1];
55    %FunctionSetName(f, key);
56    %FunctionRemovePrototype(f);
57    %SetProperty(object, key, f, attributes);
58    %SetNativeFlag(f);
59  }
60  %ToFastProperties(object);
61}
62
63// Prevents changes to the prototype of a built-infunction.
64// The "prototype" property of the function object is made non-configurable,
65// and the prototype object is made non-extensible. The latter prevents
66// changing the __proto__ property.
67function SetUpLockedPrototype(constructor, fields, methods) {
68  %CheckIsBootstrapping();
69  var prototype = constructor.prototype;
70  // Install functions first, because this function is used to initialize
71  // PropertyDescriptor itself.
72  var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
73  if (property_count >= 4) {
74    %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
75  }
76  if (fields) {
77    for (var i = 0; i < fields.length; i++) {
78      %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
79    }
80  }
81  for (var i = 0; i < methods.length; i += 2) {
82    var key = methods[i];
83    var f = methods[i + 1];
84    %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
85    %SetNativeFlag(f);
86  }
87  prototype.__proto__ = null;
88  %ToFastProperties(prototype);
89}
90
91
92// ----------------------------------------------------------------------------
93
94
95// ECMA 262 - 15.1.4
96function GlobalIsNaN(number) {
97  if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
98  return NUMBER_IS_NAN(number);
99}
100
101
102// ECMA 262 - 15.1.5
103function GlobalIsFinite(number) {
104  if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
105  return NUMBER_IS_FINITE(number);
106}
107
108
109// ECMA-262 - 15.1.2.2
110function GlobalParseInt(string, radix) {
111  if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
112    // Some people use parseInt instead of Math.floor.  This
113    // optimization makes parseInt on a Smi 12 times faster (60ns
114    // vs 800ns).  The following optimization makes parseInt on a
115    // non-Smi number 9 times faster (230ns vs 2070ns).  Together
116    // they make parseInt on a string 1.4% slower (274ns vs 270ns).
117    if (%_IsSmi(string)) return string;
118    if (IS_NUMBER(string) &&
119        ((0.01 < string && string < 1e9) ||
120            (-1e9 < string && string < -0.01))) {
121      // Truncate number.
122      return string | 0;
123    }
124    string = TO_STRING_INLINE(string);
125    radix = radix | 0;
126  } else {
127    // The spec says ToString should be evaluated before ToInt32.
128    string = TO_STRING_INLINE(string);
129    radix = TO_INT32(radix);
130    if (!(radix == 0 || (2 <= radix && radix <= 36))) {
131      return $NaN;
132    }
133  }
134
135  if (%_HasCachedArrayIndex(string) &&
136      (radix == 0 || radix == 10)) {
137    return %_GetCachedArrayIndex(string);
138  }
139  return %StringParseInt(string, radix);
140}
141
142
143// ECMA-262 - 15.1.2.3
144function GlobalParseFloat(string) {
145  string = TO_STRING_INLINE(string);
146  if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
147  return %StringParseFloat(string);
148}
149
150
151function GlobalEval(x) {
152  if (!IS_STRING(x)) return x;
153
154  var global_receiver = %GlobalReceiver(global);
155  var global_is_detached = (global === global_receiver);
156
157  // For consistency with JSC we require the global object passed to
158  // eval to be the global object from which 'eval' originated. This
159  // is not mandated by the spec.
160  // We only throw if the global has been detached, since we need the
161  // receiver as this-value for the call.
162  if (global_is_detached) {
163    throw new $EvalError('The "this" value passed to eval must ' +
164                         'be the global object from which eval originated');
165  }
166
167  var f = %CompileString(x);
168  if (!IS_FUNCTION(f)) return f;
169
170  return %_CallFunction(global_receiver, f);
171}
172
173
174// ----------------------------------------------------------------------------
175
176// Set up global object.
177function SetUpGlobal() {
178  %CheckIsBootstrapping();
179  // ECMA 262 - 15.1.1.1.
180  %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
181
182  // ECMA-262 - 15.1.1.2.
183  %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
184
185  // ECMA-262 - 15.1.1.3.
186  %SetProperty(global, "undefined", void 0,
187               DONT_ENUM | DONT_DELETE | READ_ONLY);
188
189  // Set up non-enumerable function on the global object.
190  InstallFunctions(global, DONT_ENUM, $Array(
191    "isNaN", GlobalIsNaN,
192    "isFinite", GlobalIsFinite,
193    "parseInt", GlobalParseInt,
194    "parseFloat", GlobalParseFloat,
195    "eval", GlobalEval
196  ));
197}
198
199SetUpGlobal();
200
201// ----------------------------------------------------------------------------
202// Boolean (first part of definition)
203
204
205%SetCode($Boolean, function(x) {
206  if (%_IsConstructCall()) {
207    %_SetValueOf(this, ToBoolean(x));
208  } else {
209    return ToBoolean(x);
210  }
211});
212
213%FunctionSetPrototype($Boolean, new $Boolean(false));
214
215%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
216
217// ----------------------------------------------------------------------------
218// Object
219
220$Object.prototype.constructor = $Object;
221
222// ECMA-262 - 15.2.4.2
223function ObjectToString() {
224  if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
225    return '[object Undefined]';
226  }
227  if (IS_NULL(this)) return '[object Null]';
228  return "[object " + %_ClassOf(ToObject(this)) + "]";
229}
230
231
232// ECMA-262 - 15.2.4.3
233function ObjectToLocaleString() {
234  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
235    throw MakeTypeError("called_on_null_or_undefined",
236                        ["Object.prototype.toLocaleString"]);
237  }
238  return this.toString();
239}
240
241
242// ECMA-262 - 15.2.4.4
243function ObjectValueOf() {
244  return ToObject(this);
245}
246
247
248// ECMA-262 - 15.2.4.5
249function ObjectHasOwnProperty(V) {
250  if (%IsJSProxy(this)) {
251    var handler = %GetHandler(this);
252    return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
253  }
254  return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
255}
256
257
258// ECMA-262 - 15.2.4.6
259function ObjectIsPrototypeOf(V) {
260  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
261    throw MakeTypeError("called_on_null_or_undefined",
262                        ["Object.prototype.isPrototypeOf"]);
263  }
264  if (!IS_SPEC_OBJECT(V)) return false;
265  return %IsInPrototypeChain(this, V);
266}
267
268
269// ECMA-262 - 15.2.4.6
270function ObjectPropertyIsEnumerable(V) {
271  var P = ToString(V);
272  if (%IsJSProxy(this)) {
273    var desc = GetOwnProperty(this, P);
274    return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
275  }
276  return %IsPropertyEnumerable(ToObject(this), P);
277}
278
279
280// Extensions for providing property getters and setters.
281function ObjectDefineGetter(name, fun) {
282  var receiver = this;
283  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
284    receiver = %GlobalReceiver(global);
285  }
286  if (!IS_SPEC_FUNCTION(fun)) {
287    throw new $TypeError(
288        'Object.prototype.__defineGetter__: Expecting function');
289  }
290  var desc = new PropertyDescriptor();
291  desc.setGet(fun);
292  desc.setEnumerable(true);
293  desc.setConfigurable(true);
294  DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
295}
296
297
298function ObjectLookupGetter(name) {
299  var receiver = this;
300  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
301    receiver = %GlobalReceiver(global);
302  }
303  return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
304}
305
306
307function ObjectDefineSetter(name, fun) {
308  var receiver = this;
309  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
310    receiver = %GlobalReceiver(global);
311  }
312  if (!IS_SPEC_FUNCTION(fun)) {
313    throw new $TypeError(
314        'Object.prototype.__defineSetter__: Expecting function');
315  }
316  var desc = new PropertyDescriptor();
317  desc.setSet(fun);
318  desc.setEnumerable(true);
319  desc.setConfigurable(true);
320  DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
321}
322
323
324function ObjectLookupSetter(name) {
325  var receiver = this;
326  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
327    receiver = %GlobalReceiver(global);
328  }
329  return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
330}
331
332
333function ObjectKeys(obj) {
334  if (!IS_SPEC_OBJECT(obj)) {
335    throw MakeTypeError("called_on_non_object", ["Object.keys"]);
336  }
337  if (%IsJSProxy(obj)) {
338    var handler = %GetHandler(obj);
339    var names = CallTrap0(handler, "keys", DerivedKeysTrap);
340    return ToStringArray(names);
341  }
342  return %LocalKeys(obj);
343}
344
345
346// ES5 8.10.1.
347function IsAccessorDescriptor(desc) {
348  if (IS_UNDEFINED(desc)) return false;
349  return desc.hasGetter() || desc.hasSetter();
350}
351
352
353// ES5 8.10.2.
354function IsDataDescriptor(desc) {
355  if (IS_UNDEFINED(desc)) return false;
356  return desc.hasValue() || desc.hasWritable();
357}
358
359
360// ES5 8.10.3.
361function IsGenericDescriptor(desc) {
362  if (IS_UNDEFINED(desc)) return false;
363  return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
364}
365
366
367function IsInconsistentDescriptor(desc) {
368  return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
369}
370
371
372// ES5 8.10.4
373function FromPropertyDescriptor(desc) {
374  if (IS_UNDEFINED(desc)) return desc;
375
376  if (IsDataDescriptor(desc)) {
377    return { value: desc.getValue(),
378             writable: desc.isWritable(),
379             enumerable: desc.isEnumerable(),
380             configurable: desc.isConfigurable() };
381  }
382  // Must be an AccessorDescriptor then. We never return a generic descriptor.
383  return { get: desc.getGet(),
384           set: desc.getSet(),
385           enumerable: desc.isEnumerable(),
386           configurable: desc.isConfigurable() };
387}
388
389
390// Harmony Proxies
391function FromGenericPropertyDescriptor(desc) {
392  if (IS_UNDEFINED(desc)) return desc;
393  var obj = new $Object();
394
395  if (desc.hasValue()) {
396    %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
397  }
398  if (desc.hasWritable()) {
399    %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
400  }
401  if (desc.hasGetter()) {
402    %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
403  }
404  if (desc.hasSetter()) {
405    %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
406  }
407  if (desc.hasEnumerable()) {
408    %IgnoreAttributesAndSetProperty(obj, "enumerable",
409                                    desc.isEnumerable(), NONE);
410  }
411  if (desc.hasConfigurable()) {
412    %IgnoreAttributesAndSetProperty(obj, "configurable",
413                                    desc.isConfigurable(), NONE);
414  }
415  return obj;
416}
417
418
419// ES5 8.10.5.
420function ToPropertyDescriptor(obj) {
421  if (!IS_SPEC_OBJECT(obj)) {
422    throw MakeTypeError("property_desc_object", [obj]);
423  }
424  var desc = new PropertyDescriptor();
425
426  if ("enumerable" in obj) {
427    desc.setEnumerable(ToBoolean(obj.enumerable));
428  }
429
430  if ("configurable" in obj) {
431    desc.setConfigurable(ToBoolean(obj.configurable));
432  }
433
434  if ("value" in obj) {
435    desc.setValue(obj.value);
436  }
437
438  if ("writable" in obj) {
439    desc.setWritable(ToBoolean(obj.writable));
440  }
441
442  if ("get" in obj) {
443    var get = obj.get;
444    if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
445      throw MakeTypeError("getter_must_be_callable", [get]);
446    }
447    desc.setGet(get);
448  }
449
450  if ("set" in obj) {
451    var set = obj.set;
452    if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
453      throw MakeTypeError("setter_must_be_callable", [set]);
454    }
455    desc.setSet(set);
456  }
457
458  if (IsInconsistentDescriptor(desc)) {
459    throw MakeTypeError("value_and_accessor", [obj]);
460  }
461  return desc;
462}
463
464
465// For Harmony proxies.
466function ToCompletePropertyDescriptor(obj) {
467  var desc = ToPropertyDescriptor(obj);
468  if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
469    if (!desc.hasValue()) desc.setValue(void 0);
470    if (!desc.hasWritable()) desc.setWritable(false);
471  } else {
472    // Is accessor descriptor.
473    if (!desc.hasGetter()) desc.setGet(void 0);
474    if (!desc.hasSetter()) desc.setSet(void 0);
475  }
476  if (!desc.hasEnumerable()) desc.setEnumerable(false);
477  if (!desc.hasConfigurable()) desc.setConfigurable(false);
478  return desc;
479}
480
481
482function PropertyDescriptor() {
483  // Initialize here so they are all in-object and have the same map.
484  // Default values from ES5 8.6.1.
485  this.value_ = void 0;
486  this.hasValue_ = false;
487  this.writable_ = false;
488  this.hasWritable_ = false;
489  this.enumerable_ = false;
490  this.hasEnumerable_ = false;
491  this.configurable_ = false;
492  this.hasConfigurable_ = false;
493  this.get_ = void 0;
494  this.hasGetter_ = false;
495  this.set_ = void 0;
496  this.hasSetter_ = false;
497}
498
499SetUpLockedPrototype(PropertyDescriptor, $Array(
500    "value_",
501    "hasValue_",
502    "writable_",
503    "hasWritable_",
504    "enumerable_",
505    "hasEnumerable_",
506    "configurable_",
507    "hasConfigurable_",
508    "get_",
509    "hasGetter_",
510    "set_",
511    "hasSetter_"
512  ), $Array(
513    "toString", function() {
514      return "[object PropertyDescriptor]";
515    },
516    "setValue", function(value) {
517      this.value_ = value;
518      this.hasValue_ = true;
519    },
520    "getValue", function() {
521      return this.value_;
522    },
523    "hasValue", function() {
524      return this.hasValue_;
525    },
526    "setEnumerable", function(enumerable) {
527      this.enumerable_ = enumerable;
528        this.hasEnumerable_ = true;
529    },
530    "isEnumerable", function () {
531      return this.enumerable_;
532    },
533    "hasEnumerable", function() {
534      return this.hasEnumerable_;
535    },
536    "setWritable", function(writable) {
537      this.writable_ = writable;
538      this.hasWritable_ = true;
539    },
540    "isWritable", function() {
541      return this.writable_;
542    },
543    "hasWritable", function() {
544      return this.hasWritable_;
545    },
546    "setConfigurable", function(configurable) {
547      this.configurable_ = configurable;
548      this.hasConfigurable_ = true;
549    },
550    "hasConfigurable", function() {
551      return this.hasConfigurable_;
552    },
553    "isConfigurable", function() {
554      return this.configurable_;
555    },
556    "setGet", function(get) {
557      this.get_ = get;
558        this.hasGetter_ = true;
559    },
560    "getGet", function() {
561      return this.get_;
562    },
563    "hasGetter", function() {
564      return this.hasGetter_;
565    },
566    "setSet", function(set) {
567      this.set_ = set;
568      this.hasSetter_ = true;
569    },
570    "getSet", function() {
571      return this.set_;
572    },
573    "hasSetter", function() {
574      return this.hasSetter_;
575  }));
576
577
578// Converts an array returned from Runtime_GetOwnProperty to an actual
579// property descriptor. For a description of the array layout please
580// see the runtime.cc file.
581function ConvertDescriptorArrayToDescriptor(desc_array) {
582  if (desc_array === false) {
583    throw 'Internal error: invalid desc_array';
584  }
585
586  if (IS_UNDEFINED(desc_array)) {
587    return void 0;
588  }
589
590  var desc = new PropertyDescriptor();
591  // This is an accessor.
592  if (desc_array[IS_ACCESSOR_INDEX]) {
593    desc.setGet(desc_array[GETTER_INDEX]);
594    desc.setSet(desc_array[SETTER_INDEX]);
595  } else {
596    desc.setValue(desc_array[VALUE_INDEX]);
597    desc.setWritable(desc_array[WRITABLE_INDEX]);
598  }
599  desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
600  desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
601
602  return desc;
603}
604
605
606// For Harmony proxies.
607function GetTrap(handler, name, defaultTrap) {
608  var trap = handler[name];
609  if (IS_UNDEFINED(trap)) {
610    if (IS_UNDEFINED(defaultTrap)) {
611      throw MakeTypeError("handler_trap_missing", [handler, name]);
612    }
613    trap = defaultTrap;
614  } else if (!IS_SPEC_FUNCTION(trap)) {
615    throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
616  }
617  return trap;
618}
619
620
621function CallTrap0(handler, name, defaultTrap) {
622  return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
623}
624
625
626function CallTrap1(handler, name, defaultTrap, x) {
627  return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
628}
629
630
631function CallTrap2(handler, name, defaultTrap, x, y) {
632  return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
633}
634
635
636// ES5 section 8.12.1.
637function GetOwnProperty(obj, v) {
638  var p = ToString(v);
639  if (%IsJSProxy(obj)) {
640    var handler = %GetHandler(obj);
641    var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
642    if (IS_UNDEFINED(descriptor)) return descriptor;
643    var desc = ToCompletePropertyDescriptor(descriptor);
644    if (!desc.isConfigurable()) {
645      throw MakeTypeError("proxy_prop_not_configurable",
646                          [handler, "getOwnPropertyDescriptor", p, descriptor]);
647    }
648    return desc;
649  }
650
651  // GetOwnProperty returns an array indexed by the constants
652  // defined in macros.py.
653  // If p is not a property on obj undefined is returned.
654  var props = %GetOwnProperty(ToObject(obj), ToString(v));
655
656  // A false value here means that access checks failed.
657  if (props === false) return void 0;
658
659  return ConvertDescriptorArrayToDescriptor(props);
660}
661
662
663// ES5 section 8.12.7.
664function Delete(obj, p, should_throw) {
665  var desc = GetOwnProperty(obj, p);
666  if (IS_UNDEFINED(desc)) return true;
667  if (desc.isConfigurable()) {
668    %DeleteProperty(obj, p, 0);
669    return true;
670  } else if (should_throw) {
671    throw MakeTypeError("define_disallowed", [p]);
672  } else {
673    return;
674  }
675}
676
677
678// Harmony proxies.
679function DefineProxyProperty(obj, p, attributes, should_throw) {
680  var handler = %GetHandler(obj);
681  var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
682  if (!ToBoolean(result)) {
683    if (should_throw) {
684      throw MakeTypeError("handler_returned_false",
685                          [handler, "defineProperty"]);
686    } else {
687      return false;
688    }
689  }
690  return true;
691}
692
693
694// ES5 8.12.9.
695function DefineObjectProperty(obj, p, desc, should_throw) {
696  var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
697  // A false value here means that access checks failed.
698  if (current_or_access === false) return void 0;
699
700  var current = ConvertDescriptorArrayToDescriptor(current_or_access);
701  var extensible = %IsExtensible(ToObject(obj));
702
703  // Error handling according to spec.
704  // Step 3
705  if (IS_UNDEFINED(current) && !extensible) {
706    if (should_throw) {
707      throw MakeTypeError("define_disallowed", [p]);
708    } else {
709      return false;
710    }
711  }
712
713  if (!IS_UNDEFINED(current)) {
714    // Step 5 and 6
715    if ((IsGenericDescriptor(desc) ||
716         IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
717        (!desc.hasEnumerable() ||
718         SameValue(desc.isEnumerable(), current.isEnumerable())) &&
719        (!desc.hasConfigurable() ||
720         SameValue(desc.isConfigurable(), current.isConfigurable())) &&
721        (!desc.hasWritable() ||
722         SameValue(desc.isWritable(), current.isWritable())) &&
723        (!desc.hasValue() ||
724         SameValue(desc.getValue(), current.getValue())) &&
725        (!desc.hasGetter() ||
726         SameValue(desc.getGet(), current.getGet())) &&
727        (!desc.hasSetter() ||
728         SameValue(desc.getSet(), current.getSet()))) {
729      return true;
730    }
731    if (!current.isConfigurable()) {
732      // Step 7
733      if (desc.isConfigurable() ||
734          (desc.hasEnumerable() &&
735           desc.isEnumerable() != current.isEnumerable())) {
736        if (should_throw) {
737          throw MakeTypeError("redefine_disallowed", [p]);
738        } else {
739          return false;
740        }
741      }
742      // Step 8
743      if (!IsGenericDescriptor(desc)) {
744        // Step 9a
745        if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
746          if (should_throw) {
747            throw MakeTypeError("redefine_disallowed", [p]);
748          } else {
749            return false;
750          }
751        }
752        // Step 10a
753        if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
754          if (!current.isWritable() && desc.isWritable()) {
755            if (should_throw) {
756              throw MakeTypeError("redefine_disallowed", [p]);
757            } else {
758              return false;
759            }
760          }
761          if (!current.isWritable() && desc.hasValue() &&
762              !SameValue(desc.getValue(), current.getValue())) {
763            if (should_throw) {
764              throw MakeTypeError("redefine_disallowed", [p]);
765            } else {
766              return false;
767            }
768          }
769        }
770        // Step 11
771        if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
772          if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
773            if (should_throw) {
774              throw MakeTypeError("redefine_disallowed", [p]);
775            } else {
776              return false;
777            }
778          }
779          if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
780            if (should_throw) {
781              throw MakeTypeError("redefine_disallowed", [p]);
782            } else {
783              return false;
784            }
785          }
786        }
787      }
788    }
789  }
790
791  // Send flags - enumerable and configurable are common - writable is
792  // only send to the data descriptor.
793  // Take special care if enumerable and configurable is not defined on
794  // desc (we need to preserve the existing values from current).
795  var flag = NONE;
796  if (desc.hasEnumerable()) {
797    flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
798  } else if (!IS_UNDEFINED(current)) {
799    flag |= current.isEnumerable() ? 0 : DONT_ENUM;
800  } else {
801    flag |= DONT_ENUM;
802  }
803
804  if (desc.hasConfigurable()) {
805    flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
806  } else if (!IS_UNDEFINED(current)) {
807    flag |= current.isConfigurable() ? 0 : DONT_DELETE;
808  } else
809    flag |= DONT_DELETE;
810
811  if (IsDataDescriptor(desc) ||
812      (IsGenericDescriptor(desc) &&
813       (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
814    // There are 3 cases that lead here:
815    // Step 4a - defining a new data property.
816    // Steps 9b & 12 - replacing an existing accessor property with a data
817    //                 property.
818    // Step 12 - updating an existing data property with a data or generic
819    //           descriptor.
820
821    if (desc.hasWritable()) {
822      flag |= desc.isWritable() ? 0 : READ_ONLY;
823    } else if (!IS_UNDEFINED(current)) {
824      flag |= current.isWritable() ? 0 : READ_ONLY;
825    } else {
826      flag |= READ_ONLY;
827    }
828
829    var value = void 0;  // Default value is undefined.
830    if (desc.hasValue()) {
831      value = desc.getValue();
832    } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
833      value = current.getValue();
834    }
835
836    %DefineOrRedefineDataProperty(obj, p, value, flag);
837  } else {
838    // There are 3 cases that lead here:
839    // Step 4b - defining a new accessor property.
840    // Steps 9c & 12 - replacing an existing data property with an accessor
841    //                 property.
842    // Step 12 - updating an existing accessor property with an accessor
843    //           descriptor.
844    var getter = desc.hasGetter() ? desc.getGet() : null;
845    var setter = desc.hasSetter() ? desc.getSet() : null;
846    %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
847  }
848  return true;
849}
850
851
852// ES5 section 15.4.5.1.
853function DefineArrayProperty(obj, p, desc, should_throw) {
854  // Note that the length of an array is not actually stored as part of the
855  // property, hence we use generated code throughout this function instead of
856  // DefineObjectProperty() to modify its value.
857
858  // Step 3 - Special handling for length property.
859  if (p == "length") {
860    var length = obj.length;
861    if (!desc.hasValue()) {
862      return DefineObjectProperty(obj, "length", desc, should_throw);
863    }
864    var new_length = ToUint32(desc.getValue());
865    if (new_length != ToNumber(desc.getValue())) {
866      throw new $RangeError('defineProperty() array length out of range');
867    }
868    var length_desc = GetOwnProperty(obj, "length");
869    if (new_length != length && !length_desc.isWritable()) {
870      if (should_throw) {
871        throw MakeTypeError("redefine_disallowed", [p]);
872      } else {
873        return false;
874      }
875    }
876    var threw = false;
877    while (new_length < length--) {
878      if (!Delete(obj, ToString(length), false)) {
879        new_length = length + 1;
880        threw = true;
881        break;
882      }
883    }
884    // Make sure the below call to DefineObjectProperty() doesn't overwrite
885    // any magic "length" property by removing the value.
886    obj.length = new_length;
887    desc.value_ = void 0;
888    desc.hasValue_ = false;
889    if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) {
890      if (should_throw) {
891        throw MakeTypeError("redefine_disallowed", [p]);
892      } else {
893        return false;
894      }
895    }
896    return true;
897  }
898
899  // Step 4 - Special handling for array index.
900  var index = ToUint32(p);
901  if (index == ToNumber(p) && index != 4294967295) {
902    var length = obj.length;
903    var length_desc = GetOwnProperty(obj, "length");
904    if ((index >= length && !length_desc.isWritable()) ||
905        !DefineObjectProperty(obj, p, desc, true)) {
906      if (should_throw) {
907        throw MakeTypeError("define_disallowed", [p]);
908      } else {
909        return false;
910      }
911    }
912    if (index >= length) {
913      obj.length = index + 1;
914    }
915    return true;
916  }
917
918  // Step 5 - Fallback to default implementation.
919  return DefineObjectProperty(obj, p, desc, should_throw);
920}
921
922
923// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
924function DefineOwnProperty(obj, p, desc, should_throw) {
925  if (%IsJSProxy(obj)) {
926    var attributes = FromGenericPropertyDescriptor(desc);
927    return DefineProxyProperty(obj, p, attributes, should_throw);
928  } else if (IS_ARRAY(obj)) {
929    return DefineArrayProperty(obj, p, desc, should_throw);
930  } else {
931    return DefineObjectProperty(obj, p, desc, should_throw);
932  }
933}
934
935
936// ES5 section 15.2.3.2.
937function ObjectGetPrototypeOf(obj) {
938  if (!IS_SPEC_OBJECT(obj)) {
939    throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
940  }
941  return %GetPrototype(obj);
942}
943
944
945// ES5 section 15.2.3.3
946function ObjectGetOwnPropertyDescriptor(obj, p) {
947  if (!IS_SPEC_OBJECT(obj)) {
948    throw MakeTypeError("called_on_non_object",
949                        ["Object.getOwnPropertyDescriptor"]);
950  }
951  var desc = GetOwnProperty(obj, p);
952  return FromPropertyDescriptor(desc);
953}
954
955
956// For Harmony proxies
957function ToStringArray(obj, trap) {
958  if (!IS_SPEC_OBJECT(obj)) {
959    throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
960  }
961  var n = ToUint32(obj.length);
962  var array = new $Array(n);
963  var names = {};  // TODO(rossberg): use sets once they are ready.
964  for (var index = 0; index < n; index++) {
965    var s = ToString(obj[index]);
966    if (s in names) {
967      throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
968    }
969    array[index] = s;
970    names[s] = 0;
971  }
972  return array;
973}
974
975
976// ES5 section 15.2.3.4.
977function ObjectGetOwnPropertyNames(obj) {
978  if (!IS_SPEC_OBJECT(obj)) {
979    throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
980  }
981  // Special handling for proxies.
982  if (%IsJSProxy(obj)) {
983    var handler = %GetHandler(obj);
984    var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
985    return ToStringArray(names, "getOwnPropertyNames");
986  }
987
988  // Find all the indexed properties.
989
990  // Get the local element names.
991  var propertyNames = %GetLocalElementNames(obj);
992
993  // Get names for indexed interceptor properties.
994  if (%GetInterceptorInfo(obj) & 1) {
995    var indexedInterceptorNames =
996        %GetIndexedInterceptorElementNames(obj);
997    if (indexedInterceptorNames) {
998      propertyNames = propertyNames.concat(indexedInterceptorNames);
999    }
1000  }
1001
1002  // Find all the named properties.
1003
1004  // Get the local property names.
1005  propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
1006
1007  // Get names for named interceptor properties if any.
1008
1009  if (%GetInterceptorInfo(obj) & 2) {
1010    var namedInterceptorNames =
1011        %GetNamedInterceptorPropertyNames(obj);
1012    if (namedInterceptorNames) {
1013      propertyNames = propertyNames.concat(namedInterceptorNames);
1014    }
1015  }
1016
1017  // Property names are expected to be unique strings.
1018  var propertySet = {};
1019  var j = 0;
1020  for (var i = 0; i < propertyNames.length; ++i) {
1021    var name = ToString(propertyNames[i]);
1022    // We need to check for the exact property value since for intrinsic
1023    // properties like toString if(propertySet["toString"]) will always
1024    // succeed.
1025    if (propertySet[name] === true) {
1026      continue;
1027    }
1028    propertySet[name] = true;
1029    propertyNames[j++] = name;
1030  }
1031  propertyNames.length = j;
1032
1033  return propertyNames;
1034}
1035
1036
1037// ES5 section 15.2.3.5.
1038function ObjectCreate(proto, properties) {
1039  if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1040    throw MakeTypeError("proto_object_or_null", [proto]);
1041  }
1042  var obj = new $Object();
1043  obj.__proto__ = proto;
1044  if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1045  return obj;
1046}
1047
1048
1049// ES5 section 15.2.3.6.
1050function ObjectDefineProperty(obj, p, attributes) {
1051  if (!IS_SPEC_OBJECT(obj)) {
1052    throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1053  }
1054  var name = ToString(p);
1055  if (%IsJSProxy(obj)) {
1056    // Clone the attributes object for protection.
1057    // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1058    // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1059    var attributesClone = {};
1060    for (var a in attributes) {
1061      attributesClone[a] = attributes[a];
1062    }
1063    DefineProxyProperty(obj, name, attributesClone, true);
1064    // The following would implement the spec as in the current proposal,
1065    // but after recent comments on es-discuss, is most likely obsolete.
1066    /*
1067    var defineObj = FromGenericPropertyDescriptor(desc);
1068    var names = ObjectGetOwnPropertyNames(attributes);
1069    var standardNames =
1070      {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1071    for (var i = 0; i < names.length; i++) {
1072      var N = names[i];
1073      if (!(%HasLocalProperty(standardNames, N))) {
1074        var attr = GetOwnProperty(attributes, N);
1075        DefineOwnProperty(descObj, N, attr, true);
1076      }
1077    }
1078    // This is really confusing the types, but it is what the proxies spec
1079    // currently requires:
1080    desc = descObj;
1081    */
1082  } else {
1083    var desc = ToPropertyDescriptor(attributes);
1084    DefineOwnProperty(obj, name, desc, true);
1085  }
1086  return obj;
1087}
1088
1089
1090function GetOwnEnumerablePropertyNames(properties) {
1091  var names = new InternalArray();
1092  for (var key in properties) {
1093    if (%HasLocalProperty(properties, key)) {
1094      names.push(key);
1095    }
1096  }
1097  return names;
1098}
1099
1100
1101// ES5 section 15.2.3.7.
1102function ObjectDefineProperties(obj, properties) {
1103  if (!IS_SPEC_OBJECT(obj)) {
1104    throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1105  }
1106  var props = ToObject(properties);
1107  var names = GetOwnEnumerablePropertyNames(props);
1108  var descriptors = new InternalArray();
1109  for (var i = 0; i < names.length; i++) {
1110    descriptors.push(ToPropertyDescriptor(props[names[i]]));
1111  }
1112  for (var i = 0; i < names.length; i++) {
1113    DefineOwnProperty(obj, names[i], descriptors[i], true);
1114  }
1115  return obj;
1116}
1117
1118
1119// Harmony proxies.
1120function ProxyFix(obj) {
1121  var handler = %GetHandler(obj);
1122  var props = CallTrap0(handler, "fix", void 0);
1123  if (IS_UNDEFINED(props)) {
1124    throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1125  }
1126
1127  if (%IsJSFunctionProxy(obj)) {
1128    var callTrap = %GetCallTrap(obj);
1129    var constructTrap = %GetConstructTrap(obj);
1130    var code = DelegateCallAndConstruct(callTrap, constructTrap);
1131    %Fix(obj);  // becomes a regular function
1132    %SetCode(obj, code);
1133    // TODO(rossberg): What about length and other properties? Not specified.
1134    // We just put in some half-reasonable defaults for now.
1135    var prototype = new $Object();
1136    $Object.defineProperty(prototype, "constructor",
1137      {value: obj, writable: true, enumerable: false, configurable: true});
1138    // TODO(v8:1530): defineProperty does not handle prototype and length.
1139    %FunctionSetPrototype(obj, prototype);
1140    obj.length = 0;
1141  } else {
1142    %Fix(obj);
1143  }
1144  ObjectDefineProperties(obj, props);
1145}
1146
1147
1148// ES5 section 15.2.3.8.
1149function ObjectSeal(obj) {
1150  if (!IS_SPEC_OBJECT(obj)) {
1151    throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1152  }
1153  if (%IsJSProxy(obj)) {
1154    ProxyFix(obj);
1155  }
1156  var names = ObjectGetOwnPropertyNames(obj);
1157  for (var i = 0; i < names.length; i++) {
1158    var name = names[i];
1159    var desc = GetOwnProperty(obj, name);
1160    if (desc.isConfigurable()) {
1161      desc.setConfigurable(false);
1162      DefineOwnProperty(obj, name, desc, true);
1163    }
1164  }
1165  %PreventExtensions(obj);
1166  return obj;
1167}
1168
1169
1170// ES5 section 15.2.3.9.
1171function ObjectFreeze(obj) {
1172  if (!IS_SPEC_OBJECT(obj)) {
1173    throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1174  }
1175  if (%IsJSProxy(obj)) {
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 = GetOwnProperty(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  return obj;
1190}
1191
1192
1193// ES5 section 15.2.3.10
1194function ObjectPreventExtension(obj) {
1195  if (!IS_SPEC_OBJECT(obj)) {
1196    throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1197  }
1198  if (%IsJSProxy(obj)) {
1199    ProxyFix(obj);
1200  }
1201  %PreventExtensions(obj);
1202  return obj;
1203}
1204
1205
1206// ES5 section 15.2.3.11
1207function ObjectIsSealed(obj) {
1208  if (!IS_SPEC_OBJECT(obj)) {
1209    throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1210  }
1211  if (%IsJSProxy(obj)) {
1212    return false;
1213  }
1214  var names = ObjectGetOwnPropertyNames(obj);
1215  for (var i = 0; i < names.length; i++) {
1216    var name = names[i];
1217    var desc = GetOwnProperty(obj, name);
1218    if (desc.isConfigurable()) return false;
1219  }
1220  if (!ObjectIsExtensible(obj)) {
1221    return true;
1222  }
1223  return false;
1224}
1225
1226
1227// ES5 section 15.2.3.12
1228function ObjectIsFrozen(obj) {
1229  if (!IS_SPEC_OBJECT(obj)) {
1230    throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1231  }
1232  if (%IsJSProxy(obj)) {
1233    return false;
1234  }
1235  var names = ObjectGetOwnPropertyNames(obj);
1236  for (var i = 0; i < names.length; i++) {
1237    var name = names[i];
1238    var desc = GetOwnProperty(obj, name);
1239    if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1240    if (desc.isConfigurable()) return false;
1241  }
1242  if (!ObjectIsExtensible(obj)) {
1243    return true;
1244  }
1245  return false;
1246}
1247
1248
1249// ES5 section 15.2.3.13
1250function ObjectIsExtensible(obj) {
1251  if (!IS_SPEC_OBJECT(obj)) {
1252    throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1253  }
1254  if (%IsJSProxy(obj)) {
1255    return true;
1256  }
1257  return %IsExtensible(obj);
1258}
1259
1260
1261// Harmony egal.
1262function ObjectIs(obj1, obj2) {
1263  if (obj1 === obj2) {
1264    return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1265  } else {
1266    return (obj1 !== obj1) && (obj2 !== obj2);
1267  }
1268}
1269
1270
1271%SetCode($Object, function(x) {
1272  if (%_IsConstructCall()) {
1273    if (x == null) return this;
1274    return ToObject(x);
1275  } else {
1276    if (x == null) return { };
1277    return ToObject(x);
1278  }
1279});
1280
1281%SetExpectedNumberOfProperties($Object, 4);
1282
1283// ----------------------------------------------------------------------------
1284// Object
1285
1286function SetUpObject() {
1287  %CheckIsBootstrapping();
1288  // Set Up non-enumerable functions on the Object.prototype object.
1289  InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1290    "toString", ObjectToString,
1291    "toLocaleString", ObjectToLocaleString,
1292    "valueOf", ObjectValueOf,
1293    "hasOwnProperty", ObjectHasOwnProperty,
1294    "isPrototypeOf", ObjectIsPrototypeOf,
1295    "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1296    "__defineGetter__", ObjectDefineGetter,
1297    "__lookupGetter__", ObjectLookupGetter,
1298    "__defineSetter__", ObjectDefineSetter,
1299    "__lookupSetter__", ObjectLookupSetter
1300  ));
1301  InstallFunctions($Object, DONT_ENUM, $Array(
1302    "keys", ObjectKeys,
1303    "create", ObjectCreate,
1304    "defineProperty", ObjectDefineProperty,
1305    "defineProperties", ObjectDefineProperties,
1306    "freeze", ObjectFreeze,
1307    "getPrototypeOf", ObjectGetPrototypeOf,
1308    "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1309    "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1310    "is", ObjectIs,
1311    "isExtensible", ObjectIsExtensible,
1312    "isFrozen", ObjectIsFrozen,
1313    "isSealed", ObjectIsSealed,
1314    "preventExtensions", ObjectPreventExtension,
1315    "seal", ObjectSeal
1316  ));
1317}
1318
1319SetUpObject();
1320
1321// ----------------------------------------------------------------------------
1322// Boolean
1323
1324function BooleanToString() {
1325  // NOTE: Both Boolean objects and values can enter here as
1326  // 'this'. This is not as dictated by ECMA-262.
1327  var b = this;
1328  if (!IS_BOOLEAN(b)) {
1329    if (!IS_BOOLEAN_WRAPPER(b)) {
1330      throw new $TypeError('Boolean.prototype.toString is not generic');
1331    }
1332    b = %_ValueOf(b);
1333  }
1334  return b ? 'true' : 'false';
1335}
1336
1337
1338function BooleanValueOf() {
1339  // NOTE: Both Boolean objects and values can enter here as
1340  // 'this'. This is not as dictated by ECMA-262.
1341  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1342    throw new $TypeError('Boolean.prototype.valueOf is not generic');
1343  }
1344  return %_ValueOf(this);
1345}
1346
1347
1348// ----------------------------------------------------------------------------
1349
1350
1351function SetUpBoolean () {
1352  %CheckIsBootstrapping();
1353  InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1354    "toString", BooleanToString,
1355    "valueOf", BooleanValueOf
1356  ));
1357}
1358
1359SetUpBoolean();
1360
1361
1362// ----------------------------------------------------------------------------
1363// Number
1364
1365// Set the Number function and constructor.
1366%SetCode($Number, function(x) {
1367  var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1368  if (%_IsConstructCall()) {
1369    %_SetValueOf(this, value);
1370  } else {
1371    return value;
1372  }
1373});
1374
1375%FunctionSetPrototype($Number, new $Number(0));
1376
1377// ECMA-262 section 15.7.4.2.
1378function NumberToString(radix) {
1379  // NOTE: Both Number objects and values can enter here as
1380  // 'this'. This is not as dictated by ECMA-262.
1381  var number = this;
1382  if (!IS_NUMBER(this)) {
1383    if (!IS_NUMBER_WRAPPER(this)) {
1384      throw new $TypeError('Number.prototype.toString is not generic');
1385    }
1386    // Get the value of this number in case it's an object.
1387    number = %_ValueOf(this);
1388  }
1389  // Fast case: Convert number in radix 10.
1390  if (IS_UNDEFINED(radix) || radix === 10) {
1391    return %_NumberToString(number);
1392  }
1393
1394  // Convert the radix to an integer and check the range.
1395  radix = TO_INTEGER(radix);
1396  if (radix < 2 || radix > 36) {
1397    throw new $RangeError('toString() radix argument must be between 2 and 36');
1398  }
1399  // Convert the number to a string in the given radix.
1400  return %NumberToRadixString(number, radix);
1401}
1402
1403
1404// ECMA-262 section 15.7.4.3
1405function NumberToLocaleString() {
1406  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1407    throw MakeTypeError("called_on_null_or_undefined",
1408                        ["Number.prototype.toLocaleString"]);
1409  }
1410  return this.toString();
1411}
1412
1413
1414// ECMA-262 section 15.7.4.4
1415function NumberValueOf() {
1416  // NOTE: Both Number objects and values can enter here as
1417  // 'this'. This is not as dictated by ECMA-262.
1418  if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1419    throw new $TypeError('Number.prototype.valueOf is not generic');
1420  }
1421  return %_ValueOf(this);
1422}
1423
1424
1425// ECMA-262 section 15.7.4.5
1426function NumberToFixed(fractionDigits) {
1427  var f = TO_INTEGER(fractionDigits);
1428  if (f < 0 || f > 20) {
1429    throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1430  }
1431  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1432    throw MakeTypeError("called_on_null_or_undefined",
1433                        ["Number.prototype.toFixed"]);
1434  }
1435  var x = ToNumber(this);
1436  return %NumberToFixed(x, f);
1437}
1438
1439
1440// ECMA-262 section 15.7.4.6
1441function NumberToExponential(fractionDigits) {
1442  var f = -1;
1443  if (!IS_UNDEFINED(fractionDigits)) {
1444    f = TO_INTEGER(fractionDigits);
1445    if (f < 0 || f > 20) {
1446      throw new $RangeError(
1447          "toExponential() argument must be between 0 and 20");
1448    }
1449  }
1450  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1451    throw MakeTypeError("called_on_null_or_undefined",
1452                        ["Number.prototype.toExponential"]);
1453  }
1454  var x = ToNumber(this);
1455  return %NumberToExponential(x, f);
1456}
1457
1458
1459// ECMA-262 section 15.7.4.7
1460function NumberToPrecision(precision) {
1461  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1462    throw MakeTypeError("called_on_null_or_undefined",
1463                        ["Number.prototype.toPrecision"]);
1464  }
1465  if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1466  var p = TO_INTEGER(precision);
1467  if (p < 1 || p > 21) {
1468    throw new $RangeError("toPrecision() argument must be between 1 and 21");
1469  }
1470  var x = ToNumber(this);
1471  return %NumberToPrecision(x, p);
1472}
1473
1474
1475// Harmony isFinite.
1476function NumberIsFinite(number) {
1477  return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1478}
1479
1480
1481// Harmony isNaN.
1482function NumberIsNaN(number) {
1483  return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1484}
1485
1486
1487// ----------------------------------------------------------------------------
1488
1489function SetUpNumber() {
1490  %CheckIsBootstrapping();
1491  %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1492  // Set up the constructor property on the Number prototype object.
1493  %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1494
1495  %OptimizeObjectForAddingMultipleProperties($Number, 5);
1496  // ECMA-262 section 15.7.3.1.
1497  %SetProperty($Number,
1498               "MAX_VALUE",
1499               1.7976931348623157e+308,
1500               DONT_ENUM | DONT_DELETE | READ_ONLY);
1501
1502  // ECMA-262 section 15.7.3.2.
1503  %SetProperty($Number, "MIN_VALUE", 5e-324,
1504               DONT_ENUM | DONT_DELETE | READ_ONLY);
1505
1506  // ECMA-262 section 15.7.3.3.
1507  %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1508
1509  // ECMA-262 section 15.7.3.4.
1510  %SetProperty($Number,
1511               "NEGATIVE_INFINITY",
1512               -1/0,
1513               DONT_ENUM | DONT_DELETE | READ_ONLY);
1514
1515  // ECMA-262 section 15.7.3.5.
1516  %SetProperty($Number,
1517               "POSITIVE_INFINITY",
1518               1/0,
1519               DONT_ENUM | DONT_DELETE | READ_ONLY);
1520  %ToFastProperties($Number);
1521
1522  // Set up non-enumerable functions on the Number prototype object.
1523  InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1524    "toString", NumberToString,
1525    "toLocaleString", NumberToLocaleString,
1526    "valueOf", NumberValueOf,
1527    "toFixed", NumberToFixed,
1528    "toExponential", NumberToExponential,
1529    "toPrecision", NumberToPrecision
1530  ));
1531  InstallFunctions($Number, DONT_ENUM, $Array(
1532    "isFinite", NumberIsFinite,
1533    "isNaN", NumberIsNaN
1534  ));
1535}
1536
1537SetUpNumber();
1538
1539
1540// ----------------------------------------------------------------------------
1541// Function
1542
1543$Function.prototype.constructor = $Function;
1544
1545function FunctionSourceString(func) {
1546  while (%IsJSFunctionProxy(func)) {
1547    func = %GetCallTrap(func);
1548  }
1549
1550  if (!IS_FUNCTION(func)) {
1551    throw new $TypeError('Function.prototype.toString is not generic');
1552  }
1553
1554  var source = %FunctionGetSourceCode(func);
1555  if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1556    var name = %FunctionGetName(func);
1557    if (name) {
1558      // Mimic what KJS does.
1559      return 'function ' + name + '() { [native code] }';
1560    } else {
1561      return 'function () { [native code] }';
1562    }
1563  }
1564
1565  var name = %FunctionNameShouldPrintAsAnonymous(func)
1566      ? 'anonymous'
1567      : %FunctionGetName(func);
1568  return 'function ' + name + source;
1569}
1570
1571
1572function FunctionToString() {
1573  return FunctionSourceString(this);
1574}
1575
1576
1577// ES5 15.3.4.5
1578function FunctionBind(this_arg) { // Length is 1.
1579  if (!IS_SPEC_FUNCTION(this)) {
1580    throw new $TypeError('Bind must be called on a function');
1581  }
1582  var boundFunction = function () {
1583    // Poison .arguments and .caller, but is otherwise not detectable.
1584    "use strict";
1585    // This function must not use any object literals (Object, Array, RegExp),
1586    // since the literals-array is being used to store the bound data.
1587    if (%_IsConstructCall()) {
1588      return %NewObjectFromBound(boundFunction);
1589    }
1590    var bindings = %BoundFunctionGetBindings(boundFunction);
1591
1592    var argc = %_ArgumentsLength();
1593    if (argc == 0) {
1594      return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1595    }
1596    if (bindings.length === 2) {
1597      return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1598    }
1599    var bound_argc = bindings.length - 2;
1600    var argv = new InternalArray(bound_argc + argc);
1601    for (var i = 0; i < bound_argc; i++) {
1602      argv[i] = bindings[i + 2];
1603    }
1604    for (var j = 0; j < argc; j++) {
1605      argv[i++] = %_Arguments(j);
1606    }
1607    return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1608  };
1609
1610  %FunctionRemovePrototype(boundFunction);
1611  var new_length = 0;
1612  if (%_ClassOf(this) == "Function") {
1613    // Function or FunctionProxy.
1614    var old_length = this.length;
1615    // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1616    if ((typeof old_length === "number") &&
1617        ((old_length >>> 0) === old_length)) {
1618      var argc = %_ArgumentsLength();
1619      if (argc > 0) argc--;  // Don't count the thisArg as parameter.
1620      new_length = old_length - argc;
1621      if (new_length < 0) new_length = 0;
1622    }
1623  }
1624  // This runtime function finds any remaining arguments on the stack,
1625  // so we don't pass the arguments object.
1626  var result = %FunctionBindArguments(boundFunction, this,
1627                                      this_arg, new_length);
1628
1629  // We already have caller and arguments properties on functions,
1630  // which are non-configurable. It therefore makes no sence to
1631  // try to redefine these as defined by the spec. The spec says
1632  // that bind should make these throw a TypeError if get or set
1633  // is called and make them non-enumerable and non-configurable.
1634  // To be consistent with our normal functions we leave this as it is.
1635  // TODO(lrn): Do set these to be thrower.
1636  return result;
1637}
1638
1639
1640function NewFunction(arg1) {  // length == 1
1641  var n = %_ArgumentsLength();
1642  var p = '';
1643  if (n > 1) {
1644    p = new InternalArray(n - 1);
1645    for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1646    p = Join(p, n - 1, ',', NonStringToString);
1647    // If the formal parameters string include ) - an illegal
1648    // character - it may make the combined function expression
1649    // compile. We avoid this problem by checking for this early on.
1650    if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1651  }
1652  var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
1653  var source = '(function(' + p + ') {\n' + body + '\n})';
1654
1655  // The call to SetNewFunctionAttributes will ensure the prototype
1656  // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
1657  var f = %CompileString(source)();
1658  %FunctionMarkNameShouldPrintAsAnonymous(f);
1659  return %SetNewFunctionAttributes(f);
1660}
1661
1662%SetCode($Function, NewFunction);
1663
1664// ----------------------------------------------------------------------------
1665
1666function SetUpFunction() {
1667  %CheckIsBootstrapping();
1668  InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1669    "bind", FunctionBind,
1670    "toString", FunctionToString
1671  ));
1672}
1673
1674SetUpFunction();
1675