blob: a6640955808097ed60f316aea1b285446a328890 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000028// This file relies on the fact that the following declarations have been made
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000029//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030// 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;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036// const $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000037//
38// in math.js:
39// const $floor = MathFloor
40
41const $isNaN = GlobalIsNaN;
42const $isFinite = GlobalIsFinite;
43
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000044
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000045// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000048// Helper function used to install functions on objects.
49function InstallFunctions(object, attributes, functions) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000050 if (functions.length >= 8) {
51 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
52 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000053 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 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000059 %TransformToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000060}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
ager@chromium.org9085a012009-05-11 19:22:57 +000062// 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000073// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
75
76// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000077function GlobalIsNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000078 var n = ToNumber(number);
79 return NUMBER_IS_NAN(n);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000080}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081
82
83// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000084function GlobalIsFinite(number) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000085 return %NumberIsFinite(ToNumber(number));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000086}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087
88
89// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000090function GlobalParseInt(string, radix) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000091 if (IS_UNDEFINED(radix)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 // 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;
ager@chromium.org381abbb2009-02-25 13:23:22 +000098 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +000099 ((0.01 < string && string < 1e9) ||
100 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000101 // Truncate number.
102 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000104 radix = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 } else {
106 radix = TO_INT32(radix);
107 if (!(radix == 0 || (2 <= radix && radix <= 36)))
108 return $NaN;
109 }
110 return %StringParseInt(ToString(string), radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000111}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
113
114// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000115function GlobalParseFloat(string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 return %StringParseFloat(ToString(string));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000117}
118
119
120function GlobalEval(x) {
121 if (!IS_STRING(x)) return x;
122
ager@chromium.orge2902be2009-06-08 12:21:35 +0000123 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 ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000129 'be the global object from which eval originated');
130 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000131
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000132 var f = %CompileString(x, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000133 if (!IS_FUNCTION(f)) return f;
134
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000135 return f.call(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000136}
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)) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000143 var f = %CompileString(ToString(expr), false);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000144 f.call(%GlobalReceiver(global));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000145 }
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);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000162
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000163 // 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();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175
176
177// ----------------------------------------------------------------------------
178// Boolean (first part of definition)
179
180
181%SetCode($Boolean, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000182 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 %_SetValueOf(this, ToBoolean(x));
184 } else {
185 return ToBoolean(x);
186 }
187});
188
189%FunctionSetPrototype($Boolean, new $Boolean(false));
190
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000191%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192
193// ----------------------------------------------------------------------------
194// Object
195
196$Object.prototype.constructor = $Object;
197
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000198// ECMA-262 - 15.2.4.2
199function ObjectToString() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000200 return "[object " + %_ClassOf(this) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000201}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202
203
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000204// ECMA-262 - 15.2.4.3
205function ObjectToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000207}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208
209
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000210// ECMA-262 - 15.2.4.4
211function ObjectValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 return this;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000213}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214
215
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000216// ECMA-262 - 15.2.4.5
217function ObjectHasOwnProperty(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 return %HasLocalProperty(ToObject(this), ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000219}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220
221
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000222// ECMA-262 - 15.2.4.6
223function ObjectIsPrototypeOf(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
225 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000226}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227
228
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000229// ECMA-262 - 15.2.4.6
230function ObjectPropertyIsEnumerable(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231 if (this == null) return false;
232 if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
233 return %IsPropertyEnumerable(this, ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000234}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
236
237// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000238function 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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000246}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247
248
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000249function ObjectLookupGetter(name) {
250 if (this == null) {
251 throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253 return %LookupAccessor(ToObject(this), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000254}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255
256
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000257function 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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000266}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267
268
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000269function ObjectLookupSetter(name) {
270 if (this == null) {
271 throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 return %LookupAccessor(ToObject(this), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000274}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275
276
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000277function ObjectKeys(obj) {
278 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
279 throw MakeTypeError('object_keys_non_object', [obj]);
280 return %LocalKeys(obj);
281}
282
283
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000284// 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
309// ES5 8.10.5.
310function ToPropertyDescriptor(obj) {
311 if (!IS_OBJECT(obj)) {
312 throw MakeTypeError("property_desc_object", [obj]);
313 }
314 var desc = new PropertyDescriptor();
315
316 if ("enumerable" in obj) {
317 desc.setEnumerable(ToBoolean(obj.enumerable));
318 }
319
320
321 if ("configurable" in obj) {
322 desc.setConfigurable(ToBoolean(obj.configurable));
323 }
324
325 if ("value" in obj) {
326 desc.setValue(obj.value);
327 }
328
329 if ("writable" in obj) {
330 desc.setWritable(ToBoolean(obj.writable));
331 }
332
333 if ("get" in obj) {
334 var get = obj.get;
335 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
336 throw MakeTypeError("getter_must_be_callable", [get]);
337 }
338 desc.setGet(get);
339 }
340
341 if ("set" in obj) {
342 var set = obj.set;
343 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
344 throw MakeTypeError("setter_must_be_callable", [set]);
345 }
346 desc.setSet(set);
347 }
348
349 if (IsInconsistentDescriptor(desc)) {
350 throw MakeTypeError("value_and_accessor", [obj]);
351 }
352 return desc;
353}
354
355
356function PropertyDescriptor() {
357 // Initialize here so they are all in-object and have the same map.
358 // Default values from ES5 8.6.1.
359 this.value_ = void 0;
360 this.hasValue_ = false;
361 this.writable_ = false;
362 this.hasWritable_ = false;
363 this.enumerable_ = false;
364 this.configurable_ = false;
365 this.get_ = void 0;
366 this.hasGetter_ = false;
367 this.set_ = void 0;
368 this.hasSetter_ = false;
369}
370
371
372PropertyDescriptor.prototype.setValue = function(value) {
373 this.value_ = value;
374 this.hasValue_ = true;
375}
376
377
378PropertyDescriptor.prototype.getValue = function() {
379 return this.value_;
380}
381
382
383PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
384 this.enumerable_ = enumerable;
385}
386
387
388PropertyDescriptor.prototype.isEnumerable = function () {
389 return this.enumerable_;
390}
391
392
393PropertyDescriptor.prototype.setWritable = function(writable) {
394 this.writable_ = writable;
395 this.hasWritable_ = true;
396}
397
398
399PropertyDescriptor.prototype.isWritable = function() {
400 return this.writable_;
401}
402
403
404PropertyDescriptor.prototype.setConfigurable = function(configurable) {
405 this.configurable_ = configurable;
406}
407
408
409PropertyDescriptor.prototype.isConfigurable = function() {
410 return this.configurable_;
411}
412
413
414PropertyDescriptor.prototype.setGet = function(get) {
415 this.get_ = get;
416 this.hasGetter_ = true;
417}
418
419
420PropertyDescriptor.prototype.getGet = function() {
421 return this.get_;
422}
423
424
425PropertyDescriptor.prototype.setSet = function(set) {
426 this.set_ = set;
427 this.hasSetter_ = true;
428}
429
430
431PropertyDescriptor.prototype.getSet = function() {
432 return this.set_;
433}
434
435
436// ES5 8.12.9. This version cannot cope with the property p already
437// being present on obj.
438function DefineOwnProperty(obj, p, desc, should_throw) {
439 var flag = desc.isEnumerable() ? 0 : DONT_ENUM;
440 if (IsDataDescriptor(desc)) {
441 flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY);
442 %SetProperty(obj, p, desc.getValue(), flag);
443 } else {
444 if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag);
445 if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag);
446 }
447 return true;
448}
449
450
451// ES5 section 15.2.3.5.
452function ObjectCreate(proto, properties) {
453 if (!IS_OBJECT(proto) && !IS_NULL(proto)) {
454 throw MakeTypeError("proto_object_or_null", [proto]);
455 }
456 var obj = new $Object();
457 obj.__proto__ = proto;
458 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
459 return obj;
460}
461
462
463// ES5 section 15.2.3.7. This version cannot cope with the properies already
464// being present on obj. Therefore it is not exposed as
465// Object.defineProperties yet.
466function ObjectDefineProperties(obj, properties) {
467 var props = ToObject(properties);
468 var key_values = [];
469 for (var key in props) {
470 if (%HasLocalProperty(props, key)) {
471 key_values.push(key);
472 var value = props[key];
473 var desc = ToPropertyDescriptor(value);
474 key_values.push(desc);
475 }
476 }
477 for (var i = 0; i < key_values.length; i += 2) {
478 var key = key_values[i];
479 var desc = key_values[i + 1];
480 DefineOwnProperty(obj, key, desc, true);
481 }
482}
483
484
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000486 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 if (x == null) return this;
488 return ToObject(x);
489 } else {
490 if (x == null) return { };
491 return ToObject(x);
492 }
493});
494
495
496// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497
498
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000499function SetupObject() {
500 // Setup non-enumerable functions on the Object.prototype object.
501 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
502 "toString", ObjectToString,
503 "toLocaleString", ObjectToLocaleString,
504 "valueOf", ObjectValueOf,
505 "hasOwnProperty", ObjectHasOwnProperty,
506 "isPrototypeOf", ObjectIsPrototypeOf,
507 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
508 "__defineGetter__", ObjectDefineGetter,
509 "__lookupGetter__", ObjectLookupGetter,
510 "__defineSetter__", ObjectDefineSetter,
511 "__lookupSetter__", ObjectLookupSetter
512 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000513 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 "keys", ObjectKeys,
515 "create", ObjectCreate
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000516 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000517}
518
519SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520
521
522// ----------------------------------------------------------------------------
523// Boolean
524
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000525function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 // NOTE: Both Boolean objects and values can enter here as
527 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000528 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 throw new $TypeError('Boolean.prototype.toString is not generic');
530 return ToString(%_ValueOf(this));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000531}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532
533
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000534function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 // NOTE: Both Boolean objects and values can enter here as
536 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000537 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538 throw new $TypeError('Boolean.prototype.valueOf is not generic');
539 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000540}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541
542
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000543function BooleanToJSON(key) {
544 return CheckJSONPrimitive(this.valueOf());
545}
546
547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000549
550
551function SetupBoolean() {
552 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
553 "toString", BooleanToString,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000554 "valueOf", BooleanValueOf,
555 "toJSON", BooleanToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000556 ));
557}
558
559SetupBoolean();
560
561// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562// Number
563
564// Set the Number function and constructor.
565%SetCode($Number, function(x) {
566 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000567 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 %_SetValueOf(this, value);
569 } else {
570 return value;
571 }
572});
573
574%FunctionSetPrototype($Number, new $Number(0));
575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000577function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578 // NOTE: Both Number objects and values can enter here as
579 // 'this'. This is not as dictated by ECMA-262.
580 var number = this;
581 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000582 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 throw new $TypeError('Number.prototype.toString is not generic');
584 // Get the value of this number in case it's an object.
585 number = %_ValueOf(this);
586 }
587 // Fast case: Convert number in radix 10.
588 if (IS_UNDEFINED(radix) || radix === 10) {
589 return ToString(number);
590 }
591
592 // Convert the radix to an integer and check the range.
593 radix = TO_INTEGER(radix);
594 if (radix < 2 || radix > 36) {
595 throw new $RangeError('toString() radix argument must be between 2 and 36');
596 }
597 // Convert the number to a string in the given radix.
598 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000599}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600
601
602// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000603function NumberToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000605}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606
607
608// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000609function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610 // NOTE: Both Number objects and values can enter here as
611 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000612 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613 throw new $TypeError('Number.prototype.valueOf is not generic');
614 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000615}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616
617
618// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000619function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 var f = TO_INTEGER(fractionDigits);
621 if (f < 0 || f > 20) {
622 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
623 }
624 var x = ToNumber(this);
625 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000626}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627
628
629// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000630function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 var f = -1;
632 if (!IS_UNDEFINED(fractionDigits)) {
633 f = TO_INTEGER(fractionDigits);
634 if (f < 0 || f > 20) {
635 throw new $RangeError("toExponential() argument must be between 0 and 20");
636 }
637 }
638 var x = ToNumber(this);
639 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000640}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641
642
643// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000644function NumberToPrecision(precision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
646 var p = TO_INTEGER(precision);
647 if (p < 1 || p > 21) {
648 throw new $RangeError("toPrecision() argument must be between 1 and 21");
649 }
650 var x = ToNumber(this);
651 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000652}
653
654
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000655function CheckJSONPrimitive(val) {
656 if (!IsPrimitive(val))
657 throw MakeTypeError('result_not_primitive', ['toJSON', val]);
658 return val;
659}
660
661
662function NumberToJSON(key) {
663 return CheckJSONPrimitive(this.valueOf());
664}
665
666
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000667// ----------------------------------------------------------------------------
668
669function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000670 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000671 // Setup the constructor property on the Number prototype object.
672 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
673
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000674 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000675 // ECMA-262 section 15.7.3.1.
676 %SetProperty($Number,
677 "MAX_VALUE",
678 1.7976931348623157e+308,
679 DONT_ENUM | DONT_DELETE | READ_ONLY);
680
681 // ECMA-262 section 15.7.3.2.
682 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
683
684 // ECMA-262 section 15.7.3.3.
685 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
686
687 // ECMA-262 section 15.7.3.4.
688 %SetProperty($Number,
689 "NEGATIVE_INFINITY",
690 -1/0,
691 DONT_ENUM | DONT_DELETE | READ_ONLY);
692
693 // ECMA-262 section 15.7.3.5.
694 %SetProperty($Number,
695 "POSITIVE_INFINITY",
696 1/0,
697 DONT_ENUM | DONT_DELETE | READ_ONLY);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000698 %TransformToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000699
700 // Setup non-enumerable functions on the Number prototype object.
701 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
702 "toString", NumberToString,
703 "toLocaleString", NumberToLocaleString,
704 "valueOf", NumberValueOf,
705 "toFixed", NumberToFixed,
706 "toExponential", NumberToExponential,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000707 "toPrecision", NumberToPrecision,
708 "toJSON", NumberToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000709 ));
710}
711
712SetupNumber();
713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000714
715
716// ----------------------------------------------------------------------------
717// Function
718
719$Function.prototype.constructor = $Function;
720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000722 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725
726 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000727 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728 var name = %FunctionGetName(func);
729 if (name) {
730 // Mimic what KJS does.
731 return 'function ' + name + '() { [native code] }';
732 } else {
733 return 'function () { [native code] }';
734 }
735 }
736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737 var name = %FunctionGetName(func);
738 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000739}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740
741
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000742function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000744}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745
746
747function NewFunction(arg1) { // length == 1
748 var n = %_ArgumentsLength();
749 var p = '';
750 if (n > 1) {
751 p = new $Array(n - 1);
752 // Explicitly convert all parameters to strings.
753 // Array.prototype.join replaces null with empty strings which is
754 // not appropriate.
755 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
756 p = p.join(',');
757 // If the formal parameters string include ) - an illegal
758 // character - it may make the combined function expression
759 // compile. We avoid this problem by checking for this early on.
760 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
761 }
762 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +0000763 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764
765 // The call to SetNewFunctionAttributes will ensure the prototype
766 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000767 var f = %CompileString(source, false)();
ager@chromium.org236ad962008-09-25 09:45:57 +0000768 %FunctionSetName(f, "anonymous");
769 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000770}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771
772%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000773
774// ----------------------------------------------------------------------------
775
776function SetupFunction() {
777 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
778 "toString", FunctionToString
779 ));
780}
781
782SetupFunction();