/ runtime / ObjectConstructor.cpp
ObjectConstructor.cpp
   1  /*
   2   *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
   3   *  Copyright (C) 2008-2019 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 "JSArray.h"
  26  #include "JSCInlines.h"
  27  #include "JSImmutableButterfly.h"
  28  #include "PropertyDescriptor.h"
  29  #include "PropertyNameArray.h"
  30  #include "Symbol.h"
  31  
  32  namespace JSC {
  33  
  34  static JSC_DECLARE_HOST_FUNCTION(objectConstructorAssign);
  35  static JSC_DECLARE_HOST_FUNCTION(objectConstructorValues);
  36  static JSC_DECLARE_HOST_FUNCTION(objectConstructorGetPrototypeOf);
  37  static JSC_DECLARE_HOST_FUNCTION(objectConstructorSetPrototypeOf);
  38  static JSC_DECLARE_HOST_FUNCTION(objectConstructorDefineProperty);
  39  static JSC_DECLARE_HOST_FUNCTION(objectConstructorDefineProperties);
  40  static JSC_DECLARE_HOST_FUNCTION(objectConstructorCreate);
  41  static JSC_DECLARE_HOST_FUNCTION(objectConstructorSeal);
  42  static JSC_DECLARE_HOST_FUNCTION(objectConstructorFreeze);
  43  static JSC_DECLARE_HOST_FUNCTION(objectConstructorPreventExtensions);
  44  static JSC_DECLARE_HOST_FUNCTION(objectConstructorIsSealed);
  45  static JSC_DECLARE_HOST_FUNCTION(objectConstructorIsFrozen);
  46  static JSC_DECLARE_HOST_FUNCTION(objectConstructorIsExtensible);
  47  
  48  }
  49  
  50  #include "ObjectConstructor.lut.h"
  51  
  52  namespace JSC {
  53  
  54  STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor);
  55  
  56  const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, &objectConstructorTable, nullptr, CREATE_METHOD_TABLE(ObjectConstructor) };
  57  
  58  /* Source for ObjectConstructor.lut.h
  59  @begin objectConstructorTable
  60    getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1 ObjectGetPrototypeOfIntrinsic
  61    setPrototypeOf            objectConstructorSetPrototypeOf             DontEnum|Function 2
  62    getOwnPropertyDescriptor  objectConstructorGetOwnPropertyDescriptor   DontEnum|Function 2
  63    getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors  DontEnum|Function 1
  64    getOwnPropertyNames       objectConstructorGetOwnPropertyNames        DontEnum|Function 1 ObjectGetOwnPropertyNamesIntrinsic
  65    getOwnPropertySymbols     objectConstructorGetOwnPropertySymbols      DontEnum|Function 1
  66    keys                      objectConstructorKeys                       DontEnum|Function 1 ObjectKeysIntrinsic
  67    defineProperty            objectConstructorDefineProperty             DontEnum|Function 3
  68    defineProperties          objectConstructorDefineProperties           DontEnum|Function 2
  69    create                    objectConstructorCreate                     DontEnum|Function 2 ObjectCreateIntrinsic
  70    seal                      objectConstructorSeal                       DontEnum|Function 1
  71    freeze                    objectConstructorFreeze                     DontEnum|Function 1
  72    preventExtensions         objectConstructorPreventExtensions          DontEnum|Function 1
  73    isSealed                  objectConstructorIsSealed                   DontEnum|Function 1
  74    isFrozen                  objectConstructorIsFrozen                   DontEnum|Function 1
  75    isExtensible              objectConstructorIsExtensible               DontEnum|Function 1
  76    is                        objectConstructorIs                         DontEnum|Function 2 ObjectIsIntrinsic
  77    assign                    objectConstructorAssign                     DontEnum|Function 2
  78    values                    objectConstructorValues                     DontEnum|Function 1
  79    entries                   JSBuiltin                                   DontEnum|Function 1
  80    fromEntries               JSBuiltin                                   DontEnum|Function 1
  81  @end
  82  */
  83  
  84  
  85  static JSC_DECLARE_HOST_FUNCTION(callObjectConstructor);
  86  static JSC_DECLARE_HOST_FUNCTION(constructWithObjectConstructor);
  87  
  88  ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
  89      : InternalFunction(vm, structure, callObjectConstructor, constructWithObjectConstructor)
  90  {
  91  }
  92  
  93  void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype)
  94  {
  95      Base::finishCreation(vm, 1, vm.propertyNames->Object.string(), PropertyAdditionMode::WithoutStructureTransition);
  96  
  97      putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
  98  
  99      JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().createPrivateName(), objectConstructorCreate, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
 100      JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().definePropertyPrivateName(), objectConstructorDefineProperty, static_cast<unsigned>(PropertyAttribute::DontEnum), 3);
 101      JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyNamesPrivateName(), objectConstructorGetOwnPropertyNames, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
 102  }
 103  
 104  // ES 19.1.1.1 Object([value])
 105  static ALWAYS_INLINE JSObject* constructObjectWithNewTarget(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newTarget)
 106  {
 107      VM& vm = globalObject->vm();
 108      ObjectConstructor* objectConstructor = jsCast<ObjectConstructor*>(callFrame->jsCallee());
 109      auto scope = DECLARE_THROW_SCOPE(vm);
 110  
 111      // We need to check newTarget condition in this caller side instead of InternalFunction::createSubclassStructure side.
 112      // Since if we found this condition is met, we should not fall into the type conversion in the step 3.
 113  
 114      // 1. If NewTarget is neither undefined nor the active function, then
 115      if (newTarget && newTarget != objectConstructor) {
 116          // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
 117          Structure* baseStructure = getFunctionRealm(vm, asObject(newTarget))->objectStructureForObjectConstructor();
 118          Structure* objectStructure = InternalFunction::createSubclassStructure(globalObject, asObject(newTarget), baseStructure);
 119          RETURN_IF_EXCEPTION(scope, nullptr);
 120          return constructEmptyObject(vm, objectStructure);
 121      }
 122  
 123      // 2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
 124      JSValue argument = callFrame->argument(0);
 125      if (argument.isUndefinedOrNull())
 126          return constructEmptyObject(vm, globalObject->objectStructureForObjectConstructor());
 127  
 128      // 3. Return ToObject(value).
 129      RELEASE_AND_RETURN(scope, argument.toObject(globalObject));
 130  }
 131  
 132  JSC_DEFINE_HOST_FUNCTION(constructWithObjectConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
 133  {
 134      return JSValue::encode(constructObjectWithNewTarget(globalObject, callFrame, callFrame->newTarget()));
 135  }
 136  
 137  JSC_DEFINE_HOST_FUNCTION(callObjectConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
 138  {
 139      return JSValue::encode(constructObjectWithNewTarget(globalObject, callFrame, JSValue()));
 140  }
 141  
 142  JSC_DEFINE_HOST_FUNCTION(objectConstructorGetPrototypeOf, (JSGlobalObject* globalObject, CallFrame* callFrame))
 143  {
 144      return JSValue::encode(callFrame->argument(0).getPrototype(globalObject));
 145  }
 146  
 147  JSC_DEFINE_HOST_FUNCTION(objectConstructorSetPrototypeOf, (JSGlobalObject* globalObject, CallFrame* callFrame))
 148  {
 149      VM& vm = globalObject->vm();
 150      auto scope = DECLARE_THROW_SCOPE(vm);
 151  
 152      JSValue objectValue = callFrame->argument(0);
 153      if (objectValue.isUndefinedOrNull())
 154          return throwVMTypeError(globalObject, scope, "Cannot set prototype of undefined or null"_s);
 155  
 156      JSValue protoValue = callFrame->argument(1);
 157      if (!protoValue.isObject() && !protoValue.isNull())
 158          return throwVMTypeError(globalObject, scope, "Prototype value can only be an object or null"_s);
 159  
 160      JSObject* object = objectValue.toObject(globalObject);
 161      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 162  
 163      bool shouldThrowIfCantSet = true;
 164      bool didSetPrototype = object->setPrototype(vm, globalObject, protoValue, shouldThrowIfCantSet);
 165      EXCEPTION_ASSERT_UNUSED(didSetPrototype, scope.exception() || didSetPrototype);
 166      return JSValue::encode(objectValue);
 167  }
 168  
 169  JSValue objectConstructorGetOwnPropertyDescriptor(JSGlobalObject* globalObject, JSObject* object, const Identifier& propertyName)
 170  {
 171      VM& vm = globalObject->vm();
 172      auto scope = DECLARE_THROW_SCOPE(vm);
 173      PropertyDescriptor descriptor;
 174      if (!object->getOwnPropertyDescriptor(globalObject, propertyName, descriptor))
 175          RELEASE_AND_RETURN(scope, jsUndefined());
 176      RETURN_IF_EXCEPTION(scope, { });
 177  
 178      JSObject* result = constructObjectFromPropertyDescriptor(globalObject, descriptor);
 179      scope.assertNoException();
 180      ASSERT(result);
 181      return result;
 182  }
 183  
 184  JSValue objectConstructorGetOwnPropertyDescriptors(JSGlobalObject* globalObject, JSObject* object)
 185  {
 186      VM& vm = globalObject->vm();
 187      auto scope = DECLARE_THROW_SCOPE(vm);
 188      PropertyNameArray properties(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
 189      object->methodTable(vm)->getOwnPropertyNames(object, globalObject, properties, DontEnumPropertiesMode::Include);
 190      RETURN_IF_EXCEPTION(scope, { });
 191  
 192      JSObject* descriptors = constructEmptyObject(globalObject);
 193      RETURN_IF_EXCEPTION(scope, { });
 194  
 195      for (auto& propertyName : properties) {
 196          PropertyDescriptor descriptor;
 197          bool didGetDescriptor = object->getOwnPropertyDescriptor(globalObject, propertyName, descriptor);
 198          RETURN_IF_EXCEPTION(scope, { });
 199  
 200          if (!didGetDescriptor)
 201              continue;
 202  
 203          JSObject* fromDescriptor = constructObjectFromPropertyDescriptor(globalObject, descriptor);
 204          scope.assertNoException();
 205          ASSERT(fromDescriptor);
 206  
 207          PutPropertySlot slot(descriptors);
 208          descriptors->putOwnDataPropertyMayBeIndex(globalObject, propertyName, fromDescriptor, slot);
 209          scope.assertNoException();
 210      }
 211  
 212      return descriptors;
 213  }
 214  
 215  JSC_DEFINE_HOST_FUNCTION(objectConstructorGetOwnPropertyDescriptor, (JSGlobalObject* globalObject, CallFrame* callFrame))
 216  {
 217      VM& vm = globalObject->vm();
 218      auto scope = DECLARE_THROW_SCOPE(vm);
 219      JSObject* object = callFrame->argument(0).toObject(globalObject);
 220      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 221      auto propertyName = callFrame->argument(1).toPropertyKey(globalObject);
 222      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 223      RELEASE_AND_RETURN(scope, JSValue::encode(objectConstructorGetOwnPropertyDescriptor(globalObject, object, propertyName)));
 224  }
 225  
 226  JSC_DEFINE_HOST_FUNCTION(objectConstructorGetOwnPropertyDescriptors, (JSGlobalObject* globalObject, CallFrame* callFrame))
 227  {
 228      VM& vm = globalObject->vm();
 229      auto scope = DECLARE_THROW_SCOPE(vm);
 230      JSObject* object = callFrame->argument(0).toObject(globalObject);
 231      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 232      RELEASE_AND_RETURN(scope, JSValue::encode(objectConstructorGetOwnPropertyDescriptors(globalObject, object)));
 233  }
 234  
 235  JSC_DEFINE_HOST_FUNCTION(objectConstructorGetOwnPropertyNames, (JSGlobalObject* globalObject, CallFrame* callFrame))
 236  {
 237      VM& vm = globalObject->vm();
 238      auto scope = DECLARE_THROW_SCOPE(vm);
 239      JSObject* object = callFrame->argument(0).toObject(globalObject);
 240      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 241      RELEASE_AND_RETURN(scope, JSValue::encode(ownPropertyKeys(globalObject, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Include, CachedPropertyNamesKind::GetOwnPropertyNames)));
 242  }
 243  
 244  // FIXME: Use the enumeration cache.
 245  JSC_DEFINE_HOST_FUNCTION(objectConstructorGetOwnPropertySymbols, (JSGlobalObject* globalObject, CallFrame* callFrame))
 246  {
 247      VM& vm = globalObject->vm();
 248      auto scope = DECLARE_THROW_SCOPE(vm);
 249      JSObject* object = callFrame->argument(0).toObject(globalObject);
 250      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 251      RELEASE_AND_RETURN(scope, JSValue::encode(ownPropertyKeys(globalObject, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include, WTF::nullopt)));
 252  }
 253  
 254  JSC_DEFINE_HOST_FUNCTION(objectConstructorKeys, (JSGlobalObject* globalObject, CallFrame* callFrame))
 255  {
 256      VM& vm = globalObject->vm();
 257      auto scope = DECLARE_THROW_SCOPE(vm);
 258      JSObject* object = callFrame->argument(0).toObject(globalObject);
 259      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 260      RELEASE_AND_RETURN(scope, JSValue::encode(ownPropertyKeys(globalObject, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude, CachedPropertyNamesKind::Keys)));
 261  }
 262  
 263  JSC_DEFINE_HOST_FUNCTION(objectConstructorAssign, (JSGlobalObject* globalObject, CallFrame* callFrame))
 264  {
 265      VM& vm = globalObject->vm();
 266      auto scope = DECLARE_THROW_SCOPE(vm);
 267  
 268      JSValue targetValue = callFrame->argument(0);
 269      if (targetValue.isUndefinedOrNull())
 270          return throwVMTypeError(globalObject, scope, "Object.assign requires that input parameter not be null or undefined"_s);
 271      JSObject* target = targetValue.toObject(globalObject);
 272      RETURN_IF_EXCEPTION(scope, { });
 273  
 274      // FIXME: Extend this for non JSFinalObject. For example, we would like to use this fast path for function objects too.
 275      // https://bugs.webkit.org/show_bug.cgi?id=185358
 276      bool targetCanPerformFastPut = jsDynamicCast<JSFinalObject*>(vm, target) && target->canPerformFastPutInlineExcludingProto(vm);
 277  
 278      Vector<RefPtr<UniquedStringImpl>, 8> properties;
 279      MarkedArgumentBuffer values;
 280      unsigned argsCount = callFrame->argumentCount();
 281      for (unsigned i = 1; i < argsCount; ++i) {
 282          JSValue sourceValue = callFrame->uncheckedArgument(i);
 283          if (sourceValue.isUndefinedOrNull())
 284              continue;
 285          JSObject* source = sourceValue.toObject(globalObject);
 286          RETURN_IF_EXCEPTION(scope, { });
 287  
 288          if (targetCanPerformFastPut) {
 289              if (!source->staticPropertiesReified(vm)) {
 290                  source->reifyAllStaticProperties(globalObject);
 291                  RETURN_IF_EXCEPTION(scope, { });
 292              }
 293  
 294              auto canPerformFastPropertyEnumerationForObjectAssign = [] (Structure* structure) {
 295                  if (structure->typeInfo().overridesGetOwnPropertySlot())
 296                      return false;
 297                  if (structure->typeInfo().overridesAnyFormOfGetOwnPropertyNames())
 298                      return false;
 299                  // FIXME: Indexed properties can be handled.
 300                  // https://bugs.webkit.org/show_bug.cgi?id=185358
 301                  if (hasIndexedProperties(structure->indexingType()))
 302                      return false;
 303                  if (structure->hasGetterSetterProperties())
 304                      return false;
 305                  if (structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto())
 306                      return false;
 307                  if (structure->hasCustomGetterSetterProperties())
 308                      return false;
 309                  if (structure->isUncacheableDictionary())
 310                      return false;
 311                  // Cannot perform fast [[Put]] to |target| if the property names of the |source| contain "__proto__".
 312                  if (structure->hasUnderscoreProtoPropertyExcludingOriginalProto())
 313                      return false;
 314                  return true;
 315              };
 316  
 317              if (canPerformFastPropertyEnumerationForObjectAssign(source->structure(vm))) {
 318                  // |source| Structure does not have any getters. And target can perform fast put.
 319                  // So enumerating properties and putting properties are non observable.
 320  
 321                  // FIXME: It doesn't seem like we should have to do this in two phases, but
 322                  // we're running into crashes where it appears that source is transitioning
 323                  // under us, and even ends up in a state where it has a null butterfly. My
 324                  // leading hypothesis here is that we fire some value replacement watchpoint
 325                  // that ends up transitioning the structure underneath us.
 326                  // https://bugs.webkit.org/show_bug.cgi?id=187837
 327  
 328                  // Do not clear since Vector::clear shrinks the backing store.
 329                  properties.resize(0);
 330                  values.clear();
 331                  source->structure(vm)->forEachProperty(vm, [&] (const PropertyMapEntry& entry) -> bool {
 332                      if (entry.attributes & PropertyAttribute::DontEnum)
 333                          return true;
 334  
 335                      PropertyName propertyName(entry.key);
 336                      if (propertyName.isPrivateName())
 337                          return true;
 338  
 339                      properties.append(entry.key);
 340                      values.appendWithCrashOnOverflow(source->getDirect(entry.offset));
 341  
 342                      return true;
 343                  });
 344  
 345                  for (size_t i = 0; i < properties.size(); ++i) {
 346                      // FIXME: We could put properties in a batching manner to accelerate Object.assign more.
 347                      // https://bugs.webkit.org/show_bug.cgi?id=185358
 348                      PutPropertySlot putPropertySlot(target, true);
 349                      target->putOwnDataProperty(vm, properties[i].get(), values.at(i), putPropertySlot);
 350                  }
 351                  continue;
 352              }
 353          }
 354  
 355          // [[GetOwnPropertyNames]], [[Get]] etc. could modify target object and invalidate this assumption.
 356          // For example, [[Get]] of source object could configure setter to target object. So disable the fast path.
 357          targetCanPerformFastPut = false;
 358  
 359          PropertyNameArray properties(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
 360          source->methodTable(vm)->getOwnPropertyNames(source, globalObject, properties, DontEnumPropertiesMode::Include);
 361          RETURN_IF_EXCEPTION(scope, { });
 362  
 363          unsigned numProperties = properties.size();
 364          for (unsigned j = 0; j < numProperties; j++) {
 365              const auto& propertyName = properties[j];
 366              ASSERT(!propertyName.isPrivateName());
 367  
 368              PropertySlot slot(source, PropertySlot::InternalMethodType::GetOwnProperty);
 369              bool hasProperty = source->methodTable(vm)->getOwnPropertySlot(source, globalObject, propertyName, slot);
 370              RETURN_IF_EXCEPTION(scope, { });
 371              if (!hasProperty)
 372                  continue;
 373              if (slot.attributes() & PropertyAttribute::DontEnum)
 374                  continue;
 375  
 376              JSValue value;
 377              if (LIKELY(!slot.isTaintedByOpaqueObject()))
 378                  value = slot.getValue(globalObject, propertyName);
 379              else
 380                  value = source->get(globalObject, propertyName);
 381              RETURN_IF_EXCEPTION(scope, { });
 382  
 383              PutPropertySlot putPropertySlot(target, true);
 384              target->putInline(globalObject, propertyName, value, putPropertySlot);
 385              RETURN_IF_EXCEPTION(scope, { });
 386          }
 387      }
 388      return JSValue::encode(target);
 389  }
 390  
 391  JSC_DEFINE_HOST_FUNCTION(objectConstructorValues, (JSGlobalObject* globalObject, CallFrame* callFrame))
 392  {
 393      VM& vm = globalObject->vm();
 394      auto scope = DECLARE_THROW_SCOPE(vm);
 395  
 396      JSValue targetValue = callFrame->argument(0);
 397      if (targetValue.isUndefinedOrNull())
 398          return throwVMTypeError(globalObject, scope, "Object.values requires that input parameter not be null or undefined"_s);
 399      JSObject* target = targetValue.toObject(globalObject);
 400      RETURN_IF_EXCEPTION(scope, { });
 401  
 402      JSArray* values = constructEmptyArray(globalObject, nullptr);
 403      RETURN_IF_EXCEPTION(scope, { });
 404  
 405      PropertyNameArray properties(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
 406      target->methodTable(vm)->getOwnPropertyNames(target, globalObject, properties, DontEnumPropertiesMode::Include);
 407      RETURN_IF_EXCEPTION(scope, { });
 408  
 409      unsigned index = 0;
 410      auto addValue = [&] (PropertyName propertyName) {
 411          PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
 412          bool hasProperty = target->methodTable(vm)->getOwnPropertySlot(target, globalObject, propertyName, slot);
 413          RETURN_IF_EXCEPTION(scope, void());
 414          if (!hasProperty)
 415              return;
 416          if (slot.attributes() & PropertyAttribute::DontEnum)
 417              return;
 418  
 419          JSValue value;
 420          if (LIKELY(!slot.isTaintedByOpaqueObject()))
 421              value = slot.getValue(globalObject, propertyName);
 422          else
 423              value = target->get(globalObject, propertyName);
 424          RETURN_IF_EXCEPTION(scope, void());
 425  
 426          values->putDirectIndex(globalObject, index++, value);
 427      };
 428  
 429      for (unsigned i = 0, numProperties = properties.size(); i < numProperties; i++) {
 430          const auto& propertyName = properties[i];
 431          if (propertyName.isSymbol())
 432              continue;
 433  
 434          addValue(propertyName);
 435          RETURN_IF_EXCEPTION(scope, { });
 436      }
 437  
 438      return JSValue::encode(values);
 439  }
 440  
 441  
 442  // ES6 6.2.4.5 ToPropertyDescriptor
 443  // https://tc39.github.io/ecma262/#sec-topropertydescriptor
 444  bool toPropertyDescriptor(JSGlobalObject* globalObject, JSValue in, PropertyDescriptor& desc)
 445  {
 446      VM& vm = globalObject->vm();
 447      auto scope = DECLARE_THROW_SCOPE(vm);
 448  
 449      if (!in.isObject()) {
 450          throwTypeError(globalObject, scope, "Property description must be an object."_s);
 451          return false;
 452      }
 453      JSObject* description = asObject(in);
 454  
 455      bool hasProperty = description->hasProperty(globalObject, vm.propertyNames->enumerable);
 456      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 457      if (hasProperty) {
 458          JSValue value = description->get(globalObject, vm.propertyNames->enumerable);
 459          RETURN_IF_EXCEPTION(scope, false);
 460          desc.setEnumerable(value.toBoolean(globalObject));
 461      } else
 462          RETURN_IF_EXCEPTION(scope, false);
 463  
 464      hasProperty = description->hasProperty(globalObject, vm.propertyNames->configurable);
 465      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 466      if (hasProperty) {
 467          JSValue value = description->get(globalObject, vm.propertyNames->configurable);
 468          RETURN_IF_EXCEPTION(scope, false);
 469          desc.setConfigurable(value.toBoolean(globalObject));
 470      } else
 471          RETURN_IF_EXCEPTION(scope, false);
 472  
 473      JSValue value;
 474      hasProperty = description->hasProperty(globalObject, vm.propertyNames->value);
 475      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 476      if (hasProperty) {
 477          JSValue value = description->get(globalObject, vm.propertyNames->value);
 478          RETURN_IF_EXCEPTION(scope, false);
 479          desc.setValue(value);
 480      } else
 481          RETURN_IF_EXCEPTION(scope, false);
 482  
 483      hasProperty = description->hasProperty(globalObject, vm.propertyNames->writable);
 484      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 485      if (hasProperty) {
 486          JSValue value = description->get(globalObject, vm.propertyNames->writable);
 487          RETURN_IF_EXCEPTION(scope, false);
 488          desc.setWritable(value.toBoolean(globalObject));
 489      } else
 490          RETURN_IF_EXCEPTION(scope, false);
 491  
 492      hasProperty = description->hasProperty(globalObject, vm.propertyNames->get);
 493      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 494      if (hasProperty) {
 495          JSValue get = description->get(globalObject, vm.propertyNames->get);
 496          RETURN_IF_EXCEPTION(scope, false);
 497          if (!get.isUndefined() && !get.isCallable(vm)) {
 498              throwTypeError(globalObject, scope, "Getter must be a function."_s);
 499              return false;
 500          }
 501          desc.setGetter(get);
 502      } else
 503          RETURN_IF_EXCEPTION(scope, false);
 504  
 505      hasProperty = description->hasProperty(globalObject, vm.propertyNames->set);
 506      EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
 507      if (hasProperty) {
 508          JSValue set = description->get(globalObject, vm.propertyNames->set);
 509          RETURN_IF_EXCEPTION(scope, false);
 510          if (!set.isUndefined() && !set.isCallable(vm)) {
 511              throwTypeError(globalObject, scope, "Setter must be a function."_s);
 512              return false;
 513          }
 514          desc.setSetter(set);
 515      } else
 516          RETURN_IF_EXCEPTION(scope, false);
 517  
 518      if (!desc.isAccessorDescriptor())
 519          return true;
 520  
 521      if (desc.value()) {
 522          throwTypeError(globalObject, scope, "Invalid property.  'value' present on property with getter or setter."_s);
 523          return false;
 524      }
 525  
 526      if (desc.writablePresent()) {
 527          throwTypeError(globalObject, scope, "Invalid property.  'writable' present on property with getter or setter."_s);
 528          return false;
 529      }
 530      return true;
 531  }
 532  
 533  JSC_DEFINE_HOST_FUNCTION(objectConstructorDefineProperty, (JSGlobalObject* globalObject, CallFrame* callFrame))
 534  {
 535      VM& vm = globalObject->vm();
 536      auto scope = DECLARE_THROW_SCOPE(vm);
 537  
 538      if (!callFrame->argument(0).isObject())
 539          return throwVMTypeError(globalObject, scope, "Properties can only be defined on Objects."_s);
 540      JSObject* obj = asObject(callFrame->argument(0));
 541      auto propertyName = callFrame->argument(1).toPropertyKey(globalObject);
 542      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 543      PropertyDescriptor descriptor;
 544      auto success = toPropertyDescriptor(globalObject, callFrame->argument(2), descriptor);
 545      EXCEPTION_ASSERT(!scope.exception() == success);
 546      if (!success)
 547          return JSValue::encode(jsNull());
 548      ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
 549      scope.assertNoException();
 550      obj->methodTable(vm)->defineOwnProperty(obj, globalObject, propertyName, descriptor, true);
 551      RELEASE_AND_RETURN(scope, JSValue::encode(obj));
 552  }
 553  
 554  static JSValue defineProperties(JSGlobalObject* globalObject, JSObject* object, JSObject* properties)
 555  {
 556      VM& vm = globalObject->vm();
 557      auto scope = DECLARE_THROW_SCOPE(vm);
 558  
 559      PropertyNameArray propertyNames(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
 560      asObject(properties)->methodTable(vm)->getOwnPropertyNames(asObject(properties), globalObject, propertyNames, DontEnumPropertiesMode::Exclude);
 561      RETURN_IF_EXCEPTION(scope, { });
 562      size_t numProperties = propertyNames.size();
 563      Vector<PropertyDescriptor> descriptors;
 564      MarkedArgumentBuffer markBuffer;
 565  #define RETURN_IF_EXCEPTION_CLEARING_OVERFLOW(value) do { \
 566      if (scope.exception()) { \
 567          markBuffer.overflowCheckNotNeeded(); \
 568          return value; \
 569      } \
 570  } while (false)
 571      for (size_t i = 0; i < numProperties; i++) {
 572          JSValue prop = properties->get(globalObject, propertyNames[i]);
 573          RETURN_IF_EXCEPTION_CLEARING_OVERFLOW({ });
 574          PropertyDescriptor descriptor;
 575          toPropertyDescriptor(globalObject, prop, descriptor);
 576          RETURN_IF_EXCEPTION_CLEARING_OVERFLOW({ });
 577          descriptors.append(descriptor);
 578          // Ensure we mark all the values that we're accumulating
 579          if (descriptor.isDataDescriptor() && descriptor.value())
 580              markBuffer.append(descriptor.value());
 581          if (descriptor.isAccessorDescriptor()) {
 582              if (descriptor.getter())
 583                  markBuffer.append(descriptor.getter());
 584              if (descriptor.setter())
 585                  markBuffer.append(descriptor.setter());
 586          }
 587      }
 588      RELEASE_ASSERT(!markBuffer.hasOverflowed());
 589  #undef RETURN_IF_EXCEPTION_CLEARING_OVERFLOW
 590      for (size_t i = 0; i < numProperties; i++) {
 591          auto& propertyName = propertyNames[i];
 592          ASSERT(!propertyName.isPrivateName());
 593  
 594          object->methodTable(vm)->defineOwnProperty(object, globalObject, propertyName, descriptors[i], true);
 595          RETURN_IF_EXCEPTION(scope, { });
 596      }
 597      return object;
 598  }
 599  
 600  JSC_DEFINE_HOST_FUNCTION(objectConstructorDefineProperties, (JSGlobalObject* globalObject, CallFrame* callFrame))
 601  {
 602      VM& vm = globalObject->vm();
 603      auto scope = DECLARE_THROW_SCOPE(vm);
 604  
 605      if (!callFrame->argument(0).isObject())
 606          return throwVMTypeError(globalObject, scope, "Properties can only be defined on Objects."_s);
 607      JSObject* targetObj = asObject(callFrame->argument(0));
 608      JSObject* props = callFrame->argument(1).toObject(globalObject);
 609      EXCEPTION_ASSERT(!!scope.exception() == !props);
 610      if (UNLIKELY(!props))
 611          return encodedJSValue();
 612      RELEASE_AND_RETURN(scope, JSValue::encode(defineProperties(globalObject, targetObj, props)));
 613  }
 614  
 615  JSC_DEFINE_HOST_FUNCTION(objectConstructorCreate, (JSGlobalObject* globalObject, CallFrame* callFrame))
 616  {
 617      VM& vm = globalObject->vm();
 618      auto scope = DECLARE_THROW_SCOPE(vm);
 619  
 620      JSValue proto = callFrame->argument(0);
 621      if (!proto.isObject() && !proto.isNull())
 622          return throwVMTypeError(globalObject, scope, "Object prototype may only be an Object or null."_s);
 623      JSObject* newObject = proto.isObject()
 624          ? constructEmptyObject(globalObject, asObject(proto))
 625          : constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
 626      if (callFrame->argument(1).isUndefined())
 627          return JSValue::encode(newObject);
 628      JSObject* properties = callFrame->uncheckedArgument(1).toObject(globalObject);
 629      RETURN_IF_EXCEPTION(scope, { });
 630  
 631      RELEASE_AND_RETURN(scope, JSValue::encode(defineProperties(globalObject, newObject, properties)));
 632  }
 633  
 634  enum class IntegrityLevel {
 635      Sealed,
 636      Frozen
 637  };
 638  
 639  template<IntegrityLevel level>
 640  bool setIntegrityLevel(JSGlobalObject* globalObject, VM& vm, JSObject* object)
 641  {
 642      // See https://tc39.github.io/ecma262/#sec-setintegritylevel.
 643      auto scope = DECLARE_THROW_SCOPE(vm);
 644  
 645      bool success = object->methodTable(vm)->preventExtensions(object, globalObject);
 646      RETURN_IF_EXCEPTION(scope, false);
 647      if (UNLIKELY(!success))
 648          return false;
 649  
 650      PropertyNameArray properties(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
 651      object->methodTable(vm)->getOwnPropertyNames(object, globalObject, properties, DontEnumPropertiesMode::Include);
 652      RETURN_IF_EXCEPTION(scope, false);
 653  
 654      PropertyNameArray::const_iterator end = properties.end();
 655      for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
 656          auto& propertyName = *iter;
 657          ASSERT(!propertyName.isPrivateName());
 658  
 659          PropertyDescriptor desc;
 660          if (level == IntegrityLevel::Sealed)
 661              desc.setConfigurable(false);
 662          else {
 663              bool hasPropertyDescriptor = object->getOwnPropertyDescriptor(globalObject, propertyName, desc);
 664              RETURN_IF_EXCEPTION(scope, false);
 665              if (!hasPropertyDescriptor)
 666                  continue;
 667  
 668              if (desc.isDataDescriptor())
 669                  desc.setWritable(false);
 670  
 671              desc.setConfigurable(false);
 672          }
 673  
 674          object->methodTable(vm)->defineOwnProperty(object, globalObject, propertyName, desc, true);
 675          RETURN_IF_EXCEPTION(scope, false);
 676      }
 677      return true;
 678  }
 679  
 680  template<IntegrityLevel level>
 681  bool testIntegrityLevel(JSGlobalObject* globalObject, VM& vm, JSObject* object)
 682  {
 683      auto scope = DECLARE_THROW_SCOPE(vm);
 684  
 685      // 1. Assert: Type(O) is Object.
 686      // 2. Assert: level is either "sealed" or "frozen".
 687  
 688      // 3. Let status be ?IsExtensible(O).
 689      bool status = object->isExtensible(globalObject);
 690      RETURN_IF_EXCEPTION(scope, { });
 691  
 692      // 4. If status is true, return false.
 693      if (status)
 694          return false;
 695  
 696      // 6. Let keys be ? O.[[OwnPropertyKeys]]().
 697      PropertyNameArray keys(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
 698      object->methodTable(vm)->getOwnPropertyNames(object, globalObject, keys, DontEnumPropertiesMode::Include);
 699      RETURN_IF_EXCEPTION(scope, { });
 700  
 701      // 7. For each element k of keys, do
 702      PropertyNameArray::const_iterator end = keys.end();
 703      for (PropertyNameArray::const_iterator iter = keys.begin(); iter != end; ++iter) {
 704          auto& propertyName = *iter;
 705          ASSERT(!propertyName.isPrivateName());
 706  
 707          // a. Let currentDesc be ? O.[[GetOwnProperty]](k)
 708          PropertyDescriptor desc;
 709          bool didGetDescriptor = object->getOwnPropertyDescriptor(globalObject, propertyName, desc);
 710          RETURN_IF_EXCEPTION(scope, { });
 711  
 712          // b. If currentDesc is not undefined, then
 713          if (!didGetDescriptor)
 714              continue;
 715  
 716          // i. If currentDesc.[[Configurable]] is true, return false.
 717          if (desc.configurable())
 718              return false;
 719  
 720          // ii. If level is "frozen" and IsDataDescriptor(currentDesc) is true, then
 721          // 1. If currentDesc.[[Writable]] is true, return false.
 722          if (level == IntegrityLevel::Frozen && desc.isDataDescriptor() && desc.writable())
 723              return false;
 724      }
 725  
 726      return true;
 727  }
 728  
 729  JSObject* objectConstructorSeal(JSGlobalObject* globalObject, JSObject* object)
 730  {
 731      VM& vm = globalObject->vm();
 732      auto scope = DECLARE_THROW_SCOPE(vm);
 733  
 734      if (jsDynamicCast<JSFinalObject*>(vm, object) && !hasIndexedProperties(object->indexingType())) {
 735          object->seal(vm);
 736          return object;
 737      }
 738  
 739      bool success = setIntegrityLevel<IntegrityLevel::Sealed>(globalObject, vm, object);
 740      RETURN_IF_EXCEPTION(scope, nullptr);
 741      if (UNLIKELY(!success)) {
 742          throwTypeError(globalObject, scope, "Unable to prevent extension in Object.seal"_s);
 743          return nullptr;
 744      }
 745  
 746      return object;
 747  }
 748  
 749  JSC_DEFINE_HOST_FUNCTION(objectConstructorSeal, (JSGlobalObject* globalObject, CallFrame* callFrame))
 750  {
 751      VM& vm = globalObject->vm();
 752      auto scope = DECLARE_THROW_SCOPE(vm);
 753  
 754      // 1. If Type(O) is not Object, return O.
 755      JSValue obj = callFrame->argument(0);
 756      if (!obj.isObject())
 757          return JSValue::encode(obj);
 758  
 759      RELEASE_AND_RETURN(scope, JSValue::encode(objectConstructorSeal(globalObject, asObject(obj))));
 760  }
 761  
 762  JSObject* objectConstructorFreeze(JSGlobalObject* globalObject, JSObject* object)
 763  {
 764      VM& vm = globalObject->vm();
 765      auto scope = DECLARE_THROW_SCOPE(vm);
 766  
 767      if (jsDynamicCast<JSFinalObject*>(vm, object) && !hasIndexedProperties(object->indexingType())) {
 768          object->freeze(vm);
 769          return object;
 770      }
 771  
 772      bool success = setIntegrityLevel<IntegrityLevel::Frozen>(globalObject, vm, object);
 773      RETURN_IF_EXCEPTION(scope, nullptr);
 774      if (UNLIKELY(!success)) {
 775          throwTypeError(globalObject, scope, "Unable to prevent extension in Object.freeze"_s);
 776          return nullptr;
 777      }
 778      return object;
 779  }
 780  
 781  JSC_DEFINE_HOST_FUNCTION(objectConstructorFreeze, (JSGlobalObject* globalObject, CallFrame* callFrame))
 782  {
 783      VM& vm = globalObject->vm();
 784      auto scope = DECLARE_THROW_SCOPE(vm);
 785      // 1. If Type(O) is not Object, return O.
 786      JSValue obj = callFrame->argument(0);
 787      if (!obj.isObject())
 788          return JSValue::encode(obj);
 789      JSObject* result = objectConstructorFreeze(globalObject, asObject(obj));
 790      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 791      return JSValue::encode(result);
 792  }
 793  
 794  JSC_DEFINE_HOST_FUNCTION(objectConstructorPreventExtensions, (JSGlobalObject* globalObject, CallFrame* callFrame))
 795  {
 796      VM& vm = globalObject->vm();
 797      auto scope = DECLARE_THROW_SCOPE(vm);
 798  
 799      JSValue argument = callFrame->argument(0);
 800      if (!argument.isObject())
 801          return JSValue::encode(argument);
 802      JSObject* object = asObject(argument);
 803      bool status = object->methodTable(vm)->preventExtensions(object, globalObject);
 804      RETURN_IF_EXCEPTION(scope, { });
 805      if (UNLIKELY(!status))
 806          return throwVMTypeError(globalObject, scope, "Unable to prevent extension in Object.preventExtensions"_s);
 807      return JSValue::encode(object);
 808  }
 809  
 810  JSC_DEFINE_HOST_FUNCTION(objectConstructorIsSealed, (JSGlobalObject* globalObject, CallFrame* callFrame))
 811  {
 812      VM& vm = globalObject->vm();
 813  
 814      // 1. If Type(O) is not Object, return true.
 815      JSValue obj = callFrame->argument(0);
 816      if (!obj.isObject())
 817          return JSValue::encode(jsBoolean(true));
 818      JSObject* object = asObject(obj);
 819  
 820      // Quick check for final objects.
 821      if (jsDynamicCast<JSFinalObject*>(vm, object) && !hasIndexedProperties(object->indexingType()))
 822          return JSValue::encode(jsBoolean(object->isSealed(vm)));
 823  
 824      // 2. Return ? TestIntegrityLevel(O, "sealed").
 825      return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Sealed>(globalObject, vm, object)));
 826  }
 827  
 828  JSC_DEFINE_HOST_FUNCTION(objectConstructorIsFrozen, (JSGlobalObject* globalObject, CallFrame* callFrame))
 829  {
 830      VM& vm = globalObject->vm();
 831  
 832      // 1. If Type(O) is not Object, return true.
 833      JSValue obj = callFrame->argument(0);
 834      if (!obj.isObject())
 835          return JSValue::encode(jsBoolean(true));
 836      JSObject* object = asObject(obj);
 837  
 838      // Quick check for final objects.
 839      if (jsDynamicCast<JSFinalObject*>(vm, object) && !hasIndexedProperties(object->indexingType()))
 840          return JSValue::encode(jsBoolean(object->isFrozen(vm)));
 841  
 842      // 2. Return ? TestIntegrityLevel(O, "frozen").
 843      return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Frozen>(globalObject, vm, object)));
 844  }
 845  
 846  JSC_DEFINE_HOST_FUNCTION(objectConstructorIsExtensible, (JSGlobalObject* globalObject, CallFrame* callFrame))
 847  {
 848      VM& vm = globalObject->vm();
 849      auto scope = DECLARE_THROW_SCOPE(vm);
 850      JSValue obj = callFrame->argument(0);
 851      if (!obj.isObject())
 852          return JSValue::encode(jsBoolean(false));
 853      JSObject* object = asObject(obj);
 854      bool isExtensible = object->isExtensible(globalObject);
 855      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 856      return JSValue::encode(jsBoolean(isExtensible));
 857  }
 858  
 859  JSC_DEFINE_HOST_FUNCTION(objectConstructorIs, (JSGlobalObject* globalObject, CallFrame* callFrame))
 860  {
 861      return JSValue::encode(jsBoolean(sameValue(globalObject, callFrame->argument(0), callFrame->argument(1))));
 862  }
 863  
 864  JSArray* ownPropertyKeys(JSGlobalObject* globalObject, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode, Optional<CachedPropertyNamesKind> kind)
 865  {
 866      VM& vm = globalObject->vm();
 867      auto scope = DECLARE_THROW_SCOPE(vm);
 868  
 869      // We attempt to look up own property keys cache in Object.keys / Object.getOwnPropertyNames cases.
 870      if (kind) {
 871          if (LIKELY(!globalObject->isHavingABadTime())) {
 872              if (auto* immutableButterfly = object->structure(vm)->cachedPropertyNames(kind.value())) {
 873                  Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode());
 874                  return JSArray::createWithButterfly(vm, nullptr, arrayStructure, immutableButterfly->toButterfly());
 875              }
 876          }
 877      }
 878  
 879      PropertyNameArray properties(vm, propertyNameMode, PrivateSymbolMode::Exclude);
 880      object->methodTable(vm)->getOwnPropertyNames(object, globalObject, properties, dontEnumPropertiesMode);
 881      RETURN_IF_EXCEPTION(scope, nullptr);
 882  
 883      if (propertyNameMode != PropertyNameMode::StringsAndSymbols) {
 884          ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols);
 885          if (properties.size() < MIN_SPARSE_ARRAY_INDEX) {
 886              if (LIKELY(!globalObject->isHavingABadTime())) {
 887                  if (kind) {
 888                      Structure* structure = object->structure(vm);
 889                      if (structure->canCacheOwnPropertyNames()) {
 890                          auto* cachedButterfly = structure->cachedPropertyNamesIgnoringSentinel(kind.value());
 891                          if (cachedButterfly == StructureRareData::cachedPropertyNamesSentinel()) {
 892                              size_t numProperties = properties.size();
 893                              auto* newButterfly = JSImmutableButterfly::create(vm, CopyOnWriteArrayWithContiguous, numProperties);
 894                              for (size_t i = 0; i < numProperties; i++) {
 895                                  const auto& identifier = properties[i];
 896                                  ASSERT(!identifier.isSymbol());
 897                                  newButterfly->setIndex(vm, i, jsOwnedString(vm, identifier.string()));
 898                              }
 899  
 900                              structure->setCachedPropertyNames(vm, kind.value(), newButterfly);
 901                              Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(newButterfly->indexingMode());
 902                              return JSArray::createWithButterfly(vm, nullptr, arrayStructure, newButterfly->toButterfly());
 903                          }
 904  
 905                          if (cachedButterfly == nullptr)
 906                              structure->setCachedPropertyNames(vm, kind.value(), StructureRareData::cachedPropertyNamesSentinel());
 907                      }
 908                  }
 909  
 910                  size_t numProperties = properties.size();
 911                  // FIXME: We should probably be calling tryCreate here:
 912                  // https://bugs.webkit.org/show_bug.cgi?id=221984
 913                  JSArray* keys = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), numProperties);
 914                  WriteBarrier<Unknown>* buffer = keys->butterfly()->contiguous().data();
 915                  for (size_t i = 0; i < numProperties; i++) {
 916                      const auto& identifier = properties[i];
 917                      if (propertyNameMode == PropertyNameMode::Strings) {
 918                          ASSERT(!identifier.isSymbol());
 919                          buffer[i].set(vm, keys, jsOwnedString(vm, identifier.string()));
 920                      } else {
 921                          ASSERT(identifier.isSymbol());
 922                          buffer[i].set(vm, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
 923                      }
 924                  }
 925                  return keys;
 926              }
 927          }
 928      }
 929  
 930      JSArray* keys = constructEmptyArray(globalObject, nullptr);
 931      RETURN_IF_EXCEPTION(scope, nullptr);
 932  
 933      unsigned index = 0;
 934      auto pushDirect = [&] (JSGlobalObject* globalObject, JSArray* array, JSValue value) {
 935          array->putDirectIndex(globalObject, index++, value);
 936      };
 937  
 938      switch (propertyNameMode) {
 939      case PropertyNameMode::Strings: {
 940          size_t numProperties = properties.size();
 941          for (size_t i = 0; i < numProperties; i++) {
 942              const auto& identifier = properties[i];
 943              ASSERT(!identifier.isSymbol());
 944              pushDirect(globalObject, keys, jsOwnedString(vm, identifier.string()));
 945              RETURN_IF_EXCEPTION(scope, nullptr);
 946          }
 947          break;
 948      }
 949  
 950      case PropertyNameMode::Symbols: {
 951          size_t numProperties = properties.size();
 952          for (size_t i = 0; i < numProperties; i++) {
 953              const auto& identifier = properties[i];
 954              ASSERT(identifier.isSymbol());
 955              ASSERT(!identifier.isPrivateName());
 956              pushDirect(globalObject, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
 957              RETURN_IF_EXCEPTION(scope, nullptr);
 958          }
 959          break;
 960      }
 961  
 962      case PropertyNameMode::StringsAndSymbols: {
 963          size_t numProperties = properties.size();
 964          for (size_t i = 0; i < numProperties; i++) {
 965              const auto& identifier = properties[i];
 966              if (identifier.isSymbol()) {
 967                  ASSERT(!identifier.isPrivateName());
 968                  pushDirect(globalObject, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
 969              } else
 970                  pushDirect(globalObject, keys, jsOwnedString(vm, identifier.string()));
 971              RETURN_IF_EXCEPTION(scope, nullptr);
 972          }
 973          break;
 974      }
 975      }
 976  
 977      return keys;
 978  }
 979  
 980  JSObject* constructObjectFromPropertyDescriptorSlow(JSGlobalObject* globalObject, const PropertyDescriptor& descriptor)
 981  {
 982      VM& vm = getVM(globalObject);
 983  
 984      JSObject* result = constructEmptyObject(globalObject);
 985  
 986      if (descriptor.value())
 987          result->putDirect(vm, vm.propertyNames->value, descriptor.value());
 988      if (descriptor.writablePresent())
 989          result->putDirect(vm, vm.propertyNames->writable, jsBoolean(descriptor.writable()));
 990      if (descriptor.getterPresent())
 991          result->putDirect(vm, vm.propertyNames->get, descriptor.getter());
 992      if (descriptor.setterPresent())
 993          result->putDirect(vm, vm.propertyNames->set, descriptor.setter());
 994      if (descriptor.enumerablePresent())
 995          result->putDirect(vm, vm.propertyNames->enumerable, jsBoolean(descriptor.enumerable()));
 996      if (descriptor.configurablePresent())
 997          result->putDirect(vm, vm.propertyNames->configurable, jsBoolean(descriptor.configurable()));
 998  
 999      return result;
1000  }
1001  
1002  } // namespace JSC