X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..cb9aa2694aba0ae4f946ed34b8e0f6c99c1cfe44:/runtime/JSActivation.cpp diff --git a/runtime/JSActivation.cpp b/runtime/JSActivation.cpp index 09d985a..8296506 100644 --- a/runtime/JSActivation.cpp +++ b/runtime/JSActivation.cpp @@ -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,208 +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::s_info = { "JSActivation", &Base::s_info, 0, 0 }; +const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) }; -JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable) - : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers()) - , m_numParametersMinusThis(static_cast(functionExecutable->parameterCount())) - , m_numCapturedVars(functionExecutable->capturedVariableCount()) - , m_requiresDynamicChecks(functionExecutable->usesEval()) - , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister()) +void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) { - ASSERT(inherits(&s_info)); + JSActivation* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); - // We have to manually ref and deref the symbol table as JSVariableObject - // doesn't know about SharedSymbolTable - static_cast(m_symbolTable)->ref(); -} + // No need to mark our registers if they're still in the JSStack. + if (!thisObject->isTornOff()) + return; -JSActivation::~JSActivation() -{ - static_cast(m_symbolTable)->deref(); + for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i) + visitor.append(&thisObject->storage()[i]); } -void JSActivation::visitChildren(SlotVisitor& visitor) +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot) { - ASSERT_GC_OBJECT_INHERITS(this, &s_info); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(visitor); - - // No need to mark our registers if they're still in the RegisterFile. - WriteBarrier* registerArray = m_registerArray.get(); - if (!registerArray) - return; + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); + if (entry.isNull()) + return false; - visitor.appendValues(registerArray, m_numParametersMinusThis); + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; - // Skip the call frame, which sits between the parameters and vars. - visitor.appendValues(registerArray + m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize, m_numCapturedVars, MayContainNullValues); + slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get()); + return true; } -inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) { - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); if (entry.isNull()) return false; - if (entry.getIndex() >= m_numCapturedVars) + + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) return false; - slot.setValue(registerAt(entry.getIndex()).get()); + descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes()); return true; } -inline bool JSActivation::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value) +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)); - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); - if (entry.isNull()) - return false; - if (entry.isReadOnly()) - return true; - if (entry.getIndex() >= m_numCapturedVars) - return false; - - registerAt(entry.getIndex()).set(globalData, this, value); + 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; } -void JSActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - SymbolTable::const_iterator end = symbolTable().end(); - for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { - if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) - continue; - if (it->second.getIndex() >= m_numCapturedVars) - continue; - propertyNames.add(Identifier(exec, it->first.get())); + 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 getOwnPropertyNames - JSObject::getOwnPropertyNames(exec, propertyNames, mode); + // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames + JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); } -inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) +inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - SymbolTable::iterator iter = symbolTable().find(propertyName.impl()); - if (iter == symbolTable().end()) - return false; - SymbolTableEntry& entry = iter->second; - ASSERT(!entry.isNull()); - if (entry.getIndex() >= m_numCapturedVars) - return false; - - entry.setAttributes(attributes); - registerAt(entry.getIndex()).set(globalData, this, value); + 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) { + JSActivation* thisObject = jsCast(object); + if (propertyName == exec->propertyNames().arguments) { - slot.setCustom(this, getArgumentsGetter()); - return true; + // 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; + } } - if (symbolTableGet(propertyName, slot)) + if (thisObject->symbolTableGet(propertyName, slot)) return true; - if (WriteBarrierBase* location = getDirectLocation(exec->globalData(), propertyName)) { - slot.setValue(location->get()); + 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* exec, 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(exec->globalData(), 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(exec->globalData(), 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(exec->globalData(), 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(); } -JSValue JSActivation::toStrictThisObject(ExecState*) const +EncodedJSValue JSActivation::argumentsGetter(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return jsNull(); -} - -bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const -{ - requiresDynamicChecks = m_requiresDynamicChecks; - return false; -} - -JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&) -{ - JSActivation* activation = asActivation(slotBase); + JSActivation* activation = jsCast(slotBase); CallFrame* callFrame = CallFrame::create(reinterpret_cast(activation->m_registers)); - int argumentsRegister = activation->m_argumentsRegister; - if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue()) - return arguments; - int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister); + 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(new (callFrame) Arguments(callFrame)); - callFrame->uncheckedR(argumentsRegister) = arguments; + JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame)); + callFrame->uncheckedR(argumentsRegister.offset()) = arguments; callFrame->uncheckedR(realArgumentsRegister) = arguments; - ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info)); - return callFrame->uncheckedR(realArgumentsRegister).jsValue(); -} - -// These two functions serve the purpose of isolating the common case from a -// PIC branch. - -PropertySlot::GetValueFunc JSActivation::getArgumentsGetter() -{ - return argumentsGetter; + ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info())); + return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue()); } } // namespace JSC