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