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