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 const ClassInfo
ObjectConstructor::s_info
= { "Function", &InternalFunction::s_info
, 0, ExecState::objectConstructorTable
};
60 /* Source for ObjectConstructor.lut.h
61 @begin objectConstructorTable
62 getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
63 getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
64 getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
65 keys objectConstructorKeys DontEnum|Function 1
66 defineProperty objectConstructorDefineProperty DontEnum|Function 3
67 defineProperties objectConstructorDefineProperties DontEnum|Function 2
68 create objectConstructorCreate DontEnum|Function 2
69 seal objectConstructorSeal DontEnum|Function 1
70 freeze objectConstructorFreeze DontEnum|Function 1
71 preventExtensions objectConstructorPreventExtensions DontEnum|Function 1
72 isSealed objectConstructorIsSealed DontEnum|Function 1
73 isFrozen objectConstructorIsFrozen DontEnum|Function 1
74 isExtensible objectConstructorIsExtensible DontEnum|Function 1
78 ObjectConstructor::ObjectConstructor(ExecState
* exec
, JSGlobalObject
* globalObject
, Structure
* structure
, ObjectPrototype
* objectPrototype
)
79 : InternalFunction(&exec
->globalData(), globalObject
, structure
, Identifier(exec
, "Object"))
82 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().prototype
, objectPrototype
, DontEnum
| DontDelete
| ReadOnly
);
83 // no. of arguments for constructor
84 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().length
, jsNumber(1), ReadOnly
| DontEnum
| DontDelete
);
87 bool ObjectConstructor::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
&slot
)
89 return getStaticFunctionSlot
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), this, propertyName
, slot
);
92 bool ObjectConstructor::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
94 return getStaticFunctionDescriptor
<JSObject
>(exec
, ExecState::objectConstructorTable(exec
), this, propertyName
, descriptor
);
98 static ALWAYS_INLINE JSObject
* constructObject(ExecState
* exec
, JSGlobalObject
* globalObject
, const ArgList
& args
)
100 JSValue arg
= args
.at(0);
101 if (arg
.isUndefinedOrNull())
102 return constructEmptyObject(exec
, globalObject
);
103 return arg
.toObject(exec
, globalObject
);
106 static EncodedJSValue JSC_HOST_CALL
constructWithObjectConstructor(ExecState
* exec
)
109 return JSValue::encode(constructObject(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
112 ConstructType
ObjectConstructor::getConstructData(ConstructData
& constructData
)
114 constructData
.native
.function
= constructWithObjectConstructor
;
115 return ConstructTypeHost
;
118 static EncodedJSValue JSC_HOST_CALL
callObjectConstructor(ExecState
* exec
)
121 return JSValue::encode(constructObject(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
124 CallType
ObjectConstructor::getCallData(CallData
& callData
)
126 callData
.native
.function
= callObjectConstructor
;
130 EncodedJSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
* exec
)
132 if (!exec
->argument(0).isObject())
133 return throwVMError(exec
, createTypeError(exec
, "Requested prototype of a value that is not an object."));
135 // This uses JSValue::get() instead of directly accessing the prototype from the object
136 // (using JSObject::prototype()) in order to allow objects to override the behavior, such
137 // as returning jsUndefined() for cross-origin access.
138 return JSValue::encode(exec
->argument(0).get(exec
, exec
->propertyNames().underscoreProto
));
141 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
* exec
)
143 if (!exec
->argument(0).isObject())
144 return throwVMError(exec
, createTypeError(exec
, "Requested property descriptor of a value that is not an object."));
145 UString propertyName
= exec
->argument(1).toString(exec
);
146 if (exec
->hadException())
147 return JSValue::encode(jsNull());
148 JSObject
* object
= asObject(exec
->argument(0));
149 PropertyDescriptor descriptor
;
150 if (!object
->getOwnPropertyDescriptor(exec
, Identifier(exec
, propertyName
), descriptor
))
151 return JSValue::encode(jsUndefined());
152 if (exec
->hadException())
153 return JSValue::encode(jsUndefined());
155 JSObject
* description
= constructEmptyObject(exec
);
156 if (!descriptor
.isAccessorDescriptor()) {
157 description
->putDirect(exec
->globalData(), exec
->propertyNames().value
, descriptor
.value() ? descriptor
.value() : jsUndefined(), 0);
158 description
->putDirect(exec
->globalData(), exec
->propertyNames().writable
, jsBoolean(descriptor
.writable()), 0);
160 description
->putDirect(exec
->globalData(), exec
->propertyNames().get
, descriptor
.getter() ? descriptor
.getter() : jsUndefined(), 0);
161 description
->putDirect(exec
->globalData(), exec
->propertyNames().set
, descriptor
.setter() ? descriptor
.setter() : jsUndefined(), 0);
164 description
->putDirect(exec
->globalData(), exec
->propertyNames().enumerable
, jsBoolean(descriptor
.enumerable()), 0);
165 description
->putDirect(exec
->globalData(), exec
->propertyNames().configurable
, jsBoolean(descriptor
.configurable()), 0);
167 return JSValue::encode(description
);
170 // FIXME: Use the enumeration cache.
171 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
* exec
)
173 if (!exec
->argument(0).isObject())
174 return throwVMError(exec
, createTypeError(exec
, "Requested property names of a value that is not an object."));
175 PropertyNameArray
properties(exec
);
176 asObject(exec
->argument(0))->getOwnPropertyNames(exec
, properties
, IncludeDontEnumProperties
);
177 JSArray
* names
= constructEmptyArray(exec
);
178 size_t numProperties
= properties
.size();
179 for (size_t i
= 0; i
< numProperties
; i
++)
180 names
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
181 return JSValue::encode(names
);
184 // FIXME: Use the enumeration cache.
185 EncodedJSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
* exec
)
187 if (!exec
->argument(0).isObject())
188 return throwVMError(exec
, createTypeError(exec
, "Requested keys of a value that is not an object."));
189 PropertyNameArray
properties(exec
);
190 asObject(exec
->argument(0))->getOwnPropertyNames(exec
, properties
);
191 JSArray
* keys
= constructEmptyArray(exec
);
192 size_t numProperties
= properties
.size();
193 for (size_t i
= 0; i
< numProperties
; i
++)
194 keys
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
195 return JSValue::encode(keys
);
198 // ES5 8.10.5 ToPropertyDescriptor
199 static bool toPropertyDescriptor(ExecState
* exec
, JSValue in
, PropertyDescriptor
& desc
)
201 if (!in
.isObject()) {
202 throwError(exec
, createTypeError(exec
, "Property description must be an object."));
205 JSObject
* description
= asObject(in
);
207 PropertySlot
enumerableSlot(description
);
208 if (description
->getPropertySlot(exec
, exec
->propertyNames().enumerable
, enumerableSlot
)) {
209 desc
.setEnumerable(enumerableSlot
.getValue(exec
, exec
->propertyNames().enumerable
).toBoolean(exec
));
210 if (exec
->hadException())
214 PropertySlot
configurableSlot(description
);
215 if (description
->getPropertySlot(exec
, exec
->propertyNames().configurable
, configurableSlot
)) {
216 desc
.setConfigurable(configurableSlot
.getValue(exec
, exec
->propertyNames().configurable
).toBoolean(exec
));
217 if (exec
->hadException())
222 PropertySlot
valueSlot(description
);
223 if (description
->getPropertySlot(exec
, exec
->propertyNames().value
, valueSlot
)) {
224 desc
.setValue(valueSlot
.getValue(exec
, exec
->propertyNames().value
));
225 if (exec
->hadException())
229 PropertySlot
writableSlot(description
);
230 if (description
->getPropertySlot(exec
, exec
->propertyNames().writable
, writableSlot
)) {
231 desc
.setWritable(writableSlot
.getValue(exec
, exec
->propertyNames().writable
).toBoolean(exec
));
232 if (exec
->hadException())
236 PropertySlot
getSlot(description
);
237 if (description
->getPropertySlot(exec
, exec
->propertyNames().get
, getSlot
)) {
238 JSValue get
= getSlot
.getValue(exec
, exec
->propertyNames().get
);
239 if (exec
->hadException())
241 if (!get
.isUndefined()) {
243 if (getCallData(get
, callData
) == CallTypeNone
) {
244 throwError(exec
, createTypeError(exec
, "Getter must be a function."));
252 PropertySlot
setSlot(description
);
253 if (description
->getPropertySlot(exec
, exec
->propertyNames().set
, setSlot
)) {
254 JSValue set
= setSlot
.getValue(exec
, exec
->propertyNames().set
);
255 if (exec
->hadException())
257 if (!set
.isUndefined()) {
259 if (getCallData(set
, callData
) == CallTypeNone
) {
260 throwError(exec
, createTypeError(exec
, "Setter must be a function."));
269 if (!desc
.isAccessorDescriptor())
273 throwError(exec
, createTypeError(exec
, "Invalid property. 'value' present on property with getter or setter."));
277 if (desc
.writablePresent()) {
278 throwError(exec
, createTypeError(exec
, "Invalid property. 'writable' present on property with getter or setter."));
284 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
* exec
)
286 if (!exec
->argument(0).isObject())
287 return throwVMError(exec
, createTypeError(exec
, "Properties can only be defined on Objects."));
288 JSObject
* O
= asObject(exec
->argument(0));
289 UString propertyName
= exec
->argument(1).toString(exec
);
290 if (exec
->hadException())
291 return JSValue::encode(jsNull());
292 PropertyDescriptor descriptor
;
293 if (!toPropertyDescriptor(exec
, exec
->argument(2), descriptor
))
294 return JSValue::encode(jsNull());
295 ASSERT((descriptor
.attributes() & (Getter
| Setter
)) || (!descriptor
.isAccessorDescriptor()));
296 ASSERT(!exec
->hadException());
297 O
->defineOwnProperty(exec
, Identifier(exec
, propertyName
), descriptor
, true);
298 return JSValue::encode(O
);
301 static JSValue
defineProperties(ExecState
* exec
, JSObject
* object
, JSObject
* properties
)
303 PropertyNameArray
propertyNames(exec
);
304 asObject(properties
)->getOwnPropertyNames(exec
, propertyNames
);
305 size_t numProperties
= propertyNames
.size();
306 Vector
<PropertyDescriptor
> descriptors
;
307 MarkedArgumentBuffer markBuffer
;
308 for (size_t i
= 0; i
< numProperties
; i
++) {
310 JSValue prop
= properties
->get(exec
, propertyNames
[i
]);
311 if (exec
->hadException())
313 PropertyDescriptor descriptor
;
314 if (!toPropertyDescriptor(exec
, prop
, descriptor
))
316 descriptors
.append(descriptor
);
317 // Ensure we mark all the values that we're accumulating
318 if (descriptor
.isDataDescriptor() && descriptor
.value())
319 markBuffer
.append(descriptor
.value());
320 if (descriptor
.isAccessorDescriptor()) {
321 if (descriptor
.getter())
322 markBuffer
.append(descriptor
.getter());
323 if (descriptor
.setter())
324 markBuffer
.append(descriptor
.setter());
327 for (size_t i
= 0; i
< numProperties
; i
++) {
328 object
->defineOwnProperty(exec
, propertyNames
[i
], descriptors
[i
], true);
329 if (exec
->hadException())
335 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
* exec
)
337 if (!exec
->argument(0).isObject())
338 return throwVMError(exec
, createTypeError(exec
, "Properties can only be defined on Objects."));
339 if (!exec
->argument(1).isObject())
340 return throwVMError(exec
, createTypeError(exec
, "Property descriptor list must be an Object."));
341 return JSValue::encode(defineProperties(exec
, asObject(exec
->argument(0)), asObject(exec
->argument(1))));
344 EncodedJSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
* exec
)
346 if (!exec
->argument(0).isObject() && !exec
->argument(0).isNull())
347 return throwVMError(exec
, createTypeError(exec
, "Object prototype may only be an Object or null."));
348 JSValue proto
= exec
->argument(0);
349 JSObject
* newObject
= proto
.isObject() ? constructEmptyObject(exec
, asObject(proto
)->inheritorID(exec
->globalData())) : constructEmptyObject(exec
, exec
->lexicalGlobalObject()->nullPrototypeObjectStructure());
350 if (exec
->argument(1).isUndefined())
351 return JSValue::encode(newObject
);
352 if (!exec
->argument(1).isObject())
353 return throwVMError(exec
, createTypeError(exec
, "Property descriptor list must be an Object."));
354 return JSValue::encode(defineProperties(exec
, newObject
, asObject(exec
->argument(1))));
357 EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
* exec
)
359 JSValue obj
= exec
->argument(0);
361 return throwVMError(exec
, createTypeError(exec
, "Object.seal can only be called on Objects."));
362 asObject(obj
)->seal(exec
->globalData());
363 return JSValue::encode(obj
);
366 EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
* exec
)
368 JSValue obj
= exec
->argument(0);
370 return throwVMError(exec
, createTypeError(exec
, "Object.freeze can only be called on Objects."));
371 asObject(obj
)->freeze(exec
->globalData());
372 return JSValue::encode(obj
);
375 EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
* exec
)
377 JSValue obj
= exec
->argument(0);
379 return throwVMError(exec
, createTypeError(exec
, "Object.preventExtensions can only be called on Objects."));
380 asObject(obj
)->preventExtensions(exec
->globalData());
381 return JSValue::encode(obj
);
384 EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
* exec
)
386 JSValue obj
= exec
->argument(0);
388 return throwVMError(exec
, createTypeError(exec
, "Object.isSealed can only be called on Objects."));
389 return JSValue::encode(jsBoolean(asObject(obj
)->isSealed(exec
->globalData())));
392 EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
* exec
)
394 JSValue obj
= exec
->argument(0);
396 return throwVMError(exec
, createTypeError(exec
, "Object.isFrozen can only be called on Objects."));
397 return JSValue::encode(jsBoolean(asObject(obj
)->isFrozen(exec
->globalData())));
400 EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
* exec
)
402 JSValue obj
= exec
->argument(0);
404 return throwVMError(exec
, createTypeError(exec
, "Object.isExtensible can only be called on Objects."));
405 return JSValue::encode(jsBoolean(asObject(obj
)->isExtensible()));