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"
25 #include "ExceptionHelpers.h"
26 #include "JSFunction.h"
28 #include "JSGlobalObject.h"
30 #include "ObjectPrototype.h"
31 #include "PropertyDescriptor.h"
32 #include "PropertyNameArray.h"
36 ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor
);
38 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
*);
39 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
*);
40 static EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
*);
41 static EncodedJSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
*);
42 static EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
*);
43 static EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
*);
44 static EncodedJSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
*);
45 static EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
*);
46 static EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
*);
47 static EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
*);
48 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
*);
49 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
*);
50 static EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
*);
54 #include "ObjectConstructor.lut.h"
58 ASSERT_HAS_TRIVIAL_DESTRUCTOR(ObjectConstructor
);
60 const ClassInfo
ObjectConstructor::s_info
= { "Function", &InternalFunction::s_info
, 0, ExecState::objectConstructorTable
, CREATE_METHOD_TABLE(ObjectConstructor
) };
62 /* Source for ObjectConstructor.lut.h
63 @begin objectConstructorTable
64 getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
65 getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
66 getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
67 keys objectConstructorKeys DontEnum|Function 1
68 defineProperty objectConstructorDefineProperty DontEnum|Function 3
69 defineProperties objectConstructorDefineProperties DontEnum|Function 2
70 create objectConstructorCreate DontEnum|Function 2
71 seal objectConstructorSeal DontEnum|Function 1
72 freeze objectConstructorFreeze DontEnum|Function 1
73 preventExtensions objectConstructorPreventExtensions DontEnum|Function 1
74 isSealed objectConstructorIsSealed DontEnum|Function 1
75 isFrozen objectConstructorIsFrozen DontEnum|Function 1
76 isExtensible objectConstructorIsExtensible DontEnum|Function 1
80 ObjectConstructor::ObjectConstructor(JSGlobalObject
* globalObject
, Structure
* structure
)
81 : InternalFunction(globalObject
, structure
)
85 void ObjectConstructor::finishCreation(ExecState
* exec
, ObjectPrototype
* objectPrototype
)
87 Base::finishCreation(exec
->globalData(), Identifier(exec
, "Object"));
89 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().prototype
, objectPrototype
, DontEnum
| DontDelete
| ReadOnly
);
90 // no. of arguments for constructor
91 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().length
, jsNumber(1), ReadOnly
| DontEnum
| DontDelete
);
94 bool ObjectConstructor::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
&slot
)
96 return getStaticFunctionSlot
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), jsCast
<ObjectConstructor
*>(cell
), propertyName
, slot
);
99 bool ObjectConstructor::getOwnPropertyDescriptor(JSObject
* object
, ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
101 return getStaticFunctionDescriptor
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), jsCast
<ObjectConstructor
*>(object
), propertyName
, descriptor
);
105 static ALWAYS_INLINE JSObject
* constructObject(ExecState
* exec
, JSGlobalObject
* globalObject
, const ArgList
& args
)
107 JSValue arg
= args
.at(0);
108 if (arg
.isUndefinedOrNull())
109 return constructEmptyObject(exec
, globalObject
);
110 return arg
.toObject(exec
, globalObject
);
113 static EncodedJSValue JSC_HOST_CALL
constructWithObjectConstructor(ExecState
* exec
)
116 return JSValue::encode(constructObject(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
119 ConstructType
ObjectConstructor::getConstructData(JSCell
*, ConstructData
& constructData
)
121 constructData
.native
.function
= constructWithObjectConstructor
;
122 return ConstructTypeHost
;
125 static EncodedJSValue JSC_HOST_CALL
callObjectConstructor(ExecState
* exec
)
128 return JSValue::encode(constructObject(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
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
, "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
, "Requested property descriptor of a value that is not an object."));
151 UString 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
->globalData(), exec
->propertyNames().value
, descriptor
.value() ? descriptor
.value() : jsUndefined(), 0);
164 description
->putDirect(exec
->globalData(), exec
->propertyNames().writable
, jsBoolean(descriptor
.writable()), 0);
166 ASSERT(descriptor
.getter());
167 ASSERT(descriptor
.setter());
168 description
->putDirect(exec
->globalData(), exec
->propertyNames().get
, descriptor
.getter(), 0);
169 description
->putDirect(exec
->globalData(), exec
->propertyNames().set
, descriptor
.setter(), 0);
172 description
->putDirect(exec
->globalData(), exec
->propertyNames().enumerable
, jsBoolean(descriptor
.enumerable()), 0);
173 description
->putDirect(exec
->globalData(), 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
, "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
);
186 size_t numProperties
= properties
.size();
187 for (size_t i
= 0; i
< numProperties
; i
++)
188 names
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
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
, "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
);
200 size_t numProperties
= properties
.size();
201 for (size_t i
= 0; i
< numProperties
; i
++)
202 keys
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
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
, "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
, "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
, "Setter must be a function."));
274 if (!desc
.isAccessorDescriptor())
278 throwError(exec
, createTypeError(exec
, "Invalid property. 'value' present on property with getter or setter."));
282 if (desc
.writablePresent()) {
283 throwError(exec
, createTypeError(exec
, "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
, "Properties can only be defined on Objects."));
293 JSObject
* O
= asObject(exec
->argument(0));
294 UString 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
, "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
, "Object prototype may only be an Object or null."));
351 JSValue proto
= exec
->argument(0);
352 JSObject
* newObject
= proto
.isObject() ? constructEmptyObject(exec
, asObject(proto
)->inheritorID(exec
->globalData())) : constructEmptyObject(exec
, exec
->lexicalGlobalObject()->nullPrototypeObjectStructure());
353 if (exec
->argument(1).isUndefined())
354 return JSValue::encode(newObject
);
355 if (!exec
->argument(1).isObject())
356 return throwVMError(exec
, createTypeError(exec
, "Property descriptor list must be an Object."));
357 return JSValue::encode(defineProperties(exec
, newObject
, asObject(exec
->argument(1))));
360 EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
* exec
)
362 // 1. If Type(O) is not Object throw a TypeError exception.
363 JSValue obj
= exec
->argument(0);
365 return throwVMError(exec
, createTypeError(exec
, "Object.seal can only be called on Objects."));
366 JSObject
* object
= asObject(obj
);
368 if (isJSFinalObject(object
)) {
369 object
->seal(exec
->globalData());
370 return JSValue::encode(obj
);
373 // 2. For each named own property name P of O,
374 PropertyNameArray
properties(exec
);
375 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
376 PropertyNameArray::const_iterator end
= properties
.end();
377 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
378 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
379 PropertyDescriptor desc
;
380 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
382 // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
383 desc
.setConfigurable(false);
384 // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
385 object
->methodTable()->defineOwnProperty(object
, exec
, *iter
, desc
, true);
386 if (exec
->hadException())
387 return JSValue::encode(obj
);
390 // 3. Set the [[Extensible]] internal property of O to false.
391 object
->preventExtensions(exec
->globalData());
394 return JSValue::encode(obj
);
397 EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
* exec
)
399 // 1. If Type(O) is not Object throw a TypeError exception.
400 JSValue obj
= exec
->argument(0);
402 return throwVMError(exec
, createTypeError(exec
, "Object.freeze can only be called on Objects."));
403 JSObject
* object
= asObject(obj
);
405 if (isJSFinalObject(object
)) {
406 object
->freeze(exec
->globalData());
407 return JSValue::encode(obj
);
410 // 2. For each named own property name P of O,
411 PropertyNameArray
properties(exec
);
412 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
413 PropertyNameArray::const_iterator end
= properties
.end();
414 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
415 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
416 PropertyDescriptor desc
;
417 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
419 // b. If IsDataDescriptor(desc) is true, then
420 // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
421 if (desc
.isDataDescriptor())
422 desc
.setWritable(false);
423 // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
424 desc
.setConfigurable(false);
425 // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
426 object
->methodTable()->defineOwnProperty(object
, exec
, *iter
, desc
, true);
427 if (exec
->hadException())
428 return JSValue::encode(obj
);
431 // 3. Set the [[Extensible]] internal property of O to false.
432 object
->preventExtensions(exec
->globalData());
435 return JSValue::encode(obj
);
438 EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
* exec
)
440 JSValue obj
= exec
->argument(0);
442 return throwVMError(exec
, createTypeError(exec
, "Object.preventExtensions can only be called on Objects."));
443 asObject(obj
)->preventExtensions(exec
->globalData());
444 return JSValue::encode(obj
);
447 EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
* exec
)
449 // 1. If Type(O) is not Object throw a TypeError exception.
450 JSValue obj
= exec
->argument(0);
452 return throwVMError(exec
, createTypeError(exec
, "Object.isSealed can only be called on Objects."));
453 JSObject
* object
= asObject(obj
);
455 if (isJSFinalObject(object
))
456 return JSValue::encode(jsBoolean(object
->isSealed(exec
->globalData())));
458 // 2. For each named own property name P of O,
459 PropertyNameArray
properties(exec
);
460 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
461 PropertyNameArray::const_iterator end
= properties
.end();
462 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
463 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
464 PropertyDescriptor desc
;
465 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
467 // b. If desc.[[Configurable]] is true, then return false.
468 if (desc
.configurable())
469 return JSValue::encode(jsBoolean(false));
472 // 3. If the [[Extensible]] internal property of O is false, then return true.
473 // 4. Otherwise, return false.
474 return JSValue::encode(jsBoolean(!object
->isExtensible()));
477 EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
* exec
)
479 // 1. If Type(O) is not Object throw a TypeError exception.
480 JSValue obj
= exec
->argument(0);
482 return throwVMError(exec
, createTypeError(exec
, "Object.isFrozen can only be called on Objects."));
483 JSObject
* object
= asObject(obj
);
485 if (isJSFinalObject(object
))
486 return JSValue::encode(jsBoolean(object
->isFrozen(exec
->globalData())));
488 // 2. For each named own property name P of O,
489 PropertyNameArray
properties(exec
);
490 object
->methodTable()->getOwnPropertyNames(object
, exec
, properties
, IncludeDontEnumProperties
);
491 PropertyNameArray::const_iterator end
= properties
.end();
492 for (PropertyNameArray::const_iterator iter
= properties
.begin(); iter
!= end
; ++iter
) {
493 // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
494 PropertyDescriptor desc
;
495 if (!object
->methodTable()->getOwnPropertyDescriptor(object
, exec
, *iter
, desc
))
497 // b. If IsDataDescriptor(desc) is true then
498 // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
499 if ((desc
.isDataDescriptor() && desc
.writable()) || desc
.configurable())
500 return JSValue::encode(jsBoolean(false));
503 // 3. If the [[Extensible]] internal property of O is false, then return true.
504 // 4. Otherwise, return false.
505 return JSValue::encode(jsBoolean(!object
->isExtensible()));
508 EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
* exec
)
510 JSValue obj
= exec
->argument(0);
512 return throwVMError(exec
, createTypeError(exec
, "Object.isExtensible can only be called on Objects."));
513 return JSValue::encode(jsBoolean(asObject(obj
)->isExtensible()));