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