/* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003-2020 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel (eric@webkit.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #pragma once #include "AuxiliaryBarrierInlines.h" #include "ButterflyInlines.h" #include "Error.h" #include "JSFunction.h" #include "JSObject.h" #include "JSTypedArrays.h" #include "Lookup.h" #include "StructureInlines.h" #include "TypedArrayType.h" namespace JSC { template CompleteSubspace* JSFinalObject::subspaceFor(VM& vm) { static_assert(!CellType::needsDestruction); return &vm.cellSpace; } // Section 7.3.17 of the spec. template // Add function should have a type like: (JSValue, RuntimeType) -> bool void createListFromArrayLike(JSGlobalObject* globalObject, JSValue arrayLikeValue, RuntimeTypeMask legalTypesFilter, const String& notAnObjectErroMessage, const String& illegalTypeErrorMessage, AddFunction addFunction) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); if (!arrayLikeValue.isObject()) { throwTypeError(globalObject, scope, notAnObjectErroMessage); return; } Vector result; JSValue lengthProperty = arrayLikeValue.get(globalObject, vm.propertyNames->length); RETURN_IF_EXCEPTION(scope, void()); double lengthAsDouble = lengthProperty.toLength(globalObject); RETURN_IF_EXCEPTION(scope, void()); RELEASE_ASSERT(lengthAsDouble >= 0.0 && lengthAsDouble == std::trunc(lengthAsDouble)); uint64_t length = static_cast(lengthAsDouble); for (uint64_t index = 0; index < length; index++) { JSValue next = arrayLikeValue.get(globalObject, index); RETURN_IF_EXCEPTION(scope, void()); RuntimeType type = runtimeTypeForValue(vm, next); if (!(type & legalTypesFilter)) { throwTypeError(globalObject, scope, illegalTypeErrorMessage); return; } bool exitEarly = addFunction(next, type); if (exitEarly) return; } } ALWAYS_INLINE bool JSObject::canPerformFastPutInlineExcludingProto(VM& vm) { // Check if there are any setters or getters in the prototype chain JSValue prototype; JSObject* obj = this; while (true) { Structure* structure = obj->structure(vm); if (structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || structure->typeInfo().overridesGetPrototype()) return false; prototype = obj->getPrototypeDirect(vm); if (prototype.isNull()) return true; obj = asObject(prototype); } ASSERT_NOT_REACHED(); } ALWAYS_INLINE bool JSObject::canPerformFastPutInline(VM& vm, PropertyName propertyName) { if (UNLIKELY(propertyName == vm.propertyNames->underscoreProto)) return false; return canPerformFastPutInlineExcludingProto(vm); } template ALWAYS_INLINE typename std::result_of::type JSObject::getPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, CallbackWhenNoException callback) const { PropertySlot slot(this, PropertySlot::InternalMethodType::Get); return getPropertySlot(globalObject, propertyName, slot, callback); } template ALWAYS_INLINE typename std::result_of::type JSObject::getPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot, CallbackWhenNoException callback) const { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); bool found = const_cast(this)->getPropertySlot(globalObject, propertyName, slot); RETURN_IF_EXCEPTION(scope, { }); RELEASE_AND_RETURN(scope, callback(found, slot)); } ALWAYS_INLINE bool JSObject::getPropertySlot(JSGlobalObject* globalObject, unsigned propertyName, PropertySlot& slot) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); auto& structureIDTable = vm.heap.structureIDTable(); JSObject* object = this; while (true) { Structure* structure = structureIDTable.get(object->structureID()); bool hasSlot = structure->classInfo()->methodTable.getOwnPropertySlotByIndex(object, globalObject, propertyName, slot); RETURN_IF_EXCEPTION(scope, false); if (hasSlot) return true; if (UNLIKELY(slot.isVMInquiry() && slot.isTaintedByOpaqueObject())) return false; if (object->type() == ProxyObjectType && slot.internalMethodType() == PropertySlot::InternalMethodType::HasProperty) return false; if (isTypedArrayType(object->type()) && propertyName >= jsCast(object)->length()) return false; JSValue prototype; if (LIKELY(!structure->typeInfo().overridesGetPrototype() || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry)) prototype = object->getPrototypeDirect(vm); else { prototype = object->getPrototype(vm, globalObject); RETURN_IF_EXCEPTION(scope, false); } if (!prototype.isObject()) return false; object = asObject(prototype); } } ALWAYS_INLINE bool JSObject::getPropertySlot(JSGlobalObject* globalObject, uint64_t propertyName, PropertySlot& slot) { if (LIKELY(propertyName <= MAX_ARRAY_INDEX)) return getPropertySlot(globalObject, static_cast(propertyName), slot); return getPropertySlot(globalObject, Identifier::from(globalObject->vm(), propertyName), slot); } ALWAYS_INLINE bool JSObject::getNonIndexPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { // This method only supports non-index PropertyNames. ASSERT(!parseIndex(propertyName)); VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); auto& structureIDTable = vm.heap.structureIDTable(); JSObject* object = this; while (true) { Structure* structure = structureIDTable.get(object->structureID()); if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) { if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot)) return true; } else { bool hasSlot = structure->classInfo()->methodTable.getOwnPropertySlot(object, globalObject, propertyName, slot); RETURN_IF_EXCEPTION(scope, false); if (hasSlot) return true; if (UNLIKELY(slot.isVMInquiry() && slot.isTaintedByOpaqueObject())) return false; if (object->type() == ProxyObjectType && slot.internalMethodType() == PropertySlot::InternalMethodType::HasProperty) return false; if (isTypedArrayType(object->type()) && isCanonicalNumericIndexString(propertyName)) return false; } JSValue prototype; if (LIKELY(!structure->typeInfo().overridesGetPrototype() || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry)) prototype = object->getPrototypeDirect(vm); else { prototype = object->getPrototype(vm, globalObject); RETURN_IF_EXCEPTION(scope, false); } if (!prototype.isObject()) return false; object = asObject(prototype); } } inline bool JSObject::getOwnPropertySlotInline(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { VM& vm = getVM(globalObject); if (UNLIKELY(TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags()))) return methodTable(vm)->getOwnPropertySlot(this, globalObject, propertyName, slot); return JSObject::getOwnPropertySlot(this, globalObject, propertyName, slot); } inline bool JSObject::mayInterceptIndexedAccesses(VM& vm) { return structure(vm)->mayInterceptIndexedAccesses(); } inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor)); ASSERT(!value.isCustomGetterSetter()); StructureID structureID = this->structureID(); Structure* structure = vm.heap.structureIDTable().get(structureID); PropertyOffset offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure); putDirect(vm, offset, value); if (attributes & PropertyAttribute::ReadOnly) structure->setContainsReadOnlyProperties(); } ALWAYS_INLINE PropertyOffset JSObject::prepareToPutDirectWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, StructureID structureID, Structure* structure) { unsigned oldOutOfLineCapacity = structure->outOfLineCapacity(); PropertyOffset result; structure->addPropertyWithoutTransition( vm, propertyName, attributes, [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) { unsigned newOutOfLineCapacity = Structure::outOfLineCapacity(newMaxOffset); if (newOutOfLineCapacity != oldOutOfLineCapacity) { Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity); nukeStructureAndSetButterfly(vm, structureID, butterfly); structure->setMaxOffset(vm, newMaxOffset); WTF::storeStoreFence(); setStructureIDDirectly(structureID); } else structure->setMaxOffset(vm, newMaxOffset); // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC // is running at the same time we put without transitioning. ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset))); result = offset; }); return result; } // ECMA 8.6.2.2 ALWAYS_INLINE bool JSObject::putInlineForJSObject(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsCast(cell); ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); if (UNLIKELY(isThisValueAltered(slot, thisObject))) RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode())); // Try indexed put first. This is required for correctness, since loads on property names that appear like // valid indices will never look in the named property storage. if (Optional index = parseIndex(propertyName)) RELEASE_AND_RETURN(scope, putByIndex(thisObject, globalObject, index.value(), value, slot.isStrictMode())); if (thisObject->canPerformFastPutInline(vm, propertyName)) { ASSERT(!thisObject->prototypeChainMayInterceptStoreTo(vm, propertyName)); if (!thisObject->putDirectInternal(vm, propertyName, value, 0, slot)) return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError); return true; } RELEASE_AND_RETURN(scope, thisObject->putInlineSlow(globalObject, propertyName, value, slot)); } // HasOwnProperty(O, P) from section 7.3.11 in the spec. // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) const { VM& vm = getVM(globalObject); ASSERT(slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty); if (LIKELY(const_cast(this)->methodTable(vm)->getOwnPropertySlot == JSObject::getOwnPropertySlot)) return JSObject::getOwnPropertySlot(const_cast(this), globalObject, propertyName, slot); return const_cast(this)->methodTable(vm)->getOwnPropertySlot(const_cast(this), globalObject, propertyName, slot); } ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, PropertyName propertyName) const { PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty); return hasOwnProperty(globalObject, propertyName, slot); } ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, unsigned propertyName) const { PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty); return const_cast(this)->methodTable(getVM(globalObject))->getOwnPropertySlotByIndex(const_cast(this), globalObject, propertyName, slot); } template ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot) { ASSERT(value); ASSERT(value.isGetterSetter() == !!(attributes & PropertyAttribute::Accessor)); ASSERT(value.isCustomGetterSetter() == !!(attributes & PropertyAttribute::CustomAccessorOrValue)); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); ASSERT(!parseIndex(propertyName)); StructureID structureID = this->structureID(); Structure* structure = vm.heap.structureIDTable().get(structureID); if (structure->isDictionary()) { ASSERT(!isCopyOnWrite(indexingMode())); unsigned currentAttributes; PropertyOffset offset = structure->get(vm, propertyName, currentAttributes); if (offset != invalidOffset) { if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly) return false; putDirect(vm, offset, value); structure->didReplaceProperty(offset); // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition. // https://bugs.webkit.org/show_bug.cgi?id=214342 if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes)); else slot.setExistingProperty(this, offset); return true; } if ((mode == PutModePut) && !isStructureExtensible(vm)) return false; offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure); validateOffset(offset); putDirect(vm, offset, value); slot.setNewProperty(this, offset); if (attributes & PropertyAttribute::ReadOnly) this->structure(vm)->setContainsReadOnlyProperties(); return true; } PropertyOffset offset; size_t currentCapacity = this->structure(vm)->outOfLineCapacity(); Structure* newStructure = Structure::addPropertyTransitionToExistingStructure( structure, propertyName, attributes, offset); if (newStructure) { Butterfly* newButterfly = butterfly(); if (currentCapacity != newStructure->outOfLineCapacity()) { ASSERT(newStructure != this->structure(vm)); newButterfly = allocateMoreOutOfLineStorage(vm, currentCapacity, newStructure->outOfLineCapacity()); nukeStructureAndSetButterfly(vm, structureID, newButterfly); } validateOffset(offset); ASSERT(newStructure->isValidOffset(offset)); // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC // is running at the same time we put without transitioning. ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset))); putDirect(vm, offset, value); setStructure(vm, newStructure); slot.setNewProperty(this, offset); return true; } // We want the structure transition watchpoint to fire after this object has switched structure. // This allows adaptive watchpoints to observe if the new structure is the one we want. DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure); unsigned currentAttributes; offset = structure->get(vm, propertyName, currentAttributes); if (offset != invalidOffset) { if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly) return false; structure->didReplaceProperty(offset); putDirect(vm, offset, value); // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition. // https://bugs.webkit.org/show_bug.cgi?id=214342 if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes, &deferredWatchpointFire)); else slot.setExistingProperty(this, offset); return true; } if ((mode == PutModePut) && !isStructureExtensible(vm)) return false; newStructure = Structure::addNewPropertyTransition( vm, structure, propertyName, attributes, offset, slot.context(), &deferredWatchpointFire); validateOffset(offset); ASSERT(newStructure->isValidOffset(offset)); size_t oldCapacity = structure->outOfLineCapacity(); size_t newCapacity = newStructure->outOfLineCapacity(); ASSERT(oldCapacity <= newCapacity); if (oldCapacity != newCapacity) { Butterfly* newButterfly = allocateMoreOutOfLineStorage(vm, oldCapacity, newCapacity); nukeStructureAndSetButterfly(vm, structureID, newButterfly); } // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC // is running at the same time we put without transitioning. ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset))); putDirect(vm, offset, value); setStructure(vm, newStructure); slot.setNewProperty(this, offset); if (attributes & PropertyAttribute::ReadOnly) newStructure->setContainsReadOnlyProperties(); return true; } inline bool JSObject::mayBePrototype() const { return perCellBit(); } inline void JSObject::didBecomePrototype() { setPerCellBit(true); } inline bool JSObject::canGetIndexQuicklyForTypedArray(unsigned i) const { switch (type()) { #define CASE_TYPED_ARRAY_TYPE(name) \ case name ## ArrayType :\ return jsCast(this)->canGetIndexQuickly(i); FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE) #undef CASE_TYPED_ARRAY_TYPE default: return false; } } inline bool JSObject::canSetIndexQuicklyForTypedArray(unsigned i, JSValue value) const { switch (type()) { #define CASE_TYPED_ARRAY_TYPE(name) \ case name ## ArrayType :\ return jsCast(this)->canSetIndexQuickly(i, value); FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE) #undef CASE_TYPED_ARRAY_TYPE default: return false; } } inline JSValue JSObject::getIndexQuicklyForTypedArray(unsigned i) const { switch (type()) { #define CASE_TYPED_ARRAY_TYPE(name) \ case name ## ArrayType : {\ auto* typedArray = jsCast(this);\ RELEASE_ASSERT(typedArray->canGetIndexQuickly(i));\ return typedArray->getIndexQuickly(i);\ } FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE) #undef CASE_TYPED_ARRAY_TYPE default: RELEASE_ASSERT_NOT_REACHED(); return JSValue(); } } inline void JSObject::setIndexQuicklyForTypedArray(unsigned i, JSValue value) { switch (type()) { #define CASE_TYPED_ARRAY_TYPE(name) \ case name ## ArrayType : {\ auto* typedArray = jsCast(this);\ RELEASE_ASSERT(typedArray->canSetIndexQuickly(i, value));\ typedArray->setIndexQuickly(i, value);\ break;\ } FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE) #undef CASE_TYPED_ARRAY_TYPE default: RELEASE_ASSERT_NOT_REACHED(); return; } } inline void JSObject::validatePutOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value) { #if ASSERT_ENABLED ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); unsigned attributes; PropertyOffset offset = structure(vm)->get(vm, propertyName, attributes); if (isValidOffset(offset)) ASSERT(!(attributes & (PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly))); else if (TypeInfo::hasStaticPropertyTable(inlineTypeFlags())) { if (auto entry = findPropertyHashEntry(vm, propertyName)) ASSERT(!(entry->value->attributes() & (PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly))); } #else // not ASSERT_ENABLED UNUSED_PARAM(vm); UNUSED_PARAM(propertyName); UNUSED_PARAM(value); #endif // not ASSERT_ENABLED } inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { validatePutOwnDataProperty(vm, propertyName, value); return putDirectInternal(vm, propertyName, value, 0, slot); } inline bool JSObject::putOwnDataPropertyMayBeIndex(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { VM& vm = getVM(globalObject); validatePutOwnDataProperty(vm, propertyName, value); if (Optional index = parseIndex(propertyName)) return putDirectIndex(globalObject, index.value(), value, 0, PutDirectIndexLikePutDirect); return putDirectInternal(vm, propertyName, value, 0, slot); } inline CallData getCallData(VM& vm, JSValue value) { if (!value.isCell()) return { }; JSCell* cell = value.asCell(); if (cell->type() == JSFunctionType) return JSFunction::getCallData(cell); CallData result = cell->methodTable(vm)->getCallData(cell); ASSERT(result.type == CallData::Type::None || value.isValidCallee()); return result; } inline CallData getConstructData(VM& vm, JSValue value) { if (!value.isCell()) return { }; JSCell* cell = value.asCell(); if (cell->type() == JSFunctionType) return JSFunction::getConstructData(cell); CallData result = cell->methodTable(vm)->getConstructData(cell); ASSERT(result.type == CallData::Type::None || value.isValidCallee()); return result; } inline bool JSObject::deleteProperty(JSGlobalObject* globalObject, PropertyName propertyName) { DeletePropertySlot slot; return this->methodTable(globalObject->vm())->deleteProperty(this, globalObject, propertyName, slot); } inline bool JSObject::deleteProperty(JSGlobalObject* globalObject, uint32_t propertyName) { return this->methodTable(globalObject->vm())->deletePropertyByIndex(this, globalObject, propertyName); } inline bool JSObject::deleteProperty(JSGlobalObject* globalObject, uint64_t propertyName) { if (LIKELY(propertyName <= MAX_ARRAY_INDEX)) return deleteProperty(globalObject, static_cast(propertyName)); ASSERT(propertyName <= maxSafeInteger()); return deleteProperty(globalObject, Identifier::from(globalObject->vm(), propertyName)); } inline JSValue JSObject::get(JSGlobalObject* globalObject, uint64_t propertyName) const { if (LIKELY(propertyName <= MAX_ARRAY_INDEX)) return get(globalObject, static_cast(propertyName)); ASSERT(propertyName <= maxSafeInteger()); return get(globalObject, Identifier::from(globalObject->vm(), propertyName)); } JSObject* createInvalidPrivateNameError(JSGlobalObject*); JSObject* createRedefinedPrivateNameError(JSGlobalObject*); ALWAYS_INLINE bool JSObject::getPrivateFieldSlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { ASSERT(propertyName.isPrivateName()); VM& vm = getVM(globalObject); Structure* structure = object->structure(vm); unsigned attributes; PropertyOffset offset = structure->get(vm, propertyName, attributes); if (offset == invalidOffset) return false; JSValue value = object->getDirect(offset); #if ASSERT_ENABLED ASSERT(value); if (value.isCell()) { JSCell* cell = value.asCell(); JSType type = cell->type(); UNUSED_PARAM(cell); ASSERT_UNUSED(type, type != GetterSetterType && type != CustomGetterSetterType); // FIXME: For now, private fields do not support getter/setter fields. Later on, we will need to fill in accessor metadata here, // as in JSObject::getOwnNonIndexPropertySlot() // https://bugs.webkit.org/show_bug.cgi?id=194435 } #endif slot.setValue(object, attributes, value, offset); return true; } inline bool JSObject::getPrivateField(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); ASSERT(!slot.isVMInquiry()); if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) { throwException(globalObject, scope, createInvalidPrivateNameError(globalObject)); RELEASE_AND_RETURN(scope, false); } EXCEPTION_ASSERT(!scope.exception()); RELEASE_AND_RETURN(scope, true); } inline void JSObject::setPrivateField(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& putSlot) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty); if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) { throwException(globalObject, scope, createInvalidPrivateNameError(globalObject)); RELEASE_AND_RETURN(scope, void()); } EXCEPTION_ASSERT(!scope.exception()); scope.release(); putDirect(vm, propertyName, value, putSlot); } inline void JSObject::definePrivateField(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& putSlot) { VM& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty); if (JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) { throwException(globalObject, scope, createRedefinedPrivateNameError(globalObject)); RELEASE_AND_RETURN(scope, void()); } EXCEPTION_ASSERT(!scope.exception()); scope.release(); putDirect(vm, propertyName, value, putSlot); } } // namespace JSC