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 "JSFunction.h"
27 #include "JSGlobalObject.h"
28 #include "ObjectPrototype.h"
29 #include "PropertyDescriptor.h"
30 #include "PropertyNameArray.h"
31 #include "PrototypeFunction.h"
35 ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor
);
37 static JSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
38 static JSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
39 static JSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
40 static JSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
41 static JSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
42 static JSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
43 static JSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
*, JSObject
*, JSValue
, const ArgList
&);
45 ObjectConstructor::ObjectConstructor(ExecState
* exec
, NonNullPassRefPtr
<Structure
> structure
, ObjectPrototype
* objectPrototype
, Structure
* prototypeFunctionStructure
)
46 : InternalFunction(&exec
->globalData(), structure
, Identifier(exec
, "Object"))
49 putDirectWithoutTransition(exec
->propertyNames().prototype
, objectPrototype
, DontEnum
| DontDelete
| ReadOnly
);
51 // no. of arguments for constructor
52 putDirectWithoutTransition(exec
->propertyNames().length
, jsNumber(exec
, 1), ReadOnly
| DontEnum
| DontDelete
);
54 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 1, exec
->propertyNames().getPrototypeOf
, objectConstructorGetPrototypeOf
), DontEnum
);
55 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 2, exec
->propertyNames().getOwnPropertyDescriptor
, objectConstructorGetOwnPropertyDescriptor
), DontEnum
);
56 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 1, exec
->propertyNames().getOwnPropertyNames
, objectConstructorGetOwnPropertyNames
), DontEnum
);
57 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 1, exec
->propertyNames().keys
, objectConstructorKeys
), DontEnum
);
58 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 3, exec
->propertyNames().defineProperty
, objectConstructorDefineProperty
), DontEnum
);
59 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 2, exec
->propertyNames().defineProperties
, objectConstructorDefineProperties
), DontEnum
);
60 putDirectFunctionWithoutTransition(exec
, new (exec
) NativeFunctionWrapper(exec
, prototypeFunctionStructure
, 2, exec
->propertyNames().create
, objectConstructorCreate
), DontEnum
);
64 static ALWAYS_INLINE JSObject
* constructObject(ExecState
* exec
, const ArgList
& args
)
66 JSValue arg
= args
.at(0);
67 if (arg
.isUndefinedOrNull())
68 return new (exec
) JSObject(exec
->lexicalGlobalObject()->emptyObjectStructure());
69 return arg
.toObject(exec
);
72 static JSObject
* constructWithObjectConstructor(ExecState
* exec
, JSObject
*, const ArgList
& args
)
74 return constructObject(exec
, args
);
77 ConstructType
ObjectConstructor::getConstructData(ConstructData
& constructData
)
79 constructData
.native
.function
= constructWithObjectConstructor
;
80 return ConstructTypeHost
;
83 static JSValue JSC_HOST_CALL
callObjectConstructor(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
85 return constructObject(exec
, args
);
88 CallType
ObjectConstructor::getCallData(CallData
& callData
)
90 callData
.native
.function
= callObjectConstructor
;
94 JSValue JSC_HOST_CALL
objectConstructorGetPrototypeOf(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
96 if (!args
.at(0).isObject())
97 return throwError(exec
, TypeError
, "Requested prototype of a value that is not an object.");
98 return asObject(args
.at(0))->prototype();
101 JSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyDescriptor(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
103 if (!args
.at(0).isObject())
104 return throwError(exec
, TypeError
, "Requested property descriptor of a value that is not an object.");
105 UString propertyName
= args
.at(1).toString(exec
);
106 if (exec
->hadException())
108 JSObject
* object
= asObject(args
.at(0));
109 PropertyDescriptor descriptor
;
110 if (!object
->getOwnPropertyDescriptor(exec
, Identifier(exec
, propertyName
), descriptor
))
111 return jsUndefined();
112 if (exec
->hadException())
113 return jsUndefined();
115 JSObject
* description
= constructEmptyObject(exec
);
116 if (!descriptor
.isAccessorDescriptor()) {
117 description
->putDirect(exec
->propertyNames().value
, descriptor
.value() ? descriptor
.value() : jsUndefined(), 0);
118 description
->putDirect(exec
->propertyNames().writable
, jsBoolean(descriptor
.writable()), 0);
120 description
->putDirect(exec
->propertyNames().get
, descriptor
.getter() ? descriptor
.getter() : jsUndefined(), 0);
121 description
->putDirect(exec
->propertyNames().set
, descriptor
.setter() ? descriptor
.setter() : jsUndefined(), 0);
124 description
->putDirect(exec
->propertyNames().enumerable
, jsBoolean(descriptor
.enumerable()), 0);
125 description
->putDirect(exec
->propertyNames().configurable
, jsBoolean(descriptor
.configurable()), 0);
130 // FIXME: Use the enumeration cache.
131 JSValue JSC_HOST_CALL
objectConstructorGetOwnPropertyNames(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
133 if (!args
.at(0).isObject())
134 return throwError(exec
, TypeError
, "Requested property names of a value that is not an object.");
135 PropertyNameArray
properties(exec
);
136 asObject(args
.at(0))->getOwnPropertyNames(exec
, properties
, IncludeDontEnumProperties
);
137 JSArray
* names
= constructEmptyArray(exec
);
138 size_t numProperties
= properties
.size();
139 for (size_t i
= 0; i
< numProperties
; i
++)
140 names
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
144 // FIXME: Use the enumeration cache.
145 JSValue JSC_HOST_CALL
objectConstructorKeys(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
147 if (!args
.at(0).isObject())
148 return throwError(exec
, TypeError
, "Requested keys of a value that is not an object.");
149 PropertyNameArray
properties(exec
);
150 asObject(args
.at(0))->getOwnPropertyNames(exec
, properties
);
151 JSArray
* keys
= constructEmptyArray(exec
);
152 size_t numProperties
= properties
.size();
153 for (size_t i
= 0; i
< numProperties
; i
++)
154 keys
->push(exec
, jsOwnedString(exec
, properties
[i
].ustring()));
158 // ES5 8.10.5 ToPropertyDescriptor
159 static bool toPropertyDescriptor(ExecState
* exec
, JSValue in
, PropertyDescriptor
& desc
)
161 if (!in
.isObject()) {
162 throwError(exec
, TypeError
, "Property description must be an object.");
165 JSObject
* description
= asObject(in
);
167 PropertySlot
enumerableSlot(description
);
168 if (description
->getPropertySlot(exec
, exec
->propertyNames().enumerable
, enumerableSlot
)) {
169 desc
.setEnumerable(enumerableSlot
.getValue(exec
, exec
->propertyNames().enumerable
).toBoolean(exec
));
170 if (exec
->hadException())
174 PropertySlot
configurableSlot(description
);
175 if (description
->getPropertySlot(exec
, exec
->propertyNames().configurable
, configurableSlot
)) {
176 desc
.setConfigurable(configurableSlot
.getValue(exec
, exec
->propertyNames().configurable
).toBoolean(exec
));
177 if (exec
->hadException())
182 PropertySlot
valueSlot(description
);
183 if (description
->getPropertySlot(exec
, exec
->propertyNames().value
, valueSlot
)) {
184 desc
.setValue(valueSlot
.getValue(exec
, exec
->propertyNames().value
));
185 if (exec
->hadException())
189 PropertySlot
writableSlot(description
);
190 if (description
->getPropertySlot(exec
, exec
->propertyNames().writable
, writableSlot
)) {
191 desc
.setWritable(writableSlot
.getValue(exec
, exec
->propertyNames().writable
).toBoolean(exec
));
192 if (exec
->hadException())
196 PropertySlot
getSlot(description
);
197 if (description
->getPropertySlot(exec
, exec
->propertyNames().get
, getSlot
)) {
198 JSValue get
= getSlot
.getValue(exec
, exec
->propertyNames().get
);
199 if (exec
->hadException())
201 if (!get
.isUndefined()) {
203 if (get
.getCallData(callData
) == CallTypeNone
) {
204 throwError(exec
, TypeError
, "Getter must be a function.");
212 PropertySlot
setSlot(description
);
213 if (description
->getPropertySlot(exec
, exec
->propertyNames().set
, setSlot
)) {
214 JSValue set
= setSlot
.getValue(exec
, exec
->propertyNames().set
);
215 if (exec
->hadException())
217 if (!set
.isUndefined()) {
219 if (set
.getCallData(callData
) == CallTypeNone
) {
220 throwError(exec
, TypeError
, "Setter must be a function.");
229 if (!desc
.isAccessorDescriptor())
233 throwError(exec
, TypeError
, "Invalid property. 'value' present on property with getter or setter.");
237 if (desc
.writablePresent()) {
238 throwError(exec
, TypeError
, "Invalid property. 'writable' present on property with getter or setter.");
244 JSValue JSC_HOST_CALL
objectConstructorDefineProperty(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
246 if (!args
.at(0).isObject())
247 return throwError(exec
, TypeError
, "Properties can only be defined on Objects.");
248 JSObject
* O
= asObject(args
.at(0));
249 UString propertyName
= args
.at(1).toString(exec
);
250 if (exec
->hadException())
252 PropertyDescriptor descriptor
;
253 if (!toPropertyDescriptor(exec
, args
.at(2), descriptor
))
255 ASSERT((descriptor
.attributes() & (Getter
| Setter
)) || (!descriptor
.isAccessorDescriptor()));
256 ASSERT(!exec
->hadException());
257 O
->defineOwnProperty(exec
, Identifier(exec
, propertyName
), descriptor
, true);
261 static JSValue
defineProperties(ExecState
* exec
, JSObject
* object
, JSObject
* properties
)
263 PropertyNameArray
propertyNames(exec
);
264 asObject(properties
)->getOwnPropertyNames(exec
, propertyNames
);
265 size_t numProperties
= propertyNames
.size();
266 Vector
<PropertyDescriptor
> descriptors
;
267 MarkedArgumentBuffer markBuffer
;
268 for (size_t i
= 0; i
< numProperties
; i
++) {
270 JSValue prop
= properties
->get(exec
, propertyNames
[i
]);
271 if (exec
->hadException())
273 PropertyDescriptor descriptor
;
274 if (!toPropertyDescriptor(exec
, prop
, descriptor
))
276 descriptors
.append(descriptor
);
277 // Ensure we mark all the values that we're accumulating
278 if (descriptor
.isDataDescriptor() && descriptor
.value())
279 markBuffer
.append(descriptor
.value());
280 if (descriptor
.isAccessorDescriptor()) {
281 if (descriptor
.getter())
282 markBuffer
.append(descriptor
.getter());
283 if (descriptor
.setter())
284 markBuffer
.append(descriptor
.setter());
287 for (size_t i
= 0; i
< numProperties
; i
++) {
288 object
->defineOwnProperty(exec
, propertyNames
[i
], descriptors
[i
], true);
289 if (exec
->hadException())
295 JSValue JSC_HOST_CALL
objectConstructorDefineProperties(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
297 if (!args
.at(0).isObject())
298 return throwError(exec
, TypeError
, "Properties can only be defined on Objects.");
299 if (!args
.at(1).isObject())
300 return throwError(exec
, TypeError
, "Property descriptor list must be an Object.");
301 return defineProperties(exec
, asObject(args
.at(0)), asObject(args
.at(1)));
304 JSValue JSC_HOST_CALL
objectConstructorCreate(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
306 if (!args
.at(0).isObject() && !args
.at(0).isNull())
307 return throwError(exec
, TypeError
, "Object prototype may only be an Object or null.");
308 JSObject
* newObject
= constructEmptyObject(exec
);
309 newObject
->setPrototype(args
.at(0));
310 if (args
.at(1).isUndefined())
312 if (!args
.at(1).isObject())
313 return throwError(exec
, TypeError
, "Property descriptor list must be an Object.");
314 return defineProperties(exec
, newObject
, asObject(args
.at(1)));