Rename activation to be more in line with spec language
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSScope.h
index 2e29f82..e753931 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC {
 
+class ScopeChainIterator;
+class VariableWatchpointSet;
+
+enum ResolveMode {
+    ThrowIfNotFound,
+    DoNotThrowIfNotFound
+};
+
+enum ResolveType {
+    // Lexical scope guaranteed a certain type of variable access.
+    GlobalProperty,
+    GlobalVar,
+    ClosureVar,
+
+    // Ditto, but at least one intervening scope used non-strict eval, which
+    // can inject an intercepting var delcaration at runtime.
+    GlobalPropertyWithVarInjectionChecks,
+    GlobalVarWithVarInjectionChecks,
+    ClosureVarWithVarInjectionChecks,
+
+    // Lexical scope didn't prove anything -- probably because of a 'with' scope.
+    Dynamic
+};
+
+const char* resolveModeName(ResolveMode mode);
+const char* resolveTypeName(ResolveType type);
+
+inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
+{
+    if (!needsVarInjectionChecks)
+        return type;
+
+    switch (type) {
+    case GlobalProperty:
+        return GlobalPropertyWithVarInjectionChecks;
+    case GlobalVar:
+        return GlobalVarWithVarInjectionChecks;
+    case ClosureVar:
+        return ClosureVarWithVarInjectionChecks;
+    case GlobalPropertyWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks:
+    case ClosureVarWithVarInjectionChecks:
+    case Dynamic:
+        return type;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return type;
+}
+
+inline bool needsVarInjectionChecks(ResolveType type)
+{
+    switch (type) {
+    case GlobalProperty:
+    case GlobalVar:
+    case ClosureVar:
+        return false;
+    case GlobalPropertyWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks:
+    case ClosureVarWithVarInjectionChecks:
+    case Dynamic:
+        return true;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return true;
+    }
+}
+
+struct ResolveOp {
+    ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, VariableWatchpointSet* watchpointSet, uintptr_t operand)
+        : type(type)
+        , depth(depth)
+        , structure(structure)
+        , lexicalEnvironment(lexicalEnvironment)
+        , watchpointSet(watchpointSet)
+        , operand(operand)
+    {
+    }
+
+    ResolveType type;
+    size_t depth;
+    Structure* structure;
+    JSLexicalEnvironment* lexicalEnvironment;
+    VariableWatchpointSet* watchpointSet;
+    uintptr_t operand;
+};
+
+class ResolveModeAndType {
+    typedef unsigned Operand;
+public:
+    static const size_t shift = sizeof(Operand) * 8 / 2;
+    static const unsigned mask = (1 << shift) - 1;
+
+    ResolveModeAndType(ResolveMode resolveMode, ResolveType resolveType)
+        : m_operand((resolveMode << shift) | resolveType)
+    {
+    }
+
+    explicit ResolveModeAndType(unsigned operand)
+        : m_operand(operand)
+    {
+    }
+
+    ResolveMode mode() { return static_cast<ResolveMode>(m_operand >> shift); }
+    ResolveType type() { return static_cast<ResolveType>(m_operand & mask); }
+    unsigned operand() { return m_operand; }
+
+private:
+    Operand m_operand;
+};
+
+enum GetOrPut { Get, Put };
+
 class JSScope : public JSNonFinalObject {
 public:
     typedef JSNonFinalObject Base;
 
-    static JSValue resolve(CallFrame*, const Identifier&);
-    static JSValue resolveSkip(CallFrame*, const Identifier&, int skip);
-    static JSValue resolveGlobal(
-        CallFrame*,
-        const Identifier&,
-        JSGlobalObject* globalObject,
-        WriteBarrierBase<Structure>* cachedStructure,
-        PropertyOffset* cachedOffset
-    );
-    static JSValue resolveGlobalDynamic(
-        CallFrame*,
-        const Identifier&,
-        int skip,
-        WriteBarrierBase<Structure>* cachedStructure,
-        PropertyOffset* cachedOffset
-    );
-    static JSValue resolveBase(CallFrame*, const Identifier&, bool isStrict);
-    static JSValue resolveWithBase(CallFrame*, const Identifier&, Register* base);
-    static JSValue resolveWithThis(CallFrame*, const Identifier&, Register* base);
-
-    bool isDynamicScope(bool& requiresDynamicChecks) const;
+    friend class LLIntOffsetsExtractor;
+    static size_t offsetOfNext();
+
+    static JSObject* objectAtScope(JSScope*);
+
+    static JSValue resolve(ExecState*, JSScope*, const Identifier&);
+    static ResolveOp abstractResolve(ExecState*, bool hasTopActivation, JSScope*, const Identifier&, GetOrPut, ResolveType);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    ScopeChainIterator begin();
+    ScopeChainIterator end();
+    JSScope* next();
+    int depth();
+
+    JSGlobalObject* globalObject();
+    VM* vm();
+    JSObject* globalThis();
 
 protected:
-    JSScope(JSGlobalData&, Structure*);
+    JSScope(VM&, Structure*, JSScope* next);
+
+private:
+    WriteBarrier<JSScope> m_next;
+};
+
+inline JSScope::JSScope(VM& vm, Structure* structure, JSScope* next)
+    : Base(vm, structure)
+    , m_next(vm, this, next, WriteBarrier<JSScope>::MayBeNull)
+{
+}
+
+class ScopeChainIterator {
+public:
+    ScopeChainIterator(JSScope* node)
+        : m_node(node)
+    {
+    }
+
+    JSObject* get() const { return JSScope::objectAtScope(m_node); }
+    JSObject* operator->() const { return JSScope::objectAtScope(m_node); }
+
+    ScopeChainIterator& operator++() { m_node = m_node->next(); return *this; }
+
+    // postfix ++ intentionally omitted
+
+    bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
+    bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
+
+private:
+    JSScope* m_node;
 };
 
-inline JSScope::JSScope(JSGlobalData& globalData, Structure* structure)
-    : Base(globalData, structure)
+inline ScopeChainIterator JSScope::begin()
+{
+    return ScopeChainIterator(this); 
+}
+
+inline ScopeChainIterator JSScope::end()
+{ 
+    return ScopeChainIterator(0); 
+}
+
+inline JSScope* JSScope::next()
+{ 
+    return m_next.get();
+}
+
+inline JSGlobalObject* JSScope::globalObject()
+{ 
+    return structure()->globalObject();
+}
+
+inline VM* JSScope::vm()
+{ 
+    return MarkedBlock::blockFor(this)->vm();
+}
+
+inline Register& Register::operator=(JSScope* scope)
+{
+    *this = JSValue(scope);
+    return *this;
+}
+
+inline JSScope* Register::scope() const
+{
+    return jsCast<JSScope*>(jsValue());
+}
+
+inline VM& ExecState::vm() const
+{
+    ASSERT(scope()->vm());
+    return *scope()->vm();
+}
+
+inline JSGlobalObject* ExecState::lexicalGlobalObject() const
+{
+    return scope()->globalObject();
+}
+
+inline JSObject* ExecState::globalThisValue() const
+{
+    return scope()->globalThis();
+}
+
+inline size_t JSScope::offsetOfNext()
 {
+    return OBJECT_OFFSETOF(JSScope, m_next);
 }
 
 } // namespace JSC