Added RETURN_IF_EXCEPTION() macro and use it for exception checks.
[WebKit-https.git] / Source / JavaScriptCore / runtime / ObjectConstructor.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2008, 2016 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 "BuiltinNames.h"
25 #include "ButterflyInlines.h"
26 #include "Error.h"
27 #include "ExceptionHelpers.h"
28 #include "JSArray.h"
29 #include "JSCInlines.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "JSGlobalObjectFunctions.h"
33 #include "Lookup.h"
34 #include "ObjectPrototype.h"
35 #include "PropertyDescriptor.h"
36 #include "PropertyNameArray.h"
37 #include "StackVisitor.h"
38 #include "Symbol.h"
39
40 namespace JSC {
41
42 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
43 EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState*);
44 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
45 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
46 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
47 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
48 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
49 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
50 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
51 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
52 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
53 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
54 EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState*);
55
56 }
57
58 #include "ObjectConstructor.lut.h"
59
60 namespace JSC {
61
62 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor);
63
64 const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, &objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) };
65
66 /* Source for ObjectConstructor.lut.h
67 @begin objectConstructorTable
68   getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1
69   setPrototypeOf            objectConstructorSetPrototypeOf             DontEnum|Function 2
70   getOwnPropertyDescriptor  objectConstructorGetOwnPropertyDescriptor   DontEnum|Function 2
71   getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors  DontEnum|Function 1
72   getOwnPropertyNames       objectConstructorGetOwnPropertyNames        DontEnum|Function 1
73   getOwnPropertySymbols     objectConstructorGetOwnPropertySymbols      DontEnum|Function 1
74   keys                      objectConstructorKeys                       DontEnum|Function 1
75   defineProperty            objectConstructorDefineProperty             DontEnum|Function 3
76   defineProperties          objectConstructorDefineProperties           DontEnum|Function 2
77   create                    objectConstructorCreate                     DontEnum|Function 2
78   seal                      objectConstructorSeal                       DontEnum|Function 1
79   freeze                    objectConstructorFreeze                     DontEnum|Function 1
80   preventExtensions         objectConstructorPreventExtensions          DontEnum|Function 1
81   isSealed                  objectConstructorIsSealed                   DontEnum|Function 1
82   isFrozen                  objectConstructorIsFrozen                   DontEnum|Function 1
83   isExtensible              objectConstructorIsExtensible               DontEnum|Function 1
84   is                        objectConstructorIs                         DontEnum|Function 2
85   assign                    JSBuiltin                                   DontEnum|Function 2
86   values                    JSBuiltin                                   DontEnum|Function 1
87   entries                   JSBuiltin                                   DontEnum|Function 1
88 @end
89 */
90
91 ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
92     : InternalFunction(vm, structure)
93 {
94 }
95
96 void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype)
97 {
98     Base::finishCreation(vm, objectPrototype->classInfo()->className);
99     // ECMA 15.2.3.1
100     putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
101     // no. of arguments for constructor
102     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
103
104     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().createPrivateName(), objectConstructorCreate, DontEnum, 2);
105     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().definePropertyPrivateName(), objectConstructorDefineProperty, DontEnum, 3);
106     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrototypeOfPrivateName(), objectConstructorGetPrototypeOf, DontEnum, 1);
107     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyNamesPrivateName(), objectConstructorGetOwnPropertyNames, DontEnum, 1);
108 }
109
110 JSFunction* ObjectConstructor::addDefineProperty(ExecState* exec, JSGlobalObject* globalObject)
111 {
112     VM& vm = exec->vm();
113     JSFunction* definePropertyFunction = JSFunction::create(vm, globalObject, 3, vm.propertyNames->defineProperty.string(), objectConstructorDefineProperty);
114     putDirectWithoutTransition(vm, vm.propertyNames->defineProperty, definePropertyFunction, DontEnum);
115     return definePropertyFunction;
116 }
117
118 // ES 19.1.1.1 Object([value])
119 static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSValue newTarget)
120 {
121     ObjectConstructor* objectConstructor = jsCast<ObjectConstructor*>(exec->callee());
122     JSGlobalObject* globalObject = objectConstructor->globalObject();
123     VM& vm = globalObject->vm();
124     auto scope = DECLARE_THROW_SCOPE(vm);
125
126     // We need to check newTarget condition in this caller side instead of InternalFunction::createSubclassStructure side.
127     // Since if we found this condition is met, we should not fall into the type conversion in the step 3.
128
129     // 1. If NewTarget is neither undefined nor the active function, then
130     if (newTarget && newTarget != objectConstructor) {
131         // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
132         Structure* objectStructure = InternalFunction::createSubclassStructure(exec, newTarget, globalObject->objectStructureForObjectConstructor());
133         RETURN_IF_EXCEPTION(scope, nullptr);
134         return constructEmptyObject(exec, objectStructure);
135     }
136
137     // 2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
138     ArgList args(exec);
139     JSValue arg = args.at(0);
140     if (arg.isUndefinedOrNull())
141         return constructEmptyObject(exec, globalObject->objectStructureForObjectConstructor());
142
143     // 3. Return ToObject(value).
144     return arg.toObject(exec, globalObject);
145 }
146
147 static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
148 {
149     return JSValue::encode(constructObject(exec, exec->newTarget()));
150 }
151
152 ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
153 {
154     constructData.native.function = constructWithObjectConstructor;
155     return ConstructType::Host;
156 }
157
158 static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
159 {
160     return JSValue::encode(constructObject(exec, JSValue()));
161 }
162
163 CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
164 {
165     callData.native.function = callObjectConstructor;
166     return CallType::Host;
167 }
168
169 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
170 {
171     VM& vm = exec->vm();
172     auto scope = DECLARE_THROW_SCOPE(vm);
173     JSObject* object = exec->argument(0).toObject(exec);
174     RETURN_IF_EXCEPTION(scope, encodedJSValue());
175     return JSValue::encode(object->getPrototype(exec->vm(), exec));
176 }
177
178 EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
179 {
180     VM& vm = exec->vm();
181     auto scope = DECLARE_THROW_SCOPE(vm);
182
183     JSValue objectValue = exec->argument(0);
184     if (objectValue.isUndefinedOrNull())
185         return throwVMTypeError(exec, scope);
186
187     JSValue protoValue = exec->argument(1);
188     if (!protoValue.isObject() && !protoValue.isNull())
189         return throwVMTypeError(exec, scope);
190
191     JSObject* object = objectValue.toObject(exec);
192     RETURN_IF_EXCEPTION(scope, encodedJSValue());
193
194     bool shouldThrowIfCantSet = true;
195     bool didSetPrototype = object->setPrototype(vm, exec, protoValue, shouldThrowIfCantSet);
196     ASSERT_UNUSED(didSetPrototype, scope.exception() || didSetPrototype);
197     return JSValue::encode(objectValue);
198 }
199
200 JSValue objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject* object, const Identifier& propertyName)
201 {
202     VM& vm = exec->vm();
203     auto scope = DECLARE_THROW_SCOPE(vm);
204     PropertyDescriptor descriptor;
205     if (!object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
206         return jsUndefined();
207     RETURN_IF_EXCEPTION(scope, JSValue());
208
209     JSObject* result = constructObjectFromPropertyDescriptor(exec, descriptor);
210     if (!result)
211         return jsUndefined();
212     return result;
213 }
214
215 JSValue objectConstructorGetOwnPropertyDescriptors(ExecState* exec, JSObject* object)
216 {
217     VM& vm = exec->vm();
218     auto scope = DECLARE_THROW_SCOPE(vm);
219     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
220     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
221     RETURN_IF_EXCEPTION(scope, JSValue());
222
223     JSObject* descriptors = constructEmptyObject(exec);
224     RETURN_IF_EXCEPTION(scope, JSValue());
225
226     for (auto& propertyName : properties) {
227         PropertyDescriptor descriptor;
228         bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, descriptor);
229         RETURN_IF_EXCEPTION(scope, JSValue());
230
231         if (!didGetDescriptor)
232             continue;
233
234         JSObject* fromDescriptor = constructObjectFromPropertyDescriptor(exec, descriptor);
235         if (!fromDescriptor)
236             return jsUndefined();
237
238         PutPropertySlot slot(descriptors);
239         descriptors->putOwnDataPropertyMayBeIndex(exec, propertyName, fromDescriptor, slot);
240         ASSERT(!scope.exception());
241     }
242
243     return descriptors;
244 }
245
246 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
247 {
248     VM& vm = exec->vm();
249     auto scope = DECLARE_THROW_SCOPE(vm);
250     JSObject* object = exec->argument(0).toObject(exec);
251     RETURN_IF_EXCEPTION(scope, encodedJSValue());
252     auto propertyName = exec->argument(1).toPropertyKey(exec);
253     RETURN_IF_EXCEPTION(scope, encodedJSValue());
254     return JSValue::encode(objectConstructorGetOwnPropertyDescriptor(exec, object, propertyName));
255 }
256
257 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptors(ExecState* exec)
258 {
259     VM& vm = exec->vm();
260     auto scope = DECLARE_THROW_SCOPE(vm);
261     JSObject* object = exec->argument(0).toObject(exec);
262     RETURN_IF_EXCEPTION(scope, encodedJSValue());
263     return JSValue::encode(objectConstructorGetOwnPropertyDescriptors(exec, object));
264 }
265
266 // FIXME: Use the enumeration cache.
267 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
268 {
269     VM& vm = exec->vm();
270     auto scope = DECLARE_THROW_SCOPE(vm);
271     JSObject* object = exec->argument(0).toObject(exec);
272     RETURN_IF_EXCEPTION(scope, encodedJSValue());
273     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Include));
274 }
275
276 // FIXME: Use the enumeration cache.
277 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState* exec)
278 {
279     VM& vm = exec->vm();
280     auto scope = DECLARE_THROW_SCOPE(vm);
281     JSObject* object = exec->argument(0).toObject(exec);
282     RETURN_IF_EXCEPTION(scope, encodedJSValue());
283     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include));
284 }
285
286 // FIXME: Use the enumeration cache.
287 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
288 {
289     VM& vm = exec->vm();
290     auto scope = DECLARE_THROW_SCOPE(vm);
291     JSObject* object = exec->argument(0).toObject(exec);
292     RETURN_IF_EXCEPTION(scope, encodedJSValue());
293     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude));
294 }
295
296 EncodedJSValue JSC_HOST_CALL ownEnumerablePropertyKeys(ExecState* exec)
297 {
298     VM& vm = exec->vm();
299     auto scope = DECLARE_THROW_SCOPE(vm);
300     JSObject* object = exec->argument(0).toObject(exec);
301     RETURN_IF_EXCEPTION(scope, encodedJSValue());
302     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Exclude));
303 }
304
305 // ES6 6.2.4.5 ToPropertyDescriptor
306 // https://tc39.github.io/ecma262/#sec-topropertydescriptor
307 bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
308 {
309     VM& vm = exec->vm();
310     auto scope = DECLARE_THROW_SCOPE(vm);
311
312     if (!in.isObject()) {
313         throwTypeError(exec, scope, ASCIILiteral("Property description must be an object."));
314         return false;
315     }
316     JSObject* description = asObject(in);
317
318     if (description->hasProperty(exec, exec->propertyNames().enumerable)) {
319         JSValue value = description->get(exec, exec->propertyNames().enumerable);
320         RETURN_IF_EXCEPTION(scope, false);
321         desc.setEnumerable(value.toBoolean(exec));
322     } else
323         RETURN_IF_EXCEPTION(scope, false);
324
325     if (description->hasProperty(exec, exec->propertyNames().configurable)) {
326         JSValue value = description->get(exec, exec->propertyNames().configurable);
327         RETURN_IF_EXCEPTION(scope, false);
328         desc.setConfigurable(value.toBoolean(exec));
329     } else
330         RETURN_IF_EXCEPTION(scope, false);
331
332     JSValue value;
333     if (description->hasProperty(exec, exec->propertyNames().value)) {
334         JSValue value = description->get(exec, exec->propertyNames().value);
335         RETURN_IF_EXCEPTION(scope, false);
336         desc.setValue(value);
337     } else
338         RETURN_IF_EXCEPTION(scope, false);
339
340     if (description->hasProperty(exec, exec->propertyNames().writable)) {
341         JSValue value = description->get(exec, exec->propertyNames().writable);
342         RETURN_IF_EXCEPTION(scope, false);
343         desc.setWritable(value.toBoolean(exec));
344     } else
345         RETURN_IF_EXCEPTION(scope, false);
346
347     if (description->hasProperty(exec, exec->propertyNames().get)) {
348         JSValue get = description->get(exec, exec->propertyNames().get);
349         RETURN_IF_EXCEPTION(scope, false);
350         if (!get.isUndefined()) {
351             CallData callData;
352             if (getCallData(get, callData) == CallType::None) {
353                 throwTypeError(exec, scope, ASCIILiteral("Getter must be a function."));
354                 return false;
355             }
356         }
357         desc.setGetter(get);
358     } else
359         RETURN_IF_EXCEPTION(scope, false);
360
361     if (description->hasProperty(exec, exec->propertyNames().set)) {
362         JSValue set = description->get(exec, exec->propertyNames().set);
363         RETURN_IF_EXCEPTION(scope, false);
364         if (!set.isUndefined()) {
365             CallData callData;
366             if (getCallData(set, callData) == CallType::None) {
367                 throwTypeError(exec, scope, ASCIILiteral("Setter must be a function."));
368                 return false;
369             }
370         }
371         desc.setSetter(set);
372     } else
373         RETURN_IF_EXCEPTION(scope, false);
374
375     if (!desc.isAccessorDescriptor())
376         return true;
377
378     if (desc.value()) {
379         throwTypeError(exec, scope, ASCIILiteral("Invalid property.  'value' present on property with getter or setter."));
380         return false;
381     }
382
383     if (desc.writablePresent()) {
384         throwTypeError(exec, scope, ASCIILiteral("Invalid property.  'writable' present on property with getter or setter."));
385         return false;
386     }
387     return true;
388 }
389
390 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
391 {
392     VM& vm = exec->vm();
393     auto scope = DECLARE_THROW_SCOPE(vm);
394
395     if (!exec->argument(0).isObject())
396         return throwVMTypeError(exec, scope, ASCIILiteral("Properties can only be defined on Objects."));
397     JSObject* obj = asObject(exec->argument(0));
398     auto propertyName = exec->argument(1).toPropertyKey(exec);
399     RETURN_IF_EXCEPTION(scope, encodedJSValue());
400     PropertyDescriptor descriptor;
401     auto success = toPropertyDescriptor(exec, exec->argument(2), descriptor);
402     ASSERT(!scope.exception() == success);
403     if (!success)
404         return JSValue::encode(jsNull());
405     ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
406     ASSERT(!scope.exception());
407     obj->methodTable(vm)->defineOwnProperty(obj, exec, propertyName, descriptor, true);
408     scope.release();
409     return JSValue::encode(obj);
410 }
411
412 static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
413 {
414     VM& vm = exec->vm();
415     auto scope = DECLARE_THROW_SCOPE(vm);
416
417     PropertyNameArray propertyNames(exec, PropertyNameMode::StringsAndSymbols);
418     asObject(properties)->methodTable(vm)->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude));
419     RETURN_IF_EXCEPTION(scope, JSValue());
420     size_t numProperties = propertyNames.size();
421     Vector<PropertyDescriptor> descriptors;
422     MarkedArgumentBuffer markBuffer;
423     for (size_t i = 0; i < numProperties; i++) {
424         JSValue prop = properties->get(exec, propertyNames[i]);
425         RETURN_IF_EXCEPTION(scope, JSValue());
426         PropertyDescriptor descriptor;
427         if (!toPropertyDescriptor(exec, prop, descriptor))
428             return jsNull();
429         descriptors.append(descriptor);
430         // Ensure we mark all the values that we're accumulating
431         if (descriptor.isDataDescriptor() && descriptor.value())
432             markBuffer.append(descriptor.value());
433         if (descriptor.isAccessorDescriptor()) {
434             if (descriptor.getter())
435                 markBuffer.append(descriptor.getter());
436             if (descriptor.setter())
437                 markBuffer.append(descriptor.setter());
438         }
439     }
440     for (size_t i = 0; i < numProperties; i++) {
441         Identifier propertyName = propertyNames[i];
442         if (exec->propertyNames().isPrivateName(propertyName))
443             continue;
444         object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, descriptors[i], true);
445         RETURN_IF_EXCEPTION(scope, JSValue());
446     }
447     return object;
448 }
449
450 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec)
451 {
452     VM& vm = exec->vm();
453     auto scope = DECLARE_THROW_SCOPE(vm);
454
455     if (!exec->argument(0).isObject())
456         return throwVMTypeError(exec, scope, ASCIILiteral("Properties can only be defined on Objects."));
457     JSObject* targetObj = asObject(exec->argument(0));
458     JSObject* props = exec->argument(1).toObject(exec);
459     if (!props)
460         return JSValue::encode(JSValue());
461     return JSValue::encode(defineProperties(exec, targetObj, props));
462 }
463
464 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
465 {
466     VM& vm = exec->vm();
467     auto scope = DECLARE_THROW_SCOPE(vm);
468
469     JSValue proto = exec->argument(0);
470     if (!proto.isObject() && !proto.isNull())
471         return throwVMTypeError(exec, scope, ASCIILiteral("Object prototype may only be an Object or null."));
472     JSObject* newObject = proto.isObject()
473         ? constructEmptyObject(exec, asObject(proto))
474         : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
475     if (exec->argument(1).isUndefined())
476         return JSValue::encode(newObject);
477     if (!exec->argument(1).isObject())
478         return throwVMTypeError(exec, scope, ASCIILiteral("Property descriptor list must be an Object."));
479     return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
480 }
481
482 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
483 {
484     VM& vm = exec->vm();
485     auto scope = DECLARE_THROW_SCOPE(vm);
486
487     // 1. If Type(O) is not Object, return O.
488     JSValue obj = exec->argument(0);
489     if (!obj.isObject())
490         return JSValue::encode(obj);
491     JSObject* object = asObject(obj);
492
493     if (isJSFinalObject(object)) {
494         object->seal(vm);
495         return JSValue::encode(obj);
496     }
497
498     // 2. For each named own property name P of O,
499     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
500     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
501     RETURN_IF_EXCEPTION(scope, encodedJSValue());
502     PropertyNameArray::const_iterator end = properties.end();
503     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
504         Identifier propertyName = *iter;
505         if (exec->propertyNames().isPrivateName(propertyName))
506             continue;
507         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
508         PropertyDescriptor desc;
509         if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
510             continue;
511         // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
512         desc.setConfigurable(false);
513         // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
514         object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
515         RETURN_IF_EXCEPTION(scope, encodedJSValue());
516     }
517
518     // 3. Set the [[Extensible]] internal property of O to false.
519     object->methodTable(vm)->preventExtensions(object, exec);
520     RETURN_IF_EXCEPTION(scope, encodedJSValue());
521
522     // 4. Return O.
523     return JSValue::encode(obj);
524 }
525
526 JSObject* objectConstructorFreeze(ExecState* exec, JSObject* object)
527 {
528     VM& vm = exec->vm();
529     auto scope = DECLARE_THROW_SCOPE(vm);
530
531     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
532         object->freeze(vm);
533         return object;
534     }
535
536     // 2. For each named own property name P of O,
537     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
538     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
539     RETURN_IF_EXCEPTION(scope, nullptr);
540     PropertyNameArray::const_iterator end = properties.end();
541     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
542         Identifier propertyName = *iter;
543         if (exec->propertyNames().isPrivateName(propertyName))
544             continue;
545         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
546         PropertyDescriptor desc;
547         if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
548             continue;
549         // b. If IsDataDescriptor(desc) is true, then
550         // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
551         if (desc.isDataDescriptor())
552             desc.setWritable(false);
553         // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
554         desc.setConfigurable(false);
555         // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
556         object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
557         RETURN_IF_EXCEPTION(scope, nullptr);
558     }
559
560     // 3. Set the [[Extensible]] internal property of O to false.
561     object->methodTable(vm)->preventExtensions(object, exec);
562     RETURN_IF_EXCEPTION(scope, nullptr);
563
564     // 4. Return O.
565     return object;
566 }
567
568 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
569 {
570     VM& vm = exec->vm();
571     auto scope = DECLARE_THROW_SCOPE(vm);
572     // 1. If Type(O) is not Object, return O.
573     JSValue obj = exec->argument(0);
574     if (!obj.isObject())
575         return JSValue::encode(obj);
576     JSObject* result = objectConstructorFreeze(exec, asObject(obj));
577     RETURN_IF_EXCEPTION(scope, encodedJSValue());
578     return JSValue::encode(result);
579 }
580
581 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
582 {
583     JSValue argument = exec->argument(0);
584     if (!argument.isObject())
585         return JSValue::encode(argument);
586     JSObject* object = asObject(argument);
587     object->methodTable(exec->vm())->preventExtensions(object, exec);
588     return JSValue::encode(object);
589 }
590
591 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
592 {
593     VM& vm = exec->vm();
594     auto scope = DECLARE_THROW_SCOPE(vm);
595
596     // 1. If Type(O) is not Object, return true.
597     JSValue obj = exec->argument(0);
598     if (!obj.isObject())
599         return JSValue::encode(jsBoolean(true));
600     JSObject* object = asObject(obj);
601
602     if (isJSFinalObject(object))
603         return JSValue::encode(jsBoolean(object->isSealed(vm)));
604
605     // 2. For each named own property name P of O,
606     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
607     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
608     RETURN_IF_EXCEPTION(scope, encodedJSValue());
609     PropertyNameArray::const_iterator end = properties.end();
610     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
611         Identifier propertyName = *iter;
612         if (exec->propertyNames().isPrivateName(propertyName))
613             continue;
614         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
615         PropertyDescriptor desc;
616         if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
617             continue;
618         // b. If desc.[[Configurable]] is true, then return false.
619         if (desc.configurable())
620             return JSValue::encode(jsBoolean(false));
621     }
622
623     // 3. If the [[Extensible]] internal property of O is false, then return true.
624     // 4. Otherwise, return false.
625     bool isExtensible = object->isExtensible(exec);
626     RETURN_IF_EXCEPTION(scope, encodedJSValue());
627     return JSValue::encode(jsBoolean(!isExtensible));
628 }
629
630 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
631 {
632     VM& vm = exec->vm();
633     auto scope = DECLARE_THROW_SCOPE(vm);
634
635     // 1. If Type(O) is not Object, return true.
636     JSValue obj = exec->argument(0);
637     if (!obj.isObject())
638         return JSValue::encode(jsBoolean(true));
639     JSObject* object = asObject(obj);
640
641     if (isJSFinalObject(object))
642         return JSValue::encode(jsBoolean(object->isFrozen(vm)));
643
644     // 2. For each named own property name P of O,
645     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
646     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
647     RETURN_IF_EXCEPTION(scope, encodedJSValue());
648     PropertyNameArray::const_iterator end = properties.end();
649     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
650         Identifier propertyName = *iter;
651         if (exec->propertyNames().isPrivateName(propertyName))
652             continue;
653         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
654         PropertyDescriptor desc;
655         if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
656             continue;
657         // b. If IsDataDescriptor(desc) is true then
658         // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
659         if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable())
660             return JSValue::encode(jsBoolean(false));
661     }
662
663     // 3. If the [[Extensible]] internal property of O is false, then return true.
664     // 4. Otherwise, return false.
665     bool isExtensible = object->isExtensible(exec);
666     RETURN_IF_EXCEPTION(scope, encodedJSValue());
667     return JSValue::encode(jsBoolean(!isExtensible));
668 }
669
670 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
671 {
672     VM& vm = exec->vm();
673     auto scope = DECLARE_THROW_SCOPE(vm);
674     JSValue obj = exec->argument(0);
675     if (!obj.isObject())
676         return JSValue::encode(jsBoolean(false));
677     JSObject* object = asObject(obj);
678     bool isExtensible = object->isExtensible(exec);
679     RETURN_IF_EXCEPTION(scope, encodedJSValue());
680     return JSValue::encode(jsBoolean(isExtensible));
681 }
682
683 EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState* exec)
684 {
685     return JSValue::encode(jsBoolean(sameValue(exec, exec->argument(0), exec->argument(1))));
686 }
687
688 // FIXME: Use the enumeration cache.
689 JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode)
690 {
691     VM& vm = exec->vm();
692     auto scope = DECLARE_THROW_SCOPE(vm);
693     PropertyNameArray properties(exec, propertyNameMode);
694     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
695     RETURN_IF_EXCEPTION(scope, nullptr);
696
697     JSArray* keys = constructEmptyArray(exec, 0);
698     RETURN_IF_EXCEPTION(scope, nullptr);
699
700     switch (propertyNameMode) {
701     case PropertyNameMode::Strings: {
702         size_t numProperties = properties.size();
703         for (size_t i = 0; i < numProperties; i++) {
704             const auto& identifier = properties[i];
705             ASSERT(!identifier.isSymbol());
706             keys->push(exec, jsOwnedString(exec, identifier.string()));
707         }
708         break;
709     }
710
711     case PropertyNameMode::Symbols: {
712         size_t numProperties = properties.size();
713         for (size_t i = 0; i < numProperties; i++) {
714             const auto& identifier = properties[i];
715             ASSERT(identifier.isSymbol());
716             if (!exec->propertyNames().isPrivateName(identifier))
717                 keys->push(exec, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
718         }
719         break;
720     }
721
722     case PropertyNameMode::StringsAndSymbols: {
723         Vector<Identifier, 16> propertySymbols;
724         size_t numProperties = properties.size();
725         for (size_t i = 0; i < numProperties; i++) {
726             const auto& identifier = properties[i];
727             if (identifier.isSymbol()) {
728                 if (!exec->propertyNames().isPrivateName(identifier))
729                     propertySymbols.append(identifier);
730             } else
731                 keys->push(exec, jsOwnedString(exec, identifier.string()));
732         }
733
734         // To ensure the order defined in the spec (9.1.12), we append symbols at the last elements of keys.
735         for (const auto& identifier : propertySymbols)
736             keys->push(exec, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
737
738         break;
739     }
740     }
741
742     return keys;
743 }
744
745 } // namespace JSC