Changeset 202659 in webkit


Ignore:
Timestamp:
Jun 29, 2016 4:59:35 PM (8 years ago)
Author:
Joseph Pecoraro
Message:

Web Inspector: Wrong function name next to scope
https://bugs.webkit.org/show_bug.cgi?id=158210
<rdar://problem/26543093>

Reviewed by Brian Burg.

Source/JavaScriptCore:

Add DebuggerLocation. A helper for describing a unique location.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::setConstantRegisters):
When compiled with debug info, add a SymbolTable rare data pointer
back to the CodeBlock. This will be used later to get JSScope debug
info if Web Inspector pauses.

  • runtime/SymbolTable.h:
  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::cloneScopePart):
(JSC::SymbolTable::prepareForTypeProfiling):
(JSC::SymbolTable::uniqueIDForVariable):
(JSC::SymbolTable::uniqueIDForOffset):
(JSC::SymbolTable::globalTypeSetForOffset):
(JSC::SymbolTable::globalTypeSetForVariable):
Rename rareData and include a CodeBlock pointer.

(JSC::SymbolTable::rareDataCodeBlock):
(JSC::SymbolTable::setRareDataCodeBlock):
Setter and getter for the rare data. It should only be set once.

(JSC::SymbolTable::visitChildren):
Visit the rare data code block if we have one.

  • debugger/DebuggerLocation.cpp: Added.

(JSC::DebuggerLocation::DebuggerLocation):

  • debugger/DebuggerLocation.h: Added.

(JSC::DebuggerLocation::DebuggerLocation):
Construction from a ScriptExecutable.

  • runtime/JSScope.cpp:

(JSC::JSScope::symbolTable):

  • runtime/JSScope.h:
  • debugger/DebuggerScope.h:
  • debugger/DebuggerScope.cpp:

(JSC::DebuggerScope::name):
(JSC::DebuggerScope::location):
Name and location for a scope. This uses:
JSScope -> SymbolTable -> CodeBlock -> Executable

  • inspector/protocol/Debugger.json:
  • inspector/InjectedScriptSource.js:

(InjectedScript.CallFrameProxy.prototype._wrapScopeChain):
(InjectedScript.CallFrameProxy._createScopeJson):

  • inspector/JSJavaScriptCallFrame.cpp:

(Inspector::valueForScopeType):
(Inspector::valueForScopeLocation):
(Inspector::JSJavaScriptCallFrame::scopeDescriptions):
(Inspector::JSJavaScriptCallFrame::scopeType): Deleted.

  • inspector/JSJavaScriptCallFrame.h:
  • inspector/JSJavaScriptCallFramePrototype.cpp:

(Inspector::JSJavaScriptCallFramePrototype::finishCreation):
(Inspector::jsJavaScriptCallFramePrototypeFunctionScopeDescriptions):
(Inspector::jsJavaScriptCallFramePrototypeFunctionScopeType): Deleted.
Simplify this code to build the objects we will send across the protocol
to descript a Scope.

Source/WebInspectorUI:

  • UserInterface/Controllers/DebuggerManager.js:

(WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload):
Include new payload data in the construction call.
All the new data is optional, so we gracefully handle
legacy backends.

  • UserInterface/Models/ScopeChainNode.js:

(WebInspector.ScopeChainNode):
(WebInspector.ScopeChainNode.prototype.get type):
(WebInspector.ScopeChainNode.prototype.get objects):
(WebInspector.ScopeChainNode.prototype.get name):
(WebInspector.ScopeChainNode.prototype.get location):
(WebInspector.ScopeChainNode.prototype.get hash):
Hash is a rough (name:sourceId:line:column) string for quick comparisons.

(WebInspector.ScopeChainNode.prototype.makeLocalScope):
Make this an action you take on a scope, to avoid having to
do it at construction time, or making it a generic setting.

  • UserInterface/Views/ScopeChainDetailsSidebarPanel.js:

(WebInspector.ScopeChainDetailsSidebarPanel.prototype._generateCallFramesSection):
This was wrong before. Move the work to CallFrame
and change it to be correct.

  • UserInterface/CallFrame.js:

(WebInspector.CallFrame.prototype.mergedScopeChain):

This transforms the scope chain for a call frame from:

scope1 scope2 scope3 scope4 scope5 scope6 scope7

foo foo foo bar bar - -

Block Closure Closure Closure Closure GLE GBL

To:

scope1 scope2&3 scope4&5 scope6 scope7

foo foo* bar* - -

Block Local Closure GLE GBL

Doing a few things:

  • Merge the first two Closure scopes sharing a location. These are the "var" and "let" Closure scopes in a function, and it is better to present these together in the UI.
  • Mark the first Closure scope within a function (*). When this is displayed in the UI, we can provide the name of the function: "Closure Scope (name)", and we even have location information that we can use to display a goto arrow if needed.
  • Make the first Closure scope the Local scope if it matches the Call Frame's function name. This lets us display the section as "Local Variables".

LayoutTests:

  • inspector/debugger/paused-scopes-expected.txt: Added.
  • inspector/debugger/paused-scopes.html: Added.
  • inspector/debugger/resources/paused-scopes.js: Added.

Test dumps the call frames and scope chains for each call frame
when pausing at different locations in a program. Outputting
the hashes we can see even identically named functions have
different hashes because their location is different.

Location:
trunk
Files:
5 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r202649 r202659  
     12016-06-29  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Wrong function name next to scope
     4        https://bugs.webkit.org/show_bug.cgi?id=158210
     5        <rdar://problem/26543093>
     6
     7        Reviewed by Brian Burg.
     8
     9        * inspector/debugger/paused-scopes-expected.txt: Added.
     10        * inspector/debugger/paused-scopes.html: Added.
     11        * inspector/debugger/resources/paused-scopes.js: Added.
     12        Test dumps the call frames and scope chains for each call frame
     13        when pausing at different locations in a program. Outputting
     14        the hashes we can see even identically named functions have
     15        different hashes because their location is different.
     16
    1172016-06-29  Ryan Haddad  <ryanhaddad@apple.com>
    218
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r202435 r202659  
    240240    debugger/Debugger.cpp
    241241    debugger/DebuggerCallFrame.cpp
     242    debugger/DebuggerLocation.cpp
    242243    debugger/DebuggerScope.cpp
    243244
  • trunk/Source/JavaScriptCore/ChangeLog

    r202654 r202659  
     12016-06-29  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Wrong function name next to scope
     4        https://bugs.webkit.org/show_bug.cgi?id=158210
     5        <rdar://problem/26543093>
     6
     7        Reviewed by Brian Burg.
     8
     9        * CMakeLists.txt:
     10        * JavaScriptCore.xcodeproj/project.pbxproj:
     11        Add DebuggerLocation. A helper for describing a unique location.
     12
     13        * bytecode/CodeBlock.cpp:
     14        (JSC::CodeBlock::setConstantRegisters):
     15        When compiled with debug info, add a SymbolTable rare data pointer
     16        back to the CodeBlock. This will be used later to get JSScope debug
     17        info if Web Inspector pauses.
     18
     19        * runtime/SymbolTable.h:
     20        * runtime/SymbolTable.cpp:
     21        (JSC::SymbolTable::cloneScopePart):
     22        (JSC::SymbolTable::prepareForTypeProfiling):
     23        (JSC::SymbolTable::uniqueIDForVariable):
     24        (JSC::SymbolTable::uniqueIDForOffset):
     25        (JSC::SymbolTable::globalTypeSetForOffset):
     26        (JSC::SymbolTable::globalTypeSetForVariable):
     27        Rename rareData and include a CodeBlock pointer.
     28
     29        (JSC::SymbolTable::rareDataCodeBlock):
     30        (JSC::SymbolTable::setRareDataCodeBlock):
     31        Setter and getter for the rare data. It should only be set once.
     32
     33        (JSC::SymbolTable::visitChildren):
     34        Visit the rare data code block if we have one.
     35
     36        * debugger/DebuggerLocation.cpp: Added.
     37        (JSC::DebuggerLocation::DebuggerLocation):
     38        * debugger/DebuggerLocation.h: Added.
     39        (JSC::DebuggerLocation::DebuggerLocation):
     40        Construction from a ScriptExecutable.
     41
     42        * runtime/JSScope.cpp:
     43        (JSC::JSScope::symbolTable):
     44        * runtime/JSScope.h:
     45        * debugger/DebuggerScope.h:
     46        * debugger/DebuggerScope.cpp:
     47        (JSC::DebuggerScope::name):
     48        (JSC::DebuggerScope::location):
     49        Name and location for a scope. This uses:
     50        JSScope -> SymbolTable -> CodeBlock -> Executable
     51
     52        * inspector/protocol/Debugger.json:
     53        * inspector/InjectedScriptSource.js:
     54        (InjectedScript.CallFrameProxy.prototype._wrapScopeChain):
     55        (InjectedScript.CallFrameProxy._createScopeJson):
     56        * inspector/JSJavaScriptCallFrame.cpp:
     57        (Inspector::valueForScopeType):
     58        (Inspector::valueForScopeLocation):
     59        (Inspector::JSJavaScriptCallFrame::scopeDescriptions):
     60        (Inspector::JSJavaScriptCallFrame::scopeType): Deleted.
     61        * inspector/JSJavaScriptCallFrame.h:
     62        * inspector/JSJavaScriptCallFramePrototype.cpp:
     63        (Inspector::JSJavaScriptCallFramePrototype::finishCreation):
     64        (Inspector::jsJavaScriptCallFramePrototypeFunctionScopeDescriptions):
     65        (Inspector::jsJavaScriptCallFramePrototypeFunctionScopeType): Deleted.
     66        Simplify this code to build the objects we will send across the protocol
     67        to descript a Scope.
     68
    1692016-06-29  Saam barati  <sbarati@apple.com>
    270
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r202502 r202659  
    16461646                A5EF9B181A1D440600702E90 /* generate_cpp_protocol_types_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D51A05C76F005CAB76 /* generate_cpp_protocol_types_header.py */; settings = {ATTRIBUTES = (Private, ); }; };
    16471647                A5EF9B191A1D440700702E90 /* generate_cpp_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D61A05C76F005CAB76 /* generate_cpp_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; };
     1648                A5FC84B21D1DDAD6006B5C46 /* DebuggerLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A5FC84B11D1DDAC8006B5C46 /* DebuggerLocation.h */; };
     1649                A5FC84B31D1DDAD9006B5C46 /* DebuggerLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FC84B01D1DDAC8006B5C46 /* DebuggerLocation.cpp */; };
    16481650                A5FD0067189AFE9C00633231 /* ScriptArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FD0065189AFE9C00633231 /* ScriptArguments.cpp */; };
    16491651                A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = A5FD0066189AFE9C00633231 /* ScriptArguments.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    38663868                A5EA70F819F6DE5A0098F5EC /* objc_generator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = objc_generator.py; sourceTree = "<group>"; };
    38673869                A5EA710D19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorAlternateBackendDispatchers.h; sourceTree = "<group>"; };
     3870                A5FC84B01D1DDAC8006B5C46 /* DebuggerLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerLocation.cpp; sourceTree = "<group>"; };
     3871                A5FC84B11D1DDAC8006B5C46 /* DebuggerLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerLocation.h; sourceTree = "<group>"; };
    38683872                A5FD0065189AFE9C00633231 /* ScriptArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptArguments.cpp; sourceTree = "<group>"; };
    38693873                A5FD0066189AFE9C00633231 /* ScriptArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptArguments.h; sourceTree = "<group>"; };
     
    53435347                                1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */,
    53445348                                6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */,
     5349                                A5FC84B01D1DDAC8006B5C46 /* DebuggerLocation.cpp */,
     5350                                A5FC84B11D1DDAC8006B5C46 /* DebuggerLocation.h */,
    53455351                                FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */,
    53465352                                0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */,
     
    76927698                                978801411471AD920041B016 /* JSDateMath.h in Headers */,
    76937699                                C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */,
     7700                                A5FC84B21D1DDAD6006B5C46 /* DebuggerLocation.h in Headers */,
    76947701                                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */,
    76957702                                FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */,
     
    87718778                                52B717B51A0597E1007AF4F3 /* ControlFlowProfiler.cpp in Sources */,
    87728779                                0FBADF541BD1F4B800E073C1 /* CopiedBlock.cpp in Sources */,
     8780                                A5FC84B31D1DDAD9006B5C46 /* DebuggerLocation.cpp in Sources */,
    87738781                                C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */,
    87748782                                0F6183301C45BF070072450B /* AirLowerMacros.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r202633 r202659  
    24782478                    symbolTable->prepareForTypeProfiling(locker);
    24792479                }
    2480                 constant = symbolTable->cloneScopePart(*m_vm);
     2480
     2481                SymbolTable* clone = symbolTable->cloneScopePart(*m_vm);
     2482                if (wasCompiledWithDebuggingOpcodes())
     2483                    clone->setRareDataCodeBlock(this);
     2484
     2485                constant = clone;
    24812486            }
    24822487        }
  • trunk/Source/JavaScriptCore/debugger/DebuggerScope.cpp

    r200430 r202659  
    211211}
    212212
     213String DebuggerScope::name() const
     214{
     215    SymbolTable* symbolTable = m_scope->symbolTable();
     216    if (!symbolTable)
     217        return String();
     218
     219    CodeBlock* codeBlock = symbolTable->rareDataCodeBlock();
     220    if (!codeBlock)
     221        return String();
     222
     223    return String::fromUTF8(codeBlock->inferredName());
     224}
     225
     226DebuggerLocation DebuggerScope::location() const
     227{
     228    SymbolTable* symbolTable = m_scope->symbolTable();
     229    if (!symbolTable)
     230        return DebuggerLocation();
     231
     232    CodeBlock* codeBlock = symbolTable->rareDataCodeBlock();
     233    if (!codeBlock)
     234        return DebuggerLocation();
     235
     236    ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
     237    return DebuggerLocation(executable);
     238}
     239
    213240JSValue DebuggerScope::caughtValue(ExecState* exec) const
    214241{
  • trunk/Source/JavaScriptCore/debugger/DebuggerScope.h

    r200430 r202659  
    2727#define DebuggerScope_h
    2828
     29#include "DebuggerLocation.h"
    2930#include "JSObject.h"
    3031
     
    8990    bool isNestedLexicalScope() const;
    9091
     92    String name() const;
     93    DebuggerLocation location() const;
     94
    9195    JSValue caughtValue(ExecState*) const;
    9296
  • trunk/Source/JavaScriptCore/inspector/InjectedScriptSource.js

    r202568 r202659  
    13071307    {
    13081308        var scopeChain = callFrame.scopeChain;
     1309        var scopeDescriptions = callFrame.scopeDescriptions();
     1310
    13091311        var scopeChainProxy = [];
    13101312        for (var i = 0; i < scopeChain.length; i++)
    1311             scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace");
     1313            scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(scopeChain[i], scopeDescriptions[i], "backtrace");
    13121314        return scopeChainProxy;
    13131315    }
     
    13221324    5: "globalLexicalEnvironment", // GLOBAL_LEXICAL_ENVIRONMENT_SCOPE
    13231325    6: "nestedLexical", // NESTED_LEXICAL_SCOPE
    1324 }
    1325 
    1326 InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId)
     1326};
     1327
     1328InjectedScript.CallFrameProxy._createScopeJson = function(object, {name, type, location}, groupId)
    13271329{
    1328     return {
    1329         object: injectedScript._wrapObject(scopeObject, groupId),
    1330         type: InjectedScript.CallFrameProxy._scopeTypeNames[scopeTypeCode]
     1330    var scope = {
     1331        object: injectedScript._wrapObject(object, groupId),
     1332        type: InjectedScript.CallFrameProxy._scopeTypeNames[type],
    13311333    };
     1334
     1335    if (name)
     1336        scope.name = name;
     1337    if (location)
     1338        scope.location = location;
     1339
     1340    return scope;
    13321341}
    13331342
  • trunk/Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.cpp

    r200981 r202659  
    2929#include "DebuggerScope.h"
    3030#include "Error.h"
     31#include "IdentifierInlines.h"
    3132#include "JSCJSValue.h"
    3233#include "JSCellInlines.h"
    3334#include "JSJavaScriptCallFramePrototype.h"
     35#include "ObjectConstructor.h"
    3436#include "StructureInlines.h"
    3537
     
    9395}
    9496
    95 JSValue JSJavaScriptCallFrame::scopeType(ExecState* exec)
    96 {
    97     if (!impl().scopeChain())
     97static JSValue valueForScopeType(DebuggerScope* scope)
     98{
     99    if (scope->isCatchScope())
     100        return jsNumber(JSJavaScriptCallFrame::CATCH_SCOPE);
     101    if (scope->isFunctionNameScope())
     102        return jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE);
     103    if (scope->isWithScope())
     104        return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
     105    if (scope->isNestedLexicalScope())
     106        return jsNumber(JSJavaScriptCallFrame::NESTED_LEXICAL_SCOPE);
     107    if (scope->isGlobalLexicalEnvironment())
     108        return jsNumber(JSJavaScriptCallFrame::GLOBAL_LEXICAL_ENVIRONMENT_SCOPE);
     109    if (scope->isGlobalScope())
     110        return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE);
     111
     112    ASSERT(scope->isClosureScope());
     113    return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
     114}
     115
     116static JSValue valueForScopeLocation(ExecState* exec, const DebuggerLocation& location)
     117{
     118    if (location.sourceID == noSourceID)
     119        return jsNull();
     120
     121    // Debugger.Location protocol object.
     122    JSObject* result = constructEmptyObject(exec);
     123    result->putDirect(exec->vm(), Identifier::fromString(exec, "scriptId"), jsString(exec, String::number(location.sourceID)));
     124    result->putDirect(exec->vm(), Identifier::fromString(exec, "lineNumber"), jsNumber(location.line));
     125    result->putDirect(exec->vm(), Identifier::fromString(exec, "columnNumber"), jsNumber(location.column));
     126    return result;
     127}
     128
     129JSValue JSJavaScriptCallFrame::scopeDescriptions(ExecState* exec)
     130{
     131    DebuggerScope* scopeChain = impl().scopeChain();
     132    if (!scopeChain)
    98133        return jsUndefined();
    99134
    100     if (!exec->argument(0).isInt32())
    101         return jsUndefined();
    102     int index = exec->argument(0).asInt32();
    103 
    104     DebuggerScope* scopeChain = impl().scopeChain();
     135    int index = 0;
     136    JSArray* array = constructEmptyArray(exec, nullptr);
     137
    105138    DebuggerScope::iterator end = scopeChain->end();
    106 
    107139    for (DebuggerScope::iterator iter = scopeChain->begin(); iter != end; ++iter) {
    108140        DebuggerScope* scope = iter.get();
    109 
    110         if (!index) {
    111             if (scope->isCatchScope())
    112                 return jsNumber(JSJavaScriptCallFrame::CATCH_SCOPE);
    113             if (scope->isFunctionNameScope())
    114                 return jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE);
    115             if (scope->isWithScope())
    116                 return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
    117             if (scope->isNestedLexicalScope())
    118                 return jsNumber(JSJavaScriptCallFrame::NESTED_LEXICAL_SCOPE);
    119             if (scope->isGlobalLexicalEnvironment())
    120                 return jsNumber(JSJavaScriptCallFrame::GLOBAL_LEXICAL_ENVIRONMENT_SCOPE);
    121             if (scope->isGlobalScope()) {
    122                 ASSERT(++iter == end);
    123                 return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE);
    124             }
    125             ASSERT(scope->isClosureScope());
    126             return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
    127         }
    128 
    129         --index;
     141        JSObject* description = constructEmptyObject(exec);
     142        description->putDirect(exec->vm(), Identifier::fromString(exec, "type"), valueForScopeType(scope));
     143        description->putDirect(exec->vm(), Identifier::fromString(exec, "name"), jsString(exec, scope->name()));
     144        description->putDirect(exec->vm(), Identifier::fromString(exec, "location"), valueForScopeLocation(exec, scope->location()));
     145        array->putDirectIndex(exec, index++, description);
    130146    }
    131147
    132     ASSERT_NOT_REACHED();
    133     return jsUndefined();
     148    return array;
    134149}
    135150
  • trunk/Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.h

    r200981 r202659  
    5959    // Functions.
    6060    JSC::JSValue evaluateWithScopeExtension(JSC::ExecState*);
    61     JSC::JSValue scopeType(JSC::ExecState*);
     61    JSC::JSValue scopeDescriptions(JSC::ExecState*);
    6262
    6363    // Attributes.
  • trunk/Source/JavaScriptCore/inspector/JSJavaScriptCallFramePrototype.cpp

    r200981 r202659  
    4040// Functions.
    4141static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension(ExecState*);
    42 static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionScopeType(ExecState*);
     42static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionScopeDescriptions(ExecState*);
    4343
    4444// Attributes.
     
    6262
    6363    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("evaluateWithScopeExtension", jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension, DontEnum, 1);
    64     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("scopeType", jsJavaScriptCallFramePrototypeFunctionScopeType, DontEnum, 1);
     64    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("scopeDescriptions", jsJavaScriptCallFramePrototypeFunctionScopeDescriptions, DontEnum, 0);
    6565
    6666    JSC_NATIVE_GETTER("caller", jsJavaScriptCallFrameAttributeCaller, DontEnum | Accessor);
     
    8585}
    8686
    87 EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionScopeType(ExecState* exec)
     87EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionScopeDescriptions(ExecState* exec)
    8888{
    8989    JSValue thisValue = exec->thisValue();
     
    9292        return throwVMTypeError(exec);
    9393
    94     return JSValue::encode(castedThis->scopeType(exec));
     94    return JSValue::encode(castedThis->scopeDescriptions(exec));
    9595}
    9696
  • trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json

    r200981 r202659  
    8282            "type": "object",
    8383            "properties": [
     84                { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." },
    8485                { "name": "type", "type": "string", "enum": ["global", "with", "closure", "catch", "functionName", "globalLexicalEnvironment", "nestedLexical"], "description": "Scope type." },
    85                 { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }
     86                { "name": "name", "type": "string", "optional": true, "description": "Name associated with the scope." },
     87                { "name": "location", "$ref": "Location", "optional": true, "description": "Location if available of the scope definition." }
    8688            ],
    8789            "description": "Scope description."
  • trunk/Source/JavaScriptCore/runtime/JSScope.cpp

    r201266 r202659  
    341341}
    342342
     343SymbolTable* JSScope::symbolTable()
     344{
     345    if (JSSymbolTableObject* symbolTableObject = jsDynamicCast<JSSymbolTableObject*>(this))
     346        return symbolTableObject->symbolTable();
     347
     348    return nullptr;
     349}
     350
    343351} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSScope.h

    r198989 r202659  
    3333
    3434class ScopeChainIterator;
     35class SymbolTable;
     36class VariableEnvironment;
    3537class WatchpointSet;
    36 class VariableEnvironment;
    3738
    3839class JSScope : public JSNonFinalObject {
     
    7172    VM* vm();
    7273    JSObject* globalThis();
     74
     75    SymbolTable* symbolTable();
    7376
    7477protected:
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.cpp

    r194251 r202659  
    105105    visitor.append(&thisSymbolTable->m_singletonScope);
    106106   
     107    if (thisSymbolTable->m_rareData)
     108        visitor.append(&thisSymbolTable->m_rareData->m_codeBlock);
     109   
    107110    // Save some memory. This is O(n) to rebuild and we do so on the fly.
    108111    ConcurrentJITLocker locker(thisSymbolTable->m_lock);
     
    160163        result->m_arguments.set(vm, result, arguments);
    161164   
    162     if (m_typeProfilingRareData) {
    163         result->m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>();
     165    if (m_rareData) {
     166        result->m_rareData = std::make_unique<SymbolTableRareData>();
    164167
    165168        {
    166             auto iter = m_typeProfilingRareData->m_uniqueIDMap.begin();
    167             auto end = m_typeProfilingRareData->m_uniqueIDMap.end();
     169            auto iter = m_rareData->m_uniqueIDMap.begin();
     170            auto end = m_rareData->m_uniqueIDMap.end();
    168171            for (; iter != end; ++iter)
    169                 result->m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, iter->value);
     172                result->m_rareData->m_uniqueIDMap.set(iter->key, iter->value);
    170173        }
    171174
    172175        {
    173             auto iter = m_typeProfilingRareData->m_offsetToVariableMap.begin();
    174             auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
     176            auto iter = m_rareData->m_offsetToVariableMap.begin();
     177            auto end = m_rareData->m_offsetToVariableMap.end();
    175178            for (; iter != end; ++iter)
    176                 result->m_typeProfilingRareData->m_offsetToVariableMap.set(iter->key, iter->value);
     179                result->m_rareData->m_offsetToVariableMap.set(iter->key, iter->value);
    177180        }
    178181
    179182        {
    180             auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.begin();
    181             auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end();
     183            auto iter = m_rareData->m_uniqueTypeSetMap.begin();
     184            auto end = m_rareData->m_uniqueTypeSetMap.end();
    182185            for (; iter != end; ++iter)
    183                 result->m_typeProfilingRareData->m_uniqueTypeSetMap.set(iter->key, iter->value);
     186                result->m_rareData->m_uniqueTypeSetMap.set(iter->key, iter->value);
    184187        }
    185188    }
     
    190193void SymbolTable::prepareForTypeProfiling(const ConcurrentJITLocker&)
    191194{
    192     if (m_typeProfilingRareData)
     195    if (m_rareData)
    193196        return;
    194197
    195     m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>();
     198    m_rareData = std::make_unique<SymbolTableRareData>();
    196199
    197200    for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter) {
    198         m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, TypeProfilerNeedsUniqueIDGeneration);
    199         m_typeProfilingRareData->m_offsetToVariableMap.set(iter->value.varOffset(), iter->key);
    200     }
     201        m_rareData->m_uniqueIDMap.set(iter->key, TypeProfilerNeedsUniqueIDGeneration);
     202        m_rareData->m_offsetToVariableMap.set(iter->value.varOffset(), iter->key);
     203    }
     204}
     205
     206CodeBlock* SymbolTable::rareDataCodeBlock()
     207{
     208    if (!m_rareData)
     209        return nullptr;
     210
     211    return m_rareData->m_codeBlock.get();
     212}
     213
     214void SymbolTable::setRareDataCodeBlock(CodeBlock* codeBlock)
     215{
     216    if (!m_rareData)
     217        m_rareData = std::make_unique<SymbolTableRareData>();
     218
     219    ASSERT(!m_rareData->m_codeBlock);
     220    m_rareData->m_codeBlock.set(*codeBlock->vm(), this, codeBlock);
    201221}
    202222
    203223GlobalVariableID SymbolTable::uniqueIDForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM& vm)
    204224{
    205     RELEASE_ASSERT(m_typeProfilingRareData);
    206 
    207     auto iter = m_typeProfilingRareData->m_uniqueIDMap.find(key);
    208     auto end = m_typeProfilingRareData->m_uniqueIDMap.end();
     225    RELEASE_ASSERT(m_rareData);
     226
     227    auto iter = m_rareData->m_uniqueIDMap.find(key);
     228    auto end = m_rareData->m_uniqueIDMap.end();
    209229    if (iter == end)
    210230        return TypeProfilerNoGlobalIDExists;
     
    213233    if (id == TypeProfilerNeedsUniqueIDGeneration) {
    214234        id = vm.typeProfiler()->getNextUniqueVariableID();
    215         m_typeProfilingRareData->m_uniqueIDMap.set(key, id);
    216         m_typeProfilingRareData->m_uniqueTypeSetMap.set(key, TypeSet::create()); // Make a new global typeset for this corresponding ID.
     235        m_rareData->m_uniqueIDMap.set(key, id);
     236        m_rareData->m_uniqueTypeSetMap.set(key, TypeSet::create()); // Make a new global typeset for this corresponding ID.
    217237    }
    218238
     
    222242GlobalVariableID SymbolTable::uniqueIDForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm)
    223243{
    224     RELEASE_ASSERT(m_typeProfilingRareData);
    225 
    226     auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset);
    227     auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
     244    RELEASE_ASSERT(m_rareData);
     245
     246    auto iter = m_rareData->m_offsetToVariableMap.find(offset);
     247    auto end = m_rareData->m_offsetToVariableMap.end();
    228248    if (iter == end)
    229249        return TypeProfilerNoGlobalIDExists;
     
    234254RefPtr<TypeSet> SymbolTable::globalTypeSetForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm)
    235255{
    236     RELEASE_ASSERT(m_typeProfilingRareData);
     256    RELEASE_ASSERT(m_rareData);
    237257
    238258    uniqueIDForOffset(locker, offset, vm); // Lazily create the TypeSet if necessary.
    239259
    240     auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset);
    241     auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
     260    auto iter = m_rareData->m_offsetToVariableMap.find(offset);
     261    auto end = m_rareData->m_offsetToVariableMap.end();
    242262    if (iter == end)
    243263        return nullptr;
     
    248268RefPtr<TypeSet> SymbolTable::globalTypeSetForVariable(const ConcurrentJITLocker& locker, UniquedStringImpl* key, VM& vm)
    249269{
    250     RELEASE_ASSERT(m_typeProfilingRareData);
     270    RELEASE_ASSERT(m_rareData);
    251271
    252272    uniqueIDForVariable(locker, key, vm); // Lazily create the TypeSet if necessary.
    253273
    254     auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.find(key);
    255     auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end();
     274    auto iter = m_rareData->m_uniqueTypeSetMap.find(key);
     275    auto end = m_rareData->m_uniqueTypeSetMap.end();
    256276    if (iter == end)
    257277        return nullptr;
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r202588 r202659  
    680680
    681681    void prepareForTypeProfiling(const ConcurrentJITLocker&);
     682
     683    CodeBlock* rareDataCodeBlock();
     684    void setRareDataCodeBlock(CodeBlock*);
    682685   
    683686    InferredValue* singletonScope() { return m_singletonScope.get(); }
     
    696699    ScopeOffset m_maxScopeOffset;
    697700   
    698     struct TypeProfilingRareData {
     701    struct SymbolTableRareData {
    699702        UniqueIDMap m_uniqueIDMap;
    700703        OffsetToVariableMap m_offsetToVariableMap;
    701704        UniqueTypeSetMap m_uniqueTypeSetMap;
     705        WriteBarrier<CodeBlock> m_codeBlock;
    702706    };
    703     std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData;
     707    std::unique_ptr<SymbolTableRareData> m_rareData;
    704708
    705709    bool m_usesNonStrictEval : 1;
  • trunk/Source/WebInspectorUI/ChangeLog

    r202657 r202659  
     12016-06-29  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Wrong function name next to scope
     4        https://bugs.webkit.org/show_bug.cgi?id=158210
     5        <rdar://problem/26543093>
     6
     7        Reviewed by Brian Burg.
     8
     9        * UserInterface/Controllers/DebuggerManager.js:
     10        (WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload):
     11        Include new payload data in the construction call.
     12        All the new data is optional, so we gracefully handle
     13        legacy backends.
     14
     15        * UserInterface/Models/ScopeChainNode.js:
     16        (WebInspector.ScopeChainNode):
     17        (WebInspector.ScopeChainNode.prototype.get type):
     18        (WebInspector.ScopeChainNode.prototype.get objects):
     19        (WebInspector.ScopeChainNode.prototype.get name):
     20        (WebInspector.ScopeChainNode.prototype.get location):
     21        (WebInspector.ScopeChainNode.prototype.get hash):
     22        Hash is a rough (name:sourceId:line:column) string for quick comparisons.
     23
     24        (WebInspector.ScopeChainNode.prototype.makeLocalScope):
     25        Make this an action you take on a scope, to avoid having to
     26        do it at construction time, or making it a generic setting.
     27
     28        * UserInterface/Views/ScopeChainDetailsSidebarPanel.js:
     29        (WebInspector.ScopeChainDetailsSidebarPanel.prototype._generateCallFramesSection):
     30        This was wrong before. Move the work to CallFrame
     31        and change it to be correct.
     32
     33        * UserInterface/CallFrame.js:
     34        (WebInspector.CallFrame.prototype.mergedScopeChain):
     35
     36        This transforms the scope chain for a call frame from:
     37       
     38             scope1  scope2  scope3  scope4  scope5  scope6  scope7
     39              foo     foo     foo     bar     bar      -       -
     40             Block  Closure Closure Closure Closure   GLE     GBL
     41
     42        To:
     43             scope1  scope2&3   scope4&5  scope6  scope7
     44              foo      foo*       bar*      -       -
     45             Block    Local     Closure    GLE     GBL
     46
     47        Doing a few things:
     48
     49            - Merge the first two Closure scopes sharing a location.
     50              These are the "var" and "let" Closure scopes in a function,
     51              and it is better to present these together in the UI.
     52
     53            - Mark the first Closure scope within a function (*). When
     54              this is displayed in the UI, we can provide the name of
     55              the function: "Closure Scope (name)", and we even have
     56              location information that we can use to display a goto
     57              arrow if needed.
     58
     59            - Make the first Closure scope the Local scope if it
     60              matches the Call Frame's function name. This lets us
     61              display the section as "Local Variables".
     62
    1632016-06-29  Brian Burg  <bburg@apple.com>
    264
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js

    r201211 r202659  
    663663
    664664        var object = WebInspector.RemoteObject.fromPayload(payload.object);
    665         return new WebInspector.ScopeChainNode(type, [object]);
     665        return new WebInspector.ScopeChainNode(type, [object], payload.name, payload.location);
    666666    }
    667667
  • trunk/Source/WebInspectorUI/UserInterface/Models/CallFrame.js

    r200981 r202659  
    4646    // Public
    4747
    48     get id()
    49     {
    50         return this._id;
    51     }
    52 
    53     get sourceCodeLocation()
    54     {
    55         return this._sourceCodeLocation;
    56     }
    57 
    58     get functionName()
    59     {
    60         return this._functionName;
    61     }
    62 
    63     get nativeCode()
    64     {
    65         return this._nativeCode;
    66     }
    67 
    68     get programCode()
    69     {
    70         return this._programCode;
    71     }
    72 
    73     get thisObject()
    74     {
    75         return this._thisObject;
    76     }
    77 
    78     get scopeChain()
    79     {
    80         return this._scopeChain;
    81     }
    82 
    83     get isTailDeleted()
    84     {
    85         return this._isTailDeleted;
    86     }
     48    get id() { return this._id; }
     49    get sourceCodeLocation() { return this._sourceCodeLocation; }
     50    get functionName() { return this._functionName; }
     51    get nativeCode() { return this._nativeCode; }
     52    get programCode() { return this._programCode; }
     53    get thisObject() { return this._thisObject; }
     54    get scopeChain() { return this._scopeChain; }
     55    get isTailDeleted() { return this._isTailDeleted; }
    8756
    8857    saveIdentityToCookie()
     
    11180        for (var i = 0; i < this._scopeChain.length; ++i)
    11281            this._scopeChain[i].objects[0].deprecatedGetAllProperties(propertiesCollected);
     82    }
     83
     84    mergedScopeChain()
     85    {
     86        let mergedScopes = [];
     87
     88        // Scopes list goes from top/local (1) to bottom/global (5)
     89        //   [scope1, scope2, scope3, scope4, scope5]
     90        let scopes = this._scopeChain.slice();
     91
     92        // Merge similiar scopes. Some function call frames may have multiple
     93        // top level closure scopes (one for `var`s one for `let`s) that can be
     94        // combined to a single scope of variables. Go in reverse order so we
     95        // merge the first two closure scopes with the same name. Also mark
     96        // the first time we see a new name, so we know the base for the name.
     97        //   [scope1&2, scope3, scope4, scope5]
     98        //      foo      bar     GLE    global
     99        let lastMarkedHash = null;
     100        function markAsBaseIfNeeded(scope) {
     101            if (!scope.hash)
     102                return false;
     103            if (scope.type !== WebInspector.ScopeChainNode.Type.Closure)
     104                return false;
     105            if (scope.hash === lastMarkedHash)
     106                return false;
     107            lastMarkedHash = scope.hash;
     108            scope.__baseClosureScope = true;
     109            return true;
     110        }
     111
     112        function shouldMergeClosureScopes(youngScope, oldScope, lastMerge) {
     113            if (!youngScope || !oldScope)
     114                return false;
     115
     116            // Don't merge unknown locations.
     117            if (!youngScope.hash || !oldScope.hash)
     118                return false;
     119
     120            // Only merge closure scopes.
     121            if (youngScope.type !== WebInspector.ScopeChainNode.Type.Closure)
     122                return false;
     123            if (oldScope.type !== WebInspector.ScopeChainNode.Type.Closure)
     124                return false;
     125
     126            // Don't merge if they are not the same.
     127            if (youngScope.hash !== oldScope.hash)
     128                return false;
     129
     130            // Don't merge if there was already a merge.
     131            if (lastMerge && youngScope.hash === lastMerge.hash)
     132                return false;
     133
     134            return true;
     135        }
     136
     137        let lastScope = null;
     138        let lastMerge = null;
     139        for (let i = scopes.length - 1; i >= 0; --i) {
     140            let scope = scopes[i];
     141            markAsBaseIfNeeded(scope);
     142            if (shouldMergeClosureScopes(scope, lastScope, lastMerge)) {
     143                console.assert(lastScope.__baseClosureScope);
     144                let type = WebInspector.ScopeChainNode.Type.Closure;
     145                let objects = lastScope.objects.concat(scope.objects);
     146                let merged = new WebInspector.ScopeChainNode(type, objects, scope.name, scope.location);
     147                merged.__baseClosureScope = true;
     148                console.assert(objects.length === 2);
     149
     150                mergedScopes.pop(); // Remove the last.
     151                mergedScopes.push(merged); // Add the merged scope.
     152
     153                lastMerge = merged;
     154                lastScope = null;
     155            } else {
     156                mergedScopes.push(scope);
     157
     158                lastMerge = null;
     159                lastScope = scope;
     160            }
     161        }
     162
     163        mergedScopes = mergedScopes.reverse();
     164
     165        // Mark the first Closure as Local if the name matches this call frame.
     166        for (let scope of mergedScopes) {
     167            if (scope.type === WebInspector.ScopeChainNode.Type.Closure) {
     168                if (scope.name === this._functionName)
     169                    scope.convertToLocalScope();
     170                break;
     171            }
     172        }
     173
     174        return mergedScopes;
    113175    }
    114176
  • trunk/Source/WebInspectorUI/UserInterface/Models/ScopeChainNode.js

    r201630 r202659  
    2626WebInspector.ScopeChainNode = class ScopeChainNode extends WebInspector.Object
    2727{
    28     constructor(type, objects)
     28    constructor(type, objects, name, location)
    2929    {
    3030        super();
     
    3838        this._type = type || null;
    3939        this._objects = objects || [];
     40        this._name = name || "";
     41        this._location = location || null;
    4042    }
    4143
    4244    // Public
    4345
    44     get type()
     46    get type() { return this._type; }
     47    get objects() { return this._objects; }
     48    get name() { return this._name; }
     49    get location() { return this._location; }
     50
     51    get hash()
    4552    {
    46         return this._type;
     53        if (this._hash)
     54            return this._hash;
     55
     56        this._hash = this._name;
     57        if (this._location)
     58            this._hash += `:${this._location.scriptId}:${this._location.lineNumber}:${this._location.columnNumber}`;
     59        return this._hash;
    4760    }
    4861
    49     get objects()
     62    convertToLocalScope()
    5063    {
    51         return this._objects;
     64        this._type = WebInspector.ScopeChainNode.Type.Local;
    5265    }
    5366};
  • trunk/Source/WebInspectorUI/UserInterface/Views/ScopeChainDetailsSidebarPanel.js

    r201855 r202659  
    165165            sectionCountByType.set(WebInspector.ScopeChainNode.Type[type], 0);
    166166
    167         // Scopes list goes from top/local (1) to bottom/global (5)
    168         // Call frames list goes from top/local (1) to bottom/global (2)
    169         //   [scope1, scope2, scope3, scope4, scope5]
    170         //   [CallFrame1, CallFrame2]
    171         let scopeChain = callFrame.scopeChain;
    172         let callFrames = WebInspector.debuggerManager.callFrames;
    173 
    174         // Group scopes with the call frame containing them.
    175         // Creating a map that looks like:
    176         //   CallFrame2 => [scope5, scope4]
    177         //   CallFrame1 => [scope3, scope2, scope1]
    178         let reversedScopeChain = scopeChain.slice().reverse();
    179         let callFrameScopes = new Map;
    180         let lastLength = 0;
    181         for (let i = callFrames.length - 1; i >= 0; --i) {
    182             let nextCallFrame = callFrames[i];
    183             console.assert(nextCallFrame.scopeChain.length > lastLength);
    184             callFrameScopes.set(nextCallFrame, reversedScopeChain.slice(lastLength, nextCallFrame.scopeChain.length));
    185             lastLength = nextCallFrame.scopeChain.length;
    186             if (nextCallFrame === callFrame) {
    187                 console.assert(lastLength === scopeChain.length);
     167        let scopeChain = callFrame.mergedScopeChain();
     168        for (let scope of scopeChain) {
     169            let title = null;
     170            let extraPropertyDescriptor = null;
     171            let collapsedByDefault = false;
     172
     173            let count = sectionCountByType.get(scope.type);
     174            sectionCountByType.set(scope.type, ++count);
     175
     176            switch (scope.type) {
     177            case WebInspector.ScopeChainNode.Type.Local:
     178                foundLocalScope = true;
     179                collapsedByDefault = false;
     180                title = WebInspector.UIString("Local Variables");
     181                if (callFrame.thisObject)
     182                    extraPropertyDescriptor = new WebInspector.PropertyDescriptor({name: "this", value: callFrame.thisObject});
     183                break;
     184
     185            case WebInspector.ScopeChainNode.Type.Closure:
     186                if (scope.__baseClosureScope && scope.name)
     187                    title = WebInspector.UIString("Closure Variables (%s)").format(scope.name);
     188                else
     189                    title = WebInspector.UIString("Closure Variables");
     190                collapsedByDefault = false;
     191                break;
     192
     193            case WebInspector.ScopeChainNode.Type.Block:
     194                title = WebInspector.UIString("Block Variables");
     195                collapsedByDefault = false;
     196                break;
     197
     198            case WebInspector.ScopeChainNode.Type.Catch:
     199                title = WebInspector.UIString("Catch Variables");
     200                collapsedByDefault = false;
     201                break;
     202
     203            case WebInspector.ScopeChainNode.Type.FunctionName:
     204                title = WebInspector.UIString("Function Name Variable");
     205                collapsedByDefault = true;
     206                break;
     207
     208            case WebInspector.ScopeChainNode.Type.With:
     209                title = WebInspector.UIString("With Object Properties");
     210                collapsedByDefault = foundLocalScope;
     211                break;
     212
     213            case WebInspector.ScopeChainNode.Type.Global:
     214                title = WebInspector.UIString("Global Variables");
     215                collapsedByDefault = true;
     216                break;
     217
     218            case WebInspector.ScopeChainNode.Type.GlobalLexicalEnvironment:
     219                title = WebInspector.UIString("Global Lexical Environment");
     220                collapsedByDefault = true;
    188221                break;
    189222            }
    190         }
    191 
    192         // Now that we have this map we can merge some of the scopes within an individual
    193         // call frame. In particular, function call frames may have multiple top level
    194         // closure scopes (one for `var`s one for `let`s) that can be combined to a
    195         // single scope of variables.
    196         // This modifies the Map, resulting in:
    197         //   CallFrame2 => [scope4, scope5]
    198         //   CallFrame1 => [scope1, scope2&3]
    199         for (let [currentCallFrame, scopes] of callFrameScopes) {
    200             let firstClosureScope = null;
    201             for (let scope of scopes) {
    202                 // Reached a non-closure scope. Bail.
    203                 let isClosureScope = scope.type === WebInspector.ScopeChainNode.Type.Closure;
    204                 if (!isClosureScope && firstClosureScope)
    205                     break;
    206 
    207                 // Found first closure scope. Mark it so we can provide the function name later in the UI.
    208                 if (isClosureScope && !firstClosureScope) {
    209                     firstClosureScope = scope;
    210                     firstClosureScope[WebInspector.ScopeChainDetailsSidebarPanel.CallFrameBaseClosureScopeSymbol] = true;
    211                     continue;
     223
     224            let detailsSectionIdentifier = scope.type + "-" + sectionCountByType.get(scope.type);
     225
     226            // FIXME: This just puts two ObjectTreeViews next to each other, but that means
     227            // that properties are not nicely sorted between the two separate lists.
     228
     229            let rows = [];
     230            for (let object of scope.objects) {
     231                let scopePropertyPath = WebInspector.PropertyPath.emptyPropertyPathForScope(object);
     232                let objectTree = new WebInspector.ObjectTreeView(object, WebInspector.ObjectTreeView.Mode.Properties, scopePropertyPath);
     233
     234                objectTree.showOnlyProperties();
     235
     236                if (extraPropertyDescriptor) {
     237                    objectTree.appendExtraPropertyDescriptor(extraPropertyDescriptor);
     238                    extraPropertyDescriptor = null;
    212239                }
    213240
    214                 // Found 2 sequential top level closure scopes. Merge and mark it so we can provide the function name later in the UI.
    215                 if (isClosureScope && firstClosureScope) {
    216                     let type = currentCallFrame === callFrame ? WebInspector.ScopeChainNode.Type.Local : WebInspector.ScopeChainNode.Type.Closure;
    217                     let objects = firstClosureScope.objects.concat(scope.objects);
    218                     let merged = new WebInspector.ScopeChainNode(type, objects);
    219                     merged[WebInspector.ScopeChainDetailsSidebarPanel.CallFrameBaseClosureScopeSymbol] = true;
    220                     console.assert(objects.length === 2);
    221 
    222                     let index = scopes.indexOf(firstClosureScope);
    223                     scopes.splice(index, 1); // Remove one of them.
    224                     scopes[index] = merged; // Replace the remaining with the merged.
    225                     break;
    226                 }
     241                let treeOutline = objectTree.treeOutline;
     242                treeOutline.addEventListener(WebInspector.TreeOutline.Event.ElementAdded, this._treeElementAdded.bind(this, detailsSectionIdentifier), this);
     243                treeOutline.addEventListener(WebInspector.TreeOutline.Event.ElementDisclosureDidChanged, this._treeElementDisclosureDidChange.bind(this, detailsSectionIdentifier), this);
     244
     245                // FIXME: <https://webkit.org/b/140567> Web Inspector: Do not request Scope Chain lists if section is collapsed (mainly Global Variables)
     246                // This autoexpands the ObjectTreeView and fetches all properties. Should wait to see if we are collapsed or not.
     247                rows.push(new WebInspector.DetailsSectionPropertiesRow(objectTree));
    227248            }
    228             scopes.reverse();
    229         }
    230 
    231         // Now we can walk the list of call frames and their scopes.
    232         // We walk in top -> down order:
    233         //   CallFrame1 => [scope1, scope2&3]
    234         //   CallFrame2 => [scope5, scope4]
    235         for (let [call, scopes] of [...callFrameScopes.entries()].reverse()) {
    236             for (let scope of scopes) {
    237                 let title = null;
    238                 let extraPropertyDescriptor = null;
    239                 let collapsedByDefault = false;
    240 
    241                 let count = sectionCountByType.get(scope.type);
    242                 sectionCountByType.set(scope.type, ++count);
    243 
    244                 switch (scope.type) {
    245                     case WebInspector.ScopeChainNode.Type.Local:
    246                         foundLocalScope = true;
    247                         collapsedByDefault = false;
    248                         title = WebInspector.UIString("Local Variables");
    249                         if (call.thisObject)
    250                             extraPropertyDescriptor = new WebInspector.PropertyDescriptor({name: "this", value: call.thisObject});
    251                         break;
    252 
    253                     case WebInspector.ScopeChainNode.Type.Closure:
    254                         if (scope[WebInspector.ScopeChainDetailsSidebarPanel.CallFrameBaseClosureScopeSymbol] && call.functionName)
    255                             title = WebInspector.UIString("Closure Variables (%s)").format(call.functionName);
    256                         else
    257                             title = WebInspector.UIString("Closure Variables");
    258                         collapsedByDefault = false;
    259                         break;
    260 
    261                     case WebInspector.ScopeChainNode.Type.Block:
    262                         title = WebInspector.UIString("Block Variables");
    263                         collapsedByDefault = false;
    264                         break;
    265 
    266                     case WebInspector.ScopeChainNode.Type.Catch:
    267                         title = WebInspector.UIString("Catch Variables");
    268                         collapsedByDefault = false;
    269                         break;
    270 
    271                     case WebInspector.ScopeChainNode.Type.FunctionName:
    272                         title = WebInspector.UIString("Function Name Variable");
    273                         collapsedByDefault = true;
    274                         break;
    275 
    276                     case WebInspector.ScopeChainNode.Type.With:
    277                         title = WebInspector.UIString("With Object Properties");
    278                         collapsedByDefault = foundLocalScope;
    279                         break;
    280 
    281                     case WebInspector.ScopeChainNode.Type.Global:
    282                         title = WebInspector.UIString("Global Variables");
    283                         collapsedByDefault = true;
    284                         break;
    285 
    286                     case WebInspector.ScopeChainNode.Type.GlobalLexicalEnvironment:
    287                         title = WebInspector.UIString("Global Lexical Environment");
    288                         collapsedByDefault = true;
    289                         break;
    290                 }
    291 
    292                 let detailsSectionIdentifier = scope.type + "-" + sectionCountByType.get(scope.type);
    293 
    294                 // FIXME: This just puts two ObjectTreeViews next to eachother, but that means
    295                 // that properties are not nicely sorted between the two separate lists.
    296 
    297                 let rows = [];
    298                 for (let object of scope.objects) {
    299                     let scopePropertyPath = WebInspector.PropertyPath.emptyPropertyPathForScope(object);
    300                     let objectTree = new WebInspector.ObjectTreeView(object, WebInspector.ObjectTreeView.Mode.Properties, scopePropertyPath);
    301 
    302                     objectTree.showOnlyProperties();
    303 
    304                     if (extraPropertyDescriptor) {
    305                         objectTree.appendExtraPropertyDescriptor(extraPropertyDescriptor);
    306                         extraPropertyDescriptor = null;
    307                     }
    308 
    309                     let treeOutline = objectTree.treeOutline;
    310                     treeOutline.addEventListener(WebInspector.TreeOutline.Event.ElementAdded, this._treeElementAdded.bind(this, detailsSectionIdentifier), this);
    311                     treeOutline.addEventListener(WebInspector.TreeOutline.Event.ElementDisclosureDidChanged, this._treeElementDisclosureDidChange.bind(this, detailsSectionIdentifier), this);
    312 
    313                     rows.push(new WebInspector.DetailsSectionPropertiesRow(objectTree));
    314                 }
    315 
    316                 let detailsSection = new WebInspector.DetailsSection(detailsSectionIdentifier, title, null, null, collapsedByDefault);
    317                 detailsSection.groups[0].rows = rows;
    318                 detailsSections.push(detailsSection);
    319             }
     249
     250            let detailsSection = new WebInspector.DetailsSection(detailsSectionIdentifier, title, null, null, collapsedByDefault);
     251            detailsSection.groups[0].rows = rows;
     252            detailsSections.push(detailsSection);
    320253        }
    321254
     
    546479WebInspector.ScopeChainDetailsSidebarPanel._autoExpandProperties = new Set;
    547480WebInspector.ScopeChainDetailsSidebarPanel.WatchExpressionsObjectGroupName = "watch-expressions";
    548 WebInspector.ScopeChainDetailsSidebarPanel.CallFrameBaseClosureScopeSymbol = Symbol("scope-chain-call-frame-base-closure-scope");
Note: See TracChangeset for help on using the changeset viewer.