X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..2d39b0e377c0896910ee49ae70082ba665faf986:/runtime/JSActivation.cpp?ds=sidebyside diff --git a/runtime/JSActivation.cpp b/runtime/JSActivation.cpp index 33c84c2..8296506 100644 --- a/runtime/JSActivation.cpp +++ b/runtime/JSActivation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -32,153 +32,209 @@ #include "Arguments.h" #include "Interpreter.h" #include "JSFunction.h" +#include "JSCInlines.h" -namespace JSC { +using namespace std; -ASSERT_CLASS_FITS_IN_CELL(JSActivation); +namespace JSC { -const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 }; +const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) }; -JSActivation::JSActivation(CallFrame* callFrame, PassRefPtr functionBody) - : Base(callFrame->globalData().activationStructure, new JSActivationData(functionBody, callFrame->registers())) +void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) { + JSActivation* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); + + // No need to mark our registers if they're still in the JSStack. + if (!thisObject->isTornOff()) + return; + + for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i) + visitor.append(&thisObject->storage()[i]); } -JSActivation::~JSActivation() +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot) { - delete d(); + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); + if (entry.isNull()) + return false; + + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; + + slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get()); + return true; } -void JSActivation::mark() +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) { - Base::mark(); + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); + if (entry.isNull()) + return false; - Register* registerArray = d()->registerArray.get(); - if (!registerArray) - return; + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; - size_t numParametersMinusThis = d()->functionBody->parameterCount(); + descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes()); + return true; +} - size_t i = 0; - size_t count = numParametersMinusThis; - for ( ; i < count; ++i) { - Register& r = registerArray[i]; - if (!r.marked()) - r.mark(); +inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) +{ + VM& vm = exec->vm(); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + WriteBarrierBase* reg; + { + GCSafeConcurrentJITLocker locker(symbolTable()->m_lock, exec->vm().heap); + SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid()); + if (iter == symbolTable()->end(locker)) + return false; + ASSERT(!iter->value.isNull()); + if (iter->value.isReadOnly()) { + if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return true; + } + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(iter->value)) + return false; + if (VariableWatchpointSet* set = iter->value.watchpointSet()) + set->invalidate(); // Don't mess around - if we had found this statically, we would have invcalidated it. + reg = ®isterAt(iter->value.getIndex()); } + reg->set(vm, this, value); + return true; +} - size_t numVars = d()->numVars; - - // Skip the call frame, which sits between the parameters and vars. - i += RegisterFile::CallFrameHeaderSize; - count += RegisterFile::CallFrameHeaderSize + numVars; +void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSActivation* thisObject = jsCast(object); + + CallFrame* callFrame = CallFrame::create(reinterpret_cast(thisObject->m_registers)); + if (mode == IncludeDontEnumProperties && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) + propertyNames.add(exec->propertyNames().arguments); + + { + ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock); + SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker); + for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) { + if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) + continue; + if (!thisObject->isValid(it->value)) + continue; + propertyNames.add(Identifier(exec, it->key.get())); + } + } + // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames + JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); +} - for ( ; i < count; ++i) { - Register& r = registerArray[i]; - if (r.jsValue() && !r.marked()) - r.mark(); +inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + WriteBarrierBase* reg; + { + ConcurrentJITLocker locker(symbolTable()->m_lock); + SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid()); + if (iter == symbolTable()->end(locker)) + return false; + SymbolTableEntry& entry = iter->value; + ASSERT(!entry.isNull()); + if (!isValid(entry)) + return false; + + entry.setAttributes(attributes); + reg = ®isterAt(entry.getIndex()); } + reg->set(vm, this, value); + return true; } -bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +bool JSActivation::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - if (symbolTableGet(propertyName, slot)) - return true; + JSActivation* thisObject = jsCast(object); - if (JSValue* location = getDirectLocation(propertyName)) { - slot.setValueSlot(location); - return true; + if (propertyName == exec->propertyNames().arguments) { + // Defend against the inspector asking for the arguments object after it has been optimized out. + CallFrame* callFrame = CallFrame::create(reinterpret_cast(thisObject->m_registers)); + if (!thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) { + slot.setCustom(thisObject, DontEnum, argumentsGetter); + return true; + } } - // Only return the built-in arguments object if it wasn't overridden above. - if (propertyName == exec->propertyNames().arguments) { - slot.setCustom(this, getArgumentsGetter()); + if (thisObject->symbolTableGet(propertyName, slot)) + return true; + + unsigned attributes; + if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) { + slot.setValue(thisObject, attributes, value); return true; } // We don't call through to JSObject because there's no way to give an // activation object getter properties or a prototype. - ASSERT(!hasGetterSetterProperties()); - ASSERT(prototype().isNull()); + ASSERT(!thisObject->hasGetterSetterProperties()); + ASSERT(thisObject->prototype().isNull()); return false; } -void JSActivation::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - if (symbolTablePut(propertyName, value)) - 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 activation object. - ASSERT(!hasGetterSetterProperties()); - putDirect(propertyName, value, 0, true, slot); -} - -// FIXME: Make this function honor ReadOnly (const) and DontEnum -void JSActivation::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) -{ - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + JSActivation* thisObject = jsCast(cell); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (symbolTablePutWithAttributes(propertyName, value, attributes)) + 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 activation object. - ASSERT(!hasGetterSetterProperties()); - PutPropertySlot slot; - JSObject::putWithAttributes(exec, propertyName, value, attributes, true, slot); + ASSERT(!thisObject->hasGetterSetterProperties()); + thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); } -bool JSActivation::deleteProperty(ExecState* exec, const Identifier& propertyName) +bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { if (propertyName == exec->propertyNames().arguments) return false; - return Base::deleteProperty(exec, propertyName); + return Base::deleteProperty(cell, exec, propertyName); } -JSObject* JSActivation::toThisObject(ExecState* exec) const +JSValue JSActivation::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode) { + if (ecmaMode == StrictMode) + return jsUndefined(); return exec->globalThisValue(); } -bool JSActivation::isDynamicScope() const -{ - return d()->functionBody->usesEval(); -} - -JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) -{ - JSActivation* activation = asActivation(slot.slotBase()); - - if (activation->d()->functionBody->usesArguments()) { - PropertySlot slot; - activation->symbolTableGet(exec->propertyNames().arguments, slot); - return slot.getValue(exec, exec->propertyNames().arguments); - } - - CallFrame* callFrame = CallFrame::create(activation->d()->registers); - Arguments* arguments = callFrame->optionalCalleeArguments(); - if (!arguments) { - arguments = new (callFrame) Arguments(callFrame); - arguments->copyRegisters(); - callFrame->setCalleeArguments(arguments); - } - ASSERT(arguments->isObject(&Arguments::info)); - - return arguments; -} - -// These two functions serve the purpose of isolating the common case from a -// PIC branch. - -PropertySlot::GetValueFunc JSActivation::getArgumentsGetter() +EncodedJSValue JSActivation::argumentsGetter(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return argumentsGetter; + JSActivation* activation = jsCast(slotBase); + CallFrame* callFrame = CallFrame::create(reinterpret_cast(activation->m_registers)); + ASSERT(!activation->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())); + if (activation->isTornOff() || !(callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) + return JSValue::encode(jsUndefined()); + + VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister(); + if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue()) + return JSValue::encode(arguments); + int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister).offset(); + + JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame)); + callFrame->uncheckedR(argumentsRegister.offset()) = arguments; + callFrame->uncheckedR(realArgumentsRegister) = arguments; + + ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info())); + return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue()); } } // namespace JSC