blob: f65de4f4c8e0fdaba66c9f1aee55f8b19551185a [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
28
29// This file relies on the fact that the following declarations have been made
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;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036// const $NaN = 0/0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
38
39// ECMA 262 - 15.1.1.1.
40%AddProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
41
42
43// ECMA-262 - 15.1.1.2.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000044%AddProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46
47// ECMA-262 - 15.1.1.3.
48%AddProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
49
50
51// ECMA 262 - 15.1.4
52function $isNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000053 var n = ToNumber(number);
54 return NUMBER_IS_NAN(n);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055};
56%AddProperty(global, "isNaN", $isNaN, DONT_ENUM);
57
58
59// ECMA 262 - 15.1.5
60function $isFinite(number) {
61 return %NumberIsFinite(ToNumber(number));
62};
63%AddProperty(global, "isFinite", $isFinite, DONT_ENUM);
64
65
66// ECMA-262 - 15.1.2.2
67%AddProperty(global, "parseInt", function(string, radix) {
68 if (radix === void 0) {
69 radix = 0;
70 // Some people use parseInt instead of Math.floor. This
71 // optimization makes parseInt on a Smi 12 times faster (60ns
72 // vs 800ns). The following optimization makes parseInt on a
73 // non-Smi number 9 times faster (230ns vs 2070ns). Together
74 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
75 if (%_IsSmi(string)) return string;
76 if (IS_NUMBER(string)) {
77 if (string >= 0.01 && string < 1e9)
78 return $Math_floor(string);
79 if (string <= -0.01 && string > -1e9)
80 return - $Math_floor(-string);
81 }
82 } else {
83 radix = TO_INT32(radix);
84 if (!(radix == 0 || (2 <= radix && radix <= 36)))
85 return $NaN;
86 }
87 return %StringParseInt(ToString(string), radix);
88}, DONT_ENUM);
89
90
91// ECMA-262 - 15.1.2.3
92%AddProperty(global, "parseFloat", function(string) {
93 return %StringParseFloat(ToString(string));
94}, DONT_ENUM);
95
96
97// ----------------------------------------------------------------------------
98// Boolean (first part of definition)
99
100
101%SetCode($Boolean, function(x) {
mads.s.ager31e71382008-08-13 09:32:07 +0000102 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 %_SetValueOf(this, ToBoolean(x));
104 } else {
105 return ToBoolean(x);
106 }
107});
108
109%FunctionSetPrototype($Boolean, new $Boolean(false));
110
111%AddProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
112
113// ----------------------------------------------------------------------------
114// Object
115
116$Object.prototype.constructor = $Object;
117
118%AddProperty($Object.prototype, "toString", function() {
119 var c = %ClassOf(this);
120 // Hide Arguments from the outside.
121 if (c === 'Arguments') c = 'Object';
122 return "[object " + c + "]";
123}, DONT_ENUM);
124
125
126// ECMA-262, section 15.2.4.3, page 84.
127%AddProperty($Object.prototype, "toLocaleString", function() {
128 return this.toString();
129}, DONT_ENUM);
130
131
132// ECMA-262, section 15.2.4.4, page 85.
133%AddProperty($Object.prototype, "valueOf", function() {
134 return this;
135}, DONT_ENUM);
136
137
138// ECMA-262, section 15.2.4.5, page 85.
139%AddProperty($Object.prototype, "hasOwnProperty", function(V) {
140 return %HasLocalProperty(ToObject(this), ToString(V));
141}, DONT_ENUM);
142
143
144// ECMA-262, section 15.2.4.6, page 85.
145%AddProperty($Object.prototype, "isPrototypeOf", function(V) {
146 if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
147 return %IsInPrototypeChain(this, V);
148}, DONT_ENUM);
149
150
151// ECMA-262, section 15.2.4.6, page 85.
152%AddProperty($Object.prototype, "propertyIsEnumerable", function(V) {
153 if (this == null) return false;
154 if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
155 return %IsPropertyEnumerable(this, ToString(V));
156}, DONT_ENUM);
157
158
159// Extensions for providing property getters and setters.
160%AddProperty($Object.prototype, "__defineGetter__", function(name, fun) {
161 if (this == null) throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
162 if (!IS_FUNCTION(fun)) throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
163 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
164}, DONT_ENUM);
165
166
167
168%AddProperty($Object.prototype, "__lookupGetter__", function(name) {
169 if (this == null) throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
170 return %LookupAccessor(ToObject(this), ToString(name), GETTER);
171}, DONT_ENUM);
172
173
174%AddProperty($Object.prototype, "__defineSetter__", function(name, fun) {
175 if (this == null) throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
176 if (!IS_FUNCTION(fun)) throw new $TypeError('Object.prototype.__defineSetter__: Expecting function');
177 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
178}, DONT_ENUM);
179
180
181%AddProperty($Object.prototype, "__lookupSetter__", function(name) {
182 if (this == null) throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
183 return %LookupAccessor(ToObject(this), ToString(name), SETTER);
184}, DONT_ENUM);
185
186
187%SetCode($Object, function(x) {
mads.s.ager31e71382008-08-13 09:32:07 +0000188 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 if (x == null) return this;
190 return ToObject(x);
191 } else {
192 if (x == null) return { };
193 return ToObject(x);
194 }
195});
196
197
198// ----------------------------------------------------------------------------
199// Global stuff...
200
201%AddProperty(global, "eval", function(x) {
202 if (!IS_STRING(x)) return x;
203
ager@chromium.org236ad962008-09-25 09:45:57 +0000204 var f = %CompileString(x, 0, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205 if (!IS_FUNCTION(f)) return f;
206
207 return f.call(%EvalReceiver(this));
208}, DONT_ENUM);
209
210
211// execScript for IE compatibility.
212%AddProperty(global, "execScript", function(expr, lang) {
213 // NOTE: We don't care about the character casing.
214 if (!lang || /javascript/i.test(lang)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000215 var f = %CompileString(ToString(expr), 0, false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000216 f.call(global);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217 }
218 return null;
219}, DONT_ENUM);
220
221
222// ----------------------------------------------------------------------------
223// Boolean
224
225%AddProperty($Boolean.prototype, "toString", function() {
226 // NOTE: Both Boolean objects and values can enter here as
227 // 'this'. This is not as dictated by ECMA-262.
228 if (!IS_BOOLEAN(this) && %ClassOf(this) !== 'Boolean')
229 throw new $TypeError('Boolean.prototype.toString is not generic');
230 return ToString(%_ValueOf(this));
231}, DONT_ENUM);
232
233
234%AddProperty($Boolean.prototype, "valueOf", function() {
235 // NOTE: Both Boolean objects and values can enter here as
236 // 'this'. This is not as dictated by ECMA-262.
237 if (!IS_BOOLEAN(this) && %ClassOf(this) !== 'Boolean')
238 throw new $TypeError('Boolean.prototype.valueOf is not generic');
239 return %_ValueOf(this);
240}, DONT_ENUM);
241
242
243// ----------------------------------------------------------------------------
244// Number
245
246// Set the Number function and constructor.
247%SetCode($Number, function(x) {
248 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
mads.s.ager31e71382008-08-13 09:32:07 +0000249 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 %_SetValueOf(this, value);
251 } else {
252 return value;
253 }
254});
255
256%FunctionSetPrototype($Number, new $Number(0));
257
258%AddProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
259
260// ECMA-262 section 15.7.3.1.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000261%AddProperty($Number, "MAX_VALUE", 1.7976931348623157e+308, DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262
263// ECMA-262 section 15.7.3.2.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264%AddProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265
266// ECMA-262 section 15.7.3.3.
267%AddProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
268
269// ECMA-262 section 15.7.3.4.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000270%AddProperty($Number, "NEGATIVE_INFINITY", -1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271
272// ECMA-262 section 15.7.3.5.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000273%AddProperty($Number, "POSITIVE_INFINITY", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274
275// ECMA-262 section 15.7.4.2.
276%AddProperty($Number.prototype, "toString", function(radix) {
277 // NOTE: Both Number objects and values can enter here as
278 // 'this'. This is not as dictated by ECMA-262.
279 var number = this;
280 if (!IS_NUMBER(this)) {
281 if (%ClassOf(this) !== 'Number')
282 throw new $TypeError('Number.prototype.toString is not generic');
283 // Get the value of this number in case it's an object.
284 number = %_ValueOf(this);
285 }
286 // Fast case: Convert number in radix 10.
287 if (IS_UNDEFINED(radix) || radix === 10) {
288 return ToString(number);
289 }
290
291 // Convert the radix to an integer and check the range.
292 radix = TO_INTEGER(radix);
293 if (radix < 2 || radix > 36) {
294 throw new $RangeError('toString() radix argument must be between 2 and 36');
295 }
296 // Convert the number to a string in the given radix.
297 return %NumberToRadixString(number, radix);
298}, DONT_ENUM);
299
300
301// ECMA-262 section 15.7.4.3
302%AddProperty($Number.prototype, "toLocaleString", function() {
303 return this.toString();
304}, DONT_ENUM);
305
306
307// ECMA-262 section 15.7.4.4
308%AddProperty($Number.prototype, "valueOf", function() {
309 // NOTE: Both Number objects and values can enter here as
310 // 'this'. This is not as dictated by ECMA-262.
311 if (!IS_NUMBER(this) && %ClassOf(this) !== 'Number')
312 throw new $TypeError('Number.prototype.valueOf is not generic');
313 return %_ValueOf(this);
314}, DONT_ENUM);
315
316
317// ECMA-262 section 15.7.4.5
318%AddProperty($Number.prototype, "toFixed", function(fractionDigits) {
319 var f = TO_INTEGER(fractionDigits);
320 if (f < 0 || f > 20) {
321 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
322 }
323 var x = ToNumber(this);
324 return %NumberToFixed(x, f);
325}, DONT_ENUM);
326
327
328// ECMA-262 section 15.7.4.6
329%AddProperty($Number.prototype, "toExponential", function(fractionDigits) {
330 var f = -1;
331 if (!IS_UNDEFINED(fractionDigits)) {
332 f = TO_INTEGER(fractionDigits);
333 if (f < 0 || f > 20) {
334 throw new $RangeError("toExponential() argument must be between 0 and 20");
335 }
336 }
337 var x = ToNumber(this);
338 return %NumberToExponential(x, f);
339}, DONT_ENUM);
340
341
342// ECMA-262 section 15.7.4.7
343%AddProperty($Number.prototype, "toPrecision", function(precision) {
344 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
345 var p = TO_INTEGER(precision);
346 if (p < 1 || p > 21) {
347 throw new $RangeError("toPrecision() argument must be between 1 and 21");
348 }
349 var x = ToNumber(this);
350 return %NumberToPrecision(x, p);
351}, DONT_ENUM);
352
353
354// ----------------------------------------------------------------------------
355// Function
356
357$Function.prototype.constructor = $Function;
358
359
360function FunctionSourceString(func) {
361 // NOTE: Both Function objects and values can enter here as
362 // 'func'. This is not as dictated by ECMA-262.
363 if (!IS_FUNCTION(func) && %ClassOf(func) != 'Function')
364 throw new $TypeError('Function.prototype.toString is not generic');
365
366 var source = %FunctionGetSourceCode(func);
367 if (!IS_STRING(source)) {
368 var name = %FunctionGetName(func);
369 if (name) {
370 // Mimic what KJS does.
371 return 'function ' + name + '() { [native code] }';
372 } else {
373 return 'function () { [native code] }';
374 }
375 }
376
377 // Censor occurrences of internal calls. We do that for all
378 // functions and don't cache under the assumption that people rarly
379 // convert functions to strings. Note that we (apparently) can't
380 // use regular expression literals in natives files.
381 var regexp = ORIGINAL_REGEXP("%(\\w+\\()", "gm");
382 if (source.match(regexp)) source = source.replace(regexp, "$1");
383 var name = %FunctionGetName(func);
384 return 'function ' + name + source;
385};
386
387
388%AddProperty($Function.prototype, "toString", function() {
389 return FunctionSourceString(this);
390}, DONT_ENUM);
391
392
393function NewFunction(arg1) { // length == 1
394 var n = %_ArgumentsLength();
395 var p = '';
396 if (n > 1) {
397 p = new $Array(n - 1);
398 // Explicitly convert all parameters to strings.
399 // Array.prototype.join replaces null with empty strings which is
400 // not appropriate.
401 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
402 p = p.join(',');
403 // If the formal parameters string include ) - an illegal
404 // character - it may make the combined function expression
405 // compile. We avoid this problem by checking for this early on.
406 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
407 }
408 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +0000409 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410
411 // The call to SetNewFunctionAttributes will ensure the prototype
412 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
ager@chromium.org236ad962008-09-25 09:45:57 +0000413 var f = %CompileString(source, -1, false)();
414 %FunctionSetName(f, "anonymous");
415 return %SetNewFunctionAttributes(f);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416};
417
418%SetCode($Function, NewFunction);