• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// This file relies on the fact that the following declarations have been made
29//
30// in runtime.js:
31// const $Object = global.Object;
32// const $Boolean = global.Boolean;
33// const $Number = global.Number;
34// const $Function = global.Function;
35// const $Array = global.Array;
36// const $NaN = 0/0;
37//
38// in math.js:
39// const $floor = MathFloor
40
41const $isNaN = GlobalIsNaN;
42const $isFinite = GlobalIsFinite;
43
44// ----------------------------------------------------------------------------
45
46
47// Helper function used to install functions on objects.
48function InstallFunctions(object, attributes, functions) {
49  if (functions.length >= 8) {
50    %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
51  }
52  for (var i = 0; i < functions.length; i += 2) {
53    var key = functions[i];
54    var f = functions[i + 1];
55    %FunctionSetName(f, key);
56    %SetProperty(object, key, f, attributes);
57  }
58  %TransformToFastProperties(object);
59}
60
61// Emulates JSC by installing functions on a hidden prototype that
62// lies above the current object/prototype.  This lets you override
63// functions on String.prototype etc. and then restore the old function
64// with delete.  See http://code.google.com/p/chromium/issues/detail?id=1717
65function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
66  var hidden_prototype = new $Object();
67  %SetHiddenPrototype(object, hidden_prototype);
68  InstallFunctions(hidden_prototype, attributes, functions);
69}
70
71
72// ----------------------------------------------------------------------------
73
74
75// ECMA 262 - 15.1.4
76function GlobalIsNaN(number) {
77  var n = ToNumber(number);
78  return NUMBER_IS_NAN(n);
79}
80
81
82// ECMA 262 - 15.1.5
83function GlobalIsFinite(number) {
84  return %NumberIsFinite(ToNumber(number));
85}
86
87
88// ECMA-262 - 15.1.2.2
89function GlobalParseInt(string, radix) {
90  if (radix === void 0) {
91    // Some people use parseInt instead of Math.floor.  This
92    // optimization makes parseInt on a Smi 12 times faster (60ns
93    // vs 800ns).  The following optimization makes parseInt on a
94    // non-Smi number 9 times faster (230ns vs 2070ns).  Together
95    // they make parseInt on a string 1.4% slower (274ns vs 270ns).
96    if (%_IsSmi(string)) return string;
97    if (IS_NUMBER(string) &&
98        ((string < -0.01 && -1e9 < string) ||
99            (0.01 < string && string < 1e9))) {
100      // Truncate number.
101      return string | 0;
102    }
103    radix = 0;
104  } else {
105    radix = TO_INT32(radix);
106    if (!(radix == 0 || (2 <= radix && radix <= 36)))
107      return $NaN;
108  }
109  return %StringParseInt(ToString(string), radix);
110}
111
112
113// ECMA-262 - 15.1.2.3
114function GlobalParseFloat(string) {
115  return %StringParseFloat(ToString(string));
116}
117
118
119function GlobalEval(x) {
120  if (!IS_STRING(x)) return x;
121
122  var global_receiver = %GlobalReceiver(global);
123  var this_is_global_receiver = (this === global_receiver);
124  var global_is_detached = (global === global_receiver);
125
126  if (!this_is_global_receiver || global_is_detached) {
127    throw new $EvalError('The "this" object passed to eval must ' +
128                         'be the global object from which eval originated');
129  }
130
131  var f = %CompileString(x, false);
132  if (!IS_FUNCTION(f)) return f;
133
134  return f.call(this);
135}
136
137
138// execScript for IE compatibility.
139function GlobalExecScript(expr, lang) {
140  // NOTE: We don't care about the character casing.
141  if (!lang || /javascript/i.test(lang)) {
142    var f = %CompileString(ToString(expr), false);
143    f.call(%GlobalReceiver(global));
144  }
145  return null;
146}
147
148
149// ----------------------------------------------------------------------------
150
151
152function SetupGlobal() {
153  // ECMA 262 - 15.1.1.1.
154  %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
155
156  // ECMA-262 - 15.1.1.2.
157  %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
158
159  // ECMA-262 - 15.1.1.3.
160  %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
161
162  // Setup non-enumerable function on the global object.
163  InstallFunctions(global, DONT_ENUM, $Array(
164    "isNaN", GlobalIsNaN,
165    "isFinite", GlobalIsFinite,
166    "parseInt", GlobalParseInt,
167    "parseFloat", GlobalParseFloat,
168    "eval", GlobalEval,
169    "execScript", GlobalExecScript
170  ));
171}
172
173SetupGlobal();
174
175
176// ----------------------------------------------------------------------------
177// Boolean (first part of definition)
178
179
180%SetCode($Boolean, function(x) {
181  if (%_IsConstructCall()) {
182    %_SetValueOf(this, ToBoolean(x));
183  } else {
184    return ToBoolean(x);
185  }
186});
187
188%FunctionSetPrototype($Boolean, new $Boolean(false));
189
190%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
191
192// ----------------------------------------------------------------------------
193// Object
194
195$Object.prototype.constructor = $Object;
196
197// ECMA-262 - 15.2.4.2
198function ObjectToString() {
199  var c = %_ClassOf(this);
200  // Hide Arguments from the outside.
201  if (c === 'Arguments') c  = 'Object';
202  return "[object " + c + "]";
203}
204
205
206// ECMA-262 - 15.2.4.3
207function ObjectToLocaleString() {
208  return this.toString();
209}
210
211
212// ECMA-262 - 15.2.4.4
213function ObjectValueOf() {
214  return this;
215}
216
217
218// ECMA-262 - 15.2.4.5
219function ObjectHasOwnProperty(V) {
220  return %HasLocalProperty(ToObject(this), ToString(V));
221}
222
223
224// ECMA-262 - 15.2.4.6
225function ObjectIsPrototypeOf(V) {
226  if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
227  return %IsInPrototypeChain(this, V);
228}
229
230
231// ECMA-262 - 15.2.4.6
232function ObjectPropertyIsEnumerable(V) {
233  if (this == null) return false;
234  if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
235  return %IsPropertyEnumerable(this, ToString(V));
236}
237
238
239// Extensions for providing property getters and setters.
240function ObjectDefineGetter(name, fun) {
241  if (this == null) {
242    throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
243  }
244  if (!IS_FUNCTION(fun)) {
245    throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
246  }
247  return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
248}
249
250
251function ObjectLookupGetter(name) {
252  if (this == null) {
253    throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
254  }
255  return %LookupAccessor(ToObject(this), ToString(name), GETTER);
256}
257
258
259function ObjectDefineSetter(name, fun) {
260  if (this == null) {
261    throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
262  }
263  if (!IS_FUNCTION(fun)) {
264    throw new $TypeError(
265        'Object.prototype.__defineSetter__: Expecting function');
266  }
267  return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
268}
269
270
271function ObjectLookupSetter(name) {
272  if (this == null) {
273    throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
274  }
275  return %LookupAccessor(ToObject(this), ToString(name), SETTER);
276}
277
278
279%SetCode($Object, function(x) {
280  if (%_IsConstructCall()) {
281    if (x == null) return this;
282    return ToObject(x);
283  } else {
284    if (x == null) return { };
285    return ToObject(x);
286  }
287});
288
289
290// ----------------------------------------------------------------------------
291
292
293function SetupObject() {
294  // Setup non-enumerable functions on the Object.prototype object.
295  InstallFunctions($Object.prototype, DONT_ENUM, $Array(
296    "toString", ObjectToString,
297    "toLocaleString", ObjectToLocaleString,
298    "valueOf", ObjectValueOf,
299    "hasOwnProperty", ObjectHasOwnProperty,
300    "isPrototypeOf", ObjectIsPrototypeOf,
301    "propertyIsEnumerable", ObjectPropertyIsEnumerable,
302    "__defineGetter__", ObjectDefineGetter,
303    "__lookupGetter__", ObjectLookupGetter,
304    "__defineSetter__", ObjectDefineSetter,
305    "__lookupSetter__", ObjectLookupSetter
306  ));
307}
308
309SetupObject();
310
311
312// ----------------------------------------------------------------------------
313// Boolean
314
315function BooleanToString() {
316  // NOTE: Both Boolean objects and values can enter here as
317  // 'this'. This is not as dictated by ECMA-262.
318  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
319    throw new $TypeError('Boolean.prototype.toString is not generic');
320  return ToString(%_ValueOf(this));
321}
322
323
324function BooleanValueOf() {
325  // NOTE: Both Boolean objects and values can enter here as
326  // 'this'. This is not as dictated by ECMA-262.
327  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
328    throw new $TypeError('Boolean.prototype.valueOf is not generic');
329  return %_ValueOf(this);
330}
331
332
333function BooleanToJSON(key) {
334  return CheckJSONPrimitive(this.valueOf());
335}
336
337
338// ----------------------------------------------------------------------------
339
340
341function SetupBoolean() {
342  InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
343    "toString", BooleanToString,
344    "valueOf", BooleanValueOf,
345    "toJSON", BooleanToJSON
346  ));
347}
348
349SetupBoolean();
350
351// ----------------------------------------------------------------------------
352// Number
353
354// Set the Number function and constructor.
355%SetCode($Number, function(x) {
356  var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
357  if (%_IsConstructCall()) {
358    %_SetValueOf(this, value);
359  } else {
360    return value;
361  }
362});
363
364%FunctionSetPrototype($Number, new $Number(0));
365
366// ECMA-262 section 15.7.4.2.
367function NumberToString(radix) {
368  // NOTE: Both Number objects and values can enter here as
369  // 'this'. This is not as dictated by ECMA-262.
370  var number = this;
371  if (!IS_NUMBER(this)) {
372    if (!IS_NUMBER_WRAPPER(this))
373      throw new $TypeError('Number.prototype.toString is not generic');
374    // Get the value of this number in case it's an object.
375    number = %_ValueOf(this);
376  }
377  // Fast case: Convert number in radix 10.
378  if (IS_UNDEFINED(radix) || radix === 10) {
379    return ToString(number);
380  }
381
382  // Convert the radix to an integer and check the range.
383  radix = TO_INTEGER(radix);
384  if (radix < 2 || radix > 36) {
385    throw new $RangeError('toString() radix argument must be between 2 and 36');
386  }
387  // Convert the number to a string in the given radix.
388  return %NumberToRadixString(number, radix);
389}
390
391
392// ECMA-262 section 15.7.4.3
393function NumberToLocaleString() {
394  return this.toString();
395}
396
397
398// ECMA-262 section 15.7.4.4
399function NumberValueOf() {
400  // NOTE: Both Number objects and values can enter here as
401  // 'this'. This is not as dictated by ECMA-262.
402  if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
403    throw new $TypeError('Number.prototype.valueOf is not generic');
404  return %_ValueOf(this);
405}
406
407
408// ECMA-262 section 15.7.4.5
409function NumberToFixed(fractionDigits) {
410  var f = TO_INTEGER(fractionDigits);
411  if (f < 0 || f > 20) {
412    throw new $RangeError("toFixed() digits argument must be between 0 and 20");
413  }
414  var x = ToNumber(this);
415  return %NumberToFixed(x, f);
416}
417
418
419// ECMA-262 section 15.7.4.6
420function NumberToExponential(fractionDigits) {
421  var f = -1;
422  if (!IS_UNDEFINED(fractionDigits)) {
423    f = TO_INTEGER(fractionDigits);
424    if (f < 0 || f > 20) {
425      throw new $RangeError("toExponential() argument must be between 0 and 20");
426    }
427  }
428  var x = ToNumber(this);
429  return %NumberToExponential(x, f);
430}
431
432
433// ECMA-262 section 15.7.4.7
434function NumberToPrecision(precision) {
435  if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
436  var p = TO_INTEGER(precision);
437  if (p < 1 || p > 21) {
438    throw new $RangeError("toPrecision() argument must be between 1 and 21");
439  }
440  var x = ToNumber(this);
441  return %NumberToPrecision(x, p);
442}
443
444
445function CheckJSONPrimitive(val) {
446  if (!IsPrimitive(val))
447    throw MakeTypeError('result_not_primitive', ['toJSON', val]);
448  return val;
449}
450
451
452function NumberToJSON(key) {
453  return CheckJSONPrimitive(this.valueOf());
454}
455
456
457// ----------------------------------------------------------------------------
458
459function SetupNumber() {
460  %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
461  // Setup the constructor property on the Number prototype object.
462  %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
463
464  %OptimizeObjectForAddingMultipleProperties($Number, 5);
465  // ECMA-262 section 15.7.3.1.
466  %SetProperty($Number,
467               "MAX_VALUE",
468               1.7976931348623157e+308,
469               DONT_ENUM | DONT_DELETE | READ_ONLY);
470
471  // ECMA-262 section 15.7.3.2.
472  %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
473
474  // ECMA-262 section 15.7.3.3.
475  %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
476
477  // ECMA-262 section 15.7.3.4.
478  %SetProperty($Number,
479               "NEGATIVE_INFINITY",
480               -1/0,
481               DONT_ENUM | DONT_DELETE | READ_ONLY);
482
483  // ECMA-262 section 15.7.3.5.
484  %SetProperty($Number,
485               "POSITIVE_INFINITY",
486               1/0,
487               DONT_ENUM | DONT_DELETE | READ_ONLY);
488  %TransformToFastProperties($Number);
489
490  // Setup non-enumerable functions on the Number prototype object.
491  InstallFunctions($Number.prototype, DONT_ENUM, $Array(
492    "toString", NumberToString,
493    "toLocaleString", NumberToLocaleString,
494    "valueOf", NumberValueOf,
495    "toFixed", NumberToFixed,
496    "toExponential", NumberToExponential,
497    "toPrecision", NumberToPrecision,
498    "toJSON", NumberToJSON
499  ));
500}
501
502SetupNumber();
503
504
505
506// ----------------------------------------------------------------------------
507// Function
508
509$Function.prototype.constructor = $Function;
510
511function FunctionSourceString(func) {
512  if (!IS_FUNCTION(func)) {
513    throw new $TypeError('Function.prototype.toString is not generic');
514  }
515
516  var source = %FunctionGetSourceCode(func);
517  if (!IS_STRING(source)) {
518    var name = %FunctionGetName(func);
519    if (name) {
520      // Mimic what KJS does.
521      return 'function ' + name + '() { [native code] }';
522    } else {
523      return 'function () { [native code] }';
524    }
525  }
526
527  // Censor occurrences of internal calls.  We do that for all
528  // functions and don't cache under the assumption that people rarly
529  // convert functions to strings.  Note that we (apparently) can't
530  // use regular expression literals in natives files.
531  var regexp = ORIGINAL_REGEXP("%(\\w+\\()", "gm");
532  if (source.match(regexp)) source = source.replace(regexp, "$1");
533  var name = %FunctionGetName(func);
534  return 'function ' + name + source;
535}
536
537
538function FunctionToString() {
539  return FunctionSourceString(this);
540}
541
542
543function NewFunction(arg1) {  // length == 1
544  var n = %_ArgumentsLength();
545  var p = '';
546  if (n > 1) {
547    p = new $Array(n - 1);
548    // Explicitly convert all parameters to strings.
549    // Array.prototype.join replaces null with empty strings which is
550    // not appropriate.
551    for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
552    p = p.join(',');
553    // If the formal parameters string include ) - an illegal
554    // character - it may make the combined function expression
555    // compile. We avoid this problem by checking for this early on.
556    if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
557  }
558  var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
559  var source = '(function(' + p + ') {\n' + body + '\n})';
560
561  // The call to SetNewFunctionAttributes will ensure the prototype
562  // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
563  var f = %CompileString(source, false)();
564  %FunctionSetName(f, "anonymous");
565  return %SetNewFunctionAttributes(f);
566}
567
568%SetCode($Function, NewFunction);
569
570// ----------------------------------------------------------------------------
571
572function SetupFunction() {
573  InstallFunctions($Function.prototype, DONT_ENUM, $Array(
574    "toString", FunctionToString
575  ));
576}
577
578SetupFunction();
579