2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2008 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "ObjectConstructor.h"
24 #include "ButterflyInlines.h"
25 #include "CopiedSpaceInlines.h"
27 #include "ExceptionHelpers.h"
28 #include "JSFunction.h"
30 #include "JSGlobalObject.h"
32 #include "ObjectPrototype.h"
33 #include "Operations.h"
34 #include "PropertyDescriptor.h"
35 #include "PropertyNameArray.h"
39 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
*);
40 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
*);
41 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
*);
42 static EncodedJSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
*);
43 static EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
*);
44 static EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
*);
45 static EncodedJSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
*);
46 static EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
*);
47 static EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
*);
48 static EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
*);
49 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
*);
50 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
*);
51 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
*);
55 #include "ObjectConstructor.lut.h"
59 ASSERT_HAS_TRIVIAL_DESTRUCTOR(ObjectConstructor
);
61 const ClassInfo
ObjectConstructor::s_info
= { "Function", &InternalFunction::s_info
, 0, ExecState::objectConstructorTable
, CREATE_METHOD_TABLE(ObjectConstructor
) };
63 /* Source for ObjectConstructor.lut.h
64 @begin objectConstructorTable
65 getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
66 getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
67 getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
68 keys objectConstructorKeys DontEnum|Function 1
69 defineProperty objectConstructorDefineProperty DontEnum|Function 3
70 defineProperties objectConstructorDefineProperties DontEnum|Function 2
71 create objectConstructorCreate DontEnum|Function 2
72 seal objectConstructorSeal DontEnum|Function 1
73 freeze objectConstructorFreeze DontEnum|Function 1
74 preventExtensions objectConstructorPreventExtensions DontEnum|Function 1
75 isSealed objectConstructorIsSealed DontEnum|Function 1
76 isFrozen objectConstructorIsFrozen DontEnum|Function 1
77 isExtensible objectConstructorIsExtensible DontEnum|Function 1
81 ObjectConstructor::ObjectConstructor(JSGlobalObject
* globalObject
, Structure
* structure
)
82 : InternalFunction(globalObject
, structure
)
86 void ObjectConstructor::finishCreation(ExecState
* exec
, ObjectPrototype
* objectPrototype
)
88 Base::finishCreation(exec
->vm(), Identifier(exec
, "Object").string());
90 putDirectWithoutTransition(exec
->vm(), exec
->propertyNames().prototype
, objectPrototype
, DontEnum
| DontDelete
| ReadOnly
);
91 // no. of arguments for constructor
92 putDirectWithoutTransition(exec
->vm(), exec
->propertyNames().length
, jsNumber(1), ReadOnly
| DontEnum
| DontDelete
);
95 bool ObjectConstructor::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
&slot
)
97 return getStaticFunctionSlot
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), jsCast
<ObjectConstructor
*>(cell
), propertyName
, slot
);
100 bool ObjectConstructor::getOwnPropertyDescriptor(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertyDescriptor
& descriptor
)
102 return getStaticFunctionDescriptor
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), jsCast
<ObjectConstructor
*>(object
), propertyName
, descriptor
);
105 static ALWAYS_INLINE JSObject
* constructObject(ExecState
* exec
)
107 JSGlobalObject
* globalObject
= exec
->callee()->globalObject();
109 JSValue arg
= args
.at(0);
110 if (arg
.isUndefinedOrNull())
111 return constructEmptyObject(exec
, globalObject
->objectPrototype());
112 return arg
.toObject(exec
, globalObject
);
115 static EncodedJSValue JSC_HOST_CALL
constructWithObjectConstructor(ExecState
* exec
)
117 return JSValue::encode(constructObject(exec
));
120 ConstructType
ObjectConstructor::getConstructData(JSCell
*, ConstructData
& constructData
)
122 constructData
.native
.function
= constructWithObjectConstructor
;
123 return ConstructTypeHost
;
126 static EncodedJSValue JSC_HOST_CALL
callObjectConstructor(ExecState
* exec
)
128 return JSValue::encode(constructObject(exec
));
131 CallType
ObjectConstructor::getCallData(JSCell
*, CallData
& callData
)
133 callData
.native
.function
= callObjectConstructor
;
137 EncodedJSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
* exec
)
139 if (!exec
->argument(0).isObject())
140 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Requested prototype of a value that is not an object.")));
141 JSObject
* object
= asObject(exec
->argument(0));
142 if (!object
->allowsAccessFrom(exec
->trueCallerFrame()))
143 return JSValue::encode(jsUndefined());
144 return JSValue::encode(object
->prototype());
147 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
* exec
)
149 if (!exec
->argument(0).isObject())
150 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Requested property descriptor of a value that is not an object.")));
151 String propertyName
= exec
->argument(1).toString(exec
)->value(exec
);
152 if (exec
->hadException())
153 return JSValue::encode(jsNull());
154 JSObject
* object
= asObject(exec
->argument(0));
155 PropertyDescriptor descriptor
;
156 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, Identifier(exec
, propertyName
), descriptor
))
157 return JSValue::encode(jsUndefined());
158 if (exec
->hadException())
159 return JSValue::encode(jsUndefined());
161 JSObject
* description
= constructEmptyObject(exec
);
162 if (!descriptor
.isAccessorDescriptor()) {
163 description
->putDirect(exec
->vm(), exec
->propertyNames().value
, descriptor
.value() ? descriptor
.value() : jsUndefined(), 0);
164 description
->putDirect(exec
->vm(), exec
->propertyNames().writable
, jsBoolean(descriptor
.writable()), 0);
166 ASSERT(descriptor
.getter());
167 ASSERT(descriptor
.setter());
168 description
->putDirect(exec
->vm(), exec
->propertyNames().get
, descriptor
.getter(), 0);
169 description
->putDirect(exec
->vm(), exec
->propertyNames().set
, descriptor
.setter(), 0);
172 description
->putDirect(exec
->vm(), exec
->propertyNames().enumerable
, jsBoolean(descriptor
.enumerable()), 0);
173 description
->putDirect(exec
->vm(), exec
->propertyNames().configurable
, jsBoolean(descriptor
.configurable()), 0);
175 return JSValue::encode(description
);
178 // FIXME: Use the enumeration cache.
179 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
* exec
)
181 if (!exec
->argument(0).isObject())
182 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Requested property names of a value that is not an object.")));
183 PropertyNameArray
properties(exec
);
184 asObject(exec
->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec
->argument(0)), exec
, properties
, IncludeDontEnumProperties
);
185 JSArray
* names
= constructEmptyArray(exec
, 0);
186 size_t numProperties
= properties
.size();
187 for (size_t i
= 0; i
< numProperties
; i
++)
188 names
->push(exec
, jsOwnedString(exec
, properties
[i
].string()));
189 return JSValue::encode(names
);
192 // FIXME: Use the enumeration cache.
193 EncodedJSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
* exec
)
195 if (!exec
->argument(0).isObject())
196 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Requested keys of a value that is not an object.")));
197 PropertyNameArray
properties(exec
);
198 asObject(exec
->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec
->argument(0)), exec
, properties
, ExcludeDontEnumProperties
);
199 JSArray
* keys
= constructEmptyArray(exec
, 0);
200 size_t numProperties
= properties
.size();
201 for (size_t i
= 0; i
< numProperties
; i
++)
202 keys
->push(exec
, jsOwnedString(exec
, properties
[i
].string()));
203 return JSValue::encode(keys
);
206 // ES5 8.10.5 ToPropertyDescriptor
207 static bool toPropertyDescriptor(ExecState
* exec
, JSValue in
, PropertyDescriptor
& desc
)
209 if (!in
.isObject()) {
210 throwError(exec
, createTypeError(exec
, ASCIILiteral("Property description must be an object.")));
213 JSObject
* description
= asObject(in
);
215 PropertySlot
enumerableSlot(description
);
216 if (description
->getPropertySlot(exec
, exec
->propertyNames().enumerable
, enumerableSlot
)) {
217 desc
.setEnumerable(enumerableSlot
.getValue(exec
, exec
->propertyNames().enumerable
).toBoolean(exec
));
218 if (exec
->hadException())
222 PropertySlot
configurableSlot(description
);
223 if (description
->getPropertySlot(exec
, exec
->propertyNames().configurable
, configurableSlot
)) {
224 desc
.setConfigurable(configurableSlot
.getValue(exec
, exec
->propertyNames().configurable
).toBoolean(exec
));
225 if (exec
->hadException())
230 PropertySlot
valueSlot(description
);
231 if (description
->getPropertySlot(exec
, exec
->propertyNames().value
, valueSlot
)) {
232 desc
.setValue(valueSlot
.getValue(exec
, exec
->propertyNames().value
));
233 if (exec
->hadException())
237 PropertySlot
writableSlot(description
);
238 if (description
->getPropertySlot(exec
, exec
->propertyNames().writable
, writableSlot
)) {
239 desc
.setWritable(writableSlot
.getValue(exec
, exec
->propertyNames().writable
).toBoolean(exec
));
240 if (exec
->hadException())
244 PropertySlot
getSlot(description
);
245 if (description
->getPropertySlot(exec
, exec
->propertyNames().get
, getSlot
)) {
246 JSValue get
= getSlot
.getValue(exec
, exec
->propertyNames().get
);
247 if (exec
->hadException())
249 if (!get
.isUndefined()) {
251 if (getCallData(get
, callData
) == CallTypeNone
) {
252 throwError(exec
, createTypeError(exec
, ASCIILiteral("Getter must be a function.")));
259 PropertySlot
setSlot(description
);
260 if (description
->getPropertySlot(exec
, exec
->propertyNames().set
, setSlot
)) {
261 JSValue set
= setSlot
.getValue(exec
, exec
->propertyNames().set
);
262 if (exec
->hadException())
264 if (!set
.isUndefined()) {
266 if (getCallData(set
, callData
) == CallTypeNone
) {
267 throwError(exec
, createTypeError(exec
, ASCIILiteral("Setter must be a function.")));
274 if (!desc
.isAccessorDescriptor())
278 throwError(exec
, createTypeError(exec
, ASCIILiteral("Invalid property. 'value' present on property with getter or setter.")));
282 if (desc
.writablePresent()) {
283 throwError(exec
, createTypeError(exec
, ASCIILiteral("Invalid property. 'writable' present on property with getter or setter.")));
289 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
* exec
)
291 if (!exec
->argument(0).isObject())
292 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Properties can only be defined on Objects.")));
293 JSObject
* O
= asObject(exec
->argument(0));
294 String propertyName
= exec
->argument(1).toString(exec
)->value(exec
);
295 if (exec
->hadException())
296 return JSValue::encode(jsNull());
297 PropertyDescriptor descriptor
;
298 if (!toPropertyDescriptor(exec
, exec
->argument(2), descriptor
))
299 return JSValue::encode(jsNull());
300 ASSERT((descriptor
.attributes() & Accessor
) || (!descriptor
.isAccessorDescriptor()));
301 ASSERT(!exec
->hadException());
302 O
->methodTable()->defineOwnProperty(O
, exec
, Identifier(exec
, propertyName
), descriptor
, true);
303 return JSValue::encode(O
);
306 static JSValue
defineProperties(ExecState
* exec
, JSObject
* object
, JSObject
* properties
)
308 PropertyNameArray
propertyNames(exec
);
309 asObject(properties
)->methodTable()->getOwnPropertyNames(asObject(properties
), exec
, propertyNames
, ExcludeDontEnumProperties
);
310 size_t numProperties
= propertyNames
.size();
311 Vector
<PropertyDescriptor
> descriptors
;
312 MarkedArgumentBuffer markBuffer
;
313 for (size_t i
= 0; i
< numProperties
; i
++) {
315 JSValue prop
= properties
->get(exec
, propertyNames
[i
]);
316 if (exec
->hadException())
318 PropertyDescriptor descriptor
;
319 if (!toPropertyDescriptor(exec
, prop
, descriptor
))
321 descriptors
.append(descriptor
);
322 // Ensure we mark all the values that we're accumulating
323 if (descriptor
.isDataDescriptor() && descriptor
.value())
324 markBuffer
.append(descriptor
.value());
325 if (descriptor
.isAccessorDescriptor()) {
326 if (descriptor
.getter())
327 markBuffer
.append(descriptor
.getter());
328 if (descriptor
.setter())
329 markBuffer
.append(descriptor
.setter());
332 for (size_t i
= 0; i
< numProperties
; i
++) {
333 object
->methodTable()->defineOwnProperty(object
, exec
, propertyNames
[i
], descriptors
[i
], true);
334 if (exec
->hadException())
340 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
* exec
)
342 if (!exec
->argument(0).isObject())
343 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Properties can only be defined on Objects.")));
344 return JSValue::encode(defineProperties(exec
, asObject(exec
->argument(0)), exec
->argument(1).toObject(exec
)));
347 EncodedJSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
* exec
)
349 if (!exec
->argument(0).isObject() && !exec
->argument(0).isNull())
350 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object prototype may only be an Object or null.")));
351 JSValue proto
= exec
->argument(0);
352 JSObject
* newObject
= proto
.isObject()
353 ? constructEmptyObject(exec
, asObject(proto
))
354 : constructEmptyObject(exec
, exec
->lexicalGlobalObject()->nullPrototypeObjectStructure());
355 if (exec
->argument(1).isUndefined())
356 return JSValue::encode(newObject
);
357 if (!exec
->argument(1).isObject())
358 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Property descriptor list must be an Object.")));
359 return JSValue::encode(defineProperties(exec
, newObject
, asObject(exec
->argument(1))));
362 EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
* exec
)
364 // 1. If Type(O) is not Object throw a TypeError exception.
365 JSValue obj
= exec
->argument(0);
367 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.seal can only be called on Objects.")));
368 JSObject
* object
= asObject(obj
);
370 if (isJSFinalObject(object
)) {
371 object
->seal(exec
->vm());
372 return JSValue::encode(obj
);
375 // 2. For each named own property name P of O,
376 PropertyNameArray
properties(exec
);
377 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
378 PropertyNameArray::const_iterator end
= properties
.end();
379 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
380 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
381 PropertyDescriptor desc
;
382 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
384 // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
385 desc
.setConfigurable(false);
386 // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
387 object
->methodTable()->defineOwnProperty(object
, exec
, *iter
, desc
, true);
388 if (exec
->hadException())
389 return JSValue::encode(obj
);
392 // 3. Set the [[Extensible]] internal property of O to false.
393 object
->preventExtensions(exec
->vm());
396 return JSValue::encode(obj
);
399 EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
* exec
)
401 // 1. If Type(O) is not Object throw a TypeError exception.
402 JSValue obj
= exec
->argument(0);
404 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.freeze can only be called on Objects.")));
405 JSObject
* object
= asObject(obj
);
407 if (isJSFinalObject(object
) && !hasIndexedProperties(object
->structure()->indexingType())) {
408 object
->freeze(exec
->vm());
409 return JSValue::encode(obj
);
412 // 2. For each named own property name P of O,
413 PropertyNameArray
properties(exec
);
414 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
415 PropertyNameArray::const_iterator end
= properties
.end();
416 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
417 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
418 PropertyDescriptor desc
;
419 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
421 // b. If IsDataDescriptor(desc) is true, then
422 // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
423 if (desc
.isDataDescriptor())
424 desc
.setWritable(false);
425 // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
426 desc
.setConfigurable(false);
427 // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
428 object
->methodTable()->defineOwnProperty(object
, exec
, *iter
, desc
, true);
429 if (exec
->hadException())
430 return JSValue::encode(obj
);
433 // 3. Set the [[Extensible]] internal property of O to false.
434 object
->preventExtensions(exec
->vm());
437 return JSValue::encode(obj
);
440 EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
* exec
)
442 JSValue obj
= exec
->argument(0);
444 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.preventExtensions can only be called on Objects.")));
445 asObject(obj
)->preventExtensions(exec
->vm());
446 return JSValue::encode(obj
);
449 EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
* exec
)
451 // 1. If Type(O) is not Object throw a TypeError exception.
452 JSValue obj
= exec
->argument(0);
454 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.isSealed can only be called on Objects.")));
455 JSObject
* object
= asObject(obj
);
457 if (isJSFinalObject(object
))
458 return JSValue::encode(jsBoolean(object
->isSealed(exec
->vm())));
460 // 2. For each named own property name P of O,
461 PropertyNameArray
properties(exec
);
462 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
463 PropertyNameArray::const_iterator end
= properties
.end();
464 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
465 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
466 PropertyDescriptor desc
;
467 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
469 // b. If desc.[[Configurable]] is true, then return false.
470 if (desc
.configurable())
471 return JSValue::encode(jsBoolean(false));
474 // 3. If the [[Extensible]] internal property of O is false, then return true.
475 // 4. Otherwise, return false.
476 return JSValue::encode(jsBoolean(!object
->isExtensible()));
479 EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
* exec
)
481 // 1. If Type(O) is not Object throw a TypeError exception.
482 JSValue obj
= exec
->argument(0);
484 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.isFrozen can only be called on Objects.")));
485 JSObject
* object
= asObject(obj
);
487 if (isJSFinalObject(object
))
488 return JSValue::encode(jsBoolean(object
->isFrozen(exec
->vm())));
490 // 2. For each named own property name P of O,
491 PropertyNameArray
properties(exec
);
492 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
493 PropertyNameArray::const_iterator end
= properties
.end();
494 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
495 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
496 PropertyDescriptor desc
;
497 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
499 // b. If IsDataDescriptor(desc) is true then
500 // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
501 if ((desc
.isDataDescriptor() && desc
.writable()) || desc
.configurable())
502 return JSValue::encode(jsBoolean(false));
505 // 3. If the [[Extensible]] internal property of O is false, then return true.
506 // 4. Otherwise, return false.
507 return JSValue::encode(jsBoolean(!object
->isExtensible()));
510 EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
* exec
)
512 JSValue obj
= exec
->argument(0);
514 return throwVMError(exec
, createTypeError(exec
, ASCIILiteral("Object.isExtensible can only be called on Objects.")));
515 return JSValue::encode(jsBoolean(asObject(obj
)->isExtensible()));