The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / v8natives.js @ f230a1cf

History | View | Annotate | Download (53.4 KB)

1
// Copyright 2012 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
// in runtime.js:
30
// var $Object = global.Object;
31
// var $Boolean = global.Boolean;
32
// var $Number = global.Number;
33
// var $Function = global.Function;
34
// var $Array = global.Array;
35
//
36
// in math.js:
37
// var $floor = MathFloor
38

    
39
var $isNaN = GlobalIsNaN;
40
var $isFinite = GlobalIsFinite;
41

    
42
// ----------------------------------------------------------------------------
43

    
44
// Helper function used to install functions on objects.
45
function InstallFunctions(object, attributes, functions) {
46
  if (functions.length >= 8) {
47
    %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
48
  }
49
  for (var i = 0; i < functions.length; i += 2) {
50
    var key = functions[i];
51
    var f = functions[i + 1];
52
    %FunctionSetName(f, key);
53
    %FunctionRemovePrototype(f);
54
    %SetProperty(object, key, f, attributes);
55
    %SetNativeFlag(f);
56
  }
57
  %ToFastProperties(object);
58
}
59

    
60

    
61
// Helper function to install a getter-only accessor property.
62
function InstallGetter(object, name, getter) {
63
  %FunctionSetName(getter, name);
64
  %FunctionRemovePrototype(getter);
65
  %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
66
  %SetNativeFlag(getter);
67
}
68

    
69

    
70
// Helper function to install a getter/setter accessor property.
71
function InstallGetterSetter(object, name, getter, setter) {
72
  %FunctionSetName(getter, name);
73
  %FunctionSetName(setter, name);
74
  %FunctionRemovePrototype(getter);
75
  %FunctionRemovePrototype(setter);
76
  %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
77
  %SetNativeFlag(getter);
78
  %SetNativeFlag(setter);
79
}
80

    
81

    
82
// Prevents changes to the prototype of a built-in function.
83
// The "prototype" property of the function object is made non-configurable,
84
// and the prototype object is made non-extensible. The latter prevents
85
// changing the __proto__ property.
86
function SetUpLockedPrototype(constructor, fields, methods) {
87
  %CheckIsBootstrapping();
88
  var prototype = constructor.prototype;
89
  // Install functions first, because this function is used to initialize
90
  // PropertyDescriptor itself.
91
  var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
92
  if (property_count >= 4) {
93
    %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
94
  }
95
  if (fields) {
96
    for (var i = 0; i < fields.length; i++) {
97
      %SetProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE);
98
    }
99
  }
100
  for (var i = 0; i < methods.length; i += 2) {
101
    var key = methods[i];
102
    var f = methods[i + 1];
103
    %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
104
    %SetNativeFlag(f);
105
  }
106
  %SetPrototype(prototype, null);
107
  %ToFastProperties(prototype);
108
}
109

    
110

    
111
// ----------------------------------------------------------------------------
112

    
113

    
114
// ECMA 262 - 15.1.4
115
function GlobalIsNaN(number) {
116
  if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
117
  return NUMBER_IS_NAN(number);
118
}
119

    
120

    
121
// ECMA 262 - 15.1.5
122
function GlobalIsFinite(number) {
123
  if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
124
  return NUMBER_IS_FINITE(number);
125
}
126

    
127

    
128
// ECMA-262 - 15.1.2.2
129
function GlobalParseInt(string, radix) {
130
  if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
131
    // Some people use parseInt instead of Math.floor.  This
132
    // optimization makes parseInt on a Smi 12 times faster (60ns
133
    // vs 800ns).  The following optimization makes parseInt on a
134
    // non-Smi number 9 times faster (230ns vs 2070ns).  Together
135
    // they make parseInt on a string 1.4% slower (274ns vs 270ns).
136
    if (%_IsSmi(string)) return string;
137
    if (IS_NUMBER(string) &&
138
        ((0.01 < string && string < 1e9) ||
139
            (-1e9 < string && string < -0.01))) {
140
      // Truncate number.
141
      return string | 0;
142
    }
143
    string = TO_STRING_INLINE(string);
144
    radix = radix | 0;
145
  } else {
146
    // The spec says ToString should be evaluated before ToInt32.
147
    string = TO_STRING_INLINE(string);
148
    radix = TO_INT32(radix);
149
    if (!(radix == 0 || (2 <= radix && radix <= 36))) {
150
      return NAN;
151
    }
152
  }
153

    
154
  if (%_HasCachedArrayIndex(string) &&
155
      (radix == 0 || radix == 10)) {
156
    return %_GetCachedArrayIndex(string);
157
  }
158
  return %StringParseInt(string, radix);
159
}
160

    
161

    
162
// ECMA-262 - 15.1.2.3
163
function GlobalParseFloat(string) {
164
  string = TO_STRING_INLINE(string);
165
  if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
166
  return %StringParseFloat(string);
167
}
168

    
169

    
170
function GlobalEval(x) {
171
  if (!IS_STRING(x)) return x;
172

    
173
  var global_receiver = %GlobalReceiver(global);
174
  var global_is_detached = (global === global_receiver);
175

    
176
  // For consistency with JSC we require the global object passed to
177
  // eval to be the global object from which 'eval' originated. This
178
  // is not mandated by the spec.
179
  // We only throw if the global has been detached, since we need the
180
  // receiver as this-value for the call.
181
  if (global_is_detached) {
182
    throw new $EvalError('The "this" value passed to eval must ' +
183
                         'be the global object from which eval originated');
184
  }
185

    
186
  var f = %CompileString(x, false);
187
  if (!IS_FUNCTION(f)) return f;
188

    
189
  return %_CallFunction(global_receiver, f);
190
}
191

    
192

    
193
// ----------------------------------------------------------------------------
194

    
195
// Set up global object.
196
function SetUpGlobal() {
197
  %CheckIsBootstrapping();
198

    
199
  var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
200

    
201
  // ECMA 262 - 15.1.1.1.
202
  %SetProperty(global, "NaN", NAN, attributes);
203

    
204
  // ECMA-262 - 15.1.1.2.
205
  %SetProperty(global, "Infinity", INFINITY, attributes);
206

    
207
  // ECMA-262 - 15.1.1.3.
208
  %SetProperty(global, "undefined", UNDEFINED, attributes);
209

    
210
  // Set up non-enumerable function on the global object.
211
  InstallFunctions(global, DONT_ENUM, $Array(
212
    "isNaN", GlobalIsNaN,
213
    "isFinite", GlobalIsFinite,
214
    "parseInt", GlobalParseInt,
215
    "parseFloat", GlobalParseFloat,
216
    "eval", GlobalEval
217
  ));
218
}
219

    
220
SetUpGlobal();
221

    
222

    
223
// ----------------------------------------------------------------------------
224
// Object
225

    
226
// ECMA-262 - 15.2.4.2
227
function ObjectToString() {
228
  if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
229
  if (IS_NULL(this)) return "[object Null]";
230
  return "[object " + %_ClassOf(ToObject(this)) + "]";
231
}
232

    
233

    
234
// ECMA-262 - 15.2.4.3
235
function ObjectToLocaleString() {
236
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
237
    throw MakeTypeError("called_on_null_or_undefined",
238
                        ["Object.prototype.toLocaleString"]);
239
  }
240
  return this.toString();
241
}
242

    
243

    
244
// ECMA-262 - 15.2.4.4
245
function ObjectValueOf() {
246
  return ToObject(this);
247
}
248

    
249

    
250
// ECMA-262 - 15.2.4.5
251
function ObjectHasOwnProperty(V) {
252
  if (%IsJSProxy(this)) {
253
    // TODO(rossberg): adjust once there is a story for symbols vs proxies.
254
    if (IS_SYMBOL(V)) return false;
255

    
256
    var handler = %GetHandler(this);
257
    return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
258
  }
259
  return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
260
}
261

    
262

    
263
// ECMA-262 - 15.2.4.6
264
function ObjectIsPrototypeOf(V) {
265
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
266
    throw MakeTypeError("called_on_null_or_undefined",
267
                        ["Object.prototype.isPrototypeOf"]);
268
  }
269
  if (!IS_SPEC_OBJECT(V)) return false;
270
  return %IsInPrototypeChain(this, V);
271
}
272

    
273

    
274
// ECMA-262 - 15.2.4.6
275
function ObjectPropertyIsEnumerable(V) {
276
  var P = ToName(V);
277
  if (%IsJSProxy(this)) {
278
    // TODO(rossberg): adjust once there is a story for symbols vs proxies.
279
    if (IS_SYMBOL(V)) return false;
280

    
281
    var desc = GetOwnProperty(this, P);
282
    return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
283
  }
284
  return %IsPropertyEnumerable(ToObject(this), P);
285
}
286

    
287

    
288
// Extensions for providing property getters and setters.
289
function ObjectDefineGetter(name, fun) {
290
  var receiver = this;
291
  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
292
    receiver = %GlobalReceiver(global);
293
  }
294
  if (!IS_SPEC_FUNCTION(fun)) {
295
    throw new $TypeError(
296
        'Object.prototype.__defineGetter__: Expecting function');
297
  }
298
  var desc = new PropertyDescriptor();
299
  desc.setGet(fun);
300
  desc.setEnumerable(true);
301
  desc.setConfigurable(true);
302
  DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
303
}
304

    
305

    
306
function ObjectLookupGetter(name) {
307
  var receiver = this;
308
  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
309
    receiver = %GlobalReceiver(global);
310
  }
311
  return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
312
}
313

    
314

    
315
function ObjectDefineSetter(name, fun) {
316
  var receiver = this;
317
  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
318
    receiver = %GlobalReceiver(global);
319
  }
320
  if (!IS_SPEC_FUNCTION(fun)) {
321
    throw new $TypeError(
322
        'Object.prototype.__defineSetter__: Expecting function');
323
  }
324
  var desc = new PropertyDescriptor();
325
  desc.setSet(fun);
326
  desc.setEnumerable(true);
327
  desc.setConfigurable(true);
328
  DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
329
}
330

    
331

    
332
function ObjectLookupSetter(name) {
333
  var receiver = this;
334
  if (receiver == null && !IS_UNDETECTABLE(receiver)) {
335
    receiver = %GlobalReceiver(global);
336
  }
337
  return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
338
}
339

    
340

    
341
function ObjectKeys(obj) {
342
  if (!IS_SPEC_OBJECT(obj)) {
343
    throw MakeTypeError("called_on_non_object", ["Object.keys"]);
344
  }
345
  if (%IsJSProxy(obj)) {
346
    var handler = %GetHandler(obj);
347
    var names = CallTrap0(handler, "keys", DerivedKeysTrap);
348
    return ToNameArray(names, "keys", false);
349
  }
350
  return %LocalKeys(obj);
351
}
352

    
353

    
354
// ES5 8.10.1.
355
function IsAccessorDescriptor(desc) {
356
  if (IS_UNDEFINED(desc)) return false;
357
  return desc.hasGetter() || desc.hasSetter();
358
}
359

    
360

    
361
// ES5 8.10.2.
362
function IsDataDescriptor(desc) {
363
  if (IS_UNDEFINED(desc)) return false;
364
  return desc.hasValue() || desc.hasWritable();
365
}
366

    
367

    
368
// ES5 8.10.3.
369
function IsGenericDescriptor(desc) {
370
  if (IS_UNDEFINED(desc)) return false;
371
  return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
372
}
373

    
374

    
375
function IsInconsistentDescriptor(desc) {
376
  return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
377
}
378

    
379

    
380
// ES5 8.10.4
381
function FromPropertyDescriptor(desc) {
382
  if (IS_UNDEFINED(desc)) return desc;
383

    
384
  if (IsDataDescriptor(desc)) {
385
    return { value: desc.getValue(),
386
             writable: desc.isWritable(),
387
             enumerable: desc.isEnumerable(),
388
             configurable: desc.isConfigurable() };
389
  }
390
  // Must be an AccessorDescriptor then. We never return a generic descriptor.
391
  return { get: desc.getGet(),
392
           set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
393
                                                 : desc.getSet(),
394
           enumerable: desc.isEnumerable(),
395
           configurable: desc.isConfigurable() };
396
}
397

    
398

    
399
// Harmony Proxies
400
function FromGenericPropertyDescriptor(desc) {
401
  if (IS_UNDEFINED(desc)) return desc;
402
  var obj = new $Object();
403

    
404
  if (desc.hasValue()) {
405
    %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
406
  }
407
  if (desc.hasWritable()) {
408
    %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
409
  }
410
  if (desc.hasGetter()) {
411
    %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
412
  }
413
  if (desc.hasSetter()) {
414
    %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
415
  }
416
  if (desc.hasEnumerable()) {
417
    %IgnoreAttributesAndSetProperty(obj, "enumerable",
418
                                    desc.isEnumerable(), NONE);
419
  }
420
  if (desc.hasConfigurable()) {
421
    %IgnoreAttributesAndSetProperty(obj, "configurable",
422
                                    desc.isConfigurable(), NONE);
423
  }
424
  return obj;
425
}
426

    
427

    
428
// ES5 8.10.5.
429
function ToPropertyDescriptor(obj) {
430
  if (!IS_SPEC_OBJECT(obj)) {
431
    throw MakeTypeError("property_desc_object", [obj]);
432
  }
433
  var desc = new PropertyDescriptor();
434

    
435
  if ("enumerable" in obj) {
436
    desc.setEnumerable(ToBoolean(obj.enumerable));
437
  }
438

    
439
  if ("configurable" in obj) {
440
    desc.setConfigurable(ToBoolean(obj.configurable));
441
  }
442

    
443
  if ("value" in obj) {
444
    desc.setValue(obj.value);
445
  }
446

    
447
  if ("writable" in obj) {
448
    desc.setWritable(ToBoolean(obj.writable));
449
  }
450

    
451
  if ("get" in obj) {
452
    var get = obj.get;
453
    if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
454
      throw MakeTypeError("getter_must_be_callable", [get]);
455
    }
456
    desc.setGet(get);
457
  }
458

    
459
  if ("set" in obj) {
460
    var set = obj.set;
461
    if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
462
      throw MakeTypeError("setter_must_be_callable", [set]);
463
    }
464
    desc.setSet(set);
465
  }
466

    
467
  if (IsInconsistentDescriptor(desc)) {
468
    throw MakeTypeError("value_and_accessor", [obj]);
469
  }
470
  return desc;
471
}
472

    
473

    
474
// For Harmony proxies.
475
function ToCompletePropertyDescriptor(obj) {
476
  var desc = ToPropertyDescriptor(obj);
477
  if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
478
    if (!desc.hasValue()) desc.setValue(UNDEFINED);
479
    if (!desc.hasWritable()) desc.setWritable(false);
480
  } else {
481
    // Is accessor descriptor.
482
    if (!desc.hasGetter()) desc.setGet(UNDEFINED);
483
    if (!desc.hasSetter()) desc.setSet(UNDEFINED);
484
  }
485
  if (!desc.hasEnumerable()) desc.setEnumerable(false);
486
  if (!desc.hasConfigurable()) desc.setConfigurable(false);
487
  return desc;
488
}
489

    
490

    
491
function PropertyDescriptor() {
492
  // Initialize here so they are all in-object and have the same map.
493
  // Default values from ES5 8.6.1.
494
  this.value_ = UNDEFINED;
495
  this.hasValue_ = false;
496
  this.writable_ = false;
497
  this.hasWritable_ = false;
498
  this.enumerable_ = false;
499
  this.hasEnumerable_ = false;
500
  this.configurable_ = false;
501
  this.hasConfigurable_ = false;
502
  this.get_ = UNDEFINED;
503
  this.hasGetter_ = false;
504
  this.set_ = UNDEFINED;
505
  this.hasSetter_ = false;
506
}
507

    
508
SetUpLockedPrototype(PropertyDescriptor, $Array(
509
    "value_",
510
    "hasValue_",
511
    "writable_",
512
    "hasWritable_",
513
    "enumerable_",
514
    "hasEnumerable_",
515
    "configurable_",
516
    "hasConfigurable_",
517
    "get_",
518
    "hasGetter_",
519
    "set_",
520
    "hasSetter_"
521
  ), $Array(
522
    "toString", function() {
523
      return "[object PropertyDescriptor]";
524
    },
525
    "setValue", function(value) {
526
      this.value_ = value;
527
      this.hasValue_ = true;
528
    },
529
    "getValue", function() {
530
      return this.value_;
531
    },
532
    "hasValue", function() {
533
      return this.hasValue_;
534
    },
535
    "setEnumerable", function(enumerable) {
536
      this.enumerable_ = enumerable;
537
        this.hasEnumerable_ = true;
538
    },
539
    "isEnumerable", function () {
540
      return this.enumerable_;
541
    },
542
    "hasEnumerable", function() {
543
      return this.hasEnumerable_;
544
    },
545
    "setWritable", function(writable) {
546
      this.writable_ = writable;
547
      this.hasWritable_ = true;
548
    },
549
    "isWritable", function() {
550
      return this.writable_;
551
    },
552
    "hasWritable", function() {
553
      return this.hasWritable_;
554
    },
555
    "setConfigurable", function(configurable) {
556
      this.configurable_ = configurable;
557
      this.hasConfigurable_ = true;
558
    },
559
    "hasConfigurable", function() {
560
      return this.hasConfigurable_;
561
    },
562
    "isConfigurable", function() {
563
      return this.configurable_;
564
    },
565
    "setGet", function(get) {
566
      this.get_ = get;
567
        this.hasGetter_ = true;
568
    },
569
    "getGet", function() {
570
      return this.get_;
571
    },
572
    "hasGetter", function() {
573
      return this.hasGetter_;
574
    },
575
    "setSet", function(set) {
576
      this.set_ = set;
577
      this.hasSetter_ = true;
578
    },
579
    "getSet", function() {
580
      return this.set_;
581
    },
582
    "hasSetter", function() {
583
      return this.hasSetter_;
584
  }));
585

    
586

    
587
// Converts an array returned from Runtime_GetOwnProperty to an actual
588
// property descriptor. For a description of the array layout please
589
// see the runtime.cc file.
590
function ConvertDescriptorArrayToDescriptor(desc_array) {
591
  if (desc_array === false) {
592
    throw 'Internal error: invalid desc_array';
593
  }
594

    
595
  if (IS_UNDEFINED(desc_array)) {
596
    return UNDEFINED;
597
  }
598

    
599
  var desc = new PropertyDescriptor();
600
  // This is an accessor.
601
  if (desc_array[IS_ACCESSOR_INDEX]) {
602
    desc.setGet(desc_array[GETTER_INDEX]);
603
    desc.setSet(desc_array[SETTER_INDEX]);
604
  } else {
605
    desc.setValue(desc_array[VALUE_INDEX]);
606
    desc.setWritable(desc_array[WRITABLE_INDEX]);
607
  }
608
  desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
609
  desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
610

    
611
  return desc;
612
}
613

    
614

    
615
// For Harmony proxies.
616
function GetTrap(handler, name, defaultTrap) {
617
  var trap = handler[name];
618
  if (IS_UNDEFINED(trap)) {
619
    if (IS_UNDEFINED(defaultTrap)) {
620
      throw MakeTypeError("handler_trap_missing", [handler, name]);
621
    }
622
    trap = defaultTrap;
623
  } else if (!IS_SPEC_FUNCTION(trap)) {
624
    throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
625
  }
626
  return trap;
627
}
628

    
629

    
630
function CallTrap0(handler, name, defaultTrap) {
631
  return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
632
}
633

    
634

    
635
function CallTrap1(handler, name, defaultTrap, x) {
636
  return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
637
}
638

    
639

    
640
function CallTrap2(handler, name, defaultTrap, x, y) {
641
  return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
642
}
643

    
644

    
645
// ES5 section 8.12.1.
646
function GetOwnProperty(obj, v) {
647
  var p = ToName(v);
648
  if (%IsJSProxy(obj)) {
649
    // TODO(rossberg): adjust once there is a story for symbols vs proxies.
650
    if (IS_SYMBOL(v)) return UNDEFINED;
651

    
652
    var handler = %GetHandler(obj);
653
    var descriptor = CallTrap1(
654
                         handler, "getOwnPropertyDescriptor", UNDEFINED, p);
655
    if (IS_UNDEFINED(descriptor)) return descriptor;
656
    var desc = ToCompletePropertyDescriptor(descriptor);
657
    if (!desc.isConfigurable()) {
658
      throw MakeTypeError("proxy_prop_not_configurable",
659
                          [handler, "getOwnPropertyDescriptor", p, descriptor]);
660
    }
661
    return desc;
662
  }
663

    
664
  // GetOwnProperty returns an array indexed by the constants
665
  // defined in macros.py.
666
  // If p is not a property on obj undefined is returned.
667
  var props = %GetOwnProperty(ToObject(obj), p);
668

    
669
  // A false value here means that access checks failed.
670
  if (props === false) return UNDEFINED;
671

    
672
  return ConvertDescriptorArrayToDescriptor(props);
673
}
674

    
675

    
676
// ES5 section 8.12.7.
677
function Delete(obj, p, should_throw) {
678
  var desc = GetOwnProperty(obj, p);
679
  if (IS_UNDEFINED(desc)) return true;
680
  if (desc.isConfigurable()) {
681
    %DeleteProperty(obj, p, 0);
682
    return true;
683
  } else if (should_throw) {
684
    throw MakeTypeError("define_disallowed", [p]);
685
  } else {
686
    return;
687
  }
688
}
689

    
690

    
691
// Harmony proxies.
692
function DefineProxyProperty(obj, p, attributes, should_throw) {
693
  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
694
  if (IS_SYMBOL(p)) return false;
695

    
696
  var handler = %GetHandler(obj);
697
  var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes);
698
  if (!ToBoolean(result)) {
699
    if (should_throw) {
700
      throw MakeTypeError("handler_returned_false",
701
                          [handler, "defineProperty"]);
702
    } else {
703
      return false;
704
    }
705
  }
706
  return true;
707
}
708

    
709

    
710
// ES5 8.12.9.
711
function DefineObjectProperty(obj, p, desc, should_throw) {
712
  var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
713
  // A false value here means that access checks failed.
714
  if (current_or_access === false) return UNDEFINED;
715

    
716
  var current = ConvertDescriptorArrayToDescriptor(current_or_access);
717
  var extensible = %IsExtensible(ToObject(obj));
718

    
719
  // Error handling according to spec.
720
  // Step 3
721
  if (IS_UNDEFINED(current) && !extensible) {
722
    if (should_throw) {
723
      throw MakeTypeError("define_disallowed", [p]);
724
    } else {
725
      return false;
726
    }
727
  }
728

    
729
  if (!IS_UNDEFINED(current)) {
730
    // Step 5 and 6
731
    if ((IsGenericDescriptor(desc) ||
732
         IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
733
        (!desc.hasEnumerable() ||
734
         SameValue(desc.isEnumerable(), current.isEnumerable())) &&
735
        (!desc.hasConfigurable() ||
736
         SameValue(desc.isConfigurable(), current.isConfigurable())) &&
737
        (!desc.hasWritable() ||
738
         SameValue(desc.isWritable(), current.isWritable())) &&
739
        (!desc.hasValue() ||
740
         SameValue(desc.getValue(), current.getValue())) &&
741
        (!desc.hasGetter() ||
742
         SameValue(desc.getGet(), current.getGet())) &&
743
        (!desc.hasSetter() ||
744
         SameValue(desc.getSet(), current.getSet()))) {
745
      return true;
746
    }
747
    if (!current.isConfigurable()) {
748
      // Step 7
749
      if (desc.isConfigurable() ||
750
          (desc.hasEnumerable() &&
751
           desc.isEnumerable() != current.isEnumerable())) {
752
        if (should_throw) {
753
          throw MakeTypeError("redefine_disallowed", [p]);
754
        } else {
755
          return false;
756
        }
757
      }
758
      // Step 8
759
      if (!IsGenericDescriptor(desc)) {
760
        // Step 9a
761
        if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
762
          if (should_throw) {
763
            throw MakeTypeError("redefine_disallowed", [p]);
764
          } else {
765
            return false;
766
          }
767
        }
768
        // Step 10a
769
        if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
770
          if (!current.isWritable() && desc.isWritable()) {
771
            if (should_throw) {
772
              throw MakeTypeError("redefine_disallowed", [p]);
773
            } else {
774
              return false;
775
            }
776
          }
777
          if (!current.isWritable() && desc.hasValue() &&
778
              !SameValue(desc.getValue(), current.getValue())) {
779
            if (should_throw) {
780
              throw MakeTypeError("redefine_disallowed", [p]);
781
            } else {
782
              return false;
783
            }
784
          }
785
        }
786
        // Step 11
787
        if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
788
          if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
789
            if (should_throw) {
790
              throw MakeTypeError("redefine_disallowed", [p]);
791
            } else {
792
              return false;
793
            }
794
          }
795
          if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
796
            if (should_throw) {
797
              throw MakeTypeError("redefine_disallowed", [p]);
798
            } else {
799
              return false;
800
            }
801
          }
802
        }
803
      }
804
    }
805
  }
806

    
807
  // Send flags - enumerable and configurable are common - writable is
808
  // only send to the data descriptor.
809
  // Take special care if enumerable and configurable is not defined on
810
  // desc (we need to preserve the existing values from current).
811
  var flag = NONE;
812
  if (desc.hasEnumerable()) {
813
    flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
814
  } else if (!IS_UNDEFINED(current)) {
815
    flag |= current.isEnumerable() ? 0 : DONT_ENUM;
816
  } else {
817
    flag |= DONT_ENUM;
818
  }
819

    
820
  if (desc.hasConfigurable()) {
821
    flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
822
  } else if (!IS_UNDEFINED(current)) {
823
    flag |= current.isConfigurable() ? 0 : DONT_DELETE;
824
  } else
825
    flag |= DONT_DELETE;
826

    
827
  if (IsDataDescriptor(desc) ||
828
      (IsGenericDescriptor(desc) &&
829
       (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
830
    // There are 3 cases that lead here:
831
    // Step 4a - defining a new data property.
832
    // Steps 9b & 12 - replacing an existing accessor property with a data
833
    //                 property.
834
    // Step 12 - updating an existing data property with a data or generic
835
    //           descriptor.
836

    
837
    if (desc.hasWritable()) {
838
      flag |= desc.isWritable() ? 0 : READ_ONLY;
839
    } else if (!IS_UNDEFINED(current)) {
840
      flag |= current.isWritable() ? 0 : READ_ONLY;
841
    } else {
842
      flag |= READ_ONLY;
843
    }
844

    
845
    var value = UNDEFINED;  // Default value is undefined.
846
    if (desc.hasValue()) {
847
      value = desc.getValue();
848
    } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
849
      value = current.getValue();
850
    }
851

    
852
    %DefineOrRedefineDataProperty(obj, p, value, flag);
853
  } else {
854
    // There are 3 cases that lead here:
855
    // Step 4b - defining a new accessor property.
856
    // Steps 9c & 12 - replacing an existing data property with an accessor
857
    //                 property.
858
    // Step 12 - updating an existing accessor property with an accessor
859
    //           descriptor.
860
    var getter = desc.hasGetter() ? desc.getGet() : null;
861
    var setter = desc.hasSetter() ? desc.getSet() : null;
862
    %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
863
  }
864
  return true;
865
}
866

    
867

    
868
// ES5 section 15.4.5.1.
869
function DefineArrayProperty(obj, p, desc, should_throw) {
870
  // Note that the length of an array is not actually stored as part of the
871
  // property, hence we use generated code throughout this function instead of
872
  // DefineObjectProperty() to modify its value.
873

    
874
  // Step 3 - Special handling for length property.
875
  if (p === "length") {
876
    var length = obj.length;
877
    var old_length = length;
878
    if (!desc.hasValue()) {
879
      return DefineObjectProperty(obj, "length", desc, should_throw);
880
    }
881
    var new_length = ToUint32(desc.getValue());
882
    if (new_length != ToNumber(desc.getValue())) {
883
      throw new $RangeError('defineProperty() array length out of range');
884
    }
885
    var length_desc = GetOwnProperty(obj, "length");
886
    if (new_length != length && !length_desc.isWritable()) {
887
      if (should_throw) {
888
        throw MakeTypeError("redefine_disallowed", [p]);
889
      } else {
890
        return false;
891
      }
892
    }
893
    var threw = false;
894

    
895
    var emit_splice = %IsObserved(obj) && new_length !== old_length;
896
    var removed;
897
    if (emit_splice) {
898
      BeginPerformSplice(obj);
899
      removed = [];
900
      if (new_length < old_length)
901
        removed.length = old_length - new_length;
902
    }
903

    
904
    while (new_length < length--) {
905
      var index = ToString(length);
906
      if (emit_splice) {
907
        var deletedDesc = GetOwnProperty(obj, index);
908
        if (deletedDesc && deletedDesc.hasValue())
909
          removed[length - new_length] = deletedDesc.getValue();
910
      }
911
      if (!Delete(obj, index, false)) {
912
        new_length = length + 1;
913
        threw = true;
914
        break;
915
      }
916
    }
917
    // Make sure the below call to DefineObjectProperty() doesn't overwrite
918
    // any magic "length" property by removing the value.
919
    // TODO(mstarzinger): This hack should be removed once we have addressed the
920
    // respective TODO in Runtime_DefineOrRedefineDataProperty.
921
    // For the time being, we need a hack to prevent Object.observe from
922
    // generating two change records.
923
    obj.length = new_length;
924
    desc.value_ = UNDEFINED;
925
    desc.hasValue_ = false;
926
    threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
927
    if (emit_splice) {
928
      EndPerformSplice(obj);
929
      EnqueueSpliceRecord(obj,
930
          new_length < old_length ? new_length : old_length,
931
          removed,
932
          new_length > old_length ? new_length - old_length : 0);
933
    }
934
    if (threw) {
935
      if (should_throw) {
936
        throw MakeTypeError("redefine_disallowed", [p]);
937
      } else {
938
        return false;
939
      }
940
    }
941
    return true;
942
  }
943

    
944
  // Step 4 - Special handling for array index.
945
  var index = ToUint32(p);
946
  var emit_splice = false;
947
  if (ToString(index) == p && index != 4294967295) {
948
    var length = obj.length;
949
    if (index >= length && %IsObserved(obj)) {
950
      emit_splice = true;
951
      BeginPerformSplice(obj);
952
    }
953

    
954
    var length_desc = GetOwnProperty(obj, "length");
955
    if ((index >= length && !length_desc.isWritable()) ||
956
        !DefineObjectProperty(obj, p, desc, true)) {
957
      if (emit_splice)
958
        EndPerformSplice(obj);
959
      if (should_throw) {
960
        throw MakeTypeError("define_disallowed", [p]);
961
      } else {
962
        return false;
963
      }
964
    }
965
    if (index >= length) {
966
      obj.length = index + 1;
967
    }
968
    if (emit_splice) {
969
      EndPerformSplice(obj);
970
      EnqueueSpliceRecord(obj, length, [], index + 1 - length);
971
    }
972
    return true;
973
  }
974

    
975
  // Step 5 - Fallback to default implementation.
976
  return DefineObjectProperty(obj, p, desc, should_throw);
977
}
978

    
979

    
980
// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
981
function DefineOwnProperty(obj, p, desc, should_throw) {
982
  if (%IsJSProxy(obj)) {
983
    // TODO(rossberg): adjust once there is a story for symbols vs proxies.
984
    if (IS_SYMBOL(p)) return false;
985

    
986
    var attributes = FromGenericPropertyDescriptor(desc);
987
    return DefineProxyProperty(obj, p, attributes, should_throw);
988
  } else if (IS_ARRAY(obj)) {
989
    return DefineArrayProperty(obj, p, desc, should_throw);
990
  } else {
991
    return DefineObjectProperty(obj, p, desc, should_throw);
992
  }
993
}
994

    
995

    
996
// ES5 section 15.2.3.2.
997
function ObjectGetPrototypeOf(obj) {
998
  if (!IS_SPEC_OBJECT(obj)) {
999
    throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
1000
  }
1001
  return %GetPrototype(obj);
1002
}
1003

    
1004

    
1005
// ES5 section 15.2.3.3
1006
function ObjectGetOwnPropertyDescriptor(obj, p) {
1007
  if (!IS_SPEC_OBJECT(obj)) {
1008
    throw MakeTypeError("called_on_non_object",
1009
                        ["Object.getOwnPropertyDescriptor"]);
1010
  }
1011
  var desc = GetOwnProperty(obj, p);
1012
  return FromPropertyDescriptor(desc);
1013
}
1014

    
1015

    
1016
// For Harmony proxies
1017
function ToNameArray(obj, trap, includeSymbols) {
1018
  if (!IS_SPEC_OBJECT(obj)) {
1019
    throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1020
  }
1021
  var n = ToUint32(obj.length);
1022
  var array = new $Array(n);
1023
  var realLength = 0;
1024
  var names = { __proto__: null };  // TODO(rossberg): use sets once ready.
1025
  for (var index = 0; index < n; index++) {
1026
    var s = ToName(obj[index]);
1027
    // TODO(rossberg): adjust once there is a story for symbols vs proxies.
1028
    if (IS_SYMBOL(s) && !includeSymbols) continue;
1029
    if (%HasLocalProperty(names, s)) {
1030
      throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
1031
    }
1032
    array[index] = s;
1033
    ++realLength;
1034
    names[s] = 0;
1035
  }
1036
  array.length = realLength;
1037
  return array;
1038
}
1039

    
1040

    
1041
// ES5 section 15.2.3.4.
1042
function ObjectGetOwnPropertyNames(obj) {
1043
  if (!IS_SPEC_OBJECT(obj)) {
1044
    throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
1045
  }
1046
  // Special handling for proxies.
1047
  if (%IsJSProxy(obj)) {
1048
    var handler = %GetHandler(obj);
1049
    var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
1050
    return ToNameArray(names, "getOwnPropertyNames", false);
1051
  }
1052

    
1053
  var nameArrays = new InternalArray();
1054

    
1055
  // Find all the indexed properties.
1056

    
1057
  // Get the local element names.
1058
  var localElementNames = %GetLocalElementNames(obj);
1059
  for (var i = 0; i < localElementNames.length; ++i) {
1060
    localElementNames[i] = %_NumberToString(localElementNames[i]);
1061
  }
1062
  nameArrays.push(localElementNames);
1063

    
1064
  // Get names for indexed interceptor properties.
1065
  var interceptorInfo = %GetInterceptorInfo(obj);
1066
  if ((interceptorInfo & 1) != 0) {
1067
    var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1068
    if (!IS_UNDEFINED(indexedInterceptorNames)) {
1069
      nameArrays.push(indexedInterceptorNames);
1070
    }
1071
  }
1072

    
1073
  // Find all the named properties.
1074

    
1075
  // Get the local property names.
1076
  nameArrays.push(%GetLocalPropertyNames(obj, false));
1077

    
1078
  // Get names for named interceptor properties if any.
1079
  if ((interceptorInfo & 2) != 0) {
1080
    var namedInterceptorNames = %GetNamedInterceptorPropertyNames(obj);
1081
    if (!IS_UNDEFINED(namedInterceptorNames)) {
1082
      nameArrays.push(namedInterceptorNames);
1083
    }
1084
  }
1085

    
1086
  var propertyNames =
1087
      %Apply(InternalArray.prototype.concat,
1088
             nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1089

    
1090
  // Property names are expected to be unique strings,
1091
  // but interceptors can interfere with that assumption.
1092
  if (interceptorInfo != 0) {
1093
    var propertySet = { __proto__: null };
1094
    var j = 0;
1095
    for (var i = 0; i < propertyNames.length; ++i) {
1096
      if (IS_SYMBOL(propertyNames[i])) continue;
1097
      var name = ToString(propertyNames[i]);
1098
      // We need to check for the exact property value since for intrinsic
1099
      // properties like toString if(propertySet["toString"]) will always
1100
      // succeed.
1101
      if (propertySet[name] === true) {
1102
        continue;
1103
      }
1104
      propertySet[name] = true;
1105
      propertyNames[j++] = name;
1106
    }
1107
    propertyNames.length = j;
1108
  }
1109

    
1110
  return propertyNames;
1111
}
1112

    
1113

    
1114
// ES5 section 15.2.3.5.
1115
function ObjectCreate(proto, properties) {
1116
  if (!IS_SPEC_OBJECT(proto) && proto !== null) {
1117
    throw MakeTypeError("proto_object_or_null", [proto]);
1118
  }
1119
  var obj = { __proto__: proto };
1120
  if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1121
  return obj;
1122
}
1123

    
1124

    
1125
// ES5 section 15.2.3.6.
1126
function ObjectDefineProperty(obj, p, attributes) {
1127
  if (!IS_SPEC_OBJECT(obj)) {
1128
    throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
1129
  }
1130
  var name = ToName(p);
1131
  if (%IsJSProxy(obj)) {
1132
    // Clone the attributes object for protection.
1133
    // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1134
    // non-own properties as it does (or non-enumerable ones, as it doesn't?).
1135
    var attributesClone = { __proto__: null };
1136
    for (var a in attributes) {
1137
      attributesClone[a] = attributes[a];
1138
    }
1139
    DefineProxyProperty(obj, name, attributesClone, true);
1140
    // The following would implement the spec as in the current proposal,
1141
    // but after recent comments on es-discuss, is most likely obsolete.
1142
    /*
1143
    var defineObj = FromGenericPropertyDescriptor(desc);
1144
    var names = ObjectGetOwnPropertyNames(attributes);
1145
    var standardNames =
1146
      {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1147
    for (var i = 0; i < names.length; i++) {
1148
      var N = names[i];
1149
      if (!(%HasLocalProperty(standardNames, N))) {
1150
        var attr = GetOwnProperty(attributes, N);
1151
        DefineOwnProperty(descObj, N, attr, true);
1152
      }
1153
    }
1154
    // This is really confusing the types, but it is what the proxies spec
1155
    // currently requires:
1156
    desc = descObj;
1157
    */
1158
  } else {
1159
    var desc = ToPropertyDescriptor(attributes);
1160
    DefineOwnProperty(obj, name, desc, true);
1161
  }
1162
  return obj;
1163
}
1164

    
1165

    
1166
function GetOwnEnumerablePropertyNames(properties) {
1167
  var names = new InternalArray();
1168
  for (var key in properties) {
1169
    if (%HasLocalProperty(properties, key)) {
1170
      names.push(key);
1171
    }
1172
  }
1173
  return names;
1174
}
1175

    
1176

    
1177
// ES5 section 15.2.3.7.
1178
function ObjectDefineProperties(obj, properties) {
1179
  if (!IS_SPEC_OBJECT(obj)) {
1180
    throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
1181
  }
1182
  var props = ToObject(properties);
1183
  var names = GetOwnEnumerablePropertyNames(props);
1184
  var descriptors = new InternalArray();
1185
  for (var i = 0; i < names.length; i++) {
1186
    descriptors.push(ToPropertyDescriptor(props[names[i]]));
1187
  }
1188
  for (var i = 0; i < names.length; i++) {
1189
    DefineOwnProperty(obj, names[i], descriptors[i], true);
1190
  }
1191
  return obj;
1192
}
1193

    
1194

    
1195
// Harmony proxies.
1196
function ProxyFix(obj) {
1197
  var handler = %GetHandler(obj);
1198
  var props = CallTrap0(handler, "fix", UNDEFINED);
1199
  if (IS_UNDEFINED(props)) {
1200
    throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1201
  }
1202

    
1203
  if (%IsJSFunctionProxy(obj)) {
1204
    var callTrap = %GetCallTrap(obj);
1205
    var constructTrap = %GetConstructTrap(obj);
1206
    var code = DelegateCallAndConstruct(callTrap, constructTrap);
1207
    %Fix(obj);  // becomes a regular function
1208
    %SetCode(obj, code);
1209
    // TODO(rossberg): What about length and other properties? Not specified.
1210
    // We just put in some half-reasonable defaults for now.
1211
    var prototype = new $Object();
1212
    $Object.defineProperty(prototype, "constructor",
1213
      {value: obj, writable: true, enumerable: false, configurable: true});
1214
    // TODO(v8:1530): defineProperty does not handle prototype and length.
1215
    %FunctionSetPrototype(obj, prototype);
1216
    obj.length = 0;
1217
  } else {
1218
    %Fix(obj);
1219
  }
1220
  ObjectDefineProperties(obj, props);
1221
}
1222

    
1223

    
1224
// ES5 section 15.2.3.8.
1225
function ObjectSeal(obj) {
1226
  if (!IS_SPEC_OBJECT(obj)) {
1227
    throw MakeTypeError("called_on_non_object", ["Object.seal"]);
1228
  }
1229
  if (%IsJSProxy(obj)) {
1230
    ProxyFix(obj);
1231
  }
1232
  var names = ObjectGetOwnPropertyNames(obj);
1233
  for (var i = 0; i < names.length; i++) {
1234
    var name = names[i];
1235
    var desc = GetOwnProperty(obj, name);
1236
    if (desc.isConfigurable()) {
1237
      desc.setConfigurable(false);
1238
      DefineOwnProperty(obj, name, desc, true);
1239
    }
1240
  }
1241
  %PreventExtensions(obj);
1242
  return obj;
1243
}
1244

    
1245

    
1246
// ES5 section 15.2.3.9.
1247
function ObjectFreeze(obj) {
1248
  if (!IS_SPEC_OBJECT(obj)) {
1249
    throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
1250
  }
1251
  var isProxy = %IsJSProxy(obj);
1252
  if (isProxy || %HasNonStrictArgumentsElements(obj)) {
1253
    if (isProxy) {
1254
      ProxyFix(obj);
1255
    }
1256
    var names = ObjectGetOwnPropertyNames(obj);
1257
    for (var i = 0; i < names.length; i++) {
1258
      var name = names[i];
1259
      var desc = GetOwnProperty(obj, name);
1260
      if (desc.isWritable() || desc.isConfigurable()) {
1261
        if (IsDataDescriptor(desc)) desc.setWritable(false);
1262
        desc.setConfigurable(false);
1263
        DefineOwnProperty(obj, name, desc, true);
1264
      }
1265
    }
1266
    %PreventExtensions(obj);
1267
  } else {
1268
    // TODO(adamk): Is it worth going to this fast path if the
1269
    // object's properties are already in dictionary mode?
1270
    %ObjectFreeze(obj);
1271
  }
1272
  return obj;
1273
}
1274

    
1275

    
1276
// ES5 section 15.2.3.10
1277
function ObjectPreventExtension(obj) {
1278
  if (!IS_SPEC_OBJECT(obj)) {
1279
    throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
1280
  }
1281
  if (%IsJSProxy(obj)) {
1282
    ProxyFix(obj);
1283
  }
1284
  %PreventExtensions(obj);
1285
  return obj;
1286
}
1287

    
1288

    
1289
// ES5 section 15.2.3.11
1290
function ObjectIsSealed(obj) {
1291
  if (!IS_SPEC_OBJECT(obj)) {
1292
    throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
1293
  }
1294
  if (%IsJSProxy(obj)) {
1295
    return false;
1296
  }
1297
  if (%IsExtensible(obj)) {
1298
    return false;
1299
  }
1300
  var names = ObjectGetOwnPropertyNames(obj);
1301
  for (var i = 0; i < names.length; i++) {
1302
    var name = names[i];
1303
    var desc = GetOwnProperty(obj, name);
1304
    if (desc.isConfigurable()) return false;
1305
  }
1306
  return true;
1307
}
1308

    
1309

    
1310
// ES5 section 15.2.3.12
1311
function ObjectIsFrozen(obj) {
1312
  if (!IS_SPEC_OBJECT(obj)) {
1313
    throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
1314
  }
1315
  if (%IsJSProxy(obj)) {
1316
    return false;
1317
  }
1318
  if (%IsExtensible(obj)) {
1319
    return false;
1320
  }
1321
  var names = ObjectGetOwnPropertyNames(obj);
1322
  for (var i = 0; i < names.length; i++) {
1323
    var name = names[i];
1324
    var desc = GetOwnProperty(obj, name);
1325
    if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1326
    if (desc.isConfigurable()) return false;
1327
  }
1328
  return true;
1329
}
1330

    
1331

    
1332
// ES5 section 15.2.3.13
1333
function ObjectIsExtensible(obj) {
1334
  if (!IS_SPEC_OBJECT(obj)) {
1335
    throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
1336
  }
1337
  if (%IsJSProxy(obj)) {
1338
    return true;
1339
  }
1340
  return %IsExtensible(obj);
1341
}
1342

    
1343

    
1344
// Harmony egal.
1345
function ObjectIs(obj1, obj2) {
1346
  if (obj1 === obj2) {
1347
    return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1348
  } else {
1349
    return (obj1 !== obj1) && (obj2 !== obj2);
1350
  }
1351
}
1352

    
1353

    
1354
// Harmony __proto__ getter.
1355
function ObjectGetProto() {
1356
  return %GetPrototype(this);
1357
}
1358

    
1359

    
1360
// Harmony __proto__ setter.
1361
function ObjectSetProto(obj) {
1362
  return %SetPrototype(this, obj);
1363
}
1364

    
1365

    
1366
// Harmony __proto__ poison pill.
1367
function ObjectPoisonProto(obj) {
1368
  throw MakeTypeError("proto_poison_pill", []);
1369
}
1370

    
1371

    
1372
function ObjectConstructor(x) {
1373
  if (%_IsConstructCall()) {
1374
    if (x == null) return this;
1375
    return ToObject(x);
1376
  } else {
1377
    if (x == null) return { };
1378
    return ToObject(x);
1379
  }
1380
}
1381

    
1382

    
1383
// ----------------------------------------------------------------------------
1384
// Object
1385

    
1386
function SetUpObject() {
1387
  %CheckIsBootstrapping();
1388

    
1389
  %SetNativeFlag($Object);
1390
  %SetCode($Object, ObjectConstructor);
1391
  %FunctionSetName(ObjectPoisonProto, "__proto__");
1392
  %FunctionRemovePrototype(ObjectPoisonProto);
1393
  %SetExpectedNumberOfProperties($Object, 4);
1394

    
1395
  %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1396

    
1397
  // Set up non-enumerable functions on the Object.prototype object.
1398
  InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1399
    "toString", ObjectToString,
1400
    "toLocaleString", ObjectToLocaleString,
1401
    "valueOf", ObjectValueOf,
1402
    "hasOwnProperty", ObjectHasOwnProperty,
1403
    "isPrototypeOf", ObjectIsPrototypeOf,
1404
    "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1405
    "__defineGetter__", ObjectDefineGetter,
1406
    "__lookupGetter__", ObjectLookupGetter,
1407
    "__defineSetter__", ObjectDefineSetter,
1408
    "__lookupSetter__", ObjectLookupSetter
1409
  ));
1410
  InstallGetterSetter($Object.prototype, "__proto__",
1411
                      ObjectGetProto, ObjectSetProto);
1412

    
1413
  // Set up non-enumerable functions in the Object object.
1414
  InstallFunctions($Object, DONT_ENUM, $Array(
1415
    "keys", ObjectKeys,
1416
    "create", ObjectCreate,
1417
    "defineProperty", ObjectDefineProperty,
1418
    "defineProperties", ObjectDefineProperties,
1419
    "freeze", ObjectFreeze,
1420
    "getPrototypeOf", ObjectGetPrototypeOf,
1421
    "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
1422
    "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1423
    "is", ObjectIs,
1424
    "isExtensible", ObjectIsExtensible,
1425
    "isFrozen", ObjectIsFrozen,
1426
    "isSealed", ObjectIsSealed,
1427
    "preventExtensions", ObjectPreventExtension,
1428
    "seal", ObjectSeal
1429
  ));
1430
}
1431

    
1432
SetUpObject();
1433

    
1434

    
1435
// ----------------------------------------------------------------------------
1436
// Boolean
1437

    
1438
function BooleanConstructor(x) {
1439
  if (%_IsConstructCall()) {
1440
    %_SetValueOf(this, ToBoolean(x));
1441
  } else {
1442
    return ToBoolean(x);
1443
  }
1444
}
1445

    
1446

    
1447
function BooleanToString() {
1448
  // NOTE: Both Boolean objects and values can enter here as
1449
  // 'this'. This is not as dictated by ECMA-262.
1450
  var b = this;
1451
  if (!IS_BOOLEAN(b)) {
1452
    if (!IS_BOOLEAN_WRAPPER(b)) {
1453
      throw new $TypeError('Boolean.prototype.toString is not generic');
1454
    }
1455
    b = %_ValueOf(b);
1456
  }
1457
  return b ? 'true' : 'false';
1458
}
1459

    
1460

    
1461
function BooleanValueOf() {
1462
  // NOTE: Both Boolean objects and values can enter here as
1463
  // 'this'. This is not as dictated by ECMA-262.
1464
  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
1465
    throw new $TypeError('Boolean.prototype.valueOf is not generic');
1466
  }
1467
  return %_ValueOf(this);
1468
}
1469

    
1470

    
1471
// ----------------------------------------------------------------------------
1472

    
1473
function SetUpBoolean () {
1474
  %CheckIsBootstrapping();
1475

    
1476
  %SetCode($Boolean, BooleanConstructor);
1477
  %FunctionSetPrototype($Boolean, new $Boolean(false));
1478
  %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1479

    
1480
  InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1481
    "toString", BooleanToString,
1482
    "valueOf", BooleanValueOf
1483
  ));
1484
}
1485

    
1486
SetUpBoolean();
1487

    
1488

    
1489
// ----------------------------------------------------------------------------
1490
// Number
1491

    
1492
function NumberConstructor(x) {
1493
  var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1494
  if (%_IsConstructCall()) {
1495
    %_SetValueOf(this, value);
1496
  } else {
1497
    return value;
1498
  }
1499
}
1500

    
1501

    
1502
// ECMA-262 section 15.7.4.2.
1503
function NumberToString(radix) {
1504
  // NOTE: Both Number objects and values can enter here as
1505
  // 'this'. This is not as dictated by ECMA-262.
1506
  var number = this;
1507
  if (!IS_NUMBER(this)) {
1508
    if (!IS_NUMBER_WRAPPER(this)) {
1509
      throw new $TypeError('Number.prototype.toString is not generic');
1510
    }
1511
    // Get the value of this number in case it's an object.
1512
    number = %_ValueOf(this);
1513
  }
1514
  // Fast case: Convert number in radix 10.
1515
  if (IS_UNDEFINED(radix) || radix === 10) {
1516
    return %_NumberToString(number);
1517
  }
1518

    
1519
  // Convert the radix to an integer and check the range.
1520
  radix = TO_INTEGER(radix);
1521
  if (radix < 2 || radix > 36) {
1522
    throw new $RangeError('toString() radix argument must be between 2 and 36');
1523
  }
1524
  // Convert the number to a string in the given radix.
1525
  return %NumberToRadixString(number, radix);
1526
}
1527

    
1528

    
1529
// ECMA-262 section 15.7.4.3
1530
function NumberToLocaleString() {
1531
  return %_CallFunction(this, NumberToString);
1532
}
1533

    
1534

    
1535
// ECMA-262 section 15.7.4.4
1536
function NumberValueOf() {
1537
  // NOTE: Both Number objects and values can enter here as
1538
  // 'this'. This is not as dictated by ECMA-262.
1539
  if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
1540
    throw new $TypeError('Number.prototype.valueOf is not generic');
1541
  }
1542
  return %_ValueOf(this);
1543
}
1544

    
1545

    
1546
// ECMA-262 section 15.7.4.5
1547
function NumberToFixed(fractionDigits) {
1548
  var x = this;
1549
  if (!IS_NUMBER(this)) {
1550
    if (!IS_NUMBER_WRAPPER(this)) {
1551
      throw MakeTypeError("incompatible_method_receiver",
1552
                          ["Number.prototype.toFixed", this]);
1553
    }
1554
    // Get the value of this number in case it's an object.
1555
    x = %_ValueOf(this);
1556
  }
1557
  var f = TO_INTEGER(fractionDigits);
1558

    
1559
  if (f < 0 || f > 20) {
1560
    throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1561
  }
1562

    
1563
  if (NUMBER_IS_NAN(x)) return "NaN";
1564
  if (x == INFINITY) return "Infinity";
1565
  if (x == -INFINITY) return "-Infinity";
1566

    
1567
  return %NumberToFixed(x, f);
1568
}
1569

    
1570

    
1571
// ECMA-262 section 15.7.4.6
1572
function NumberToExponential(fractionDigits) {
1573
  var x = this;
1574
  if (!IS_NUMBER(this)) {
1575
    if (!IS_NUMBER_WRAPPER(this)) {
1576
      throw MakeTypeError("incompatible_method_receiver",
1577
                          ["Number.prototype.toExponential", this]);
1578
    }
1579
    // Get the value of this number in case it's an object.
1580
    x = %_ValueOf(this);
1581
  }
1582
  var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits);
1583

    
1584
  if (NUMBER_IS_NAN(x)) return "NaN";
1585
  if (x == INFINITY) return "Infinity";
1586
  if (x == -INFINITY) return "-Infinity";
1587

    
1588
  if (IS_UNDEFINED(f)) {
1589
    f = -1;  // Signal for runtime function that f is not defined.
1590
  } else if (f < 0 || f > 20) {
1591
    throw new $RangeError("toExponential() argument must be between 0 and 20");
1592
  }
1593
  return %NumberToExponential(x, f);
1594
}
1595

    
1596

    
1597
// ECMA-262 section 15.7.4.7
1598
function NumberToPrecision(precision) {
1599
  var x = this;
1600
  if (!IS_NUMBER(this)) {
1601
    if (!IS_NUMBER_WRAPPER(this)) {
1602
      throw MakeTypeError("incompatible_method_receiver",
1603
                          ["Number.prototype.toPrecision", this]);
1604
    }
1605
    // Get the value of this number in case it's an object.
1606
    x = %_ValueOf(this);
1607
  }
1608
  if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1609
  var p = TO_INTEGER(precision);
1610

    
1611
  if (NUMBER_IS_NAN(x)) return "NaN";
1612
  if (x == INFINITY) return "Infinity";
1613
  if (x == -INFINITY) return "-Infinity";
1614

    
1615
  if (p < 1 || p > 21) {
1616
    throw new $RangeError("toPrecision() argument must be between 1 and 21");
1617
  }
1618
  return %NumberToPrecision(x, p);
1619
}
1620

    
1621

    
1622
// Harmony isFinite.
1623
function NumberIsFinite(number) {
1624
  return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1625
}
1626

    
1627

    
1628
// Harmony isNaN.
1629
function NumberIsNaN(number) {
1630
  return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1631
}
1632

    
1633

    
1634
// ----------------------------------------------------------------------------
1635

    
1636
function SetUpNumber() {
1637
  %CheckIsBootstrapping();
1638

    
1639
  %SetCode($Number, NumberConstructor);
1640
  %FunctionSetPrototype($Number, new $Number(0));
1641

    
1642
  %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1643
  // Set up the constructor property on the Number prototype object.
1644
  %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1645

    
1646
  %OptimizeObjectForAddingMultipleProperties($Number, 5);
1647
  // ECMA-262 section 15.7.3.1.
1648
  %SetProperty($Number,
1649
               "MAX_VALUE",
1650
               1.7976931348623157e+308,
1651
               DONT_ENUM | DONT_DELETE | READ_ONLY);
1652

    
1653
  // ECMA-262 section 15.7.3.2.
1654
  %SetProperty($Number, "MIN_VALUE", 5e-324,
1655
               DONT_ENUM | DONT_DELETE | READ_ONLY);
1656

    
1657
  // ECMA-262 section 15.7.3.3.
1658
  %SetProperty($Number, "NaN", NAN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1659

    
1660
  // ECMA-262 section 15.7.3.4.
1661
  %SetProperty($Number,
1662
               "NEGATIVE_INFINITY",
1663
               -INFINITY,
1664
               DONT_ENUM | DONT_DELETE | READ_ONLY);
1665

    
1666
  // ECMA-262 section 15.7.3.5.
1667
  %SetProperty($Number,
1668
               "POSITIVE_INFINITY",
1669
               INFINITY,
1670
               DONT_ENUM | DONT_DELETE | READ_ONLY);
1671
  %ToFastProperties($Number);
1672

    
1673
  // Set up non-enumerable functions on the Number prototype object.
1674
  InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1675
    "toString", NumberToString,
1676
    "toLocaleString", NumberToLocaleString,
1677
    "valueOf", NumberValueOf,
1678
    "toFixed", NumberToFixed,
1679
    "toExponential", NumberToExponential,
1680
    "toPrecision", NumberToPrecision
1681
  ));
1682
  InstallFunctions($Number, DONT_ENUM, $Array(
1683
    "isFinite", NumberIsFinite,
1684
    "isNaN", NumberIsNaN
1685
  ));
1686
}
1687

    
1688
SetUpNumber();
1689

    
1690

    
1691
// ----------------------------------------------------------------------------
1692
// Function
1693

    
1694
function FunctionSourceString(func) {
1695
  while (%IsJSFunctionProxy(func)) {
1696
    func = %GetCallTrap(func);
1697
  }
1698

    
1699
  if (!IS_FUNCTION(func)) {
1700
    throw new $TypeError('Function.prototype.toString is not generic');
1701
  }
1702

    
1703
  var source = %FunctionGetSourceCode(func);
1704
  if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1705
    var name = %FunctionGetName(func);
1706
    if (name) {
1707
      // Mimic what KJS does.
1708
      return 'function ' + name + '() { [native code] }';
1709
    } else {
1710
      return 'function () { [native code] }';
1711
    }
1712
  }
1713

    
1714
  var name = %FunctionNameShouldPrintAsAnonymous(func)
1715
      ? 'anonymous'
1716
      : %FunctionGetName(func);
1717
  var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1718
  return head + name + source;
1719
}
1720

    
1721

    
1722
function FunctionToString() {
1723
  return FunctionSourceString(this);
1724
}
1725

    
1726

    
1727
// ES5 15.3.4.5
1728
function FunctionBind(this_arg) { // Length is 1.
1729
  if (!IS_SPEC_FUNCTION(this)) {
1730
    throw new $TypeError('Bind must be called on a function');
1731
  }
1732
  var boundFunction = function () {
1733
    // Poison .arguments and .caller, but is otherwise not detectable.
1734
    "use strict";
1735
    // This function must not use any object literals (Object, Array, RegExp),
1736
    // since the literals-array is being used to store the bound data.
1737
    if (%_IsConstructCall()) {
1738
      return %NewObjectFromBound(boundFunction);
1739
    }
1740
    var bindings = %BoundFunctionGetBindings(boundFunction);
1741

    
1742
    var argc = %_ArgumentsLength();
1743
    if (argc == 0) {
1744
      return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1745
    }
1746
    if (bindings.length === 2) {
1747
      return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1748
    }
1749
    var bound_argc = bindings.length - 2;
1750
    var argv = new InternalArray(bound_argc + argc);
1751
    for (var i = 0; i < bound_argc; i++) {
1752
      argv[i] = bindings[i + 2];
1753
    }
1754
    for (var j = 0; j < argc; j++) {
1755
      argv[i++] = %_Arguments(j);
1756
    }
1757
    return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1758
  };
1759

    
1760
  %FunctionRemovePrototype(boundFunction);
1761
  var new_length = 0;
1762
  if (%_ClassOf(this) == "Function") {
1763
    // Function or FunctionProxy.
1764
    var old_length = this.length;
1765
    // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1766
    if ((typeof old_length === "number") &&
1767
        ((old_length >>> 0) === old_length)) {
1768
      var argc = %_ArgumentsLength();
1769
      if (argc > 0) argc--;  // Don't count the thisArg as parameter.
1770
      new_length = old_length - argc;
1771
      if (new_length < 0) new_length = 0;
1772
    }
1773
  }
1774
  // This runtime function finds any remaining arguments on the stack,
1775
  // so we don't pass the arguments object.
1776
  var result = %FunctionBindArguments(boundFunction, this,
1777
                                      this_arg, new_length);
1778

    
1779
  // We already have caller and arguments properties on functions,
1780
  // which are non-configurable. It therefore makes no sence to
1781
  // try to redefine these as defined by the spec. The spec says
1782
  // that bind should make these throw a TypeError if get or set
1783
  // is called and make them non-enumerable and non-configurable.
1784
  // To be consistent with our normal functions we leave this as it is.
1785
  // TODO(lrn): Do set these to be thrower.
1786
  return result;
1787
}
1788

    
1789

    
1790
function NewFunctionString(arguments, function_token) {
1791
  var n = arguments.length;
1792
  var p = '';
1793
  if (n > 1) {
1794
    p = ToString(arguments[0]);
1795
    for (var i = 1; i < n - 1; i++) {
1796
      p += ',' + ToString(arguments[i]);
1797
    }
1798
    // If the formal parameters string include ) - an illegal
1799
    // character - it may make the combined function expression
1800
    // compile. We avoid this problem by checking for this early on.
1801
    if (%_CallFunction(p, ')', StringIndexOf) != -1) {
1802
      throw MakeSyntaxError('paren_in_arg_string', []);
1803
    }
1804
    // If the formal parameters include an unbalanced block comment, the
1805
    // function must be rejected. Since JavaScript does not allow nested
1806
    // comments we can include a trailing block comment to catch this.
1807
    p += '\n/' + '**/';
1808
  }
1809
  var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1810
  return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
1811
}
1812

    
1813

    
1814
function FunctionConstructor(arg1) {  // length == 1
1815
  var source = NewFunctionString(arguments, 'function');
1816
  var global_receiver = %GlobalReceiver(global);
1817
  // Compile the string in the constructor and not a helper so that errors
1818
  // appear to come from here.
1819
  var f = %_CallFunction(global_receiver, %CompileString(source, true));
1820
  %FunctionMarkNameShouldPrintAsAnonymous(f);
1821
  return f;
1822
}
1823

    
1824

    
1825
// ----------------------------------------------------------------------------
1826

    
1827
function SetUpFunction() {
1828
  %CheckIsBootstrapping();
1829

    
1830
  %SetCode($Function, FunctionConstructor);
1831
  %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1832

    
1833
  InstallFunctions($Function.prototype, DONT_ENUM, $Array(
1834
    "bind", FunctionBind,
1835
    "toString", FunctionToString
1836
  ));
1837
}
1838

    
1839
SetUpFunction();