blob: 76eeac6a58f98552c433103302590d543793b65e [file] [log] [blame]
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000028// This file relies on the fact that the following declarations have been made
29// in runtime.js:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000030// 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// var $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000036//
37// in math.js:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000038// var $floor = MathFloor
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000039
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000040var $isNaN = GlobalIsNaN;
41var $isFinite = GlobalIsFinite;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000042
43// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000045// Helper function used to install functions on objects.
46function InstallFunctions(object, attributes, functions) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000047 if (functions.length >= 8) {
48 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
49 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000050 for (var i = 0; i < functions.length; i += 2) {
51 var key = functions[i];
52 var f = functions[i + 1];
53 %FunctionSetName(f, key);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000054 %FunctionRemovePrototype(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000055 %SetProperty(object, key, f, attributes);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000056 %SetNativeFlag(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000057 }
ager@chromium.org5c838252010-02-19 08:53:10 +000058 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000059}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000061
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000062// Helper function to install a getter-only accessor property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000063function InstallGetter(object, name, getter) {
64 %FunctionSetName(getter, name);
65 %FunctionRemovePrototype(getter);
66 %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
67 %SetNativeFlag(getter);
68}
69
70
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000071// Helper function to install a getter/setter accessor property.
72function InstallGetterSetter(object, name, getter, setter) {
73 %FunctionSetName(getter, name);
74 %FunctionSetName(setter, name);
75 %FunctionRemovePrototype(getter);
76 %FunctionRemovePrototype(setter);
77 %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
78 %SetNativeFlag(getter);
79 %SetNativeFlag(setter);
80}
81
82
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000083// Prevents changes to the prototype of a built-in function.
fschneider@chromium.org1805e212011-09-05 10:49:12 +000084// The "prototype" property of the function object is made non-configurable,
85// and the prototype object is made non-extensible. The latter prevents
86// changing the __proto__ property.
87function SetUpLockedPrototype(constructor, fields, methods) {
88 %CheckIsBootstrapping();
89 var prototype = constructor.prototype;
90 // Install functions first, because this function is used to initialize
91 // PropertyDescriptor itself.
92 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
93 if (property_count >= 4) {
94 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
95 }
96 if (fields) {
97 for (var i = 0; i < fields.length; i++) {
98 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
99 }
100 }
101 for (var i = 0; i < methods.length; i += 2) {
102 var key = methods[i];
103 var f = methods[i + 1];
104 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
105 %SetNativeFlag(f);
106 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000107 %SetPrototype(prototype, null);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000108 %ToFastProperties(prototype);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000109}
110
111
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000112// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
114
115// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000116function GlobalIsNaN(number) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000117 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
118 return NUMBER_IS_NAN(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000119}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120
121
122// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000123function GlobalIsFinite(number) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000124 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000125 return NUMBER_IS_FINITE(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000126}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127
128
129// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000130function GlobalParseInt(string, radix) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000131 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 // Some people use parseInt instead of Math.floor. This
133 // optimization makes parseInt on a Smi 12 times faster (60ns
134 // vs 800ns). The following optimization makes parseInt on a
135 // non-Smi number 9 times faster (230ns vs 2070ns). Together
136 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
137 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000138 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000139 ((0.01 < string && string < 1e9) ||
140 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000141 // Truncate number.
142 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000144 string = TO_STRING_INLINE(string);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000145 radix = radix | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000147 // The spec says ToString should be evaluated before ToInt32.
148 string = TO_STRING_INLINE(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 radix = TO_INT32(radix);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000150 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 return $NaN;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000154
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000155 if (%_HasCachedArrayIndex(string) &&
156 (radix == 0 || radix == 10)) {
157 return %_GetCachedArrayIndex(string);
158 }
159 return %StringParseInt(string, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000160}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161
162
163// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000164function GlobalParseFloat(string) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000165 string = TO_STRING_INLINE(string);
166 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
167 return %StringParseFloat(string);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000168}
169
170
171function GlobalEval(x) {
172 if (!IS_STRING(x)) return x;
173
ager@chromium.orge2902be2009-06-08 12:21:35 +0000174 var global_receiver = %GlobalReceiver(global);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000175 var global_is_detached = (global === global_receiver);
176
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000177 // For consistency with JSC we require the global object passed to
178 // eval to be the global object from which 'eval' originated. This
179 // is not mandated by the spec.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000180 // We only throw if the global has been detached, since we need the
181 // receiver as this-value for the call.
182 if (global_is_detached) {
183 throw new $EvalError('The "this" value passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000184 'be the global object from which eval originated');
185 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000186
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000187 var f = %CompileString(x, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000188 if (!IS_FUNCTION(f)) return f;
189
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000190 return %_CallFunction(global_receiver, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000191}
192
193
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000194// ----------------------------------------------------------------------------
195
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000196// Set up global object.
197function SetUpGlobal() {
198 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000199
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200 // ECMA 262 - 15.1.1.1.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000201 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000202
203 // ECMA-262 - 15.1.1.2.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000205
206 // ECMA-262 - 15.1.1.3.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000207 %SetProperty(global, "undefined", void 0,
208 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000209
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000210 // Set up non-enumerable function on the global object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000211 InstallFunctions(global, DONT_ENUM, $Array(
212 "isNaN", GlobalIsNaN,
213 "isFinite", GlobalIsFinite,
214 "parseInt", GlobalParseInt,
215 "parseFloat", GlobalParseFloat,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000216 "eval", GlobalEval
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000217 ));
218}
219
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000220SetUpGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222
223// ----------------------------------------------------------------------------
224// Object
225
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000226// ECMA-262 - 15.2.4.2
227function ObjectToString() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000228 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
229 if (IS_NULL(this)) return "[object Null]";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000230 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000231}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232
233
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000234// ECMA-262 - 15.2.4.3
235function ObjectToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000236 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
237 throw MakeTypeError("called_on_null_or_undefined",
238 ["Object.prototype.toLocaleString"]);
239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000241}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242
243
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000244// ECMA-262 - 15.2.4.4
245function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000247}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
249
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000250// ECMA-262 - 15.2.4.5
251function ObjectHasOwnProperty(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000252 if (%IsJSProxy(this)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000253 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
254 if (IS_SYMBOL(V)) return false;
255
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000256 var handler = %GetHandler(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000257 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000258 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000259 return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000260}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
262
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000263// ECMA-262 - 15.2.4.6
264function ObjectIsPrototypeOf(V) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000265 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
266 throw MakeTypeError("called_on_null_or_undefined",
267 ["Object.prototype.isPrototypeOf"]);
268 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000269 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000271}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272
273
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000274// ECMA-262 - 15.2.4.6
275function ObjectPropertyIsEnumerable(V) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000276 var P = ToName(V);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000277 if (%IsJSProxy(this)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000278 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
279 if (IS_SYMBOL(V)) return false;
280
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000281 var desc = GetOwnProperty(this, P);
282 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
283 }
284 return %IsPropertyEnumerable(ToObject(this), P);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000285}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286
287
288// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000289function ObjectDefineGetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000290 var receiver = this;
291 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
292 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000294 if (!IS_SPEC_FUNCTION(fun)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000295 throw new $TypeError(
296 'Object.prototype.__defineGetter__: Expecting function');
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000298 var desc = new PropertyDescriptor();
299 desc.setGet(fun);
300 desc.setEnumerable(true);
301 desc.setConfigurable(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000302 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000303}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304
305
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306function ObjectLookupGetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000307 var receiver = this;
308 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
309 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000310 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000311 return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313
314
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000315function ObjectDefineSetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000316 var receiver = this;
317 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
318 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000319 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000320 if (!IS_SPEC_FUNCTION(fun)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 throw new $TypeError(
322 'Object.prototype.__defineSetter__: Expecting function');
323 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000324 var desc = new PropertyDescriptor();
325 desc.setSet(fun);
326 desc.setEnumerable(true);
327 desc.setConfigurable(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000328 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000329}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
331
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000332function ObjectLookupSetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000333 var receiver = this;
334 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
335 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000337 return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000338}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
340
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000341function ObjectKeys(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000342 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000343 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000344 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000345 if (%IsJSProxy(obj)) {
346 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000347 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000348 return ToNameArray(names, "keys", false);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000349 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000350 return %LocalKeys(obj);
351}
352
353
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000354// ES5 8.10.1.
355function IsAccessorDescriptor(desc) {
356 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000357 return desc.hasGetter() || desc.hasSetter();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000358}
359
360
361// ES5 8.10.2.
362function IsDataDescriptor(desc) {
363 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000364 return desc.hasValue() || desc.hasWritable();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000365}
366
367
368// ES5 8.10.3.
369function IsGenericDescriptor(desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000370 if (IS_UNDEFINED(desc)) return false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000371 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
372}
373
374
375function IsInconsistentDescriptor(desc) {
376 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
377}
378
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000379
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000380// ES5 8.10.4
381function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000382 if (IS_UNDEFINED(desc)) return desc;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000383
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000384 if (IsDataDescriptor(desc)) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000385 return { value: desc.getValue(),
386 writable: desc.isWritable(),
387 enumerable: desc.isEnumerable(),
388 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000389 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000390 // Must be an AccessorDescriptor then. We never return a generic descriptor.
391 return { get: desc.getGet(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000392 set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
393 : desc.getSet(),
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000394 enumerable: desc.isEnumerable(),
395 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000396}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000397
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000398
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000399// Harmony Proxies
400function FromGenericPropertyDescriptor(desc) {
401 if (IS_UNDEFINED(desc)) return desc;
402 var obj = new $Object();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000403
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 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000424 return obj;
425}
426
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000427
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000428// ES5 8.10.5.
429function ToPropertyDescriptor(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000430 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000431 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
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000439 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;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000453 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000454 throw MakeTypeError("getter_must_be_callable", [get]);
455 }
456 desc.setGet(get);
457 }
458
459 if ("set" in obj) {
460 var set = obj.set;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000461 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 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
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000474// For Harmony proxies.
475function ToCompletePropertyDescriptor(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000476 var desc = ToPropertyDescriptor(obj);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000477 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000478 if (!desc.hasValue()) desc.setValue(void 0);
479 if (!desc.hasWritable()) desc.setWritable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000480 } else {
481 // Is accessor descriptor.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000482 if (!desc.hasGetter()) desc.setGet(void 0);
483 if (!desc.hasSetter()) desc.setSet(void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000484 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000485 if (!desc.hasEnumerable()) desc.setEnumerable(false);
486 if (!desc.hasConfigurable()) desc.setConfigurable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000487 return desc;
488}
489
490
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000491function 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_ = void 0;
495 this.hasValue_ = false;
496 this.writable_ = false;
497 this.hasWritable_ = false;
498 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000499 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000501 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502 this.get_ = void 0;
503 this.hasGetter_ = false;
504 this.set_ = void 0;
505 this.hasSetter_ = false;
506}
507
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000508SetUpLockedPrototype(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 }));
ager@chromium.org5c838252010-02-19 08:53:10 +0000585
586
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000587// 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.
590function ConvertDescriptorArrayToDescriptor(desc_array) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000591 if (desc_array === false) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000592 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000593 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000594
595 if (IS_UNDEFINED(desc_array)) {
596 return void 0;
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]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000610
611 return desc;
612}
613
614
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000615// For Harmony proxies.
616function 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;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000623 } else if (!IS_SPEC_FUNCTION(trap)) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000624 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
625 }
626 return trap;
627}
628
629
630function CallTrap0(handler, name, defaultTrap) {
631 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
632}
633
634
635function CallTrap1(handler, name, defaultTrap, x) {
636 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
637}
638
639
640function CallTrap2(handler, name, defaultTrap, x, y) {
641 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
642}
643
644
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000645// ES5 section 8.12.1.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000646function GetOwnProperty(obj, v) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000647 var p = ToName(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000648 if (%IsJSProxy(obj)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000649 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
650 if (IS_SYMBOL(v)) return void 0;
651
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000652 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000653 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000654 if (IS_UNDEFINED(descriptor)) return descriptor;
655 var desc = ToCompletePropertyDescriptor(descriptor);
656 if (!desc.isConfigurable()) {
657 throw MakeTypeError("proxy_prop_not_configurable",
658 [handler, "getOwnPropertyDescriptor", p, descriptor]);
659 }
660 return desc;
661 }
662
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000663 // GetOwnProperty returns an array indexed by the constants
664 // defined in macros.py.
665 // If p is not a property on obj undefined is returned.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000666 var props = %GetOwnProperty(ToObject(obj), p);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000667
668 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000669 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000670
671 return ConvertDescriptorArrayToDescriptor(props);
672}
673
674
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000675// ES5 section 8.12.7.
676function Delete(obj, p, should_throw) {
677 var desc = GetOwnProperty(obj, p);
678 if (IS_UNDEFINED(desc)) return true;
679 if (desc.isConfigurable()) {
680 %DeleteProperty(obj, p, 0);
681 return true;
682 } else if (should_throw) {
683 throw MakeTypeError("define_disallowed", [p]);
684 } else {
685 return;
686 }
687}
688
689
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000690// Harmony proxies.
691function DefineProxyProperty(obj, p, attributes, should_throw) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000692 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
693 if (IS_SYMBOL(p)) return false;
694
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000695 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000696 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000697 if (!ToBoolean(result)) {
698 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699 throw MakeTypeError("handler_returned_false",
700 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000701 } else {
702 return false;
703 }
704 }
705 return true;
706}
707
708
lrn@chromium.org25156de2010-04-06 13:10:27 +0000709// ES5 8.12.9.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000710function DefineObjectProperty(obj, p, desc, should_throw) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000711 var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000712 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000713 if (current_or_access === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000714
715 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 var extensible = %IsExtensible(ToObject(obj));
717
718 // Error handling according to spec.
719 // Step 3
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000720 if (IS_UNDEFINED(current) && !extensible) {
721 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000722 throw MakeTypeError("define_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000723 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000724 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000725 }
726 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000727
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000728 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000729 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000730 if ((IsGenericDescriptor(desc) ||
731 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
732 (!desc.hasEnumerable() ||
733 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000734 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000735 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000736 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000737 SameValue(desc.isWritable(), current.isWritable())) &&
738 (!desc.hasValue() ||
739 SameValue(desc.getValue(), current.getValue())) &&
740 (!desc.hasGetter() ||
741 SameValue(desc.getGet(), current.getGet())) &&
742 (!desc.hasSetter() ||
743 SameValue(desc.getSet(), current.getSet()))) {
744 return true;
745 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000746 if (!current.isConfigurable()) {
747 // Step 7
748 if (desc.isConfigurable() ||
749 (desc.hasEnumerable() &&
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000750 desc.isEnumerable() != current.isEnumerable())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000751 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000752 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000753 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000754 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000755 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000756 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000757 // Step 8
758 if (!IsGenericDescriptor(desc)) {
759 // Step 9a
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000760 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000761 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000762 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000763 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000765 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000766 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000767 // Step 10a
768 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000769 if (!current.isWritable() && desc.isWritable()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000770 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000771 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000772 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000773 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000774 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000775 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000776 if (!current.isWritable() && desc.hasValue() &&
777 !SameValue(desc.getValue(), current.getValue())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000778 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000779 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000780 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000781 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000782 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 }
784 }
785 // Step 11
786 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000787 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000788 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000789 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000790 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000791 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000792 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000793 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000794 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000795 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000796 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000797 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000798 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000799 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000800 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000801 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 }
803 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000804 }
805
lrn@chromium.org25156de2010-04-06 13:10:27 +0000806 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000807 // only send to the data descriptor.
808 // Take special care if enumerable and configurable is not defined on
809 // desc (we need to preserve the existing values from current).
810 var flag = NONE;
811 if (desc.hasEnumerable()) {
812 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
813 } else if (!IS_UNDEFINED(current)) {
814 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000815 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000816 flag |= DONT_ENUM;
817 }
818
819 if (desc.hasConfigurable()) {
820 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
821 } else if (!IS_UNDEFINED(current)) {
822 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
823 } else
824 flag |= DONT_DELETE;
825
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000826 if (IsDataDescriptor(desc) ||
827 (IsGenericDescriptor(desc) &&
828 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
829 // There are 3 cases that lead here:
830 // Step 4a - defining a new data property.
831 // Steps 9b & 12 - replacing an existing accessor property with a data
832 // property.
833 // Step 12 - updating an existing data property with a data or generic
834 // descriptor.
835
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000836 if (desc.hasWritable()) {
837 flag |= desc.isWritable() ? 0 : READ_ONLY;
838 } else if (!IS_UNDEFINED(current)) {
839 flag |= current.isWritable() ? 0 : READ_ONLY;
840 } else {
841 flag |= READ_ONLY;
842 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000844 var value = void 0; // Default value is undefined.
845 if (desc.hasValue()) {
846 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000848 value = current.getValue();
849 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000850
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000851 %DefineOrRedefineDataProperty(obj, p, value, flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000852 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000853 // There are 3 cases that lead here:
854 // Step 4b - defining a new accessor property.
855 // Steps 9c & 12 - replacing an existing data property with an accessor
856 // property.
857 // Step 12 - updating an existing accessor property with an accessor
858 // descriptor.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000859 var getter = desc.hasGetter() ? desc.getGet() : null;
860 var setter = desc.hasSetter() ? desc.getSet() : null;
861 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000862 }
863 return true;
864}
865
866
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000867// ES5 section 15.4.5.1.
868function DefineArrayProperty(obj, p, desc, should_throw) {
869 // Note that the length of an array is not actually stored as part of the
870 // property, hence we use generated code throughout this function instead of
871 // DefineObjectProperty() to modify its value.
872
873 // Step 3 - Special handling for length property.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000874 if (p === "length") {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000875 var length = obj.length;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000876 var old_length = length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000877 if (!desc.hasValue()) {
878 return DefineObjectProperty(obj, "length", desc, should_throw);
879 }
880 var new_length = ToUint32(desc.getValue());
881 if (new_length != ToNumber(desc.getValue())) {
882 throw new $RangeError('defineProperty() array length out of range');
883 }
884 var length_desc = GetOwnProperty(obj, "length");
885 if (new_length != length && !length_desc.isWritable()) {
886 if (should_throw) {
887 throw MakeTypeError("redefine_disallowed", [p]);
888 } else {
889 return false;
890 }
891 }
892 var threw = false;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000893
894 var emit_splice = %IsObserved(obj) && new_length !== old_length;
895 var removed;
896 if (emit_splice) {
897 BeginPerformSplice(obj);
898 removed = [];
899 if (new_length < old_length)
900 removed.length = old_length - new_length;
901 }
902
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000903 while (new_length < length--) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000904 var index = ToString(length);
905 if (emit_splice) {
906 var deletedDesc = GetOwnProperty(obj, index);
907 if (deletedDesc && deletedDesc.hasValue())
908 removed[length - new_length] = deletedDesc.getValue();
909 }
910 if (!Delete(obj, index, false)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000911 new_length = length + 1;
912 threw = true;
913 break;
914 }
915 }
916 // Make sure the below call to DefineObjectProperty() doesn't overwrite
917 // any magic "length" property by removing the value.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000918 // TODO(mstarzinger): This hack should be removed once we have addressed the
919 // respective TODO in Runtime_DefineOrRedefineDataProperty.
920 // For the time being, we need a hack to prevent Object.observe from
921 // generating two change records.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000922 obj.length = new_length;
923 desc.value_ = void 0;
924 desc.hasValue_ = false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000925 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000926 if (emit_splice) {
927 EndPerformSplice(obj);
928 EnqueueSpliceRecord(obj,
929 new_length < old_length ? new_length : old_length,
930 removed,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000931 new_length > old_length ? new_length - old_length : 0);
932 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000933 if (threw) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000934 if (should_throw) {
935 throw MakeTypeError("redefine_disallowed", [p]);
936 } else {
937 return false;
938 }
939 }
940 return true;
941 }
942
943 // Step 4 - Special handling for array index.
944 var index = ToUint32(p);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000945 var emit_splice = false;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000946 if (ToString(index) == p && index != 4294967295) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000947 var length = obj.length;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000948 if (index >= length && %IsObserved(obj)) {
949 emit_splice = true;
950 BeginPerformSplice(obj);
951 }
952
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000953 var length_desc = GetOwnProperty(obj, "length");
954 if ((index >= length && !length_desc.isWritable()) ||
955 !DefineObjectProperty(obj, p, desc, true)) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000956 if (emit_splice)
957 EndPerformSplice(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000958 if (should_throw) {
959 throw MakeTypeError("define_disallowed", [p]);
960 } else {
961 return false;
962 }
963 }
964 if (index >= length) {
965 obj.length = index + 1;
966 }
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000967 if (emit_splice) {
968 EndPerformSplice(obj);
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000969 EnqueueSpliceRecord(obj, length, [], index + 1 - length);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000970 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000971 return true;
972 }
973
974 // Step 5 - Fallback to default implementation.
975 return DefineObjectProperty(obj, p, desc, should_throw);
976}
977
978
979// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
980function DefineOwnProperty(obj, p, desc, should_throw) {
981 if (%IsJSProxy(obj)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000982 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
983 if (IS_SYMBOL(p)) return false;
984
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000985 var attributes = FromGenericPropertyDescriptor(desc);
986 return DefineProxyProperty(obj, p, attributes, should_throw);
987 } else if (IS_ARRAY(obj)) {
988 return DefineArrayProperty(obj, p, desc, should_throw);
989 } else {
990 return DefineObjectProperty(obj, p, desc, should_throw);
991 }
992}
993
994
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000995// ES5 section 15.2.3.2.
996function ObjectGetPrototypeOf(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000997 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000998 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000999 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001000 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001}
1002
1003
lrn@chromium.org25156de2010-04-06 13:10:27 +00001004// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001005function ObjectGetOwnPropertyDescriptor(obj, p) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001006 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001007 throw MakeTypeError("called_on_non_object",
1008 ["Object.getOwnPropertyDescriptor"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001009 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001010 var desc = GetOwnProperty(obj, p);
1011 return FromPropertyDescriptor(desc);
1012}
1013
1014
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001015// For Harmony proxies
ulan@chromium.org750145a2013-03-07 15:14:13 +00001016function ToNameArray(obj, trap, includeSymbols) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001017 if (!IS_SPEC_OBJECT(obj)) {
1018 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
1019 }
1020 var n = ToUint32(obj.length);
1021 var array = new $Array(n);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001022 var realLength = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001023 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001024 for (var index = 0; index < n; index++) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001025 var s = ToName(obj[index]);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001026 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001027 if (IS_SYMBOL(s) && !includeSymbols) continue;
verwaest@chromium.org37141392012-05-31 13:27:02 +00001028 if (%HasLocalProperty(names, s)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001029 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001030 }
1031 array[index] = s;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001032 ++realLength;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 names[s] = 0;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001034 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001035 array.length = realLength;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001036 return array;
1037}
1038
1039
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001040// ES5 section 15.2.3.4.
1041function ObjectGetOwnPropertyNames(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001042 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001043 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001044 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001045 // Special handling for proxies.
1046 if (%IsJSProxy(obj)) {
1047 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001048 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001049 return ToNameArray(names, "getOwnPropertyNames", false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001050 }
1051
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001052 var nameArrays = new InternalArray();
1053
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001054 // Find all the indexed properties.
1055
1056 // Get the local element names.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001057 var localElementNames = %GetLocalElementNames(obj);
1058 for (var i = 0; i < localElementNames.length; ++i) {
1059 localElementNames[i] = %_NumberToString(localElementNames[i]);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001060 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001061 nameArrays.push(localElementNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001062
1063 // Get names for indexed interceptor properties.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001064 var interceptorInfo = %GetInterceptorInfo(obj);
1065 if ((interceptorInfo & 1) != 0) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001066 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1067 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1068 nameArrays.push(indexedInterceptorNames);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001069 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001070 }
1071
1072 // Find all the named properties.
1073
1074 // Get the local property names.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001075 nameArrays.push(%GetLocalPropertyNames(obj, false));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001076
1077 // Get names for named interceptor properties if any.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001078 if ((interceptorInfo & 2) != 0) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001079 var namedInterceptorNames = %GetNamedInterceptorPropertyNames(obj);
1080 if (!IS_UNDEFINED(namedInterceptorNames)) {
1081 nameArrays.push(namedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001082 }
1083 }
1084
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001085 var propertyNames =
1086 %Apply(InternalArray.prototype.concat,
1087 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1088
1089 // Property names are expected to be unique strings,
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001090 // but interceptors can interfere with that assumption.
1091 if (interceptorInfo != 0) {
1092 var propertySet = { __proto__: null };
1093 var j = 0;
1094 for (var i = 0; i < propertyNames.length; ++i) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001095 if (IS_SYMBOL(propertyNames[i])) continue;
1096 var name = ToString(propertyNames[i]);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001097 // We need to check for the exact property value since for intrinsic
1098 // properties like toString if(propertySet["toString"]) will always
1099 // succeed.
1100 if (propertySet[name] === true) {
1101 continue;
1102 }
1103 propertySet[name] = true;
1104 propertyNames[j++] = name;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001105 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001106 propertyNames.length = j;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001107 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001108
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001109 return propertyNames;
1110}
1111
1112
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001113// ES5 section 15.2.3.5.
1114function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001115 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001116 throw MakeTypeError("proto_object_or_null", [proto]);
1117 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001118 var obj = { __proto__: proto };
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001119 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1120 return obj;
1121}
1122
1123
ager@chromium.org5c838252010-02-19 08:53:10 +00001124// ES5 section 15.2.3.6.
1125function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001126 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001127 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001128 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001129 var name = ToName(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001130 if (%IsJSProxy(obj)) {
1131 // Clone the attributes object for protection.
1132 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1133 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001134 var attributesClone = { __proto__: null };
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001135 for (var a in attributes) {
1136 attributesClone[a] = attributes[a];
1137 }
1138 DefineProxyProperty(obj, name, attributesClone, true);
1139 // The following would implement the spec as in the current proposal,
1140 // but after recent comments on es-discuss, is most likely obsolete.
1141 /*
1142 var defineObj = FromGenericPropertyDescriptor(desc);
1143 var names = ObjectGetOwnPropertyNames(attributes);
1144 var standardNames =
1145 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1146 for (var i = 0; i < names.length; i++) {
1147 var N = names[i];
1148 if (!(%HasLocalProperty(standardNames, N))) {
1149 var attr = GetOwnProperty(attributes, N);
1150 DefineOwnProperty(descObj, N, attr, true);
1151 }
1152 }
1153 // This is really confusing the types, but it is what the proxies spec
1154 // currently requires:
1155 desc = descObj;
1156 */
1157 } else {
1158 var desc = ToPropertyDescriptor(attributes);
1159 DefineOwnProperty(obj, name, desc, true);
1160 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001161 return obj;
1162}
1163
1164
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001165function GetOwnEnumerablePropertyNames(properties) {
1166 var names = new InternalArray();
1167 for (var key in properties) {
1168 if (%HasLocalProperty(properties, key)) {
1169 names.push(key);
1170 }
1171 }
1172 return names;
1173}
1174
1175
ager@chromium.org5c838252010-02-19 08:53:10 +00001176// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001177function ObjectDefineProperties(obj, properties) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001178 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001179 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001180 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001181 var props = ToObject(properties);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001182 var names = GetOwnEnumerablePropertyNames(props);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001183 var descriptors = new InternalArray();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001184 for (var i = 0; i < names.length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001185 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1186 }
1187 for (var i = 0; i < names.length; i++) {
1188 DefineOwnProperty(obj, names[i], descriptors[i], true);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001189 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001190 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001191}
1192
1193
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001194// Harmony proxies.
1195function ProxyFix(obj) {
1196 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001197 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001198 if (IS_UNDEFINED(props)) {
1199 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1200 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001201
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001202 if (%IsJSFunctionProxy(obj)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001203 var callTrap = %GetCallTrap(obj);
1204 var constructTrap = %GetConstructTrap(obj);
1205 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1206 %Fix(obj); // becomes a regular function
1207 %SetCode(obj, code);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001208 // TODO(rossberg): What about length and other properties? Not specified.
1209 // We just put in some half-reasonable defaults for now.
1210 var prototype = new $Object();
1211 $Object.defineProperty(prototype, "constructor",
danno@chromium.org2c456792011-11-11 12:00:53 +00001212 {value: obj, writable: true, enumerable: false, configurable: true});
1213 // TODO(v8:1530): defineProperty does not handle prototype and length.
1214 %FunctionSetPrototype(obj, prototype);
1215 obj.length = 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001216 } else {
1217 %Fix(obj);
1218 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001219 ObjectDefineProperties(obj, props);
1220}
1221
1222
ager@chromium.orgb5737492010-07-15 09:29:43 +00001223// ES5 section 15.2.3.8.
1224function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001225 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001226 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001227 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001228 if (%IsJSProxy(obj)) {
1229 ProxyFix(obj);
1230 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001231 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001232 for (var i = 0; i < names.length; i++) {
1233 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001234 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 if (desc.isConfigurable()) {
1236 desc.setConfigurable(false);
1237 DefineOwnProperty(obj, name, desc, true);
1238 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001239 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001240 %PreventExtensions(obj);
1241 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001242}
1243
1244
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001245// ES5 section 15.2.3.9.
1246function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001247 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001248 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001249 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001250 var isProxy = %IsJSProxy(obj);
1251 if (isProxy || %HasNonStrictArgumentsElements(obj)) {
1252 if (isProxy) {
1253 ProxyFix(obj);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001254 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001255 var names = ObjectGetOwnPropertyNames(obj);
1256 for (var i = 0; i < names.length; i++) {
1257 var name = names[i];
1258 var desc = GetOwnProperty(obj, name);
1259 if (desc.isWritable() || desc.isConfigurable()) {
1260 if (IsDataDescriptor(desc)) desc.setWritable(false);
1261 desc.setConfigurable(false);
1262 DefineOwnProperty(obj, name, desc, true);
1263 }
1264 }
1265 %PreventExtensions(obj);
1266 } else {
1267 // TODO(adamk): Is it worth going to this fast path if the
1268 // object's properties are already in dictionary mode?
1269 %ObjectFreeze(obj);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001270 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001271 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001272}
1273
1274
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001275// ES5 section 15.2.3.10
1276function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001277 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001278 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001279 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001280 if (%IsJSProxy(obj)) {
1281 ProxyFix(obj);
1282 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001283 %PreventExtensions(obj);
1284 return obj;
1285}
1286
1287
ager@chromium.orgb5737492010-07-15 09:29:43 +00001288// ES5 section 15.2.3.11
1289function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001290 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001291 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001292 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001293 if (%IsJSProxy(obj)) {
1294 return false;
1295 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001296 if (%IsExtensible(obj)) {
1297 return false;
1298 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001299 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001300 for (var i = 0; i < names.length; i++) {
1301 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001302 var desc = GetOwnProperty(obj, name);
1303 if (desc.isConfigurable()) return false;
1304 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001305 return true;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001306}
1307
1308
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001309// ES5 section 15.2.3.12
1310function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001311 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001312 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001313 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001314 if (%IsJSProxy(obj)) {
1315 return false;
1316 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001317 if (%IsExtensible(obj)) {
1318 return false;
1319 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001320 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001321 for (var i = 0; i < names.length; i++) {
1322 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001323 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001324 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1325 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001326 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001327 return true;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001328}
1329
1330
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001331// ES5 section 15.2.3.13
1332function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001333 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001334 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001335 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001336 if (%IsJSProxy(obj)) {
1337 return true;
1338 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001339 return %IsExtensible(obj);
1340}
1341
1342
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001343// Harmony egal.
1344function ObjectIs(obj1, obj2) {
1345 if (obj1 === obj2) {
1346 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1347 } else {
1348 return (obj1 !== obj1) && (obj2 !== obj2);
1349 }
1350}
1351
1352
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001353// Harmony __proto__ getter.
1354function ObjectGetProto() {
1355 return %GetPrototype(this);
1356}
1357
1358
1359// Harmony __proto__ setter.
1360function ObjectSetProto(obj) {
1361 return %SetPrototype(this, obj);
1362}
1363
1364
1365// Harmony __proto__ poison pill.
1366function ObjectPoisonProto(obj) {
1367 throw MakeTypeError("proto_poison_pill", []);
1368}
1369
1370
1371function ObjectConstructor(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001372 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 if (x == null) return this;
1374 return ToObject(x);
1375 } else {
1376 if (x == null) return { };
1377 return ToObject(x);
1378 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001379}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
1381
1382// ----------------------------------------------------------------------------
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001383// Object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001385function SetUpObject() {
1386 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001387
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001388 %SetNativeFlag($Object);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001389 %SetCode($Object, ObjectConstructor);
1390 %FunctionSetName(ObjectPoisonProto, "__proto__");
1391 %FunctionRemovePrototype(ObjectPoisonProto);
1392 %SetExpectedNumberOfProperties($Object, 4);
1393
1394 %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1395
1396 // Set up non-enumerable functions on the Object.prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001397 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1398 "toString", ObjectToString,
1399 "toLocaleString", ObjectToLocaleString,
1400 "valueOf", ObjectValueOf,
1401 "hasOwnProperty", ObjectHasOwnProperty,
1402 "isPrototypeOf", ObjectIsPrototypeOf,
1403 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1404 "__defineGetter__", ObjectDefineGetter,
1405 "__lookupGetter__", ObjectLookupGetter,
1406 "__defineSetter__", ObjectDefineSetter,
1407 "__lookupSetter__", ObjectLookupSetter
1408 ));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001409 InstallGetterSetter($Object.prototype, "__proto__",
1410 ObjectGetProto, ObjectSetProto);
1411
1412 // Set up non-enumerable functions in the Object object.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001413 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001414 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001415 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001416 "defineProperty", ObjectDefineProperty,
1417 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001418 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001419 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001420 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001421 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001422 "is", ObjectIs,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001423 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001424 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001425 "isSealed", ObjectIsSealed,
1426 "preventExtensions", ObjectPreventExtension,
1427 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001428 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001429}
1430
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001431SetUpObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434// ----------------------------------------------------------------------------
1435// Boolean
1436
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001437function BooleanConstructor(x) {
1438 if (%_IsConstructCall()) {
1439 %_SetValueOf(this, ToBoolean(x));
1440 } else {
1441 return ToBoolean(x);
1442 }
1443}
1444
1445
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001446function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447 // NOTE: Both Boolean objects and values can enter here as
1448 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001449 var b = this;
1450 if (!IS_BOOLEAN(b)) {
1451 if (!IS_BOOLEAN_WRAPPER(b)) {
1452 throw new $TypeError('Boolean.prototype.toString is not generic');
1453 }
1454 b = %_ValueOf(b);
1455 }
1456 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001457}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458
1459
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001460function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // NOTE: Both Boolean objects and values can enter here as
1462 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001463 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 throw new $TypeError('Boolean.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001467}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
1469
1470// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001471
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001472function SetUpBoolean () {
1473 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001474
1475 %SetCode($Boolean, BooleanConstructor);
1476 %FunctionSetPrototype($Boolean, new $Boolean(false));
1477 %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1478
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001479 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1480 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001481 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001482 ));
1483}
1484
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001485SetUpBoolean();
1486
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001487
1488// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489// Number
1490
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001491function NumberConstructor(x) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001493 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 %_SetValueOf(this, value);
1495 } else {
1496 return value;
1497 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001498}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001502function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 // NOTE: Both Number objects and values can enter here as
1504 // 'this'. This is not as dictated by ECMA-262.
1505 var number = this;
1506 if (!IS_NUMBER(this)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 if (!IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 throw new $TypeError('Number.prototype.toString is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 // Get the value of this number in case it's an object.
1511 number = %_ValueOf(this);
1512 }
1513 // Fast case: Convert number in radix 10.
1514 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001515 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 }
1517
1518 // Convert the radix to an integer and check the range.
1519 radix = TO_INTEGER(radix);
1520 if (radix < 2 || radix > 36) {
1521 throw new $RangeError('toString() radix argument must be between 2 and 36');
1522 }
1523 // Convert the number to a string in the given radix.
1524 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001525}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526
1527
1528// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001529function NumberToLocaleString() {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001530 return %_CallFunction(this, NumberToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001531}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532
1533
1534// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001535function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 // NOTE: Both Number objects and values can enter here as
1537 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001538 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 throw new $TypeError('Number.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001542}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
1544
1545// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001546function NumberToFixed(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001547 var x = this;
1548 if (!IS_NUMBER(this)) {
1549 if (!IS_NUMBER_WRAPPER(this)) {
1550 throw MakeTypeError("incompatible_method_receiver",
1551 ["Number.prototype.toFixed", this]);
1552 }
1553 // Get the value of this number in case it's an object.
1554 x = %_ValueOf(this);
1555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 var f = TO_INTEGER(fractionDigits);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 if (f < 0 || f > 20) {
1559 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1560 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001561
1562 if (NUMBER_IS_NAN(x)) return "NaN";
1563 if (x == 1/0) return "Infinity";
1564 if (x == -1/0) return "-Infinity";
1565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001567}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568
1569
1570// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001571function NumberToExponential(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001572 var x = this;
1573 if (!IS_NUMBER(this)) {
1574 if (!IS_NUMBER_WRAPPER(this)) {
1575 throw MakeTypeError("incompatible_method_receiver",
1576 ["Number.prototype.toExponential", this]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001578 // Get the value of this number in case it's an object.
1579 x = %_ValueOf(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001581 var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
1582
1583 if (NUMBER_IS_NAN(x)) return "NaN";
1584 if (x == 1/0) return "Infinity";
1585 if (x == -1/0) return "-Infinity";
1586
1587 if (IS_UNDEFINED(f)) {
1588 f = -1; // Signal for runtime function that f is not defined.
1589 } else if (f < 0 || f > 20) {
1590 throw new $RangeError("toExponential() argument must be between 0 and 20");
lrn@chromium.org1c092762011-05-09 09:42:16 +00001591 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001593}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
1595
1596// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001597function NumberToPrecision(precision) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001598 var x = this;
1599 if (!IS_NUMBER(this)) {
1600 if (!IS_NUMBER_WRAPPER(this)) {
1601 throw MakeTypeError("incompatible_method_receiver",
1602 ["Number.prototype.toPrecision", this]);
1603 }
1604 // Get the value of this number in case it's an object.
1605 x = %_ValueOf(this);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1608 var p = TO_INTEGER(precision);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001609
1610 if (NUMBER_IS_NAN(x)) return "NaN";
1611 if (x == 1/0) return "Infinity";
1612 if (x == -1/0) return "-Infinity";
1613
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 if (p < 1 || p > 21) {
1615 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001618}
1619
1620
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001621// Harmony isFinite.
1622function NumberIsFinite(number) {
1623 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1624}
1625
1626
1627// Harmony isNaN.
1628function NumberIsNaN(number) {
1629 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1630}
1631
1632
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001633// ----------------------------------------------------------------------------
1634
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001635function SetUpNumber() {
1636 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001637
1638 %SetCode($Number, NumberConstructor);
1639 %FunctionSetPrototype($Number, new $Number(0));
1640
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001641 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001642 // Set up the constructor property on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001643 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1644
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001645 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001646 // ECMA-262 section 15.7.3.1.
1647 %SetProperty($Number,
1648 "MAX_VALUE",
1649 1.7976931348623157e+308,
1650 DONT_ENUM | DONT_DELETE | READ_ONLY);
1651
1652 // ECMA-262 section 15.7.3.2.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001653 %SetProperty($Number, "MIN_VALUE", 5e-324,
1654 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001655
1656 // ECMA-262 section 15.7.3.3.
1657 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1658
1659 // ECMA-262 section 15.7.3.4.
1660 %SetProperty($Number,
1661 "NEGATIVE_INFINITY",
1662 -1/0,
1663 DONT_ENUM | DONT_DELETE | READ_ONLY);
1664
1665 // ECMA-262 section 15.7.3.5.
1666 %SetProperty($Number,
1667 "POSITIVE_INFINITY",
1668 1/0,
1669 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001670 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001671
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001672 // Set up non-enumerable functions on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001673 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1674 "toString", NumberToString,
1675 "toLocaleString", NumberToLocaleString,
1676 "valueOf", NumberValueOf,
1677 "toFixed", NumberToFixed,
1678 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001679 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001680 ));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001681 InstallFunctions($Number, DONT_ENUM, $Array(
1682 "isFinite", NumberIsFinite,
1683 "isNaN", NumberIsNaN
1684 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001685}
1686
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001687SetUpNumber();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690// ----------------------------------------------------------------------------
1691// Function
1692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693function FunctionSourceString(func) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001694 while (%IsJSFunctionProxy(func)) {
1695 func = %GetCallTrap(func);
1696 }
1697
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001698 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701
1702 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001703 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001704 var name = %FunctionGetName(func);
1705 if (name) {
1706 // Mimic what KJS does.
1707 return 'function ' + name + '() { [native code] }';
1708 } else {
1709 return 'function () { [native code] }';
1710 }
1711 }
1712
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001713 var name = %FunctionNameShouldPrintAsAnonymous(func)
1714 ? 'anonymous'
1715 : %FunctionGetName(func);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001716 var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1717 return head + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001718}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719
1720
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001721function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001723}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724
1725
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001726// ES5 15.3.4.5
1727function FunctionBind(this_arg) { // Length is 1.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001728 if (!IS_SPEC_FUNCTION(this)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001729 throw new $TypeError('Bind must be called on a function');
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001730 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001731 var boundFunction = function () {
1732 // Poison .arguments and .caller, but is otherwise not detectable.
1733 "use strict";
1734 // This function must not use any object literals (Object, Array, RegExp),
1735 // since the literals-array is being used to store the bound data.
1736 if (%_IsConstructCall()) {
1737 return %NewObjectFromBound(boundFunction);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001738 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001739 var bindings = %BoundFunctionGetBindings(boundFunction);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001740
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001741 var argc = %_ArgumentsLength();
1742 if (argc == 0) {
1743 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1744 }
1745 if (bindings.length === 2) {
1746 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1747 }
1748 var bound_argc = bindings.length - 2;
1749 var argv = new InternalArray(bound_argc + argc);
1750 for (var i = 0; i < bound_argc; i++) {
1751 argv[i] = bindings[i + 2];
1752 }
1753 for (var j = 0; j < argc; j++) {
1754 argv[i++] = %_Arguments(j);
1755 }
1756 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1757 };
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001758
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001759 %FunctionRemovePrototype(boundFunction);
1760 var new_length = 0;
1761 if (%_ClassOf(this) == "Function") {
1762 // Function or FunctionProxy.
1763 var old_length = this.length;
1764 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1765 if ((typeof old_length === "number") &&
1766 ((old_length >>> 0) === old_length)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001767 var argc = %_ArgumentsLength();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001768 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1769 new_length = old_length - argc;
1770 if (new_length < 0) new_length = 0;
1771 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001772 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001773 // This runtime function finds any remaining arguments on the stack,
1774 // so we don't pass the arguments object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001775 var result = %FunctionBindArguments(boundFunction, this,
1776 this_arg, new_length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001777
1778 // We already have caller and arguments properties on functions,
1779 // which are non-configurable. It therefore makes no sence to
1780 // try to redefine these as defined by the spec. The spec says
1781 // that bind should make these throw a TypeError if get or set
1782 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001783 // To be consistent with our normal functions we leave this as it is.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001784 // TODO(lrn): Do set these to be thrower.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001785 return result;
1786}
1787
1788
danno@chromium.org41728482013-06-12 22:31:22 +00001789function NewFunctionString(arguments, function_token) {
1790 var n = arguments.length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791 var p = '';
1792 if (n > 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00001793 p = ToString(arguments[0]);
1794 for (var i = 1; i < n - 1; i++) {
1795 p += ',' + ToString(arguments[i]);
1796 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 // If the formal parameters string include ) - an illegal
1798 // character - it may make the combined function expression
1799 // compile. We avoid this problem by checking for this early on.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001800 if (%_CallFunction(p, ')', StringIndexOf) != -1) {
danno@chromium.org41728482013-06-12 22:31:22 +00001801 throw MakeSyntaxError('paren_in_arg_string', []);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001802 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001803 // If the formal parameters include an unbalanced block comment, the
1804 // function must be rejected. Since JavaScript does not allow nested
1805 // comments we can include a trailing block comment to catch this.
1806 p += '\n/' + '**/';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 }
danno@chromium.org41728482013-06-12 22:31:22 +00001808 var body = (n > 0) ? ToString(arguments[n - 1]) : '';
1809 return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
1810}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811
danno@chromium.org41728482013-06-12 22:31:22 +00001812
1813function FunctionConstructor(arg1) { // length == 1
1814 var source = NewFunctionString(arguments, 'function');
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001815 var global_receiver = %GlobalReceiver(global);
danno@chromium.org41728482013-06-12 22:31:22 +00001816 // Compile the string in the constructor and not a helper so that errors
1817 // appear to come from here.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001818 var f = %_CallFunction(global_receiver, %CompileString(source, true));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001819 %FunctionMarkNameShouldPrintAsAnonymous(f);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001820 return f;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001821}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001823
1824// ----------------------------------------------------------------------------
1825
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001826function SetUpFunction() {
1827 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001828
danno@chromium.org41728482013-06-12 22:31:22 +00001829 %SetCode($Function, FunctionConstructor);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001830 %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1831
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001832 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001833 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001834 "toString", FunctionToString
1835 ));
1836}
1837
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001838SetUpFunction();