Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / runtime / ObjectConstructor.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2008-2017 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 objectConstructorAssign(ExecState*);
43 EncodedJSValue JSC_HOST_CALL objectConstructorValues(ExecState*);
44 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
45 EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState*);
46 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
47 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
48 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
49 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
50 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
51 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
52 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
53 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
54 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
55 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
56 EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState*);
57
58 }
59
60 #include "ObjectConstructor.lut.h"
61
62 namespace JSC {
63
64 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor);
65
66 const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, &objectConstructorTable, nullptr, CREATE_METHOD_TABLE(ObjectConstructor) };
67
68 /* Source for ObjectConstructor.lut.h
69 @begin objectConstructorTable
70   getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1
71   setPrototypeOf            objectConstructorSetPrototypeOf             DontEnum|Function 2
72   getOwnPropertyDescriptor  objectConstructorGetOwnPropertyDescriptor   DontEnum|Function 2
73   getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors  DontEnum|Function 1
74   getOwnPropertyNames       objectConstructorGetOwnPropertyNames        DontEnum|Function 1
75   getOwnPropertySymbols     objectConstructorGetOwnPropertySymbols      DontEnum|Function 1
76   keys                      objectConstructorKeys                       DontEnum|Function 1
77   defineProperty            objectConstructorDefineProperty             DontEnum|Function 3
78   defineProperties          objectConstructorDefineProperties           DontEnum|Function 2
79   create                    objectConstructorCreate                     DontEnum|Function 2
80   seal                      objectConstructorSeal                       DontEnum|Function 1
81   freeze                    objectConstructorFreeze                     DontEnum|Function 1
82   preventExtensions         objectConstructorPreventExtensions          DontEnum|Function 1
83   isSealed                  objectConstructorIsSealed                   DontEnum|Function 1
84   isFrozen                  objectConstructorIsFrozen                   DontEnum|Function 1
85   isExtensible              objectConstructorIsExtensible               DontEnum|Function 1
86   is                        objectConstructorIs                         DontEnum|Function 2
87   assign                    objectConstructorAssign                     DontEnum|Function 2
88   values                    objectConstructorValues                     DontEnum|Function 1
89   entries                   JSBuiltin                                   DontEnum|Function 1
90 @end
91 */
92
93 ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
94     : InternalFunction(vm, structure)
95 {
96 }
97
98 void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype)
99 {
100     Base::finishCreation(vm, objectPrototype->classInfo(vm)->className);
101
102     putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
103     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum);
104
105     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().createPrivateName(), objectConstructorCreate, DontEnum, 2);
106     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().definePropertyPrivateName(), objectConstructorDefineProperty, DontEnum, 3);
107     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrototypeOfPrivateName(), objectConstructorGetPrototypeOf, DontEnum, 1);
108     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyNamesPrivateName(), objectConstructorGetOwnPropertyNames, DontEnum, 1);
109 }
110
111 // ES 19.1.1.1 Object([value])
112 static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSValue newTarget)
113 {
114     ObjectConstructor* objectConstructor = jsCast<ObjectConstructor*>(exec->jsCallee());
115     JSGlobalObject* globalObject = objectConstructor->globalObject();
116     VM& vm = globalObject->vm();
117     auto scope = DECLARE_THROW_SCOPE(vm);
118
119     // We need to check newTarget condition in this caller side instead of InternalFunction::createSubclassStructure side.
120     // Since if we found this condition is met, we should not fall into the type conversion in the step 3.
121
122     // 1. If NewTarget is neither undefined nor the active function, then
123     if (newTarget && newTarget != objectConstructor) {
124         // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
125         Structure* objectStructure = InternalFunction::createSubclassStructure(exec, newTarget, globalObject->objectStructureForObjectConstructor());
126         RETURN_IF_EXCEPTION(scope, nullptr);
127         return constructEmptyObject(exec, objectStructure);
128     }
129
130     // 2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
131     ArgList args(exec);
132     JSValue arg = args.at(0);
133     if (arg.isUndefinedOrNull())
134         return constructEmptyObject(exec, globalObject->objectStructureForObjectConstructor());
135
136     // 3. Return ToObject(value).
137     scope.release();
138     return arg.toObject(exec, globalObject);
139 }
140
141 static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
142 {
143     return JSValue::encode(constructObject(exec, exec->newTarget()));
144 }
145
146 ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
147 {
148     constructData.native.function = constructWithObjectConstructor;
149     return ConstructType::Host;
150 }
151
152 static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
153 {
154     return JSValue::encode(constructObject(exec, JSValue()));
155 }
156
157 CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
158 {
159     callData.native.function = callObjectConstructor;
160     return CallType::Host;
161 }
162
163 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
164 {
165     VM& vm = exec->vm();
166     auto scope = DECLARE_THROW_SCOPE(vm);
167     JSObject* object = exec->argument(0).toObject(exec);
168     RETURN_IF_EXCEPTION(scope, encodedJSValue());
169     scope.release();
170     return JSValue::encode(object->getPrototype(vm, exec));
171 }
172
173 EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
174 {
175     VM& vm = exec->vm();
176     auto scope = DECLARE_THROW_SCOPE(vm);
177
178     JSValue objectValue = exec->argument(0);
179     if (objectValue.isUndefinedOrNull())
180         return throwVMTypeError(exec, scope, ASCIILiteral("Cannot set prototype of undefined or null"));
181
182     JSValue protoValue = exec->argument(1);
183     if (!protoValue.isObject() && !protoValue.isNull())
184         return throwVMTypeError(exec, scope, ASCIILiteral("Prototype value can only be an object or null"));
185
186     JSObject* object = objectValue.toObject(exec);
187     RETURN_IF_EXCEPTION(scope, encodedJSValue());
188
189     bool shouldThrowIfCantSet = true;
190     bool didSetPrototype = object->setPrototype(vm, exec, protoValue, shouldThrowIfCantSet);
191     ASSERT_UNUSED(didSetPrototype, scope.exception() || didSetPrototype);
192     return JSValue::encode(objectValue);
193 }
194
195 JSValue objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject* object, const Identifier& propertyName)
196 {
197     VM& vm = exec->vm();
198     auto scope = DECLARE_THROW_SCOPE(vm);
199     PropertyDescriptor descriptor;
200     if (!object->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
201         scope.release();
202         return jsUndefined();
203     }
204     RETURN_IF_EXCEPTION(scope, { });
205
206     JSObject* result = constructObjectFromPropertyDescriptor(exec, descriptor);
207     ASSERT(!!scope.exception() == !result);
208     if (!result)
209         return jsUndefined();
210     return result;
211 }
212
213 JSValue objectConstructorGetOwnPropertyDescriptors(ExecState* exec, JSObject* object)
214 {
215     VM& vm = exec->vm();
216     auto scope = DECLARE_THROW_SCOPE(vm);
217     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
218     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
219     RETURN_IF_EXCEPTION(scope, { });
220
221     JSObject* descriptors = constructEmptyObject(exec);
222     RETURN_IF_EXCEPTION(scope, { });
223
224     for (auto& propertyName : properties) {
225         PropertyDescriptor descriptor;
226         bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, descriptor);
227         RETURN_IF_EXCEPTION(scope, { });
228
229         if (!didGetDescriptor)
230             continue;
231
232         JSObject* fromDescriptor = constructObjectFromPropertyDescriptor(exec, descriptor);
233         ASSERT(!!scope.exception() == !fromDescriptor);
234         if (!fromDescriptor)
235             return jsUndefined();
236
237         PutPropertySlot slot(descriptors);
238         descriptors->putOwnDataPropertyMayBeIndex(exec, propertyName, fromDescriptor, slot);
239         scope.assertNoException();
240     }
241
242     return descriptors;
243 }
244
245 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
246 {
247     VM& vm = exec->vm();
248     auto scope = DECLARE_THROW_SCOPE(vm);
249     JSObject* object = exec->argument(0).toObject(exec);
250     RETURN_IF_EXCEPTION(scope, encodedJSValue());
251     auto propertyName = exec->argument(1).toPropertyKey(exec);
252     RETURN_IF_EXCEPTION(scope, encodedJSValue());
253     scope.release();
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     scope.release();
264     return JSValue::encode(objectConstructorGetOwnPropertyDescriptors(exec, object));
265 }
266
267 // FIXME: Use the enumeration cache.
268 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
269 {
270     VM& vm = exec->vm();
271     auto scope = DECLARE_THROW_SCOPE(vm);
272     JSObject* object = exec->argument(0).toObject(exec);
273     RETURN_IF_EXCEPTION(scope, encodedJSValue());
274     scope.release();
275     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Include));
276 }
277
278 // FIXME: Use the enumeration cache.
279 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState* exec)
280 {
281     VM& vm = exec->vm();
282     auto scope = DECLARE_THROW_SCOPE(vm);
283     JSObject* object = exec->argument(0).toObject(exec);
284     RETURN_IF_EXCEPTION(scope, encodedJSValue());
285     scope.release();
286     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include));
287 }
288
289 // FIXME: Use the enumeration cache.
290 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
291 {
292     VM& vm = exec->vm();
293     auto scope = DECLARE_THROW_SCOPE(vm);
294     JSObject* object = exec->argument(0).toObject(exec);
295     RETURN_IF_EXCEPTION(scope, encodedJSValue());
296     scope.release();
297     return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude));
298 }
299
300 EncodedJSValue JSC_HOST_CALL objectConstructorAssign(ExecState* exec)
301 {
302     VM& vm = exec->vm();
303     auto scope = DECLARE_THROW_SCOPE(vm);
304
305     JSValue targetValue = exec->argument(0);
306     if (targetValue.isUndefinedOrNull())
307         return throwVMTypeError(exec, scope, ASCIILiteral("Object.assign requires that input parameter not be null or undefined"));
308     JSObject* target = targetValue.toObject(exec);
309     RETURN_IF_EXCEPTION(scope, { });
310
311     unsigned argsCount = exec->argumentCount();
312     for (unsigned i = 1; i < argsCount; ++i) {
313         JSValue sourceValue = exec->uncheckedArgument(i);
314         if (sourceValue.isUndefinedOrNull())
315             continue;
316         JSObject* source = sourceValue.toObject(exec);
317         RETURN_IF_EXCEPTION(scope, { });
318
319         PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
320         source->methodTable(vm)->getOwnPropertyNames(source, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
321         RETURN_IF_EXCEPTION(scope, { });
322
323         auto assign = [&] (PropertyName propertyName) {
324             PropertySlot slot(source, PropertySlot::InternalMethodType::GetOwnProperty);
325             if (!source->methodTable(vm)->getOwnPropertySlot(source, exec, propertyName, slot))
326                 return;
327             if (slot.attributes() & DontEnum)
328                 return;
329
330             JSValue value;
331             if (LIKELY(!slot.isTaintedByOpaqueObject()))
332                 value = slot.getValue(exec, propertyName);
333             else
334                 value = source->get(exec, propertyName);
335             RETURN_IF_EXCEPTION(scope, void());
336
337             PutPropertySlot putPropertySlot(target, true);
338             target->putInline(exec, propertyName, value, putPropertySlot);
339         };
340
341         // First loop is for strings. Second loop is for symbols to keep standardized order requirement in the spec.
342         // https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys
343         bool foundSymbol = false;
344         unsigned numProperties = properties.size();
345         for (unsigned j = 0; j < numProperties; j++) {
346             const auto& propertyName = properties[j];
347             if (propertyName.isSymbol()) {
348                 foundSymbol = true;
349                 continue;
350             }
351
352             assign(propertyName);
353             RETURN_IF_EXCEPTION(scope, { });
354         }
355
356         if (foundSymbol) {
357             for (unsigned j = 0; j < numProperties; j++) {
358                 const auto& propertyName = properties[j];
359                 if (propertyName.isSymbol() && !vm.propertyNames->isPrivateName(propertyName)) {
360                     assign(propertyName);
361                     RETURN_IF_EXCEPTION(scope, { });
362                 }
363             }
364         }
365     }
366     return JSValue::encode(target);
367 }
368
369 EncodedJSValue JSC_HOST_CALL objectConstructorValues(ExecState* exec)
370 {
371     VM& vm = exec->vm();
372     auto scope = DECLARE_THROW_SCOPE(vm);
373
374     JSValue targetValue = exec->argument(0);
375     if (targetValue.isUndefinedOrNull())
376         return throwVMTypeError(exec, scope, ASCIILiteral("Object.values requires that input parameter not be null or undefined"));
377     JSObject* target = targetValue.toObject(exec);
378     RETURN_IF_EXCEPTION(scope, { });
379
380     JSArray* values = constructEmptyArray(exec, 0);
381     RETURN_IF_EXCEPTION(scope, { });
382
383     PropertyNameArray properties(exec, PropertyNameMode::Strings);
384     target->methodTable(vm)->getOwnPropertyNames(target, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
385     RETURN_IF_EXCEPTION(scope, { });
386
387     auto addValue = [&] (PropertyName propertyName) {
388         PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
389         if (!target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot))
390             return;
391         if (slot.attributes() & DontEnum)
392             return;
393
394         JSValue value;
395         if (LIKELY(!slot.isTaintedByOpaqueObject()))
396             value = slot.getValue(exec, propertyName);
397         else
398             value = target->get(exec, propertyName);
399         RETURN_IF_EXCEPTION(scope, void());
400
401         values->push(exec, value);
402     };
403
404     for (unsigned i = 0, numProperties = properties.size(); i < numProperties; i++) {
405         const auto& propertyName = properties[i];
406         if (propertyName.isSymbol())
407             continue;
408
409         addValue(propertyName);
410         RETURN_IF_EXCEPTION(scope, { });
411     }
412
413     return JSValue::encode(values);
414 }
415
416
417 // ES6 6.2.4.5 ToPropertyDescriptor
418 // https://tc39.github.io/ecma262/#sec-topropertydescriptor
419 bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
420 {
421     VM& vm = exec->vm();
422     auto scope = DECLARE_THROW_SCOPE(vm);
423
424     if (!in.isObject()) {
425         throwTypeError(exec, scope, ASCIILiteral("Property description must be an object."));
426         return false;
427     }
428     JSObject* description = asObject(in);
429
430     bool hasProperty = description->hasProperty(exec, vm.propertyNames->enumerable);
431     ASSERT(!scope.exception() || !hasProperty);
432     if (hasProperty) {
433         JSValue value = description->get(exec, vm.propertyNames->enumerable);
434         RETURN_IF_EXCEPTION(scope, false);
435         desc.setEnumerable(value.toBoolean(exec));
436     } else
437         RETURN_IF_EXCEPTION(scope, false);
438
439     hasProperty = description->hasProperty(exec, vm.propertyNames->configurable);
440     ASSERT(!scope.exception() || !hasProperty);
441     if (hasProperty) {
442         JSValue value = description->get(exec, vm.propertyNames->configurable);
443         RETURN_IF_EXCEPTION(scope, false);
444         desc.setConfigurable(value.toBoolean(exec));
445     } else
446         RETURN_IF_EXCEPTION(scope, false);
447
448     JSValue value;
449     hasProperty = description->hasProperty(exec, vm.propertyNames->value);
450     ASSERT(!scope.exception() || !hasProperty);
451     if (hasProperty) {
452         JSValue value = description->get(exec, vm.propertyNames->value);
453         RETURN_IF_EXCEPTION(scope, false);
454         desc.setValue(value);
455     } else
456         RETURN_IF_EXCEPTION(scope, false);
457
458     hasProperty = description->hasProperty(exec, vm.propertyNames->writable);
459     ASSERT(!scope.exception() || !hasProperty);
460     if (hasProperty) {
461         JSValue value = description->get(exec, vm.propertyNames->writable);
462         RETURN_IF_EXCEPTION(scope, false);
463         desc.setWritable(value.toBoolean(exec));
464     } else
465         RETURN_IF_EXCEPTION(scope, false);
466
467     hasProperty = description->hasProperty(exec, vm.propertyNames->get);
468     ASSERT(!scope.exception() || !hasProperty);
469     if (hasProperty) {
470         JSValue get = description->get(exec, vm.propertyNames->get);
471         RETURN_IF_EXCEPTION(scope, false);
472         if (!get.isUndefined()) {
473             CallData callData;
474             if (getCallData(get, callData) == CallType::None) {
475                 throwTypeError(exec, scope, ASCIILiteral("Getter must be a function."));
476                 return false;
477             }
478         }
479         desc.setGetter(get);
480     } else
481         RETURN_IF_EXCEPTION(scope, false);
482
483     hasProperty = description->hasProperty(exec, vm.propertyNames->set);
484     ASSERT(!scope.exception() || !hasProperty);
485     if (hasProperty) {
486         JSValue set = description->get(exec, vm.propertyNames->set);
487         RETURN_IF_EXCEPTION(scope, false);
488         if (!set.isUndefined()) {
489             CallData callData;
490             if (getCallData(set, callData) == CallType::None) {
491                 throwTypeError(exec, scope, ASCIILiteral("Setter must be a function."));
492                 return false;
493             }
494         }
495         desc.setSetter(set);
496     } else
497         RETURN_IF_EXCEPTION(scope, false);
498
499     if (!desc.isAccessorDescriptor())
500         return true;
501
502     if (desc.value()) {
503         throwTypeError(exec, scope, ASCIILiteral("Invalid property.  'value' present on property with getter or setter."));
504         return false;
505     }
506
507     if (desc.writablePresent()) {
508         throwTypeError(exec, scope, ASCIILiteral("Invalid property.  'writable' present on property with getter or setter."));
509         return false;
510     }
511     return true;
512 }
513
514 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
515 {
516     VM& vm = exec->vm();
517     auto scope = DECLARE_THROW_SCOPE(vm);
518
519     if (!exec->argument(0).isObject())
520         return throwVMTypeError(exec, scope, ASCIILiteral("Properties can only be defined on Objects."));
521     JSObject* obj = asObject(exec->argument(0));
522     auto propertyName = exec->argument(1).toPropertyKey(exec);
523     RETURN_IF_EXCEPTION(scope, encodedJSValue());
524     PropertyDescriptor descriptor;
525     auto success = toPropertyDescriptor(exec, exec->argument(2), descriptor);
526     ASSERT(!scope.exception() == success);
527     if (!success)
528         return JSValue::encode(jsNull());
529     ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
530     scope.assertNoException();
531     obj->methodTable(vm)->defineOwnProperty(obj, exec, propertyName, descriptor, true);
532     scope.release();
533     return JSValue::encode(obj);
534 }
535
536 static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
537 {
538     VM& vm = exec->vm();
539     auto scope = DECLARE_THROW_SCOPE(vm);
540
541     PropertyNameArray propertyNames(exec, PropertyNameMode::StringsAndSymbols);
542     asObject(properties)->methodTable(vm)->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude));
543     RETURN_IF_EXCEPTION(scope, { });
544     size_t numProperties = propertyNames.size();
545     Vector<PropertyDescriptor> descriptors;
546     MarkedArgumentBuffer markBuffer;
547     for (size_t i = 0; i < numProperties; i++) {
548         JSValue prop = properties->get(exec, propertyNames[i]);
549         RETURN_IF_EXCEPTION(scope, { });
550         PropertyDescriptor descriptor;
551         bool success = toPropertyDescriptor(exec, prop, descriptor);
552         ASSERT(!scope.exception() || !success);
553         if (UNLIKELY(!success))
554             return jsNull();
555         descriptors.append(descriptor);
556         // Ensure we mark all the values that we're accumulating
557         if (descriptor.isDataDescriptor() && descriptor.value())
558             markBuffer.append(descriptor.value());
559         if (descriptor.isAccessorDescriptor()) {
560             if (descriptor.getter())
561                 markBuffer.append(descriptor.getter());
562             if (descriptor.setter())
563                 markBuffer.append(descriptor.setter());
564         }
565     }
566     for (size_t i = 0; i < numProperties; i++) {
567         Identifier propertyName = propertyNames[i];
568         if (vm.propertyNames->isPrivateName(propertyName))
569             continue;
570         object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, descriptors[i], true);
571         RETURN_IF_EXCEPTION(scope, { });
572     }
573     return object;
574 }
575
576 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec)
577 {
578     VM& vm = exec->vm();
579     auto scope = DECLARE_THROW_SCOPE(vm);
580
581     if (!exec->argument(0).isObject())
582         return throwVMTypeError(exec, scope, ASCIILiteral("Properties can only be defined on Objects."));
583     JSObject* targetObj = asObject(exec->argument(0));
584     JSObject* props = exec->argument(1).toObject(exec);
585     ASSERT(!!scope.exception() == !props);
586     if (UNLIKELY(!props))
587         return encodedJSValue();
588     scope.release();
589     return JSValue::encode(defineProperties(exec, targetObj, props));
590 }
591
592 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
593 {
594     VM& vm = exec->vm();
595     auto scope = DECLARE_THROW_SCOPE(vm);
596
597     JSValue proto = exec->argument(0);
598     if (!proto.isObject() && !proto.isNull())
599         return throwVMTypeError(exec, scope, ASCIILiteral("Object prototype may only be an Object or null."));
600     JSObject* newObject = proto.isObject()
601         ? constructEmptyObject(exec, asObject(proto))
602         : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
603     if (exec->argument(1).isUndefined())
604         return JSValue::encode(newObject);
605     if (!exec->argument(1).isObject())
606         return throwVMTypeError(exec, scope, ASCIILiteral("Property descriptor list must be an Object."));
607     scope.release();
608     return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
609 }
610
611 enum class IntegrityLevel {
612     Sealed,
613     Frozen
614 };
615
616 template<IntegrityLevel level>
617 bool setIntegrityLevel(ExecState* exec, VM& vm, JSObject* object)
618 {
619     // See https://tc39.github.io/ecma262/#sec-setintegritylevel.
620     auto scope = DECLARE_THROW_SCOPE(vm);
621
622     bool success = object->methodTable(vm)->preventExtensions(object, exec);
623     RETURN_IF_EXCEPTION(scope, false);
624     if (UNLIKELY(!success))
625         return false;
626
627     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
628     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
629     RETURN_IF_EXCEPTION(scope, false);
630
631     PropertyNameArray::const_iterator end = properties.end();
632     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
633         Identifier propertyName = *iter;
634         if (vm.propertyNames->isPrivateName(propertyName))
635             continue;
636
637         PropertyDescriptor desc;
638         if (level == IntegrityLevel::Sealed)
639             desc.setConfigurable(false);
640         else {
641             bool hasPropertyDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, desc);
642             RETURN_IF_EXCEPTION(scope, false);
643             if (!hasPropertyDescriptor)
644                 continue;
645
646             if (desc.isDataDescriptor())
647                 desc.setWritable(false);
648
649             desc.setConfigurable(false);
650         }
651
652         object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
653         RETURN_IF_EXCEPTION(scope, false);
654     }
655     return true;
656 }
657
658 template<IntegrityLevel level>
659 bool testIntegrityLevel(ExecState* exec, VM& vm, JSObject* object)
660 {
661     auto scope = DECLARE_THROW_SCOPE(vm);
662
663     // 1. Assert: Type(O) is Object.
664     // 2. Assert: level is either "sealed" or "frozen".
665
666     // 3. Let status be ?IsExtensible(O).
667     bool status = object->isExtensible(exec);
668     RETURN_IF_EXCEPTION(scope, { });
669
670     // 4. If status is true, return false.
671     if (status)
672         return false;
673
674     // 6. Let keys be ? O.[[OwnPropertyKeys]]().
675     PropertyNameArray keys(exec, PropertyNameMode::StringsAndSymbols);
676     object->methodTable(vm)->getOwnPropertyNames(object, exec, keys, EnumerationMode(DontEnumPropertiesMode::Include));
677     RETURN_IF_EXCEPTION(scope, { });
678
679     // 7. For each element k of keys, do
680     PropertyNameArray::const_iterator end = keys.end();
681     for (PropertyNameArray::const_iterator iter = keys.begin(); iter != end; ++iter) {
682         Identifier propertyName = *iter;
683         if (vm.propertyNames->isPrivateName(propertyName))
684             continue;
685
686         // a. Let currentDesc be ? O.[[GetOwnProperty]](k)
687         PropertyDescriptor desc;
688         bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, desc);
689         RETURN_IF_EXCEPTION(scope, { });
690
691         // b. If currentDesc is not undefined, then
692         if (!didGetDescriptor)
693             continue;
694
695         // i. If currentDesc.[[Configurable]] is true, return false.
696         if (desc.configurable())
697             return false;
698
699         // ii. If level is "frozen" and IsDataDescriptor(currentDesc) is true, then
700         // 1. If currentDesc.[[Writable]] is true, return false.
701         if (level == IntegrityLevel::Frozen && desc.isDataDescriptor() && desc.writable())
702             return false;
703     }
704
705     return true;
706 }
707
708 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
709 {
710     VM& vm = exec->vm();
711     auto scope = DECLARE_THROW_SCOPE(vm);
712
713     // 1. If Type(O) is not Object, return O.
714     JSValue obj = exec->argument(0);
715     if (!obj.isObject())
716         return JSValue::encode(obj);
717     JSObject* object = asObject(obj);
718
719     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
720         object->seal(vm);
721         return JSValue::encode(obj);
722     }
723
724     bool success = setIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object);
725     RETURN_IF_EXCEPTION(scope, encodedJSValue());
726     if (UNLIKELY(!success)) {
727         throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.seal"));
728         return encodedJSValue();
729     }
730
731     return JSValue::encode(obj);
732 }
733
734 JSObject* objectConstructorFreeze(ExecState* exec, JSObject* object)
735 {
736     VM& vm = exec->vm();
737     auto scope = DECLARE_THROW_SCOPE(vm);
738
739     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
740         object->freeze(vm);
741         return object;
742     }
743
744     bool success = setIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object);
745     RETURN_IF_EXCEPTION(scope, nullptr);
746     if (!success)
747         return throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.freeze"));
748     return object;
749 }
750
751 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
752 {
753     VM& vm = exec->vm();
754     auto scope = DECLARE_THROW_SCOPE(vm);
755     // 1. If Type(O) is not Object, return O.
756     JSValue obj = exec->argument(0);
757     if (!obj.isObject())
758         return JSValue::encode(obj);
759     JSObject* result = objectConstructorFreeze(exec, asObject(obj));
760     RETURN_IF_EXCEPTION(scope, encodedJSValue());
761     return JSValue::encode(result);
762 }
763
764 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
765 {
766     VM& vm = exec->vm();
767     JSValue argument = exec->argument(0);
768     if (!argument.isObject())
769         return JSValue::encode(argument);
770     JSObject* object = asObject(argument);
771     object->methodTable(vm)->preventExtensions(object, exec);
772     return JSValue::encode(object);
773 }
774
775 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
776 {
777     VM& vm = exec->vm();
778
779     // 1. If Type(O) is not Object, return true.
780     JSValue obj = exec->argument(0);
781     if (!obj.isObject())
782         return JSValue::encode(jsBoolean(true));
783     JSObject* object = asObject(obj);
784
785     // Quick check for final objects.
786     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType()))
787         return JSValue::encode(jsBoolean(object->isSealed(vm)));
788
789     // 2. Return ? TestIntegrityLevel(O, "sealed").
790     return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object)));
791 }
792
793 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
794 {
795     VM& vm = exec->vm();
796
797     // 1. If Type(O) is not Object, return true.
798     JSValue obj = exec->argument(0);
799     if (!obj.isObject())
800         return JSValue::encode(jsBoolean(true));
801     JSObject* object = asObject(obj);
802
803     // Quick check for final objects.
804     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType()))
805         return JSValue::encode(jsBoolean(object->isFrozen(vm)));
806
807     // 2. Return ? TestIntegrityLevel(O, "frozen").
808     return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object)));
809 }
810
811 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
812 {
813     VM& vm = exec->vm();
814     auto scope = DECLARE_THROW_SCOPE(vm);
815     JSValue obj = exec->argument(0);
816     if (!obj.isObject())
817         return JSValue::encode(jsBoolean(false));
818     JSObject* object = asObject(obj);
819     bool isExtensible = object->isExtensible(exec);
820     RETURN_IF_EXCEPTION(scope, encodedJSValue());
821     return JSValue::encode(jsBoolean(isExtensible));
822 }
823
824 EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState* exec)
825 {
826     return JSValue::encode(jsBoolean(sameValue(exec, exec->argument(0), exec->argument(1))));
827 }
828
829 // FIXME: Use the enumeration cache.
830 JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode)
831 {
832     VM& vm = exec->vm();
833     auto scope = DECLARE_THROW_SCOPE(vm);
834     PropertyNameArray properties(exec, propertyNameMode);
835     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
836     RETURN_IF_EXCEPTION(scope, nullptr);
837
838     JSArray* keys = constructEmptyArray(exec, 0);
839     RETURN_IF_EXCEPTION(scope, nullptr);
840
841     // https://tc39.github.io/ecma262/#sec-enumerableownproperties
842     // If {object} is a Proxy, an explicit and observable [[GetOwnProperty]] op is required to filter out non-enumerable properties.
843     // In other cases, filtering has already been performed.
844     const bool mustFilterProperty = dontEnumPropertiesMode == DontEnumPropertiesMode::Exclude && object->type() == ProxyObjectType;
845     auto filterPropertyIfNeeded = [exec, object, mustFilterProperty](const Identifier& identifier) {
846         if (!mustFilterProperty)
847             return true;
848         PropertyDescriptor descriptor;
849         PropertyName name(identifier);
850         return object->getOwnPropertyDescriptor(exec, name, descriptor) && descriptor.enumerable();
851     };
852
853     switch (propertyNameMode) {
854     case PropertyNameMode::Strings: {
855         size_t numProperties = properties.size();
856         for (size_t i = 0; i < numProperties; i++) {
857             const auto& identifier = properties[i];
858             ASSERT(!identifier.isSymbol());
859             if (filterPropertyIfNeeded(identifier))
860                 keys->push(exec, jsOwnedString(exec, identifier.string()));
861             RETURN_IF_EXCEPTION(scope, nullptr);
862         }
863         break;
864     }
865
866     case PropertyNameMode::Symbols: {
867         size_t numProperties = properties.size();
868         for (size_t i = 0; i < numProperties; i++) {
869             const auto& identifier = properties[i];
870             ASSERT(identifier.isSymbol());
871             if (!vm.propertyNames->isPrivateName(identifier)) {
872                 if (filterPropertyIfNeeded(identifier))
873                     keys->push(exec, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
874                 RETURN_IF_EXCEPTION(scope, nullptr);
875             }
876         }
877         break;
878     }
879
880     case PropertyNameMode::StringsAndSymbols: {
881         Vector<Identifier, 16> propertySymbols;
882         size_t numProperties = properties.size();
883         for (size_t i = 0; i < numProperties; i++) {
884             const auto& identifier = properties[i];
885             if (identifier.isSymbol()) {
886                 if (!vm.propertyNames->isPrivateName(identifier))
887                     propertySymbols.append(identifier);
888             } else {
889                 if (filterPropertyIfNeeded(identifier))
890                     keys->push(exec, jsOwnedString(exec, identifier.string()));
891                 RETURN_IF_EXCEPTION(scope, nullptr);
892             }
893         }
894
895         // To ensure the order defined in the spec (9.1.12), we append symbols at the last elements of keys.
896         for (const auto& identifier : propertySymbols) {
897             if (filterPropertyIfNeeded(identifier))
898                 keys->push(exec, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
899             RETURN_IF_EXCEPTION(scope, nullptr);
900         }
901
902         break;
903     }
904     }
905
906     return keys;
907 }
908
909 } // namespace JSC