Example #1
0
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);
}
Example #3
0
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);
}
Example #5
0
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);
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #8
0
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);
}
Example #9
0
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);
}
Example #10
0
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);
}
Example #11
0
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);
}
Example #12
0
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);
}
Example #13
0
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();
}
Example #16
0
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);
}
Example #17
0
// 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;
}
Example #18
0
// 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));
}