Changeset 173100 in webkit


Ignore:
Timestamp:
Aug 28, 2014 5:48:59 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

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

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Rolling back in r170680 with the fix for <https://webkit.org/b/135656>.

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, its liveness is determined by its reachability.
However, its "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.

Fix for <https://webkit.org/b/135656>:

  1. DebuggerScope::getOwnPropertySlot() and DebuggerScope::put() need to set m_thisValue in the returned slot to the wrapped scope object. Previously, it was pointing to the DebuggerScope though the rest of the fields in the returned slot will be set to data pertaining the wrapped scope object.
  1. DebuggerScope::getOwnPropertySlot() will invoke getPropertySlot() on its wrapped scope. This is because JSObject::getPropertySlot() cannot be overridden, and when called on a DebuggerScope, will not know to look in the ptototype chain of the DebuggerScope's wrapped scope. Hence, we'll treat all properties in the wrapped scope as own properties in the DebuggerScope. This is fine because the WebInspector does not presently care about where in the prototype chain the scope property comes from.

Note that the DebuggerScope and the JSActivation objects that it wraps do
not have prototypes. They are always jsNull(). This works perfectly with
the above change to use getPropertySlot() instead of getOwnPropertySlot().
To make this an explicit invariant, I also changed DebuggerScope::createStructure()
and JSActivation::createStructure() to not take a prototype argument, and
to always use jsNull() for their prototype value.

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

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

  • 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::isFunctionOrEvalScope):

  • debugger/DebuggerScope.h:

(JSC::DebuggerScope::create):
(JSC::DebuggerScope::createStructure):
(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/JSActivation.h:

(JSC::JSActivation::createStructure):

  • runtime/JSGlobalObject.cpp:

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

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::debuggerScopeStructure):

  • runtime/JSObject.cpp:
  • runtime/JSObject.h:

(JSC::JSObject::isWithScope):

  • runtime/JSScope.h:
  • runtime/PropertySlot.h:

(JSC::PropertySlot::setThisValue):

  • runtime/PutPropertySlot.h:

(JSC::PutPropertySlot::setThisValue):

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:

Source/WebCore:

No new tests.

Rolling back in r170680 with the fix for <https://webkit.org/b/135656>.

  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::attachDebugger):

  • We should acquire the JSLock before modifying a JS global object.
Location:
trunk/Source
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r173082 r173100  
     12014-08-28  Mark Lam  <mark.lam@apple.com>
     2
     3        DebuggerCallFrame::scope() should return a DebuggerScope.
     4        <https://webkit.org/b/134420>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Rolling back in r170680 with the fix for <https://webkit.org/b/135656>.
     9
     10        Previously, DebuggerCallFrame::scope() returns a JSActivation (and relevant
     11        peers) which the WebInspector will use to introspect CallFrame variables.
     12        Instead, we should be returning a DebuggerScope as an abstraction layer that
     13        provides the introspection functionality that the WebInspector needs.  This
     14        is the first step towards not forcing every frame to have a JSActivation
     15        object just because the debugger is enabled.
     16
     17        1. Instantiate the debuggerScopeStructure as a member of the JSGlobalObject
     18           instead of the VM.  This allows JSObject::globalObject() to be able to
     19           return the global object for the DebuggerScope.
     20
     21        2. On the DebuggerScope's life-cycle management:
     22
     23           The DebuggerCallFrame is designed to be "valid" only during a debugging session
     24           (while the debugger is broken) through the use of a DebuggerCallFrameScope in
     25           Debugger::pauseIfNeeded().  Once the debugger resumes from the break, the
     26           DebuggerCallFrameScope destructs, and the DebuggerCallFrame will be invalidated.
     27           We can't guarantee (from this code alone) that the Inspector code isn't still
     28           holding a ref to the DebuggerCallFrame (though they shouldn't), but by contract,
     29           the frame will be invalidated, and any attempt to query it will return null values.
     30           This is pre-existing behavior.
     31
     32           Now, we're adding the DebuggerScope into the picture.  While a single debugger
     33           pause session is in progress, the Inspector may request the scope from the
     34           DebuggerCallFrame.  While the DebuggerCallFrame is still valid, we want
     35           DebuggerCallFrame::scope() to always return the same DebuggerScope object.
     36           This is why we hold on to the DebuggerScope with a strong ref.
     37
     38           If we use a weak ref instead, the following cooky behavior can manifest:
     39           1. The Inspector calls Debugger::scope() to get the top scope.
     40           2. The Inspector iterates down the scope chain and is now only holding a
     41              reference to a parent scope.  It is no longer referencing the top scope.
     42           3. A GC occurs, and the DebuggerCallFrame's weak m_scope ref to the top scope
     43              gets cleared.
     44           4. The Inspector calls DebuggerCallFrame::scope() to get the top scope again but gets
     45              a different DebuggerScope instance.
     46           5. The Inspector iterates down the scope chain but never sees the parent scope
     47              instance that retained a ref to in step 2 above.  This is because when iterating
     48              this new DebuggerScope instance (which has no knowledge of the previous parent
     49              DebuggerScope instance), a new DebuggerScope instance will get created for the
     50              same parent scope.
     51
     52           Since the DebuggerScope is a JSObject, its liveness is determined by its reachability.
     53           However, its "validity" is determined by the life-cycle of its owner DebuggerCallFrame.
     54           When the owner DebuggerCallFrame gets invalidated, its debugger scope chain (if
     55           instantiated) will also get invalidated.  This is why we need the
     56           DebuggerScope::invalidateChain() method.  The Inspector should not be using the
     57           DebuggerScope instance after its owner DebuggerCallFrame is invalidated.  If it does,
     58           those methods will do nothing or returned a failed status.
     59
     60        Fix for <https://webkit.org/b/135656>:
     61        3. DebuggerScope::getOwnPropertySlot() and DebuggerScope::put() need to set
     62           m_thisValue in the returned slot to the wrapped scope object.  Previously,
     63           it was pointing to the DebuggerScope though the rest of the fields in the
     64           returned slot will be set to data pertaining the wrapped scope object.
     65
     66        4. DebuggerScope::getOwnPropertySlot() will invoke getPropertySlot() on its
     67           wrapped scope.  This is because JSObject::getPropertySlot() cannot be
     68           overridden, and when called on a DebuggerScope, will not know to look in
     69           the ptototype chain of the DebuggerScope's wrapped scope.  Hence, we'll
     70           treat all properties in the wrapped scope as own properties in the
     71           DebuggerScope.  This is fine because the WebInspector does not presently
     72           care about where in the prototype chain the scope property comes from.
     73
     74           Note that the DebuggerScope and the JSActivation objects that it wraps do
     75           not have prototypes.  They are always jsNull().  This works perfectly with
     76           the above change to use getPropertySlot() instead of getOwnPropertySlot().
     77           To make this an explicit invariant, I also changed DebuggerScope::createStructure()
     78           and JSActivation::createStructure() to not take a prototype argument, and
     79           to always use jsNull() for their prototype value.
     80
     81        * debugger/Debugger.h:
     82        * debugger/DebuggerCallFrame.cpp:
     83        (JSC::DebuggerCallFrame::scope):
     84        (JSC::DebuggerCallFrame::evaluate):
     85        (JSC::DebuggerCallFrame::invalidate):
     86        * debugger/DebuggerCallFrame.h:
     87        * debugger/DebuggerScope.cpp:
     88        (JSC::DebuggerScope::DebuggerScope):
     89        (JSC::DebuggerScope::finishCreation):
     90        (JSC::DebuggerScope::visitChildren):
     91        (JSC::DebuggerScope::className):
     92        (JSC::DebuggerScope::getOwnPropertySlot):
     93        (JSC::DebuggerScope::put):
     94        (JSC::DebuggerScope::deleteProperty):
     95        (JSC::DebuggerScope::getOwnPropertyNames):
     96        (JSC::DebuggerScope::defineOwnProperty):
     97        (JSC::DebuggerScope::next):
     98        (JSC::DebuggerScope::invalidateChain):
     99        (JSC::DebuggerScope::isWithScope):
     100        (JSC::DebuggerScope::isGlobalScope):
     101        (JSC::DebuggerScope::isFunctionOrEvalScope):
     102        * debugger/DebuggerScope.h:
     103        (JSC::DebuggerScope::create):
     104        (JSC::DebuggerScope::createStructure):
     105        (JSC::DebuggerScope::iterator::iterator):
     106        (JSC::DebuggerScope::iterator::get):
     107        (JSC::DebuggerScope::iterator::operator++):
     108        (JSC::DebuggerScope::iterator::operator==):
     109        (JSC::DebuggerScope::iterator::operator!=):
     110        (JSC::DebuggerScope::isValid):
     111        (JSC::DebuggerScope::jsScope):
     112        (JSC::DebuggerScope::begin):
     113        (JSC::DebuggerScope::end):
     114        * inspector/JSJavaScriptCallFrame.cpp:
     115        (Inspector::JSJavaScriptCallFrame::scopeType):
     116        (Inspector::JSJavaScriptCallFrame::scopeChain):
     117        * inspector/JavaScriptCallFrame.h:
     118        (Inspector::JavaScriptCallFrame::scopeChain):
     119        * inspector/ScriptDebugServer.cpp:
     120        * runtime/JSActivation.h:
     121        (JSC::JSActivation::createStructure):
     122        * runtime/JSGlobalObject.cpp:
     123        (JSC::JSGlobalObject::reset):
     124        (JSC::JSGlobalObject::visitChildren):
     125        * runtime/JSGlobalObject.h:
     126        (JSC::JSGlobalObject::debuggerScopeStructure):
     127        * runtime/JSObject.cpp:
     128        * runtime/JSObject.h:
     129        (JSC::JSObject::isWithScope):
     130        * runtime/JSScope.h:
     131        * runtime/PropertySlot.h:
     132        (JSC::PropertySlot::setThisValue):
     133        * runtime/PutPropertySlot.h:
     134        (JSC::PutPropertySlot::setThisValue):
     135        * runtime/VM.cpp:
     136        (JSC::VM::VM):
     137        * runtime/VM.h:
     138
    11392014-08-28  Andreas Kling  <akling@apple.com>
    2140
  • trunk/Source/JavaScriptCore/debugger/Debugger.h

    r172372 r173100  
    3434namespace JSC {
    3535
     36class CodeBlock;
    3637class ExecState;
    3738class JSGlobalObject;
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

    r172665 r173100  
    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 {
     
    133135}
    134136
    135 JSScope* DebuggerCallFrame::scope() const
    136 {
    137     ASSERT(isValid());
    138     if (!isValid())
    139         return 0;
    140 
    141     CodeBlock* codeBlock = m_callFrame->codeBlock();
    142     if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
    143         JSActivation* activation = JSActivation::create(*codeBlock->vm(), m_callFrame, codeBlock);
    144         m_callFrame->setActivation(activation);
    145         m_callFrame->setScope(activation);
    146     }
    147 
    148     return m_callFrame->scope();
     137DebuggerScope* DebuggerCallFrame::scope()
     138{
     139    ASSERT(isValid());
     140    if (!isValid())
     141        return 0;
     142
     143    if (!m_scope) {
     144        VM& vm = m_callFrame->vm();
     145        CodeBlock* codeBlock = m_callFrame->codeBlock();
     146        if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
     147            ASSERT(!m_callFrame->scope()->isWithScope());
     148            JSActivation* activation = JSActivation::create(vm, m_callFrame, codeBlock);
     149            m_callFrame->setActivation(activation);
     150            m_callFrame->setScope(activation);
     151        }
     152
     153        m_scope.set(vm, DebuggerScope::create(vm, m_callFrame->scope()));
     154    }
     155    return m_scope.get();
    149156}
    150157
     
    189196
    190197    JSValue thisValue = thisValueForCallFrame(callFrame);
    191     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope());
     198    JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
    192199    if (vm.exception()) {
    193200        exception = vm.exception();
     
    201208{
    202209    m_callFrame = nullptr;
     210    if (m_scope) {
     211        m_scope->invalidateChain();
     212        m_scope.clear();
     213    }
    203214    RefPtr<DebuggerCallFrame> frame = m_caller.release();
    204215    while (frame) {
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.h

    r172372 r173100  
    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
  • trunk/Source/JavaScriptCore/debugger/DebuggerScope.cpp

    r172372 r173100  
    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, 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
     
    5454    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    5555    JSObject::visitChildren(thisObject, visitor);
    56     visitor.append(&thisObject->m_activation);
     56    visitor.append(&thisObject->m_scope);
     57    visitor.append(&thisObject->m_next);
    5758}
    5859
    5960String DebuggerScope::className(const JSObject* object)
    6061{
    61     const DebuggerScope* thisObject = jsCast<const DebuggerScope*>(object);
    62     return thisObject->m_activation->methodTable()->className(thisObject->m_activation.get());
     62    const DebuggerScope* scope = jsCast<const DebuggerScope*>(object);
     63    ASSERT(scope->isValid());
     64    if (!scope->isValid())
     65        return String();
     66    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     67    return thisObject->methodTable()->className(thisObject);
    6368}
    6469
    6570bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    6671{
    67     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    68     return thisObject->m_activation->methodTable()->getOwnPropertySlot(thisObject->m_activation.get(), exec, propertyName, slot);
     72    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     73    ASSERT(scope->isValid());
     74    if (!scope->isValid())
     75        return false;
     76    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     77    slot.setThisValue(JSValue(thisObject));
     78
     79    // By default, JSObject::getPropertySlot() will look in the DebuggerScope's prototype
     80    // chain and not the wrapped scope, and JSObject::getPropertySlot() cannot be overridden
     81    // to behave differently for the DebuggerScope.
     82    //
     83    // Instead, we'll treat all properties in the wrapped scope and its prototype chain as
     84    // the own properties of the DebuggerScope. This is fine because the WebInspector
     85    // does not presently need to distinguish between what's owned at each level in the
     86    // prototype chain. Hence, we'll invoke getPropertySlot() on the wrapped scope here
     87    // instead of getOwnPropertySlot().
     88    return thisObject->getPropertySlot(exec, propertyName, slot);
    6989}
    7090
    7191void DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    7292{
    73     DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
    74     thisObject->m_activation->methodTable()->put(thisObject->m_activation.get(), exec, propertyName, value, slot);
     93    DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
     94    ASSERT(scope->isValid());
     95    if (!scope->isValid())
     96        return;
     97    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     98    slot.setThisValue(JSValue(thisObject));
     99    thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot);
    75100}
    76101
    77102bool DebuggerScope::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
    78103{
    79     DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
    80     return thisObject->m_activation->methodTable()->deleteProperty(thisObject->m_activation.get(), exec, propertyName);
     104    DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
     105    ASSERT(scope->isValid());
     106    if (!scope->isValid())
     107        return false;
     108    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     109    return thisObject->methodTable()->deleteProperty(thisObject, exec, propertyName);
    81110}
    82111
    83112void DebuggerScope::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    84113{
    85     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    86     thisObject->m_activation->methodTable()->getPropertyNames(thisObject->m_activation.get(), exec, propertyNames, mode);
     114    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     115    ASSERT(scope->isValid());
     116    if (!scope->isValid())
     117        return;
     118    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     119    thisObject->methodTable()->getPropertyNames(thisObject, exec, propertyNames, mode);
    87120}
    88121
    89122bool DebuggerScope::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
    90123{
    91     DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
    92     return thisObject->m_activation->methodTable()->defineOwnProperty(thisObject->m_activation.get(), exec, propertyName, descriptor, shouldThrow);
     124    DebuggerScope* scope = jsCast<DebuggerScope*>(object);
     125    ASSERT(scope->isValid());
     126    if (!scope->isValid())
     127        return false;
     128    JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
     129    return thisObject->methodTable()->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
     130}
     131
     132DebuggerScope* DebuggerScope::next()
     133{
     134    ASSERT(isValid());
     135    if (!m_next && m_scope->next()) {
     136        VM& vm = *m_scope->vm();
     137        DebuggerScope* nextScope = create(vm, m_scope->next());
     138        m_next.set(vm, this, nextScope);
     139    }
     140    return m_next.get();
     141}
     142
     143void DebuggerScope::invalidateChain()
     144{
     145    DebuggerScope* scope = this;
     146    while (scope) {
     147        ASSERT(scope->isValid());
     148        DebuggerScope* nextScope = scope->m_next.get();
     149        scope->m_next.clear();
     150        scope->m_scope.clear();
     151        scope = nextScope;
     152    }
     153}
     154
     155bool DebuggerScope::isWithScope() const
     156{
     157    return m_scope->isWithScope();
     158}
     159
     160bool DebuggerScope::isGlobalScope() const
     161{
     162    return m_scope->isGlobalObject();
     163}
     164
     165bool DebuggerScope::isFunctionOrEvalScope() const
     166{
     167    // In the current debugger implementation, every function or eval will create an
     168    // activation object. Hence, an activation object implies a function or eval scope.
     169    return m_scope->isActivationObject();
    93170}
    94171
  • trunk/Source/JavaScriptCore/debugger/DebuggerScope.h

    r172372 r173100  
    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
     
    5255    DECLARE_EXPORT_INFO;
    5356
    54     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     57    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
    5558    {
    56         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     59        return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), info());
    5760    }
    5861
    59 protected:
    60     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
     62    class iterator {
     63    public:
     64        iterator(DebuggerScope* node)
     65            : m_node(node)
     66        {
     67        }
    6168
    62     JS_EXPORT_PRIVATE void finishCreation(VM&, JSObject* activation);
     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 isFunctionOrEvalScope() const;
    6390
    6491private:
    65     JS_EXPORT_PRIVATE DebuggerScope(VM&);
    66     WriteBarrier<JSActivation> m_activation;
     92    JS_EXPORT_PRIVATE DebuggerScope(VM&, JSScope*);
     93    JS_EXPORT_PRIVATE void finishCreation(VM&);
     94
     95    JSScope* jsScope() const { return m_scope.get(); }
     96
     97    static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
     98
     99    WriteBarrier<JSScope> m_scope;
     100    WriteBarrier<DebuggerScope> m_next;
     101
     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
  • trunk/Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.cpp

    r172372 r173100  
    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->isFunctionOrEvalScope()) {
     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->isFunctionOrEvalScope());
     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.
  • trunk/Source/JavaScriptCore/inspector/JavaScriptCallFrame.h

    r172372 r173100  
    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
  • trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp

    r172372 r173100  
    3535
    3636#include "DebuggerCallFrame.h"
     37#include "DebuggerScope.h"
    3738#include "JSJavaScriptCallFrame.h"
    3839#include "JSLock.h"
  • trunk/Source/JavaScriptCore/runtime/JSActivation.h

    r171939 r173100  
    8282    DECLARE_INFO;
    8383
    84     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), info()); }
     84    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ActivationObjectType, StructureFlags), info()); }
    8585
    8686    WriteBarrierBase<Unknown>& registerAt(int) const;
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r172372 r173100  
    4646#include "DatePrototype.h"
    4747#include "Debugger.h"
     48#include "DebuggerScope.h"
    4849#include "Error.h"
    4950#include "ErrorConstructor.h"
     
    319320
    320321    m_nameScopeStructure.set(vm, this, JSNameScope::createStructure(vm, this, jsNull()));
    321     m_activationStructure.set(vm, this, JSActivation::createStructure(vm, this, jsNull()));
     322    m_activationStructure.set(vm, this, JSActivation::createStructure(vm, this));
    322323    m_strictEvalActivationStructure.set(vm, this, StrictEvalActivation::createStructure(vm, this, jsNull()));
     324    m_debuggerScopeStructure.set(m_vm, this, DebuggerScope::createStructure(m_vm, this));
    323325    m_withScopeStructure.set(vm, this, JSWithScope::createStructure(vm, this, jsNull()));
    324326
     
    663665#endif
    664666
     667    visitor.append(&thisObject->m_debuggerScopeStructure);
    665668    visitor.append(&thisObject->m_withScopeStructure);
    666669    visitor.append(&thisObject->m_strictEvalActivationStructure);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r172372 r173100  
    187187#endif
    188188
     189    WriteBarrier<Structure> m_debuggerScopeStructure;
    189190    WriteBarrier<Structure> m_withScopeStructure;
    190191    WriteBarrier<Structure> m_strictEvalActivationStructure;
     
    392393#endif
    393394
     395    Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); }
    394396    Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
    395397    Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r172176 r173100  
    27832783}
    27842784
    2785 
    27862785} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r172372 r173100  
    595595    bool isActivationObject() const;
    596596    bool isErrorInstance() const;
     597    bool isWithScope() const;
    597598
    598599    JS_EXPORT_PRIVATE void seal(VM&);
     
    11511152}
    11521153
     1154inline bool JSObject::isWithScope() const
     1155{
     1156    return type() == WithScopeType;
     1157}
     1158
    11531159inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
    11541160{
  • trunk/Source/JavaScriptCore/runtime/JSScope.h

    r172808 r173100  
    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&);
  • trunk/Source/JavaScriptCore/runtime/PropertySlot.h

    r172120 r173100  
    205205    }
    206206
     207    void setThisValue(JSValue thisValue)
     208    {
     209        m_thisValue = thisValue;
     210    }
     211
    207212    void setUndefined()
    208213    {
     
    236241    PropertyType m_propertyType;
    237242    PropertyOffset m_offset;
    238     const JSValue m_thisValue;
     243    JSValue m_thisValue;
    239244    JSObject* m_slotBase;
    240245    WatchpointSet* m_watchpointSet;
  • trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h

    r166945 r173100  
    8181        }
    8282
     83        void setThisValue(JSValue thisValue)
     84        {
     85            m_thisValue = thisValue;
     86        }
     87
    8388        PutValueFunc customSetter() const { return m_putFunction; }
    8489
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r173069 r173100  
    4141#include "DFGLongLivedState.h"
    4242#include "DFGWorklist.h"
    43 #include "DebuggerScope.h"
    4443#include "ErrorInstance.h"
    4544#include "FTLThunks.h"
     
    210209    structureStructure.set(*this, Structure::createStructure(*this));
    211210    structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
    212     debuggerScopeStructure.set(*this, DebuggerScope::createStructure(*this, 0, jsNull()));
    213211    terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
    214212    stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r173069 r173100  
    247247        Strong<Structure> structureStructure;
    248248        Strong<Structure> structureRareDataStructure;
    249         Strong<Structure> debuggerScopeStructure;
    250249        Strong<Structure> terminatedExecutionErrorStructure;
    251250        Strong<Structure> stringStructure;
  • trunk/Source/WebCore

  • trunk/Source/WebCore/ChangeLog

    r173097 r173100  
     12014-08-28  Mark Lam  <mark.lam@apple.com>
     2
     3        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        Rolling back in r170680 with the fix for <https://webkit.org/b/135656>.
     11
     12        * bindings/js/ScriptController.cpp:
     13        (WebCore::ScriptController::attachDebugger):
     14        - We should acquire the JSLock before modifying a JS global object.
     15
    1162014-08-28  Enrica Casucci  <enrica@apple.com>
    217
  • trunk/Source/WebCore/bindings/js/ScriptController.cpp

    r172372 r173100  
    308308
    309309    JSDOMWindow* globalObject = shell->window();
     310    JSLockHolder lock(globalObject->vm());
    310311    if (debugger)
    311312        debugger->attach(globalObject);
Note: See TracChangeset for help on using the changeset viewer.