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, CREATE_METHOD_TABLE(ObjectConstructor) };
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(JSGlobalObject* globalObject, Structure* structure)
79 : InternalFunction(globalObject, structure)
83 void ObjectConstructor::finishCreation(ExecState* exec, ObjectPrototype* objectPrototype)
85 Base::finishCreation(exec->globalData(), Identifier(exec, "Object"));
87 putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
88 // no. of arguments for constructor
89 putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
92 bool ObjectConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
94 return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(cell), propertyName, slot);
97 bool ObjectConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
99 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(object), propertyName, descriptor);
103 static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
105 JSValue arg = args.at(0);
106 if (arg.isUndefinedOrNull())
107 return constructEmptyObject(exec, globalObject);
108 return arg.toObject(exec, globalObject);
111 static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
114 return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
117 ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
119 constructData.native.function = constructWithObjectConstructor;
120 return ConstructTypeHost;
123 static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
126 return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
129 CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
131 callData.native.function = callObjectConstructor;
135 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
137 if (!exec->argument(0).isObject())
138 return throwVMError(exec, createTypeError(exec, "Requested prototype of a value that is not an object."));
140 // This uses JSValue::get() instead of directly accessing the prototype from the object
141 // (using JSObject::prototype()) in order to allow objects to override the behavior, such
142 // as returning jsUndefined() for cross-origin access.
143 return JSValue::encode(exec->argument(0).get(exec, exec->propertyNames().underscoreProto));
146 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
148 if (!exec->argument(0).isObject())
149 return throwVMError(exec, createTypeError(exec, "Requested property descriptor of a value that is not an object."));
150 UString propertyName = exec->argument(1).toString(exec);
151 if (exec->hadException())
152 return JSValue::encode(jsNull());
153 JSObject* object = asObject(exec->argument(0));
154 PropertyDescriptor descriptor;
155 if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, Identifier(exec, propertyName), descriptor))
156 return JSValue::encode(jsUndefined());
157 if (exec->hadException())
158 return JSValue::encode(jsUndefined());
160 JSObject* description = constructEmptyObject(exec);
161 if (!descriptor.isAccessorDescriptor()) {
162 description->putDirect(exec->globalData(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0);
163 description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
165 description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0);
166 description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0);
169 description->putDirect(exec->globalData(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
170 description->putDirect(exec->globalData(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
172 return JSValue::encode(description);
175 // FIXME: Use the enumeration cache.
176 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
178 if (!exec->argument(0).isObject())
179 return throwVMError(exec, createTypeError(exec, "Requested property names of a value that is not an object."));
180 PropertyNameArray properties(exec);
181 asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
182 JSArray* names = constructEmptyArray(exec);
183 size_t numProperties = properties.size();
184 for (size_t i = 0; i < numProperties; i++)
185 names->push(exec, jsOwnedString(exec, properties[i].ustring()));
186 return JSValue::encode(names);
189 // FIXME: Use the enumeration cache.
190 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
192 if (!exec->argument(0).isObject())
193 return throwVMError(exec, createTypeError(exec, "Requested keys of a value that is not an object."));
194 PropertyNameArray properties(exec);
195 asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
196 JSArray* keys = constructEmptyArray(exec);
197 size_t numProperties = properties.size();
198 for (size_t i = 0; i < numProperties; i++)
199 keys->push(exec, jsOwnedString(exec, properties[i].ustring()));
200 return JSValue::encode(keys);
203 // ES5 8.10.5 ToPropertyDescriptor
204 static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
206 if (!in.isObject()) {
207 throwError(exec, createTypeError(exec, "Property description must be an object."));
210 JSObject* description = asObject(in);
212 PropertySlot enumerableSlot(description);
213 if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) {
214 desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec));
215 if (exec->hadException())
219 PropertySlot configurableSlot(description);
220 if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) {
221 desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec));
222 if (exec->hadException())
227 PropertySlot valueSlot(description);
228 if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) {
229 desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value));
230 if (exec->hadException())
234 PropertySlot writableSlot(description);
235 if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) {
236 desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec));
237 if (exec->hadException())
241 PropertySlot getSlot(description);
242 if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) {
243 JSValue get = getSlot.getValue(exec, exec->propertyNames().get);
244 if (exec->hadException())
246 if (!get.isUndefined()) {
248 if (getCallData(get, callData) == CallTypeNone) {
249 throwError(exec, createTypeError(exec, "Getter must be a function."));
257 PropertySlot setSlot(description);
258 if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) {
259 JSValue set = setSlot.getValue(exec, exec->propertyNames().set);
260 if (exec->hadException())
262 if (!set.isUndefined()) {
264 if (getCallData(set, callData) == CallTypeNone) {
265 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);
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() & (Getter | Setter)) || (!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 if (!exec->argument(1).isObject())
345 return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object."));
346 return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), asObject(exec->argument(1))));
349 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
351 if (!exec->argument(0).isObject() && !exec->argument(0).isNull())
352 return throwVMError(exec, createTypeError(exec, "Object prototype may only be an Object or null."));
353 JSValue proto = exec->argument(0);
354 JSObject* newObject = proto.isObject() ? constructEmptyObject(exec, asObject(proto)->inheritorID(exec->globalData())) : 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, "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 JSValue obj = exec->argument(0);
366 return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects."));
367 asObject(obj)->seal(exec->globalData());
368 return JSValue::encode(obj);
371 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
373 JSValue obj = exec->argument(0);
375 return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects."));
376 asObject(obj)->freeze(exec->globalData());
377 return JSValue::encode(obj);
380 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
382 JSValue obj = exec->argument(0);
384 return throwVMError(exec, createTypeError(exec, "Object.preventExtensions can only be called on Objects."));
385 asObject(obj)->preventExtensions(exec->globalData());
386 return JSValue::encode(obj);
389 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
391 JSValue obj = exec->argument(0);
393 return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects."));
394 return JSValue::encode(jsBoolean(asObject(obj)->isSealed(exec->globalData())));
397 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
399 JSValue obj = exec->argument(0);
401 return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects."));
402 return JSValue::encode(jsBoolean(asObject(obj)->isFrozen(exec->globalData())));
405 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
407 JSValue obj = exec->argument(0);
409 return throwVMError(exec, createTypeError(exec, "Object.isExtensible can only be called on Objects."));
410 return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));