• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2006-2008 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
48// Helper function used to install functions on objects.
49function InstallFunctions(object, attributes, functions) {
50  if (functions.length >= 8) {
51    %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
52  }
53  for (var i = 0; i < functions.length; i += 2) {
54    var key = functions[i];
55    var f = functions[i + 1];
56    %FunctionSetName(f, key);
57    %SetProperty(object, key, f, attributes);
58  }
59  %ToFastProperties(object);
60}
61
62// Emulates JSC by installing functions on a hidden prototype that
63// lies above the current object/prototype.  This lets you override
64// functions on String.prototype etc. and then restore the old function
65// with delete.  See http://code.google.com/p/chromium/issues/detail?id=1717
66function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
67  var hidden_prototype = new $Object();
68  %SetHiddenPrototype(object, hidden_prototype);
69  InstallFunctions(hidden_prototype, attributes, functions);
70}
71
72
73// ----------------------------------------------------------------------------
74
75
76// ECMA 262 - 15.1.4
77function GlobalIsNaN(number) {
78  var n = ToNumber(number);
79  return NUMBER_IS_NAN(n);
80}
81
82
83// ECMA 262 - 15.1.5
84function GlobalIsFinite(number) {
85  return %NumberIsFinite(ToNumber(number));
86}
87
88
89// ECMA-262 - 15.1.2.2
90function GlobalParseInt(string, radix) {
91  if (IS_UNDEFINED(radix)) {
92    // Some people use parseInt instead of Math.floor.  This
93    // optimization makes parseInt on a Smi 12 times faster (60ns
94    // vs 800ns).  The following optimization makes parseInt on a
95    // non-Smi number 9 times faster (230ns vs 2070ns).  Together
96    // they make parseInt on a string 1.4% slower (274ns vs 270ns).
97    if (%_IsSmi(string)) return string;
98    if (IS_NUMBER(string) &&
99        ((0.01 < string && string < 1e9) ||
100            (-1e9 < string && string < -0.01))) {
101      // Truncate number.
102      return string | 0;
103    }
104    radix = 0;
105  } else {
106    radix = TO_INT32(radix);
107    if (!(radix == 0 || (2 <= radix && radix <= 36)))
108      return $NaN;
109  }
110  return %StringParseInt(ToString(string), radix);
111}
112
113
114// ECMA-262 - 15.1.2.3
115function GlobalParseFloat(string) {
116  return %StringParseFloat(ToString(string));
117}
118
119
120function GlobalEval(x) {
121  if (!IS_STRING(x)) return x;
122
123  var global_receiver = %GlobalReceiver(global);
124  var this_is_global_receiver = (this === global_receiver);
125  var global_is_detached = (global === global_receiver);
126
127  if (!this_is_global_receiver || global_is_detached) {
128    throw new $EvalError('The "this" object passed to eval must ' +
129                         'be the global object from which eval originated');
130  }
131
132  var f = %CompileString(x, false);
133  if (!IS_FUNCTION(f)) return f;
134
135  return f.call(this);
136}
137
138
139// execScript for IE compatibility.
140function GlobalExecScript(expr, lang) {
141  // NOTE: We don't care about the character casing.
142  if (!lang || /javascript/i.test(lang)) {
143    var f = %CompileString(ToString(expr), false);
144    f.call(%GlobalReceiver(global));
145  }
146  return null;
147}
148
149
150// ----------------------------------------------------------------------------
151
152
153function SetupGlobal() {
154  // ECMA 262 - 15.1.1.1.
155  %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
156
157  // ECMA-262 - 15.1.1.2.
158  %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
159
160  // ECMA-262 - 15.1.1.3.
161  %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
162
163  // Setup non-enumerable function on the global object.
164  InstallFunctions(global, DONT_ENUM, $Array(
165    "isNaN", GlobalIsNaN,
166    "isFinite", GlobalIsFinite,
167    "parseInt", GlobalParseInt,
168    "parseFloat", GlobalParseFloat,
169    "eval", GlobalEval,
170    "execScript", GlobalExecScript
171  ));
172}
173
174SetupGlobal();
175
176
177// ----------------------------------------------------------------------------
178// Boolean (first part of definition)
179
180
181%SetCode($Boolean, function(x) {
182  if (%_IsConstructCall()) {
183    %_SetValueOf(this, ToBoolean(x));
184  } else {
185    return ToBoolean(x);
186  }
187});
188
189%FunctionSetPrototype($Boolean, new $Boolean(false));
190
191%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
192
193// ----------------------------------------------------------------------------
194// Object
195
196$Object.prototype.constructor = $Object;
197
198// ECMA-262 - 15.2.4.2
199function ObjectToString() {
200  return "[object " + %_ClassOf(ToObject(this)) + "]";
201}
202
203
204// ECMA-262 - 15.2.4.3
205function ObjectToLocaleString() {
206  return this.toString();
207}
208
209
210// ECMA-262 - 15.2.4.4
211function ObjectValueOf() {
212  return ToObject(this);
213}
214
215
216// ECMA-262 - 15.2.4.5
217function ObjectHasOwnProperty(V) {
218  return %HasLocalProperty(ToObject(this), ToString(V));
219}
220
221
222// ECMA-262 - 15.2.4.6
223function ObjectIsPrototypeOf(V) {
224  if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
225  return %IsInPrototypeChain(this, V);
226}
227
228
229// ECMA-262 - 15.2.4.6
230function ObjectPropertyIsEnumerable(V) {
231  if (this == null) return false;
232  if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
233  return %IsPropertyEnumerable(this, ToString(V));
234}
235
236
237// Extensions for providing property getters and setters.
238function ObjectDefineGetter(name, fun) {
239  if (this == null) {
240    throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
241  }
242  if (!IS_FUNCTION(fun)) {
243    throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
244  }
245  return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
246}
247
248
249function ObjectLookupGetter(name) {
250  if (this == null) {
251    throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
252  }
253  return %LookupAccessor(ToObject(this), ToString(name), GETTER);
254}
255
256
257function ObjectDefineSetter(name, fun) {
258  if (this == null) {
259    throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
260  }
261  if (!IS_FUNCTION(fun)) {
262    throw new $TypeError(
263        'Object.prototype.__defineSetter__: Expecting function');
264  }
265  return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
266}
267
268
269function ObjectLookupSetter(name) {
270  if (this == null) {
271    throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
272  }
273  return %LookupAccessor(ToObject(this), ToString(name), SETTER);
274}
275
276
277function ObjectKeys(obj) {
278  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
279    throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
280  return %LocalKeys(obj);
281}
282
283
284// ES5 8.10.1.
285function IsAccessorDescriptor(desc) {
286  if (IS_UNDEFINED(desc)) return false;
287  return desc.hasGetter_ || desc.hasSetter_;
288}
289
290
291// ES5 8.10.2.
292function IsDataDescriptor(desc) {
293  if (IS_UNDEFINED(desc)) return false;
294  return desc.hasValue_ || desc.hasWritable_;
295}
296
297
298// ES5 8.10.3.
299function IsGenericDescriptor(desc) {
300  return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
301}
302
303
304function IsInconsistentDescriptor(desc) {
305  return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
306}
307
308// ES5 8.10.4
309function FromPropertyDescriptor(desc) {
310  if (IS_UNDEFINED(desc)) return desc;
311  var obj = new $Object();
312  if (IsDataDescriptor(desc)) {
313    obj.value = desc.getValue();
314    obj.writable = desc.isWritable();
315  }
316  if (IsAccessorDescriptor(desc)) {
317    obj.get = desc.getGet();
318    obj.set = desc.getSet();
319  }
320  obj.enumerable = desc.isEnumerable();
321  obj.configurable = desc.isConfigurable();
322  return obj;
323}
324
325// ES5 8.10.5.
326function ToPropertyDescriptor(obj) {
327  if (!IS_OBJECT(obj)) {
328    throw MakeTypeError("property_desc_object", [obj]);
329  }
330  var desc = new PropertyDescriptor();
331
332  if ("enumerable" in obj) {
333    desc.setEnumerable(ToBoolean(obj.enumerable));
334  }
335
336  if ("configurable" in obj) {
337    desc.setConfigurable(ToBoolean(obj.configurable));
338  }
339
340  if ("value" in obj) {
341    desc.setValue(obj.value);
342  }
343
344  if ("writable" in obj) {
345    desc.setWritable(ToBoolean(obj.writable));
346  }
347
348  if ("get" in obj) {
349    var get = obj.get;
350    if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
351      throw MakeTypeError("getter_must_be_callable", [get]);
352    }
353    desc.setGet(get);
354  }
355
356  if ("set" in obj) {
357    var set = obj.set;
358    if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
359      throw MakeTypeError("setter_must_be_callable", [set]);
360    }
361    desc.setSet(set);
362  }
363
364  if (IsInconsistentDescriptor(desc)) {
365    throw MakeTypeError("value_and_accessor", [obj]);
366  }
367  return desc;
368}
369
370
371function PropertyDescriptor() {
372  // Initialize here so they are all in-object and have the same map.
373  // Default values from ES5 8.6.1.
374  this.value_ = void 0;
375  this.hasValue_ = false;
376  this.writable_ = false;
377  this.hasWritable_ = false;
378  this.enumerable_ = false;
379  this.hasEnumerable_ = false;
380  this.configurable_ = false;
381  this.hasConfigurable_ = false;
382  this.get_ = void 0;
383  this.hasGetter_ = false;
384  this.set_ = void 0;
385  this.hasSetter_ = false;
386}
387
388
389PropertyDescriptor.prototype.setValue = function(value) {
390  this.value_ = value;
391  this.hasValue_ = true;
392}
393
394
395PropertyDescriptor.prototype.getValue = function() {
396  return this.value_;
397}
398
399
400PropertyDescriptor.prototype.hasValue = function() {
401  return this.hasValue_;
402}
403
404
405PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
406  this.enumerable_ = enumerable;
407  this.hasEnumerable_ = true;
408}
409
410
411PropertyDescriptor.prototype.isEnumerable = function () {
412  return this.enumerable_;
413}
414
415
416PropertyDescriptor.prototype.hasEnumerable = function() {
417  return this.hasEnumerable_;
418}
419
420
421PropertyDescriptor.prototype.setWritable = function(writable) {
422  this.writable_ = writable;
423  this.hasWritable_ = true;
424}
425
426
427PropertyDescriptor.prototype.isWritable = function() {
428  return this.writable_;
429}
430
431
432PropertyDescriptor.prototype.setConfigurable = function(configurable) {
433  this.configurable_ = configurable;
434  this.hasConfigurable_ = true;
435}
436
437
438PropertyDescriptor.prototype.hasConfigurable = function() {
439  return this.hasConfigurable_;
440}
441
442
443PropertyDescriptor.prototype.isConfigurable = function() {
444  return this.configurable_;
445}
446
447
448PropertyDescriptor.prototype.setGet = function(get) {
449  this.get_ = get;
450  this.hasGetter_ = true;
451}
452
453
454PropertyDescriptor.prototype.getGet = function() {
455  return this.get_;
456}
457
458
459PropertyDescriptor.prototype.hasGetter = function() {
460  return this.hasGetter_;
461}
462
463
464PropertyDescriptor.prototype.setSet = function(set) {
465  this.set_ = set;
466  this.hasSetter_ = true;
467}
468
469
470PropertyDescriptor.prototype.getSet = function() {
471  return this.set_;
472}
473
474
475PropertyDescriptor.prototype.hasSetter = function() {
476  return this.hasSetter_;
477}
478
479
480
481// ES5 section 8.12.1.
482function GetOwnProperty(obj, p) {
483  var desc = new PropertyDescriptor();
484
485  // An array with:
486  //  obj is a data property [false, value, Writeable, Enumerable, Configurable]
487  //  obj is an accessor [true, Get, Set, Enumerable, Configurable]
488  var props = %GetOwnProperty(ToObject(obj), ToString(p));
489
490  if (IS_UNDEFINED(props)) return void 0;
491
492  // This is an accessor
493  if (props[0]) {
494    desc.setGet(props[1]);
495    desc.setSet(props[2]);
496  } else {
497    desc.setValue(props[1]);
498    desc.setWritable(props[2]);
499  }
500  desc.setEnumerable(props[3]);
501  desc.setConfigurable(props[4]);
502
503  return desc;
504}
505
506
507// ES5 section 8.12.2.
508function GetProperty(obj, p) {
509  var prop = GetOwnProperty(obj);
510  if (!IS_UNDEFINED(prop)) return prop;
511  var proto = obj.__proto__;
512  if (IS_NULL(proto)) return void 0;
513  return GetProperty(proto, p);
514}
515
516
517// ES5 section 8.12.6
518function HasProperty(obj, p) {
519  var desc = GetProperty(obj, p);
520  return IS_UNDEFINED(desc) ? false : true;
521}
522
523
524// ES5 8.12.9.
525function DefineOwnProperty(obj, p, desc, should_throw) {
526  var current = GetOwnProperty(obj, p);
527  var extensible = %IsExtensible(ToObject(obj));
528
529  // Error handling according to spec.
530  // Step 3
531  if (IS_UNDEFINED(current) && !extensible)
532    throw MakeTypeError("define_disallowed", ["defineProperty"]);
533
534  if (!IS_UNDEFINED(current) && !current.isConfigurable()) {
535    // Step 7
536    if (desc.isConfigurable() ||  desc.isEnumerable() != current.isEnumerable())
537      throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
538    // Step 9
539    if (IsDataDescriptor(current) != IsDataDescriptor(desc))
540      throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
541    // Step 10
542    if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
543      if (!current.isWritable() && desc.isWritable())
544        throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
545      if (!current.isWritable() && desc.hasValue() &&
546          !SameValue(desc.getValue(), current.getValue())) {
547        throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
548      }
549    }
550    // Step 11
551    if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
552      if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){
553        throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
554      }
555      if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet()))
556        throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
557    }
558  }
559
560  // Send flags - enumerable and configurable are common - writable is
561  // only send to the data descriptor.
562  // Take special care if enumerable and configurable is not defined on
563  // desc (we need to preserve the existing values from current).
564  var flag = NONE;
565  if (desc.hasEnumerable()) {
566    flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
567  } else if (!IS_UNDEFINED(current)) {
568    flag |= current.isEnumerable() ? 0 : DONT_ENUM;
569  } else {
570    flag |= DONT_ENUM;
571  }
572
573  if (desc.hasConfigurable()) {
574    flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
575  } else if (!IS_UNDEFINED(current)) {
576    flag |= current.isConfigurable() ? 0 : DONT_DELETE;
577  } else
578    flag |= DONT_DELETE;
579
580  if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) {
581    flag |= desc.isWritable() ? 0 : READ_ONLY;
582    %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag);
583  } else {
584    if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) {
585       %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
586    }
587    if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) {
588      %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
589    }
590  }
591  return true;
592}
593
594
595// ES5 section 15.2.3.2.
596function ObjectGetPrototypeOf(obj) {
597  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
598    throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
599  return obj.__proto__;
600}
601
602
603// ES5 section 15.2.3.3
604function ObjectGetOwnPropertyDescriptor(obj, p) {
605  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
606    throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]);
607  var desc = GetOwnProperty(obj, p);
608  return FromPropertyDescriptor(desc);
609}
610
611
612// ES5 section 15.2.3.4.
613function ObjectGetOwnPropertyNames(obj) {
614  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
615    throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
616
617  // Find all the indexed properties.
618
619  // Get the local element names.
620  var propertyNames = %GetLocalElementNames(obj);
621
622  // Get names for indexed interceptor properties.
623  if (%GetInterceptorInfo(obj) & 1) {
624    var indexedInterceptorNames =
625        %GetIndexedInterceptorElementNames(obj);
626    if (indexedInterceptorNames)
627      propertyNames = propertyNames.concat(indexedInterceptorNames);
628  }
629
630  // Find all the named properties.
631
632  // Get the local property names.
633  propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
634
635  // Get names for named interceptor properties if any.
636
637  if (%GetInterceptorInfo(obj) & 2) {
638    var namedInterceptorNames =
639        %GetNamedInterceptorPropertyNames(obj);
640    if (namedInterceptorNames) {
641      propertyNames = propertyNames.concat(namedInterceptorNames);
642    }
643  }
644
645  // Property names are expected to be strings.
646  for (var i = 0; i < propertyNames.length; ++i)
647    propertyNames[i] = ToString(propertyNames[i]);
648
649  return propertyNames;
650}
651
652
653// ES5 section 15.2.3.5.
654function ObjectCreate(proto, properties) {
655  if (!IS_OBJECT(proto) && !IS_NULL(proto)) {
656    throw MakeTypeError("proto_object_or_null", [proto]);
657  }
658  var obj = new $Object();
659  obj.__proto__ = proto;
660  if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
661  return obj;
662}
663
664
665// ES5 section 15.2.3.6.
666function ObjectDefineProperty(obj, p, attributes) {
667  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
668    throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
669  var name = ToString(p);
670  var desc = ToPropertyDescriptor(attributes);
671  DefineOwnProperty(obj, name, desc, true);
672  return obj;
673}
674
675
676// ES5 section 15.2.3.7.
677function ObjectDefineProperties(obj, properties) {
678 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
679    throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
680  var props = ToObject(properties);
681  var key_values = [];
682  for (var key in props) {
683    if (%HasLocalProperty(props, key)) {
684      key_values.push(key);
685      var value = props[key];
686      var desc = ToPropertyDescriptor(value);
687      key_values.push(desc);
688    }
689  }
690  for (var i = 0; i < key_values.length; i += 2) {
691    var key = key_values[i];
692    var desc = key_values[i + 1];
693    DefineOwnProperty(obj, key, desc, true);
694  }
695  return obj;
696}
697
698
699%SetCode($Object, function(x) {
700  if (%_IsConstructCall()) {
701    if (x == null) return this;
702    return ToObject(x);
703  } else {
704    if (x == null) return { };
705    return ToObject(x);
706  }
707});
708
709
710// ----------------------------------------------------------------------------
711
712
713function SetupObject() {
714  // Setup non-enumerable functions on the Object.prototype object.
715  InstallFunctions($Object.prototype, DONT_ENUM, $Array(
716    "toString", ObjectToString,
717    "toLocaleString", ObjectToLocaleString,
718    "valueOf", ObjectValueOf,
719    "hasOwnProperty", ObjectHasOwnProperty,
720    "isPrototypeOf", ObjectIsPrototypeOf,
721    "propertyIsEnumerable", ObjectPropertyIsEnumerable,
722    "__defineGetter__", ObjectDefineGetter,
723    "__lookupGetter__", ObjectLookupGetter,
724    "__defineSetter__", ObjectDefineSetter,
725    "__lookupSetter__", ObjectLookupSetter
726  ));
727  InstallFunctions($Object, DONT_ENUM, $Array(
728    "keys", ObjectKeys,
729    "create", ObjectCreate,
730    "defineProperty", ObjectDefineProperty,
731    "defineProperties", ObjectDefineProperties,
732    "getPrototypeOf", ObjectGetPrototypeOf,
733    "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
734    "getOwnPropertyNames", ObjectGetOwnPropertyNames
735  ));
736}
737
738SetupObject();
739
740
741// ----------------------------------------------------------------------------
742// Boolean
743
744function BooleanToString() {
745  // NOTE: Both Boolean objects and values can enter here as
746  // 'this'. This is not as dictated by ECMA-262.
747  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
748    throw new $TypeError('Boolean.prototype.toString is not generic');
749  return ToString(%_ValueOf(this));
750}
751
752
753function BooleanValueOf() {
754  // NOTE: Both Boolean objects and values can enter here as
755  // 'this'. This is not as dictated by ECMA-262.
756  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
757    throw new $TypeError('Boolean.prototype.valueOf is not generic');
758  return %_ValueOf(this);
759}
760
761
762function BooleanToJSON(key) {
763  return CheckJSONPrimitive(this.valueOf());
764}
765
766
767// ----------------------------------------------------------------------------
768
769
770function SetupBoolean() {
771  InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
772    "toString", BooleanToString,
773    "valueOf", BooleanValueOf,
774    "toJSON", BooleanToJSON
775  ));
776}
777
778SetupBoolean();
779
780// ----------------------------------------------------------------------------
781// Number
782
783// Set the Number function and constructor.
784%SetCode($Number, function(x) {
785  var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
786  if (%_IsConstructCall()) {
787    %_SetValueOf(this, value);
788  } else {
789    return value;
790  }
791});
792
793%FunctionSetPrototype($Number, new $Number(0));
794
795// ECMA-262 section 15.7.4.2.
796function NumberToString(radix) {
797  // NOTE: Both Number objects and values can enter here as
798  // 'this'. This is not as dictated by ECMA-262.
799  var number = this;
800  if (!IS_NUMBER(this)) {
801    if (!IS_NUMBER_WRAPPER(this))
802      throw new $TypeError('Number.prototype.toString is not generic');
803    // Get the value of this number in case it's an object.
804    number = %_ValueOf(this);
805  }
806  // Fast case: Convert number in radix 10.
807  if (IS_UNDEFINED(radix) || radix === 10) {
808    return ToString(number);
809  }
810
811  // Convert the radix to an integer and check the range.
812  radix = TO_INTEGER(radix);
813  if (radix < 2 || radix > 36) {
814    throw new $RangeError('toString() radix argument must be between 2 and 36');
815  }
816  // Convert the number to a string in the given radix.
817  return %NumberToRadixString(number, radix);
818}
819
820
821// ECMA-262 section 15.7.4.3
822function NumberToLocaleString() {
823  return this.toString();
824}
825
826
827// ECMA-262 section 15.7.4.4
828function NumberValueOf() {
829  // NOTE: Both Number objects and values can enter here as
830  // 'this'. This is not as dictated by ECMA-262.
831  if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
832    throw new $TypeError('Number.prototype.valueOf is not generic');
833  return %_ValueOf(this);
834}
835
836
837// ECMA-262 section 15.7.4.5
838function NumberToFixed(fractionDigits) {
839  var f = TO_INTEGER(fractionDigits);
840  if (f < 0 || f > 20) {
841    throw new $RangeError("toFixed() digits argument must be between 0 and 20");
842  }
843  var x = ToNumber(this);
844  return %NumberToFixed(x, f);
845}
846
847
848// ECMA-262 section 15.7.4.6
849function NumberToExponential(fractionDigits) {
850  var f = -1;
851  if (!IS_UNDEFINED(fractionDigits)) {
852    f = TO_INTEGER(fractionDigits);
853    if (f < 0 || f > 20) {
854      throw new $RangeError("toExponential() argument must be between 0 and 20");
855    }
856  }
857  var x = ToNumber(this);
858  return %NumberToExponential(x, f);
859}
860
861
862// ECMA-262 section 15.7.4.7
863function NumberToPrecision(precision) {
864  if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
865  var p = TO_INTEGER(precision);
866  if (p < 1 || p > 21) {
867    throw new $RangeError("toPrecision() argument must be between 1 and 21");
868  }
869  var x = ToNumber(this);
870  return %NumberToPrecision(x, p);
871}
872
873
874function CheckJSONPrimitive(val) {
875  if (!IsPrimitive(val))
876    throw MakeTypeError('result_not_primitive', ['toJSON', val]);
877  return val;
878}
879
880
881function NumberToJSON(key) {
882  return CheckJSONPrimitive(this.valueOf());
883}
884
885
886// ----------------------------------------------------------------------------
887
888function SetupNumber() {
889  %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
890  // Setup the constructor property on the Number prototype object.
891  %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
892
893  %OptimizeObjectForAddingMultipleProperties($Number, 5);
894  // ECMA-262 section 15.7.3.1.
895  %SetProperty($Number,
896               "MAX_VALUE",
897               1.7976931348623157e+308,
898               DONT_ENUM | DONT_DELETE | READ_ONLY);
899
900  // ECMA-262 section 15.7.3.2.
901  %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
902
903  // ECMA-262 section 15.7.3.3.
904  %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
905
906  // ECMA-262 section 15.7.3.4.
907  %SetProperty($Number,
908               "NEGATIVE_INFINITY",
909               -1/0,
910               DONT_ENUM | DONT_DELETE | READ_ONLY);
911
912  // ECMA-262 section 15.7.3.5.
913  %SetProperty($Number,
914               "POSITIVE_INFINITY",
915               1/0,
916               DONT_ENUM | DONT_DELETE | READ_ONLY);
917  %ToFastProperties($Number);
918
919  // Setup non-enumerable functions on the Number prototype object.
920  InstallFunctions($Number.prototype, DONT_ENUM, $Array(
921    "toString", NumberToString,
922    "toLocaleString", NumberToLocaleString,
923    "valueOf", NumberValueOf,
924    "toFixed", NumberToFixed,
925    "toExponential", NumberToExponential,
926    "toPrecision", NumberToPrecision,
927    "toJSON", NumberToJSON
928  ));
929}
930
931SetupNumber();
932
933
934
935// ----------------------------------------------------------------------------
936// Function
937
938$Function.prototype.constructor = $Function;
939
940function FunctionSourceString(func) {
941  if (!IS_FUNCTION(func)) {
942    throw new $TypeError('Function.prototype.toString is not generic');
943  }
944
945  var source = %FunctionGetSourceCode(func);
946  if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
947    var name = %FunctionGetName(func);
948    if (name) {
949      // Mimic what KJS does.
950      return 'function ' + name + '() { [native code] }';
951    } else {
952      return 'function () { [native code] }';
953    }
954  }
955
956  var name = %FunctionGetName(func);
957  return 'function ' + name + source;
958}
959
960
961function FunctionToString() {
962  return FunctionSourceString(this);
963}
964
965
966function NewFunction(arg1) {  // length == 1
967  var n = %_ArgumentsLength();
968  var p = '';
969  if (n > 1) {
970    p = new $Array(n - 1);
971    // Explicitly convert all parameters to strings.
972    // Array.prototype.join replaces null with empty strings which is
973    // not appropriate.
974    for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
975    p = p.join(',');
976    // If the formal parameters string include ) - an illegal
977    // character - it may make the combined function expression
978    // compile. We avoid this problem by checking for this early on.
979    if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
980  }
981  var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
982  var source = '(function(' + p + ') {\n' + body + '\n})';
983
984  // The call to SetNewFunctionAttributes will ensure the prototype
985  // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
986  var f = %CompileString(source, false)();
987  %FunctionSetName(f, "anonymous");
988  return %SetNewFunctionAttributes(f);
989}
990
991%SetCode($Function, NewFunction);
992
993// ----------------------------------------------------------------------------
994
995function SetupFunction() {
996  InstallFunctions($Function.prototype, DONT_ENUM, $Array(
997    "toString", FunctionToString
998  ));
999}
1000
1001SetupFunction();
1002