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