Changeset 170680 in webkit


Ignore:
Timestamp:
Jul 1, 2014 5:12:09 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

[ftlopt] DebuggerCallFrame::scope() should return a DebuggerScope.
<https://webkit.org/b/134420>

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:
Previously, DebuggerCallFrame::scope() returns a JSActivation (and relevant
peers) which the WebInspector will use to introspect CallFrame variables.
Instead, we should be returning a DebuggerScope as an abstraction layer that
provides the introspection functionality that the WebInspector needs. This
is the first step towards not forcing every frame to have a JSActivation
object just because the debugger is enabled.

  1. Instantiate the debuggerScopeStructure as a member of the JSGlobalObject instead of the VM. This allows JSObject::globalObject() to be able to return the global object for the DebuggerScope.
  1. On the DebuggerScope's life-cycle management:

The DebuggerCallFrame is designed to be "valid" only during a debugging session
(while the debugger is broken) through the use of a DebuggerCallFrameScope in
Debugger::pauseIfNeeded(). Once the debugger resumes from the break, the
DebuggerCallFrameScope destructs, and the DebuggerCallFrame will be invalidated.
We can't guarantee (from this code alone) that the Inspector code isn't still
holding a ref to the DebuggerCallFrame (though they shouldn't), but by contract,
the frame will be invalidated, and any attempt to query it will return null values.
This is pre-existing behavior.

Now, we're adding the DebuggerScope into the picture. While a single debugger
pause session is in progress, the Inspector may request the scope from the
DebuggerCallFrame. While the DebuggerCallFrame is still valid, we want
DebuggerCallFrame::scope() to always return the same DebuggerScope object.
This is why we hold on to the DebuggerScope with a strong ref.

If we use a weak ref instead, the following cooky behavior can manifest:

  1. The Inspector calls Debugger::scope() to get the top scope.
  2. The Inspector iterates down the scope chain and is now only holding a reference to a parent scope. It is no longer referencing the top scope.
  3. A GC occurs, and the DebuggerCallFrame's weak m_scope ref to the top scope gets cleared.
  4. The Inspector calls DebuggerCallFrame::scope() to get the top scope again but gets a different DebuggerScope instance.
  5. The Inspector iterates down the scope chain but never sees the parent scope instance that retained a ref to in step 2 above. This is because when iterating this new DebuggerScope instance (which has no knowledge of the previous parent DebuggerScope instance), a new DebuggerScope instance will get created for the same parent scope.

Since the DebuggerScope is a JSObject, it's liveness is determined by its reachability.
However, it's "validity" is determined by the life-cycle of its owner DebuggerCallFrame.
When the owner DebuggerCallFrame gets invalidated, its debugger scope chain (if
instantiated) will also get invalidated. This is why we need the
DebuggerScope::invalidateChain() method. The Inspector should not be using the
DebuggerScope instance after its owner DebuggerCallFrame is invalidated. If it does,
those methods will do nothing or returned a failed status.

  • debugger/Debugger.h:
  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::scope):
(JSC::DebuggerCallFrame::evaluate):
(JSC::DebuggerCallFrame::invalidate):
(JSC::DebuggerCallFrame::vm):
(JSC::DebuggerCallFrame::lexicalGlobalObject):

  • debugger/DebuggerCallFrame.h:
  • debugger/DebuggerScope.cpp:

(JSC::DebuggerScope::DebuggerScope):
(JSC::DebuggerScope::finishCreation):
(JSC::DebuggerScope::visitChildren):
(JSC::DebuggerScope::className):
(JSC::DebuggerScope::getOwnPropertySlot):
(JSC::DebuggerScope::put):
(JSC::DebuggerScope::deleteProperty):
(JSC::DebuggerScope::getOwnPropertyNames):
(JSC::DebuggerScope::defineOwnProperty):
(JSC::DebuggerScope::next):
(JSC::DebuggerScope::invalidateChain):
(JSC::DebuggerScope::isWithScope):
(JSC::DebuggerScope::isGlobalScope):
(JSC::DebuggerScope::isFunctionScope):

  • debugger/DebuggerScope.h:

(JSC::DebuggerScope::create):
(JSC::DebuggerScope::Iterator::Iterator):
(JSC::DebuggerScope::Iterator::get):
(JSC::DebuggerScope::Iterator::operator++):
(JSC::DebuggerScope::Iterator::operator==):
(JSC::DebuggerScope::Iterator::operator!=):
(JSC::DebuggerScope::isValid):
(JSC::DebuggerScope::jsScope):
(JSC::DebuggerScope::begin):
(JSC::DebuggerScope::end):

  • inspector/JSJavaScriptCallFrame.cpp:

(Inspector::JSJavaScriptCallFrame::scopeType):
(Inspector::JSJavaScriptCallFrame::scopeChain):

  • inspector/JavaScriptCallFrame.h:

(Inspector::JavaScriptCallFrame::scopeChain):

  • inspector/ScriptDebugServer.cpp:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::reset):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::debuggerScopeStructure):

  • runtime/JSObject.h:

(JSC::JSObject::isWithScope):

  • runtime/JSScope.h:
  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:

Source/WebCore:
No new tests.

  • ForwardingHeaders/debugger/DebuggerCallFrame.h: Removed.
  • This is not in use. Hence, we can remove it.
  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::attachDebugger):

  • We should acquire the JSLock before modifying a JS global object.
Location:
branches/ftlopt/Source
Files:
1 deleted
17 edited

Legend:

Unmodified
Added
Removed
  • branches/ftlopt/Source/JavaScriptCore/ChangeLog

    r170672 r170680  
     12014-07-01  Mark Lam  <mark.lam@apple.com>
     2
     3        [ftlopt] DebuggerCallFrame::scope() should return a DebuggerScope.
     4        <https://webkit.org/b/134420>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Previously, DebuggerCallFrame::scope() returns a JSActivation (and relevant
     9        peers) which the WebInspector will use to introspect CallFrame variables.
     10        Instead, we should be returning a DebuggerScope as an abstraction layer that
     11        provides the introspection functionality that the WebInspector needs.  This
     12        is the first step towards not forcing every frame to have a JSActivation
     13        object just because the debugger is enabled.
     14
     15        1. Instantiate the debuggerScopeStructure as a member of the JSGlobalObject
     16           instead of the VM.  This allows JSObject::globalObject() to be able to
     17           return the global object for the DebuggerScope.
     18
     19        2. On the DebuggerScope's life-cycle management:
     20
     21           The DebuggerCallFrame is designed to be "valid" only during a debugging session
     22           (while the debugger is broken) through the use of a DebuggerCallFrameScope in
     23           Debugger::pauseIfNeeded().  Once the debugger resumes from the break, the
     24           DebuggerCallFrameScope destructs, and the DebuggerCallFrame will be invalidated.
     25           We can't guarantee (from this code alone) that the Inspector code isn't still
     26           holding a ref to the DebuggerCallFrame (though they shouldn't), but by contract,
     27           the frame will be invalidated, and any attempt to query it will return null values.
     28           This is pre-existing behavior.
     29
     30           Now, we're adding the DebuggerScope into the picture.  While a single debugger
     31           pause session is in progress, the Inspector may request the scope from the
     32           DebuggerCallFrame.  While the DebuggerCallFrame is still valid, we want
     33           DebuggerCallFrame::scope() to always return the same DebuggerScope object.
     34           This is why we hold on to the DebuggerScope with a strong ref.
     35
     36           If we use a weak ref instead, the following cooky behavior can manifest:
     37           1. The Inspector calls Debugger::scope() to get the top scope.
     38           2. The Inspector iterates down the scope chain and is now only holding a
     39              reference to a parent scope.  It is no longer referencing the top scope.
     40           3. A GC occurs, and the DebuggerCallFrame's weak m_scope ref to the top scope
     41              gets cleared.
     42           4. The Inspector calls DebuggerCallFrame::scope() to get the top scope again but gets
     43              a different DebuggerScope instance.
     44           5. The Inspector iterates down the scope chain but never sees the parent scope
     45              instance that retained a ref to in step 2 above.  This is because when iterating
     46              this new DebuggerScope instance (which has no knowledge of the previous parent
     47              DebuggerScope instance), a new DebuggerScope instance will get created for the
     48              same parent scope.
     49
     50           Since the DebuggerScope is a JSObject, it's liveness is determined by its reachability.
     51           However, it's "validity" is determined by the life-cycle of its owner DebuggerCallFrame.
     52           When the owner DebuggerCallFrame gets invalidated, its debugger scope chain (if
     53           instantiated) will also get invalidated.  This is why we need the
     54           DebuggerScope::invalidateChain() method.  The Inspector should not be using the
     55           DebuggerScope instance after its owner DebuggerCallFrame is invalidated.  If it does,
     56           those methods will do nothing or returned a failed status.
     57
     58        * debugger/Debugger.h:
     59        * debugger/DebuggerCallFrame.cpp:
     60        (JSC::DebuggerCallFrame::scope):
     61        (JSC::DebuggerCallFrame::evaluate):
     62        (JSC::DebuggerCallFrame::invalidate):
     63        (JSC::DebuggerCallFrame::vm):
     64        (JSC::DebuggerCallFrame::lexicalGlobalObject):
     65        * debugger/DebuggerCallFrame.h:
     66        * debugger/DebuggerScope.cpp:
     67        (JSC::DebuggerScope::DebuggerScope):
     68        (JSC::DebuggerScope::finishCreation):
     69        (JSC::DebuggerScope::visitChildren):
     70        (JSC::DebuggerScope::className):
     71        (JSC::DebuggerScope::getOwnPropertySlot):
     72        (JSC::DebuggerScope::put):
     73        (JSC::DebuggerScope::deleteProperty):
     74        (JSC::DebuggerScope::getOwnPropertyNames):
     75        (JSC::DebuggerScope::defineOwnProperty):
     76        (JSC::DebuggerScope::next):
     77        (JSC::DebuggerScope::invalidateChain):
     78        (JSC::DebuggerScope::isWithScope):
     79        (JSC::DebuggerScope::isGlobalScope):
     80        (JSC::DebuggerScope::isFunctionScope):
     81        * debugger/DebuggerScope.h:
     82        (JSC::DebuggerScope::create):
     83        (JSC::DebuggerScope::Iterator::Iterator):
     84        (JSC::DebuggerScope::Iterator::get):
     85        (JSC::DebuggerScope::Iterator::operator++):
     86        (JSC::DebuggerScope::Iterator::operator==):
     87        (JSC::DebuggerScope::Iterator::operator!=):
     88        (JSC::DebuggerScope::isValid):
     89        (JSC::DebuggerScope::jsScope):
     90        (JSC::DebuggerScope::begin):
     91        (JSC::DebuggerScope::end):
     92        * inspector/JSJavaScriptCallFrame.cpp:
     93        (Inspector::JSJavaScriptCallFrame::scopeType):
     94        (Inspector::JSJavaScriptCallFrame::scopeChain):
     95        * inspector/JavaScriptCallFrame.h:
     96        (Inspector::JavaScriptCallFrame::scopeChain):
     97        * inspector/ScriptDebugServer.cpp:
     98        * runtime/JSGlobalObject.cpp:
     99        (JSC::JSGlobalObject::reset):
     100        (JSC::JSGlobalObject::visitChildren):
     101        * runtime/JSGlobalObject.h:
     102        (JSC::JSGlobalObject::debuggerScopeStructure):
     103        * runtime/JSObject.h:
     104        (JSC::JSObject::isWithScope):
     105        * runtime/JSScope.h:
     106        * runtime/VM.cpp:
     107        (JSC::VM::VM):
     108        * runtime/VM.h:
     109
    11102014-07-01  Filip Pizlo  <fpizlo@apple.com>
    2111
  • branches/ftlopt/Source/JavaScriptCore/debugger/Debugger.h

    r165005 r170680  
    3535namespace JSC {
    3636
     37class CodeBlock;
    3738class ExecState;
    3839class JSGlobalObject;
  • branches/ftlopt/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

    r165676 r170680  
    3131
    3232#include "CodeBlock.h"
     33#include "DebuggerScope.h"
    3334#include "Interpreter.h"
    3435#include "JSActivation.h"
     
    3738#include "Parser.h"
    3839#include "StackVisitor.h"
     40#include "StrongInlines.h"
    3941
    4042namespace JSC {
     
    107109}
    108110
    109 JSScope* DebuggerCallFrame::scope() const
    110 {
    111     ASSERT(isValid());
    112     if (!isValid())
    113         return 0;
    114 
    115     CodeBlock* codeBlock = m_callFrame->codeBlock();
    116     if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
    117         JSActivation* activation = JSActivation::create(*codeBlock->vm(), m_callFrame, codeBlock);
    118         m_callFrame->setActivation(activation);
    119         m_callFrame->setScope(activation);
    120     }
    121 
    122     return m_callFrame->scope();
     111DebuggerScope* DebuggerCallFrame::scope()
     112{
     113    ASSERT(isValid());
     114    if (!isValid())
     115        return 0;
     116
     117    if (!m_scope) {
     118        VM& vm = m_callFrame->vm();
     119        CodeBlock* codeBlock = m_callFrame->codeBlock();
     120        if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
     121            ASSERT(!m_callFrame->scope()->isWithScope());
     122            JSActivation* activation = JSActivation::create(vm, m_callFrame, codeBlock);
     123            m_callFrame->setActivation(activation);
     124            m_callFrame->setScope(activation);
     125        }
     126
     127        m_scope.set(vm, DebuggerScope::create(vm, m_callFrame->scope()));
     128    }
     129    return m_scope.get();
    123130}
    124131
     
    163170
    164171    JSValue thisValue = thisValueForCallFrame(callFrame);
    165     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope());
     172    JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
    166173    if (vm.exception()) {
    167174        exception = vm.exception();
     
    175182{
    176183    m_callFrame = nullptr;
     184    if (m_scope) {
     185        m_scope->invalidateChain();
     186        m_scope.clear();
     187    }
    177188    RefPtr<DebuggerCallFrame> frame = m_caller.release();
    178189    while (frame) {
  • branches/ftlopt/Source/JavaScriptCore/debugger/DebuggerCallFrame.h

    r165676 r170680  
    3030#define DebuggerCallFrame_h
    3131
    32 #include "CallFrame.h"
    3332#include "DebuggerPrimitives.h"
     33#include "Strong.h"
    3434#include <wtf/PassRefPtr.h>
    3535#include <wtf/RefCounted.h>
     
    3737
    3838namespace JSC {
     39
     40class DebuggerScope;
     41class ExecState;
     42typedef ExecState CallFrame;
    3943
    4044class DebuggerCallFrame : public RefCounted<DebuggerCallFrame> {
     
    5963
    6064    JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject() const;
    61     JS_EXPORT_PRIVATE JSScope* scope() const;
     65    JS_EXPORT_PRIVATE DebuggerScope* scope();
    6266    JS_EXPORT_PRIVATE String functionName() const;
    6367    JS_EXPORT_PRIVATE Type type() const;
     
    7983    RefPtr<DebuggerCallFrame> m_caller;
    8084    TextPosition m_position;
     85    // The DebuggerCallFrameScope is responsible for calling invalidate() which,
     86    // in turn, will clear this strong ref.
     87    Strong<DebuggerScope> m_scope;
    8188};
    8289
  • branches/ftlopt/Source/JavaScriptCore/debugger/DebuggerScope.cpp

    r170399 r170680  
    2929#include "JSActivation.h"
    3030#include "JSCInlines.h"
     31#include "JSWithScope.h"
    3132
    3233namespace JSC {
     
    3637const ClassInfo DebuggerScope::s_info = { "DebuggerScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(DebuggerScope) };
    3738
    38 DebuggerScope::DebuggerScope(VM& vm)
    39     : JSNonFinalObject(vm, vm.debuggerScopeStructure.get())
     39DebuggerScope::DebuggerScope(VM& vm, JSScope* scope)
     40    : JSNonFinalObject(vm, scope->globalObject()->debuggerScopeStructure())
    4041{
     42    ASSERT(scope);
     43    m_scope.set(vm, this, scope);
    4144}
    4245
    43 void DebuggerScope::finishCreation(VM& vm, JSObject* activation)
     46void DebuggerScope::finishCreation(VM& vm)
    4447{
    4548    Base::finishCreation(vm);
    46     ASSERT(activation);
    47     ASSERT(activation->isActivationObject());
    48     m_activation.set(vm, this, jsCast<JSActivation*>(activation));
    4949}
    5050
     
    5757
    5858    JSObject::visitChildren(thisObject, visitor);
    59     visitor.append(&thisObject->m_activation);
     59    visitor.append(&thisObject->m_scope);
     60    visitor.append(&thisObject->m_next);
    6061}
    6162
    6263String DebuggerScope::className(const JSObject* object)
    6364{
    64     const DebuggerScope* thisObject = jsCast<const DebuggerScope*>(object);
    65     return thisObject->m_activation->methodTable()->className(thisObject->m_activation.get());
     65    const DebuggerScope* scope = jsCast<const DebuggerScope*>(object);
     66    ASSERT(scope->isValid());
     67    if (!scope->isValid())
     68        return String();
     69    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     70    return thisObject->methodTable()->className(thisObject);
    6671}
    6772
    6873bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    6974{
    70     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    71     return thisObject->m_activation->methodTable()->getOwnPropertySlot(thisObject->m_activation.get(), exec, propertyName, slot);
     75    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     76    ASSERT(scope->isValid());
     77    if (!scope->isValid())
     78        return false;
     79    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     80    return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
    7281}
    7382
    7483void DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    7584{
    76     DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
    77     thisObject->m_activation->methodTable()->put(thisObject->m_activation.get(), exec, propertyName, value, slot);
     85    DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
     86    ASSERT(scope->isValid());
     87    if (!scope->isValid())
     88        return;
     89    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     90    thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot);
    7891}
    7992
    8093bool DebuggerScope::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
    8194{
    82     DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
    83     return thisObject->m_activation->methodTable()->deleteProperty(thisObject->m_activation.get(), exec, propertyName);
     95    DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
     96    ASSERT(scope->isValid());
     97    if (!scope->isValid())
     98        return false;
     99    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     100    return thisObject->methodTable()->deleteProperty(thisObject, exec, propertyName);
    84101}
    85102
    86103void DebuggerScope::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    87104{
    88     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    89     thisObject->m_activation->methodTable()->getPropertyNames(thisObject->m_activation.get(), exec, propertyNames, mode);
     105    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     106    ASSERT(scope->isValid());
     107    if (!scope->isValid())
     108        return;
     109    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     110    thisObject->methodTable()->getPropertyNames(thisObject, exec, propertyNames, mode);
    90111}
    91112
    92113bool DebuggerScope::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
    93114{
    94     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    95     return thisObject->m_activation->methodTable()->defineOwnProperty(thisObject->m_activation.get(), exec, propertyName, descriptor, shouldThrow);
     115    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     116    ASSERT(scope->isValid());
     117    if (!scope->isValid())
     118        return false;
     119    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     120    return thisObject->methodTable()->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
     121}
     122
     123DebuggerScope* DebuggerScope::next()
     124{
     125    ASSERT(isValid());
     126    if (!m_next && m_scope->next()) {
     127        VM& vm = *m_scope->vm();
     128        DebuggerScope* nextScope = create(vm, m_scope->next());
     129        m_next.set(vm, this, nextScope);
     130    }
     131    return m_next.get();
     132}
     133
     134void DebuggerScope::invalidateChain()
     135{
     136    DebuggerScope* scope = this;
     137    while (scope) {
     138        ASSERT(scope->isValid());
     139        DebuggerScope* nextScope = scope->m_next.get();
     140        scope->m_next.clear();
     141        scope->m_scope.clear();
     142        scope = nextScope;
     143    }
     144}
     145
     146bool DebuggerScope::isWithScope() const
     147{
     148    return m_scope->isWithScope();
     149}
     150
     151bool DebuggerScope::isGlobalScope() const
     152{
     153    return m_scope->isGlobalObject();
     154}
     155
     156bool DebuggerScope::isFunctionScope() const
     157{
     158    // In the current debugger implementation, every function will create an
     159    // activation object. Hence, an activation object implies a function scope.
     160    return m_scope->isActivationObject();
    96161}
    97162
  • branches/ftlopt/Source/JavaScriptCore/debugger/DebuggerScope.h

    r170399 r170680  
    3131namespace JSC {
    3232
     33class DebuggerCallFrame;
     34class JSScope;
     35
    3336class DebuggerScope : public JSNonFinalObject {
    3437public:
    3538    typedef JSNonFinalObject Base;
    3639
    37     static DebuggerScope* create(VM& vm, JSObject* object)
     40    static DebuggerScope* create(VM& vm, JSScope* scope)
    3841    {
    39         DebuggerScope* activation = new (NotNull, allocateCell<DebuggerScope>(vm.heap)) DebuggerScope(vm);
    40         activation->finishCreation(vm, object);
    41         return activation;
     42        DebuggerScope* debuggerScope = new (NotNull, allocateCell<DebuggerScope>(vm.heap)) DebuggerScope(vm, scope);
     43        debuggerScope->finishCreation(vm);
     44        return debuggerScope;
    4245    }
    4346
     
    5760    }
    5861
    59 protected:
     62    class Iterator {
     63    public:
     64        Iterator(DebuggerScope* node)
     65            : m_node(node)
     66        {
     67        }
     68
     69        DebuggerScope* get() { return m_node; }
     70        Iterator& operator++() { m_node = m_node->next(); return *this; }
     71        // postfix ++ intentionally omitted
     72
     73        bool operator==(const Iterator& other) const { return m_node == other.m_node; }
     74        bool operator!=(const Iterator& other) const { return m_node != other.m_node; }
     75
     76    private:
     77        DebuggerScope* m_node;
     78    };
     79
     80    Iterator begin();
     81    Iterator end();
     82    DebuggerScope* next();
     83
     84    void invalidateChain();
     85    bool isValid() const { return !!m_scope; }
     86
     87    bool isWithScope() const;
     88    bool isGlobalScope() const;
     89    bool isFunctionScope() const;
     90
     91private:
     92    JS_EXPORT_PRIVATE DebuggerScope(VM&, JSScope*);
     93    JS_EXPORT_PRIVATE void finishCreation(VM&);
     94
     95    JSScope* jsScope() const { return m_scope.get(); }
     96
    6097    static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | JSObject::StructureFlags;
    6198
    62     JS_EXPORT_PRIVATE void finishCreation(VM&, JSObject* activation);
     99    WriteBarrier<JSScope> m_scope;
     100    WriteBarrier<DebuggerScope> m_next;
    63101
    64 private:
    65     JS_EXPORT_PRIVATE DebuggerScope(VM&);
    66     WriteBarrier<JSActivation> m_activation;
     102    friend class DebuggerCallFrame;
    67103};
     104
     105inline DebuggerScope::Iterator DebuggerScope::begin()
     106{
     107    return Iterator(this);
     108}
     109
     110inline DebuggerScope::Iterator DebuggerScope::end()
     111{
     112    return Iterator(0);
     113}
    68114
    69115} // namespace JSC
  • branches/ftlopt/Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.cpp

    r162970 r170680  
    2929#if ENABLE(INSPECTOR)
    3030
     31#include "DebuggerScope.h"
    3132#include "Error.h"
    3233#include "JSCJSValue.h"
     
    9697    int index = exec->argument(0).asInt32();
    9798
    98     JSScope* scopeChain = impl().scopeChain();
    99     ScopeChainIterator end = scopeChain->end();
    100 
    101     // FIXME: We should be identifying and returning CATCH_SCOPE appropriately.
     99    DebuggerScope* scopeChain = impl().scopeChain();
     100    DebuggerScope::Iterator end = scopeChain->end();
    102101
    103102    bool foundLocalScope = false;
    104     for (ScopeChainIterator iter = scopeChain->begin(); iter != end; ++iter) {
    105         JSObject* scope = iter.get();
    106         if (scope->isActivationObject()) {
    107             if (!foundLocalScope) {
    108                 // First activation object is local scope, each successive activation object is closure.
    109                 if (!index)
    110                     return jsNumber(JSJavaScriptCallFrame::LOCAL_SCOPE);
    111                 foundLocalScope = true;
    112             } else if (!index)
    113                 return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
     103    for (DebuggerScope::Iterator iter = scopeChain->begin(); iter != end; ++iter) {
     104        DebuggerScope* scope = iter.get();
     105
     106        if (!foundLocalScope && scope->isFunctionScope()) {
     107            // First function scope is the local scope, each successive one is a closure.
     108            if (!index)
     109                return jsNumber(JSJavaScriptCallFrame::LOCAL_SCOPE);
     110            foundLocalScope = true;
    114111        }
    115112
    116113        if (!index) {
    117             // Last in the chain is global scope.
    118             if (++iter == end)
     114            if (scope->isWithScope())
     115                return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
     116            if (scope->isGlobalScope()) {
     117                ASSERT(++iter == end);
    119118                return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE);
    120             return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
     119            }
     120            // FIXME: We should be identifying and returning CATCH_SCOPE appropriately.
     121            ASSERT(scope->isFunctionScope());
     122            return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
    121123        }
    122124
     
    158160        return jsNull();
    159161
    160     JSScope* scopeChain = impl().scopeChain();
    161     ScopeChainIterator iter = scopeChain->begin();
    162     ScopeChainIterator end = scopeChain->end();
     162    DebuggerScope* scopeChain = impl().scopeChain();
     163    DebuggerScope::Iterator iter = scopeChain->begin();
     164    DebuggerScope::Iterator end = scopeChain->end();
    163165
    164166    // We must always have something in the scope chain.
  • branches/ftlopt/Source/JavaScriptCore/inspector/JavaScriptCallFrame.h

    r162970 r170680  
    11/*
    2  * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2008, 2013-2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5454    String functionName() const { return m_debuggerCallFrame->functionName(); }
    5555    JSC::DebuggerCallFrame::Type type() const { return m_debuggerCallFrame->type(); }
    56     JSC::JSScope* scopeChain() const { return m_debuggerCallFrame->scope(); }
     56    JSC::DebuggerScope* scopeChain() const { return m_debuggerCallFrame->scope(); }
    5757    JSC::JSGlobalObject* vmEntryGlobalObject() const { return m_debuggerCallFrame->vmEntryGlobalObject(); }
    5858
  • branches/ftlopt/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp

    r167816 r170680  
    3535
    3636#include "DebuggerCallFrame.h"
     37#include "DebuggerScope.h"
    3738#include "JSJavaScriptCallFrame.h"
    3839#include "JSLock.h"
  • branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r170564 r170680  
    4646#include "DatePrototype.h"
    4747#include "Debugger.h"
     48#include "DebuggerScope.h"
    4849#include "Error.h"
    4950#include "ErrorConstructor.h"
     
    321322    m_activationStructure.set(vm, this, JSActivation::createStructure(vm, this, jsNull()));
    322323    m_strictEvalActivationStructure.set(vm, this, StrictEvalActivation::createStructure(vm, this, jsNull()));
     324    m_debuggerScopeStructure.set(m_vm, this, DebuggerScope::createStructure(m_vm, this, jsNull()));
    323325    m_withScopeStructure.set(vm, this, JSWithScope::createStructure(vm, this, jsNull()));
    324326
     
    662664#endif
    663665
     666    visitor.append(&thisObject->m_debuggerScopeStructure);
    664667    visitor.append(&thisObject->m_withScopeStructure);
    665668    visitor.append(&thisObject->m_strictEvalActivationStructure);
  • branches/ftlopt/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r167963 r170680  
    184184#endif
    185185
     186    WriteBarrier<Structure> m_debuggerScopeStructure;
    186187    WriteBarrier<Structure> m_withScopeStructure;
    187188    WriteBarrier<Structure> m_strictEvalActivationStructure;
     
    389390#endif
    390391
     392    Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); }
    391393    Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
    392394    Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }
  • branches/ftlopt/Source/JavaScriptCore/runtime/JSObject.h

    r169628 r170680  
    600600    bool isActivationObject() const;
    601601    bool isErrorInstance() const;
     602    bool isWithScope() const;
    602603
    603604    JS_EXPORT_PRIVATE void seal(VM&);
     
    11481149}
    11491150
     1151inline bool JSObject::isWithScope() const
     1152{
     1153    return type() == WithScopeType;
     1154}
     1155
    11501156inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
    11511157{
  • branches/ftlopt/Source/JavaScriptCore/runtime/JSScope.h

    r163223 r170680  
    151151    static size_t offsetOfNext();
    152152
    153     JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*);
     153    static JSObject* objectAtScope(JSScope*);
    154154
    155155    static JSValue resolve(ExecState*, JSScope*, const Identifier&);
  • branches/ftlopt/Source/JavaScriptCore/runtime/VM.cpp

    r170564 r170680  
    4040#include "DFGLongLivedState.h"
    4141#include "DFGWorklist.h"
    42 #include "DebuggerScope.h"
    4342#include "ErrorInstance.h"
    4443#include "FTLThunks.h"
     
    256255    structureStructure.set(*this, Structure::createStructure(*this));
    257256    structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
    258     debuggerScopeStructure.set(*this, DebuggerScope::createStructure(*this, 0, jsNull()));
    259257    terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
    260258    stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
  • branches/ftlopt/Source/JavaScriptCore/runtime/VM.h

    r170490 r170680  
    263263        Strong<Structure> structureStructure;
    264264        Strong<Structure> structureRareDataStructure;
    265         Strong<Structure> debuggerScopeStructure;
    266265        Strong<Structure> terminatedExecutionErrorStructure;
    267266        Strong<Structure> stringStructure;
  • branches/ftlopt/Source/WebCore/ChangeLog

    r170564 r170680  
     12014-07-01  Mark Lam  <mark.lam@apple.com>
     2
     3        [ftlopt] DebuggerCallFrame::scope() should return a DebuggerScope.
     4        <https://webkit.org/b/134420>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        No new tests.
     9
     10        * ForwardingHeaders/debugger/DebuggerCallFrame.h: Removed.
     11        - This is not in use.  Hence, we can remove it.
     12        * bindings/js/ScriptController.cpp:
     13        (WebCore::ScriptController::attachDebugger):
     14        - We should acquire the JSLock before modifying a JS global object.
     15
    1162014-06-25  Filip Pizlo  <fpizlo@apple.com>
    217
  • branches/ftlopt/Source/WebCore/bindings/js/ScriptController.cpp

    r165199 r170680  
    296296
    297297    JSDOMWindow* globalObject = shell->window();
     298    JSLockHolder lock(globalObject->vm());
    298299    if (debugger)
    299300        debugger->attach(globalObject);
Note: See TracChangeset for help on using the changeset viewer.