1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 *
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.
9 *
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.
14 *
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
18 *
19 */
20
21#include "config.h"
22#include "ObjectConstructor.h"
23
24#include "Error.h"
25#include "JSFunction.h"
26#include "JSArray.h"
27#include "JSGlobalObject.h"
28#include "ObjectPrototype.h"
29#include "PropertyDescriptor.h"
30#include "PropertyNameArray.h"
31#include "PrototypeFunction.h"
32
33namespace JSC {
34
35ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
36
37static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&);
38static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&);
39static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*, JSObject*, JSValue, const ArgList&);
40static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&);
41static JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*, JSObject*, JSValue, const ArgList&);
42static JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*, JSObject*, JSValue, const ArgList&);
43static JSValue JSC_HOST_CALL objectConstructorCreate(ExecState*, JSObject*, JSValue, const ArgList&);
44
45ObjectConstructor::ObjectConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure)
46: InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object"))
47{
48 // ECMA 15.2.3.1
49 putDirectWithoutTransition(propertyName: exec->propertyNames().prototype, value: objectPrototype, attributes: DontEnum | DontDelete | ReadOnly);
50
51 // no. of arguments for constructor
52 putDirectWithoutTransition(propertyName: exec->propertyNames().length, value: jsNumber(exec, i: 1), attributes: ReadOnly | DontEnum | DontDelete);
53
54 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), attr: DontEnum);
55 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), attr: DontEnum);
56 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getOwnPropertyNames, objectConstructorGetOwnPropertyNames), attr: DontEnum);
57 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), attr: DontEnum);
58 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), attr: DontEnum);
59 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), attr: DontEnum);
60 putDirectFunctionWithoutTransition(exec, function: new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().create, objectConstructorCreate), attr: DontEnum);
61}
62
63// ECMA 15.2.2
64static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, const ArgList& args)
65{
66 JSValue arg = args.at(idx: 0);
67 if (arg.isUndefinedOrNull())
68 return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
69 return arg.toObject(exec);
70}
71
72static JSObject* constructWithObjectConstructor(ExecState* exec, JSObject*, const ArgList& args)
73{
74 return constructObject(exec, args);
75}
76
77ConstructType ObjectConstructor::getConstructData(ConstructData& constructData)
78{
79 constructData.native.function = constructWithObjectConstructor;
80 return ConstructTypeHost;
81}
82
83static JSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
84{
85 return constructObject(exec, args);
86}
87
88CallType ObjectConstructor::getCallData(CallData& callData)
89{
90 callData.native.function = callObjectConstructor;
91 return CallTypeHost;
92}
93
94JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec, JSObject*, JSValue, const ArgList& args)
95{
96 if (!args.at(idx: 0).isObject())
97 return throwError(exec, TypeError, message: "Requested prototype of a value that is not an object.");
98 return asObject(value: args.at(idx: 0))->prototype();
99}
100
101JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
102{
103 if (!args.at(idx: 0).isObject())
104 return throwError(exec, TypeError, message: "Requested property descriptor of a value that is not an object.");
105 UString propertyName = args.at(idx: 1).toString(exec);
106 if (exec->hadException())
107 return jsNull();
108 JSObject* object = asObject(value: args.at(idx: 0));
109 PropertyDescriptor descriptor;
110 if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor))
111 return jsUndefined();
112 if (exec->hadException())
113 return jsUndefined();
114
115 JSObject* description = constructEmptyObject(exec);
116 if (!descriptor.isAccessorDescriptor()) {
117 description->putDirect(propertyName: exec->propertyNames().value, value: descriptor.value() ? descriptor.value() : jsUndefined(), attributes: 0);
118 description->putDirect(propertyName: exec->propertyNames().writable, value: jsBoolean(b: descriptor.writable()), attributes: 0);
119 } else {
120 description->putDirect(propertyName: exec->propertyNames().get, value: descriptor.getter() ? descriptor.getter() : jsUndefined(), attributes: 0);
121 description->putDirect(propertyName: exec->propertyNames().set, value: descriptor.setter() ? descriptor.setter() : jsUndefined(), attributes: 0);
122 }
123
124 description->putDirect(propertyName: exec->propertyNames().enumerable, value: jsBoolean(b: descriptor.enumerable()), attributes: 0);
125 description->putDirect(propertyName: exec->propertyNames().configurable, value: jsBoolean(b: descriptor.configurable()), attributes: 0);
126
127 return description;
128}
129
130// FIXME: Use the enumeration cache.
131JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec, JSObject*, JSValue, const ArgList& args)
132{
133 if (!args.at(idx: 0).isObject())
134 return throwError(exec, TypeError, message: "Requested property names of a value that is not an object.");
135 PropertyNameArray properties(exec);
136 asObject(value: args.at(idx: 0))->getOwnPropertyNames(exec, properties, mode: 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, s: properties[i].ustring()));
141 return names;
142}
143
144// FIXME: Use the enumeration cache.
145JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
146{
147 if (!args.at(idx: 0).isObject())
148 return throwError(exec, TypeError, message: "Requested keys of a value that is not an object.");
149 PropertyNameArray properties(exec);
150 asObject(value: args.at(idx: 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, s: properties[i].ustring()));
155 return keys;
156}
157
158// ES5 8.10.5 ToPropertyDescriptor
159static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
160{
161 if (!in.isObject()) {
162 throwError(exec, TypeError, message: "Property description must be an object.");
163 return false;
164 }
165 JSObject* description = asObject(value: in);
166
167 PropertySlot enumerableSlot(description);
168 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().enumerable, slot&: enumerableSlot)) {
169 desc.setEnumerable(enumerableSlot.getValue(exec, propertyName: exec->propertyNames().enumerable).toBoolean(exec));
170 if (exec->hadException())
171 return false;
172 }
173
174 PropertySlot configurableSlot(description);
175 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().configurable, slot&: configurableSlot)) {
176 desc.setConfigurable(configurableSlot.getValue(exec, propertyName: exec->propertyNames().configurable).toBoolean(exec));
177 if (exec->hadException())
178 return false;
179 }
180
181 JSValue value;
182 PropertySlot valueSlot(description);
183 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().value, slot&: valueSlot)) {
184 desc.setValue(valueSlot.getValue(exec, propertyName: exec->propertyNames().value));
185 if (exec->hadException())
186 return false;
187 }
188
189 PropertySlot writableSlot(description);
190 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().writable, slot&: writableSlot)) {
191 desc.setWritable(writableSlot.getValue(exec, propertyName: exec->propertyNames().writable).toBoolean(exec));
192 if (exec->hadException())
193 return false;
194 }
195
196 PropertySlot getSlot(description);
197 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().get, slot&: getSlot)) {
198 JSValue get = getSlot.getValue(exec, propertyName: exec->propertyNames().get);
199 if (exec->hadException())
200 return false;
201 if (!get.isUndefined()) {
202 CallData callData;
203 if (get.getCallData(callData) == CallTypeNone) {
204 throwError(exec, TypeError, message: "Getter must be a function.");
205 return false;
206 }
207 } else
208 get = JSValue();
209 desc.setGetter(get);
210 }
211
212 PropertySlot setSlot(description);
213 if (description->getPropertySlot(exec, propertyName: exec->propertyNames().set, slot&: setSlot)) {
214 JSValue set = setSlot.getValue(exec, propertyName: exec->propertyNames().set);
215 if (exec->hadException())
216 return false;
217 if (!set.isUndefined()) {
218 CallData callData;
219 if (set.getCallData(callData) == CallTypeNone) {
220 throwError(exec, TypeError, message: "Setter must be a function.");
221 return false;
222 }
223 } else
224 set = JSValue();
225
226 desc.setSetter(set);
227 }
228
229 if (!desc.isAccessorDescriptor())
230 return true;
231
232 if (desc.value()) {
233 throwError(exec, TypeError, message: "Invalid property. 'value' present on property with getter or setter.");
234 return false;
235 }
236
237 if (desc.writablePresent()) {
238 throwError(exec, TypeError, message: "Invalid property. 'writable' present on property with getter or setter.");
239 return false;
240 }
241 return true;
242}
243
244JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec, JSObject*, JSValue, const ArgList& args)
245{
246 if (!args.at(idx: 0).isObject())
247 return throwError(exec, TypeError, message: "Properties can only be defined on Objects.");
248 JSObject* O = asObject(value: args.at(idx: 0));
249 UString propertyName = args.at(idx: 1).toString(exec);
250 if (exec->hadException())
251 return jsNull();
252 PropertyDescriptor descriptor;
253 if (!toPropertyDescriptor(exec, in: args.at(idx: 2), desc&: descriptor))
254 return jsNull();
255 ASSERT((descriptor.attributes() & (Getter | Setter)) || (!descriptor.isAccessorDescriptor()));
256 ASSERT(!exec->hadException());
257 O->defineOwnProperty(exec, propertyName: Identifier(exec, propertyName), descriptor, shouldThrow: true);
258 return O;
259}
260
261static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
262{
263 PropertyNameArray propertyNames(exec);
264 asObject(cell: 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++) {
269 PropertySlot slot;
270 JSValue prop = properties->get(exec, propertyName: propertyNames[i]);
271 if (exec->hadException())
272 return jsNull();
273 PropertyDescriptor descriptor;
274 if (!toPropertyDescriptor(exec, in: prop, desc&: descriptor))
275 return jsNull();
276 descriptors.append(val: descriptor);
277 // Ensure we mark all the values that we're accumulating
278 if (descriptor.isDataDescriptor() && descriptor.value())
279 markBuffer.append(v: descriptor.value());
280 if (descriptor.isAccessorDescriptor()) {
281 if (descriptor.getter())
282 markBuffer.append(v: descriptor.getter());
283 if (descriptor.setter())
284 markBuffer.append(v: descriptor.setter());
285 }
286 }
287 for (size_t i = 0; i < numProperties; i++) {
288 object->defineOwnProperty(exec, propertyName: propertyNames[i], descriptors[i], shouldThrow: true);
289 if (exec->hadException())
290 return jsNull();
291 }
292 return object;
293}
294
295JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec, JSObject*, JSValue, const ArgList& args)
296{
297 if (!args.at(idx: 0).isObject())
298 return throwError(exec, TypeError, message: "Properties can only be defined on Objects.");
299 if (!args.at(idx: 1).isObject())
300 return throwError(exec, TypeError, message: "Property descriptor list must be an Object.");
301 return defineProperties(exec, object: asObject(value: args.at(idx: 0)), properties: asObject(value: args.at(idx: 1)));
302}
303
304JSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec, JSObject*, JSValue, const ArgList& args)
305{
306 if (!args.at(idx: 0).isObject() && !args.at(idx: 0).isNull())
307 return throwError(exec, TypeError, message: "Object prototype may only be an Object or null.");
308 JSObject* newObject = constructEmptyObject(exec);
309 newObject->setPrototype(args.at(idx: 0));
310 if (args.at(idx: 1).isUndefined())
311 return newObject;
312 if (!args.at(idx: 1).isObject())
313 return throwError(exec, TypeError, message: "Property descriptor list must be an Object.");
314 return defineProperties(exec, object: newObject, properties: asObject(value: args.at(idx: 1)));
315}
316
317} // namespace JSC
318

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp