]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSActivation.cpp
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / runtime / JSActivation.cpp
index 09d985afbcfb593d5fbd04599a2a682b5f17f05d..3a3bb50af7e58692e735115ff6470424002e0266 100644 (file)
 #include "Arguments.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
+#include "Operations.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<int>(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<JSActivation*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_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<SharedSymbolTable*>(m_symbolTable)->ref();
-}
+    // No need to mark our registers if they're still in the JSStack.
+    if (!thisObject->isTornOff())
+        return;
 
-JSActivation::~JSActivation()
-{
-    static_cast<SharedSymbolTable*>(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<Unknown>* registerArray = m_registerArray.get();
-    if (!registerArray)
-        return;
+    SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
+    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(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.publicName());
     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());
+    SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
     if (entry.isNull())
         return false;
-    if (entry.isReadOnly())
+    if (entry.isReadOnly()) {
+        if (shouldThrow)
+            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
         return true;
-    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;
 
-    registerAt(entry.getIndex()).set(globalData, this, value);
+    registerAt(entry.getIndex()).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)
+    JSActivation* thisObject = jsCast<JSActivation*>(object);
+
+    if (mode == IncludeDontEnumProperties && !thisObject->isTornOff())
+        propertyNames.add(exec->propertyNames().arguments);
+
+    SymbolTable::const_iterator end = thisObject->symbolTable()->end();
+    for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) {
+        if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
             continue;
-        if (it->second.getIndex() >= m_numCapturedVars)
+        if (!thisObject->isValid(it->value))
             continue;
-        propertyNames.add(Identifier(exec, it->first.get()));
+        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())
+    SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName());
+    if (iter == symbolTable()->end())
         return false;
-    SymbolTableEntry& entry = iter->second;
+    SymbolTableEntry& entry = iter->value;
     ASSERT(!entry.isNull());
-    if (entry.getIndex() >= m_numCapturedVars)
+    if (!isValid(entry))
         return false;
 
     entry.setAttributes(attributes);
-    registerAt(entry.getIndex()).set(globalData, this, value);
+    registerAt(entry.getIndex()).set(vm, this, value);
     return true;
 }
 
-bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
+    JSActivation* thisObject = jsCast<JSActivation*>(cell);
+
     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.
+        if (!thisObject->isTornOff()) {
+            slot.setCustom(thisObject, thisObject->getArgumentsGetter());
+            return true;
+        }
     }
 
-    if (symbolTableGet(propertyName, slot))
+    if (thisObject->symbolTableGet(propertyName, slot))
         return true;
 
-    if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
-        slot.setValue(location->get());
+    if (JSValue value = thisObject->getDirect(exec->vm(), propertyName)) {
+        slot.setValue(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)
+bool JSActivation::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
 {
-    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+    JSActivation* thisObject = jsCast<JSActivation*>(object);
+
+    if (propertyName == exec->propertyNames().arguments) {
+        // Defend against the inspector asking for the arguments object after it has been optimized out.
+        if (!thisObject->isTornOff()) {
+            PropertySlot slot;
+            JSActivation::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+            descriptor.setDescriptor(slot.getValue(exec, propertyName), DontEnum);
+            return true;
+        }
+    }
+
+    if (thisObject->symbolTableGet(propertyName, descriptor))
+        return true;
+
+    return Base::getOwnPropertyDescriptor(object, exec, propertyName, descriptor);
+}
 
-    if (symbolTablePut(exec->globalData(), propertyName, value))
+void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+    JSActivation* thisObject = jsCast<JSActivation*>(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 activation object.
-    ASSERT(!hasGetterSetterProperties());
-    putDirect(exec->globalData(), propertyName, value, 0, true, slot);
+    ASSERT(!thisObject->hasGetterSetterProperties());
+    thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot);
 }
 
 // FIXME: Make this function honor ReadOnly (const) and DontEnum
-void JSActivation::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
+void JSActivation::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
 {
-    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+    JSActivation* thisObject = jsCast<JSActivation*>(object);
+    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
 
-    if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
+    if (thisObject->symbolTablePutWithAttributes(exec->vm(), propertyName, value, attributes))
         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());
+    JSObject::putDirectVirtual(thisObject, exec, propertyName, value, attributes);
 }
 
-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
+JSObject* JSActivation::toThisObject(JSCell*, ExecState* exec)
 {
     return exec->globalThisValue();
 }
 
-JSValue JSActivation::toStrictThisObject(ExecState*) const
+JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName)
 {
-    return jsNull();
-}
-    
-bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const
-{
-    requiresDynamicChecks = m_requiresDynamicChecks;
-    return false;
-}
+    JSActivation* activation = jsCast<JSActivation*>(slotBase);
+    if (activation->isTornOff())
+        return jsUndefined();
 
-JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
-{
-    JSActivation* activation = asActivation(slotBase);
     CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
-    int argumentsRegister = activation->m_argumentsRegister;
+    int argumentsRegister = callFrame->codeBlock()->argumentsRegister();
     if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
         return arguments;
     int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
 
-    JSValue arguments = JSValue(new (callFrame) Arguments(callFrame));
+    JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame));
     callFrame->uncheckedR(argumentsRegister) = arguments;
     callFrame->uncheckedR(realArgumentsRegister) = arguments;