blob: 700b9e47e78f6c4d35f2cfe1c4089970eacf3071 [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
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000308// 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}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000324
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
337 if ("configurable" in obj) {
338 desc.setConfigurable(ToBoolean(obj.configurable));
339 }
340
341 if ("value" in obj) {
342 desc.setValue(obj.value);
343 }
344
345 if ("writable" in obj) {
346 desc.setWritable(ToBoolean(obj.writable));
347 }
348
349 if ("get" in obj) {
350 var get = obj.get;
351 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
352 throw MakeTypeError("getter_must_be_callable", [get]);
353 }
354 desc.setGet(get);
355 }
356
357 if ("set" in obj) {
358 var set = obj.set;
359 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
360 throw MakeTypeError("setter_must_be_callable", [set]);
361 }
362 desc.setSet(set);
363 }
364
365 if (IsInconsistentDescriptor(desc)) {
366 throw MakeTypeError("value_and_accessor", [obj]);
367 }
368 return desc;
369}
370
371
372function PropertyDescriptor() {
373 // Initialize here so they are all in-object and have the same map.
374 // Default values from ES5 8.6.1.
375 this.value_ = void 0;
376 this.hasValue_ = false;
377 this.writable_ = false;
378 this.hasWritable_ = false;
379 this.enumerable_ = false;
380 this.configurable_ = false;
381 this.get_ = void 0;
382 this.hasGetter_ = false;
383 this.set_ = void 0;
384 this.hasSetter_ = false;
385}
386
387
388PropertyDescriptor.prototype.setValue = function(value) {
389 this.value_ = value;
390 this.hasValue_ = true;
391}
392
393
394PropertyDescriptor.prototype.getValue = function() {
395 return this.value_;
396}
397
398
399PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
400 this.enumerable_ = enumerable;
401}
402
403
404PropertyDescriptor.prototype.isEnumerable = function () {
405 return this.enumerable_;
406}
407
408
409PropertyDescriptor.prototype.setWritable = function(writable) {
410 this.writable_ = writable;
411 this.hasWritable_ = true;
412}
413
414
415PropertyDescriptor.prototype.isWritable = function() {
416 return this.writable_;
417}
418
419
420PropertyDescriptor.prototype.setConfigurable = function(configurable) {
421 this.configurable_ = configurable;
422}
423
424
425PropertyDescriptor.prototype.isConfigurable = function() {
426 return this.configurable_;
427}
428
429
430PropertyDescriptor.prototype.setGet = function(get) {
431 this.get_ = get;
432 this.hasGetter_ = true;
433}
434
435
436PropertyDescriptor.prototype.getGet = function() {
437 return this.get_;
438}
439
440
441PropertyDescriptor.prototype.setSet = function(set) {
442 this.set_ = set;
443 this.hasSetter_ = true;
444}
445
446
447PropertyDescriptor.prototype.getSet = function() {
448 return this.set_;
449}
450
451
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000452// ES5 section 8.12.1.
453function GetOwnProperty(obj, p) {
454 var desc = new PropertyDescriptor();
455
456 // An array with:
457 // obj is a data property [false, value, Writeable, Enumerable, Configurable]
458 // obj is an accessor [true, Get, Set, Enumerable, Configurable]
459 var props = %GetOwnProperty(ToObject(obj), ToString(p));
460
461 if (IS_UNDEFINED(props))
462 return void 0;
463
464 // This is an accessor
465 if (props[0]) {
466 desc.setGet(props[1]);
467 desc.setSet(props[2]);
468 } else {
469 desc.setValue(props[1]);
470 desc.setWritable(props[2]);
471 }
472 desc.setEnumerable(props[3]);
473 desc.setConfigurable(props[4]);
474
475 return desc;
476}
477
478
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000479// ES5 8.12.9. This version cannot cope with the property p already
480// being present on obj.
481function DefineOwnProperty(obj, p, desc, should_throw) {
482 var flag = desc.isEnumerable() ? 0 : DONT_ENUM;
483 if (IsDataDescriptor(desc)) {
484 flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY);
485 %SetProperty(obj, p, desc.getValue(), flag);
486 } else {
487 if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag);
488 if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag);
489 }
490 return true;
491}
492
493
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000494// ES5 section 15.2.3.2.
495function ObjectGetPrototypeOf(obj) {
496 if (!IS_OBJECT(obj) && !IS_FUNCTION(obj)) {
497 throw MakeTypeError("object_get_prototype_non_object", [obj]);
498 }
499 return obj.__proto__;
500}
501
502
503// ES5 section 15.2.3.3
504function ObjectGetOwnPropertyDescriptor(obj, p) {
505 if (!IS_OBJECT(obj) && !IS_FUNCTION(obj)) {
506 throw MakeTypeError("object_get_prototype_non_object", [obj]);
507 }
508 var desc = GetOwnProperty(obj, p);
509 return FromPropertyDescriptor(desc);
510}
511
512
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513// ES5 section 15.2.3.5.
514function ObjectCreate(proto, properties) {
515 if (!IS_OBJECT(proto) && !IS_NULL(proto)) {
516 throw MakeTypeError("proto_object_or_null", [proto]);
517 }
518 var obj = new $Object();
519 obj.__proto__ = proto;
520 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
521 return obj;
522}
523
524
525// ES5 section 15.2.3.7. This version cannot cope with the properies already
526// being present on obj. Therefore it is not exposed as
527// Object.defineProperties yet.
528function ObjectDefineProperties(obj, properties) {
529 var props = ToObject(properties);
530 var key_values = [];
531 for (var key in props) {
532 if (%HasLocalProperty(props, key)) {
533 key_values.push(key);
534 var value = props[key];
535 var desc = ToPropertyDescriptor(value);
536 key_values.push(desc);
537 }
538 }
539 for (var i = 0; i < key_values.length; i += 2) {
540 var key = key_values[i];
541 var desc = key_values[i + 1];
542 DefineOwnProperty(obj, key, desc, true);
543 }
544}
545
546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000548 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 if (x == null) return this;
550 return ToObject(x);
551 } else {
552 if (x == null) return { };
553 return ToObject(x);
554 }
555});
556
557
558// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
560
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000561function SetupObject() {
562 // Setup non-enumerable functions on the Object.prototype object.
563 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
564 "toString", ObjectToString,
565 "toLocaleString", ObjectToLocaleString,
566 "valueOf", ObjectValueOf,
567 "hasOwnProperty", ObjectHasOwnProperty,
568 "isPrototypeOf", ObjectIsPrototypeOf,
569 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
570 "__defineGetter__", ObjectDefineGetter,
571 "__lookupGetter__", ObjectLookupGetter,
572 "__defineSetter__", ObjectDefineSetter,
573 "__lookupSetter__", ObjectLookupSetter
574 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000575 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000577 "create", ObjectCreate,
578 "getPrototypeOf", ObjectGetPrototypeOf,
579 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000580 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000581}
582
583SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584
585
586// ----------------------------------------------------------------------------
587// Boolean
588
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000589function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590 // NOTE: Both Boolean objects and values can enter here as
591 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000592 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593 throw new $TypeError('Boolean.prototype.toString is not generic');
594 return ToString(%_ValueOf(this));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000595}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596
597
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000598function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // NOTE: Both Boolean objects and values can enter here as
600 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000601 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602 throw new $TypeError('Boolean.prototype.valueOf is not generic');
603 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000604}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605
606
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000607function BooleanToJSON(key) {
608 return CheckJSONPrimitive(this.valueOf());
609}
610
611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000613
614
615function SetupBoolean() {
616 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
617 "toString", BooleanToString,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000618 "valueOf", BooleanValueOf,
619 "toJSON", BooleanToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000620 ));
621}
622
623SetupBoolean();
624
625// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626// Number
627
628// Set the Number function and constructor.
629%SetCode($Number, function(x) {
630 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000631 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632 %_SetValueOf(this, value);
633 } else {
634 return value;
635 }
636});
637
638%FunctionSetPrototype($Number, new $Number(0));
639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000641function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642 // NOTE: Both Number objects and values can enter here as
643 // 'this'. This is not as dictated by ECMA-262.
644 var number = this;
645 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000646 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 throw new $TypeError('Number.prototype.toString is not generic');
648 // Get the value of this number in case it's an object.
649 number = %_ValueOf(this);
650 }
651 // Fast case: Convert number in radix 10.
652 if (IS_UNDEFINED(radix) || radix === 10) {
653 return ToString(number);
654 }
655
656 // Convert the radix to an integer and check the range.
657 radix = TO_INTEGER(radix);
658 if (radix < 2 || radix > 36) {
659 throw new $RangeError('toString() radix argument must be between 2 and 36');
660 }
661 // Convert the number to a string in the given radix.
662 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000663}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664
665
666// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000667function NumberToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000669}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670
671
672// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000673function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 // NOTE: Both Number objects and values can enter here as
675 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000676 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 throw new $TypeError('Number.prototype.valueOf is not generic');
678 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000679}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680
681
682// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000683function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684 var f = TO_INTEGER(fractionDigits);
685 if (f < 0 || f > 20) {
686 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
687 }
688 var x = ToNumber(this);
689 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000690}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
692
693// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000694function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695 var f = -1;
696 if (!IS_UNDEFINED(fractionDigits)) {
697 f = TO_INTEGER(fractionDigits);
698 if (f < 0 || f > 20) {
699 throw new $RangeError("toExponential() argument must be between 0 and 20");
700 }
701 }
702 var x = ToNumber(this);
703 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000704}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705
706
707// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000708function NumberToPrecision(precision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
710 var p = TO_INTEGER(precision);
711 if (p < 1 || p > 21) {
712 throw new $RangeError("toPrecision() argument must be between 1 and 21");
713 }
714 var x = ToNumber(this);
715 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000716}
717
718
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000719function CheckJSONPrimitive(val) {
720 if (!IsPrimitive(val))
721 throw MakeTypeError('result_not_primitive', ['toJSON', val]);
722 return val;
723}
724
725
726function NumberToJSON(key) {
727 return CheckJSONPrimitive(this.valueOf());
728}
729
730
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000731// ----------------------------------------------------------------------------
732
733function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000734 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000735 // Setup the constructor property on the Number prototype object.
736 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
737
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000738 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000739 // ECMA-262 section 15.7.3.1.
740 %SetProperty($Number,
741 "MAX_VALUE",
742 1.7976931348623157e+308,
743 DONT_ENUM | DONT_DELETE | READ_ONLY);
744
745 // ECMA-262 section 15.7.3.2.
746 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
747
748 // ECMA-262 section 15.7.3.3.
749 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
750
751 // ECMA-262 section 15.7.3.4.
752 %SetProperty($Number,
753 "NEGATIVE_INFINITY",
754 -1/0,
755 DONT_ENUM | DONT_DELETE | READ_ONLY);
756
757 // ECMA-262 section 15.7.3.5.
758 %SetProperty($Number,
759 "POSITIVE_INFINITY",
760 1/0,
761 DONT_ENUM | DONT_DELETE | READ_ONLY);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000762 %TransformToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000763
764 // Setup non-enumerable functions on the Number prototype object.
765 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
766 "toString", NumberToString,
767 "toLocaleString", NumberToLocaleString,
768 "valueOf", NumberValueOf,
769 "toFixed", NumberToFixed,
770 "toExponential", NumberToExponential,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000771 "toPrecision", NumberToPrecision,
772 "toJSON", NumberToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000773 ));
774}
775
776SetupNumber();
777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778
779
780// ----------------------------------------------------------------------------
781// Function
782
783$Function.prototype.constructor = $Function;
784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000786 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789
790 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000791 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 var name = %FunctionGetName(func);
793 if (name) {
794 // Mimic what KJS does.
795 return 'function ' + name + '() { [native code] }';
796 } else {
797 return 'function () { [native code] }';
798 }
799 }
800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801 var name = %FunctionGetName(func);
802 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000803}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804
805
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000806function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000808}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809
810
811function NewFunction(arg1) { // length == 1
812 var n = %_ArgumentsLength();
813 var p = '';
814 if (n > 1) {
815 p = new $Array(n - 1);
816 // Explicitly convert all parameters to strings.
817 // Array.prototype.join replaces null with empty strings which is
818 // not appropriate.
819 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
820 p = p.join(',');
821 // If the formal parameters string include ) - an illegal
822 // character - it may make the combined function expression
823 // compile. We avoid this problem by checking for this early on.
824 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
825 }
826 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +0000827 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828
829 // The call to SetNewFunctionAttributes will ensure the prototype
830 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000831 var f = %CompileString(source, false)();
ager@chromium.org236ad962008-09-25 09:45:57 +0000832 %FunctionSetName(f, "anonymous");
833 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000834}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835
836%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000837
838// ----------------------------------------------------------------------------
839
840function SetupFunction() {
841 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
842 "toString", FunctionToString
843 ));
844}
845
846SetupFunction();