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."));
134 return JSValue::encode(asObject(exec
->argument(0))->prototype());
137 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
* exec
)
139 if (!exec
->argument(0).isObject())
140 return throwVMError(exec
, createTypeError(exec
, "Requested property descriptor of a value that is not an object."));
141 UString propertyName
= exec
->argument(1).toString(exec
);
142 if (exec
->hadException())
143 return JSValue::encode(jsNull());
144 JSObject
* object
= asObject(exec
->argument(0));
145 PropertyDescriptor descriptor
;
146 if (!object
->getOwnPropertyDescriptor(exec
, Identifier(exec
, propertyName
), descriptor
))
147 return JSValue::encode(jsUndefined());
148 if (exec
->hadException())
149 return JSValue::encode(jsUndefined());
151 JSObject
* description
= constructEmptyObject(exec
);
152 if (!descriptor
.isAccessorDescriptor()) {
153 description
->putDirect(exec
->globalData(), exec
->propertyNames().value
, descriptor
.value() ? descriptor
.value() : jsUndefined(), 0);
154 description
->putDirect(exec
->globalData(), exec
->propertyNames().writable
, jsBoolean(descriptor
.writable()), 0);
156 description
->putDirect(exec
->globalData(), exec
->propertyNames().get
, descriptor
.getter() ? descriptor
.getter() : jsUndefined(), 0);
157 description
->putDirect(exec
->globalData(), exec
->propertyNames().set
, descriptor
.setter() ? descriptor
.setter() : jsUndefined(), 0);
160 description
->putDirect(exec
->globalData(), exec
->propertyNames().enumerable
, jsBoolean(descriptor
.enumerable()), 0);
161 description
->putDirect(exec
->globalData(), exec
->propertyNames().configurable
, jsBoolean(descriptor
.configurable()), 0);
163 return JSValue::encode(description
);
166 // FIXME: Use the enumeration cache.
167 EncodedJSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
* exec
)
169 if (!exec
->argument(0).isObject())
170 return throwVMError(exec
, createTypeError(exec
, "Requested property names of a value that is not an object."));
171 PropertyNameArray
properties(exec
);
172 asObject(exec
->argument(0))->getOwnPropertyNames(exec
, properties
, IncludeDontEnumProperties
);
173 JSArray
* names
= constructEmptyArray(exec
);
174 size_t numProperties
= properties
.size();
175 for (size_t i
= 0; i
< numProperties
; i
++)
176 names
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
177 return JSValue::encode(names
);
180 // FIXME: Use the enumeration cache.
181 EncodedJSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
* exec
)
183 if (!exec
->argument(0).isObject())
184 return throwVMError(exec
, createTypeError(exec
, "Requested keys of a value that is not an object."));
185 PropertyNameArray
properties(exec
);
186 asObject(exec
->argument(0))->getOwnPropertyNames(exec
, properties
);
187 JSArray
* keys
= constructEmptyArray(exec
);
188 size_t numProperties
= properties
.size();
189 for (size_t i
= 0; i
< numProperties
; i
++)
190 keys
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
191 return JSValue::encode(keys
);
194 // ES5 8.10.5 ToPropertyDescriptor
195 static bool toPropertyDescriptor(ExecState
* exec
, JSValue in
, PropertyDescriptor
& desc
)
197 if (!in
.isObject()) {
198 throwError(exec
, createTypeError(exec
, "Property description must be an object."));
201 JSObject
* description
= asObject(in
);
203 PropertySlot
enumerableSlot(description
);
204 if (description
->getPropertySlot(exec
, exec
->propertyNames().enumerable
, enumerableSlot
)) {
205 desc
.setEnumerable(enumerableSlot
.getValue(exec
, exec
->propertyNames().enumerable
).toBoolean(exec
));
206 if (exec
->hadException())
210 PropertySlot
configurableSlot(description
);
211 if (description
->getPropertySlot(exec
, exec
->propertyNames().configurable
, configurableSlot
)) {
212 desc
.setConfigurable(configurableSlot
.getValue(exec
, exec
->propertyNames().configurable
).toBoolean(exec
));
213 if (exec
->hadException())
218 PropertySlot
valueSlot(description
);
219 if (description
->getPropertySlot(exec
, exec
->propertyNames().value
, valueSlot
)) {
220 desc
.setValue(valueSlot
.getValue(exec
, exec
->propertyNames().value
));
221 if (exec
->hadException())
225 PropertySlot
writableSlot(description
);
226 if (description
->getPropertySlot(exec
, exec
->propertyNames().writable
, writableSlot
)) {
227 desc
.setWritable(writableSlot
.getValue(exec
, exec
->propertyNames().writable
).toBoolean(exec
));
228 if (exec
->hadException())
232 PropertySlot
getSlot(description
);
233 if (description
->getPropertySlot(exec
, exec
->propertyNames().get
, getSlot
)) {
234 JSValue get
= getSlot
.getValue(exec
, exec
->propertyNames().get
);
235 if (exec
->hadException())
237 if (!get
.isUndefined()) {
239 if (getCallData(get
, callData
) == CallTypeNone
) {
240 throwError(exec
, createTypeError(exec
, "Getter must be a function."));
248 PropertySlot
setSlot(description
);
249 if (description
->getPropertySlot(exec
, exec
->propertyNames().set
, setSlot
)) {
250 JSValue set
= setSlot
.getValue(exec
, exec
->propertyNames().set
);
251 if (exec
->hadException())
253 if (!set
.isUndefined()) {
255 if (getCallData(set
, callData
) == CallTypeNone
) {
256 throwError(exec
, createTypeError(exec
, "Setter must be a function."));
265 if (!desc
.isAccessorDescriptor())
269 throwError(exec
, createTypeError(exec
, "Invalid property. 'value' present on property with getter or setter."));
273 if (desc
.writablePresent()) {
274 throwError(exec
, createTypeError(exec
, "Invalid property. 'writable' present on property with getter or setter."));
280 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
* exec
)
282 if (!exec
->argument(0).isObject())
283 return throwVMError(exec
, createTypeError(exec
, "Properties can only be defined on Objects."));
284 JSObject
* O
= asObject(exec
->argument(0));
285 UString propertyName
= exec
->argument(1).toString(exec
);
286 if (exec
->hadException())
287 return JSValue::encode(jsNull());
288 PropertyDescriptor descriptor
;
289 if (!toPropertyDescriptor(exec
, exec
->argument(2), descriptor
))
290 return JSValue::encode(jsNull());
291 ASSERT((descriptor
.attributes() & (Getter
| Setter
)) || (!descriptor
.isAccessorDescriptor()));
292 ASSERT(!exec
->hadException());
293 O
->defineOwnProperty(exec
, Identifier(exec
, propertyName
), descriptor
, true);
294 return JSValue::encode(O
);
297 static JSValue
defineProperties(ExecState
* exec
, JSObject
* object
, JSObject
* properties
)
299 PropertyNameArray
propertyNames(exec
);
300 asObject(properties
)->getOwnPropertyNames(exec
, propertyNames
);
301 size_t numProperties
= propertyNames
.size();
302 Vector
<PropertyDescriptor
> descriptors
;
303 MarkedArgumentBuffer markBuffer
;
304 for (size_t i
= 0; i
< numProperties
; i
++) {
306 JSValue prop
= properties
->get(exec
, propertyNames
[i
]);
307 if (exec
->hadException())
309 PropertyDescriptor descriptor
;
310 if (!toPropertyDescriptor(exec
, prop
, descriptor
))
312 descriptors
.append(descriptor
);
313 // Ensure we mark all the values that we're accumulating
314 if (descriptor
.isDataDescriptor() && descriptor
.value())
315 markBuffer
.append(descriptor
.value());
316 if (descriptor
.isAccessorDescriptor()) {
317 if (descriptor
.getter())
318 markBuffer
.append(descriptor
.getter());
319 if (descriptor
.setter())
320 markBuffer
.append(descriptor
.setter());
323 for (size_t i
= 0; i
< numProperties
; i
++) {
324 object
->defineOwnProperty(exec
, propertyNames
[i
], descriptors
[i
], true);
325 if (exec
->hadException())
331 EncodedJSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
* exec
)
333 if (!exec
->argument(0).isObject())
334 return throwVMError(exec
, createTypeError(exec
, "Properties can only be defined on Objects."));
335 if (!exec
->argument(1).isObject())
336 return throwVMError(exec
, createTypeError(exec
, "Property descriptor list must be an Object."));
337 return JSValue::encode(defineProperties(exec
, asObject(exec
->argument(0)), asObject(exec
->argument(1))));
340 EncodedJSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
* exec
)
342 if (!exec
->argument(0).isObject() && !exec
->argument(0).isNull())
343 return throwVMError(exec
, createTypeError(exec
, "Object prototype may only be an Object or null."));
344 JSValue proto
= exec
->argument(0);
345 JSObject
* newObject
= proto
.isObject() ? constructEmptyObject(exec
, asObject(proto
)->inheritorID(exec
->globalData())) : constructEmptyObject(exec
, exec
->lexicalGlobalObject()->nullPrototypeObjectStructure());
346 if (exec
->argument(1).isUndefined())
347 return JSValue::encode(newObject
);
348 if (!exec
->argument(1).isObject())
349 return throwVMError(exec
, createTypeError(exec
, "Property descriptor list must be an Object."));
350 return JSValue::encode(defineProperties(exec
, newObject
, asObject(exec
->argument(1))));
353 EncodedJSValue JSC_HOST_CALL
objectConstructorSeal(ExecState
* exec
)
355 JSValue obj
= exec
->argument(0);
357 return throwVMError(exec
, createTypeError(exec
, "Object.seal can only be called on Objects."));
358 asObject(obj
)->seal(exec
->globalData());
359 return JSValue::encode(obj
);
362 EncodedJSValue JSC_HOST_CALL
objectConstructorFreeze(ExecState
* exec
)
364 JSValue obj
= exec
->argument(0);
366 return throwVMError(exec
, createTypeError(exec
, "Object.freeze can only be called on Objects."));
367 asObject(obj
)->freeze(exec
->globalData());
368 return JSValue::encode(obj
);
371 EncodedJSValue JSC_HOST_CALL
objectConstructorPreventExtensions(ExecState
* exec
)
373 JSValue obj
= exec
->argument(0);
375 return throwVMError(exec
, createTypeError(exec
, "Object.preventExtensions can only be called on Objects."));
376 asObject(obj
)->preventExtensions(exec
->globalData());
377 return JSValue::encode(obj
);
380 EncodedJSValue JSC_HOST_CALL
objectConstructorIsSealed(ExecState
* exec
)
382 JSValue obj
= exec
->argument(0);
384 return throwVMError(exec
, createTypeError(exec
, "Object.isSealed can only be called on Objects."));
385 return JSValue::encode(jsBoolean(asObject(obj
)->isSealed(exec
->globalData())));
388 EncodedJSValue JSC_HOST_CALL
objectConstructorIsFrozen(ExecState
* exec
)
390 JSValue obj
= exec
->argument(0);
392 return throwVMError(exec
, createTypeError(exec
, "Object.isFrozen can only be called on Objects."));
393 return JSValue::encode(jsBoolean(asObject(obj
)->isFrozen(exec
->globalData())));
396 EncodedJSValue JSC_HOST_CALL
objectConstructorIsExtensible(ExecState
* exec
)
398 JSValue obj
= exec
->argument(0);
400 return throwVMError(exec
, createTypeError(exec
, "Object.isExtensible can only be called on Objects."));
401 return JSValue::encode(jsBoolean(asObject(obj
)->isExtensible()));