void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { JSValue object = getDirect(propertyName); if (object && object.isGetterSetter()) { ASSERT(m_structure->hasGetterSetterProperties()); asGetterSetter(object)->setSetter(setterFunction); return; } PutPropertySlot slot; GetterSetter* getterSetter = new (exec) GetterSetter(exec); putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. if (slot.type() != PutPropertySlot::NewProperty) { if (!m_structure->isDictionary()) { RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); setStructure(structure.release()); } } m_structure->setHasGetterSetterProperties(true); getterSetter->setSetter(setterFunction); }
void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) { JSValue* object = getDirect(propertyName); if (object && object->isGetterSetter()) { ASSERT(m_structureID->hasGetterSetterProperties()); asGetterSetter(object)->setSetter(setterFunction); return; } PutPropertySlot slot; GetterSetter* getterSetter = new (exec) GetterSetter; putDirect(propertyName, getterSetter, None, true, slot); // putDirect will change our StructureID if we add a new property. For // getters and setters, though, we also need to change our StructureID // if we override an existing non-getter or non-setter. if (slot.type() != PutPropertySlot::NewProperty) { if (!m_structureID->isDictionary()) { RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID); setStructureID(structureID.release()); } } m_structureID->setHasGetterSetterProperties(true); getterSetter->setSetter(setterFunction); }
void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode() ? regExpObjectSetLastIndexStrict : regExpObjectSetLastIndexNonStrict); return; } Base::put(cell, exec, propertyName, value, slot); }
bool JSArrayBuffer::put( JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(cell); if (UNLIKELY(isThisValueAltered(slot, thisObject))) return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()); if (propertyName == exec->propertyNames().byteLength) return reject(exec, slot.isStrictMode(), "Attempting to write to a read-only array buffer property."); return Base::put(thisObject, exec, propertyName, value, slot); }
void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSFunction* thisObject = jsCast<JSFunction*>(cell); if (thisObject->isHostFunction()) { Base::put(thisObject, exec, propertyName, value, slot); return; } if (propertyName == exec->propertyNames().prototype) { // Make sure prototype has been reified, such that it can only be overwritten // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); thisObject->m_allocationProfile.clear(); thisObject->m_allocationProfileWatchpoint.notifyWrite(); // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile. PutPropertySlot dontCache; Base::put(thisObject, exec, propertyName, value, dontCache); return; } if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) { // This will trigger the property to be reified, if this is not already the case! bool okay = thisObject->hasProperty(exec, propertyName); ASSERT_UNUSED(okay, okay); Base::put(thisObject, exec, propertyName, value, slot); return; } if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name || propertyName == exec->propertyNames().caller) { if (slot.isStrictMode()) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return; } Base::put(thisObject, exec, propertyName, value, slot); }
bool RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { RegExpObject* thisObject = jsCast<RegExpObject*>(cell); if (UNLIKELY(isThisValueAltered(slot, thisObject))) return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()); if (propertyName == exec->propertyNames().lastIndex) { bool result = asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); slot.setCustomValue(asRegExpObject(cell), slot.isStrictMode() ? regExpObjectSetLastIndexStrict : regExpObjectSetLastIndexNonStrict); return result; } return Base::put(cell, exec, propertyName, value, slot); }
bool StringObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); StringObject* thisObject = jsCast<StringObject*>(cell); if (UNLIKELY(isThisValueAltered(slot, thisObject))) return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()); if (propertyName == vm.propertyNames->length) return typeError(exec, scope, slot.isStrictMode(), ASCIILiteral(ReadonlyPropertyWriteError)); if (Optional<uint32_t> index = parseIndex(propertyName)) return putByIndex(cell, exec, index.value(), value, slot.isStrictMode()); return JSObject::put(cell, exec, propertyName, value, slot); }
void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); return; } lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot); }
void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; Base::put(thisObject, exec, propertyName, value, slot); }
void StringObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().length) { if (slot.isStrictMode()) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return; } JSObject::put(cell, exec, propertyName, value, slot); }
void DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { DebuggerScope* scope = jsCast<DebuggerScope*>(cell); ASSERT(scope->isValid()); if (!scope->isValid()) return; JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); slot.setThisValue(JSValue(thisObject)); thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot); }
bool JSArrayBufferView::put( JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell); if (UNLIKELY(isThisValueAltered(slot, thisObject))) return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()); return Base::put(thisObject, exec, propertyName, value, slot); }
void JSDataView::put( JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSDataView* thisObject = jsCast<JSDataView*>(cell); if (propertyName == exec->propertyNames().byteLength || propertyName == exec->propertyNames().byteOffset) { reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property."); return; } Base::put(thisObject, exec, propertyName, value, slot); }
void JSArrayBuffer::put( JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(cell); if (propertyName == exec->propertyNames().byteLength) { reject(exec, slot.isStrictMode(), "Attempting to write to a read-only array buffer property."); return; } Base::put(thisObject, exec, propertyName, value, slot); }
void JSNameScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSNameScope* thisObject = jsCast<JSNameScope*>(cell); if (slot.isStrictMode()) { // Double lookup in strict mode, but this only occurs when // a) indirectly writing to an exception slot // b) writing to a function expression name // (a) is unlikely, and (b) is an error. // Also with a single entry the symbol table lookup should simply be // a pointer compare. PropertySlot slot; bool isWritable = true; symbolTableGet(thisObject, propertyName, slot, isWritable); if (!isWritable) { throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); return; } } if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; RELEASE_ASSERT_NOT_REACHED(); }
void JSLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(cell); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) return; // We don't call through to JSObject because __proto__ and getter/setter // properties are non-standard extensions that other implementations do not // expose in the lexicalEnvironment object. ASSERT(!thisObject->hasGetterSetterProperties()); thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); }
// ECMA 8.7.2 bool JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (Optional<uint32_t> index = parseIndex(propertyName)) return putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode()); // Check if there are any setters or getters in the prototype chain JSObject* obj = synthesizePrototype(exec); if (UNLIKELY(!obj)) return false; JSValue prototype; if (propertyName != exec->propertyNames().underscoreProto) { for (; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { prototype = obj->getPrototypeDirect(); if (prototype.isNull()) { if (slot.isStrictMode()) throwTypeError(exec, scope, StrictModeReadonlyPropertyWriteError); return false; } } } for (; ; obj = asObject(prototype)) { unsigned attributes; PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes); if (offset != invalidOffset) { if (attributes & ReadOnly) { if (slot.isStrictMode()) throwTypeError(exec, scope, StrictModeReadonlyPropertyWriteError); return false; } JSValue gs = obj->getDirect(offset); if (gs.isGetterSetter()) return callSetter(exec, *this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode); if (gs.isCustomGetterSetter()) return callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value); // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; } prototype = obj->getPrototype(vm, exec); if (vm.exception()) return false; if (prototype.isNull()) break; } if (slot.isStrictMode()) throwTypeError(exec, scope, StrictModeReadonlyPropertyWriteError); return false; }
// ECMA 15.4.5.1 void JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSArray* thisObject = jsCast<JSArray*>(cell); if (propertyName == exec->propertyNames().length) { unsigned newLength = value.toUInt32(exec); if (value.toNumber(exec) != static_cast<double>(newLength)) { exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); return; } thisObject->setLength(exec, newLength, slot.isStrictMode()); return; } JSObject::put(thisObject, exec, propertyName, value, slot); }
bool JSLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(cell); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); bool shouldThrowReadOnlyError = slot.isStrictMode() || thisObject->isLexicalScope(); bool ignoreReadOnlyErrors = false; bool putResult = false; if (symbolTablePutInvalidateWatchpointSet(thisObject, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult)) return putResult; // We don't call through to JSObject because __proto__ and getter/setter // properties are non-standard extensions that other implementations do not // expose in the lexicalEnvironment object. ASSERT(!thisObject->hasGetterSetterProperties()); return thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); }
void JSModuleNamespaceObject::put(JSCell*, ExecState* exec, PropertyName, JSValue, PutPropertySlot& slot) { // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-set-p-v-receiver if (slot.isStrictMode()) throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); }