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