@@ -546,53 +546,16 @@ namespace Js
546546 return !*isPropertyInDebuggerScope;
547547 }
548548
549- // Gets an adjusted offset for the current bytecode location based on which stack frame we're in.
550- // If we're in the top frame (leaf node), then the byte code offset should remain as is, to reflect
551- // the current position of the instruction pointer. If we're not in the top frame, we need to subtract
552- // 1 as the byte code location will be placed at the next statement to be executed at the top frame.
553- // In the case of block scoping, this is an inaccurate location for viewing variables since the next
554- // statement could be beyond the current block scope. For inspection, we want to remain in the
555- // current block that the function was called from.
556- // An example is this:
557- // function foo() { ... } // Frame 0 (with breakpoint inside)
558- // function bar() { // Frame 1
559- // {
560- // let a = 0;
561- // foo(); // <-- Inspecting here, foo is already evaluated.
562- // }
563- // foo(); // <-- Byte code offset is now here, so we need to -1 to get back in the block scope.
564549 int VariableWalkerBase::GetAdjustedByteCodeOffset () const
565550 {
566- Assert (pFrame);
567- int offset = pFrame->GetByteCodeOffset ();
568- if (!pFrame->IsTopFrame () && pFrame->IsInterpreterFrame ())
569- {
570- // Native frames are already adjusted so just need to adjust interpreted
571- // frames that are not the top frame.
572- --offset;
573- }
574-
575- return offset;
551+ return LocalsWalker::GetAdjustedByteCodeOffset (pFrame);
576552 }
577553
578554 DebuggerScope * VariableWalkerBase::GetScopeWhenHaltAtFormals ()
579555 {
580556 if (IsWalkerForCurrentFrame ())
581557 {
582- Js::ScopeObjectChain * scopeObjectChain = pFrame->GetJavascriptFunction ()->GetFunctionBody ()->GetScopeObjectChain ();
583-
584- if (scopeObjectChain != nullptr && scopeObjectChain->pScopeChain != nullptr )
585- {
586- int currentOffset = GetAdjustedByteCodeOffset ();
587- for (int i = 0 ; i < scopeObjectChain->pScopeChain ->Count (); i++)
588- {
589- Js::DebuggerScope * scope = scopeObjectChain->pScopeChain ->Item (i);
590- if (scope->scopeType == Js::DiagParamScope && scope->GetEnd () > currentOffset)
591- {
592- return scope;
593- }
594- }
595- }
558+ return LocalsWalker::GetScopeWhenHaltAtFormals (pFrame);
596559 }
597560
598561 return nullptr ;
@@ -631,13 +594,35 @@ namespace Js
631594
632595 if (slotArray.IsFunctionScopeSlotArray ())
633596 {
597+ DebuggerScope *formalScope = GetScopeWhenHaltAtFormals ();
634598 Js::FunctionBody *pFBody = slotArray.GetFunctionBody ();
635- if (pFBody->GetPropertyIdsForScopeSlotArray () != nullptr )
599+ uint slotArrayCount = slotArray.GetCount ();
600+
601+ if (formalScope != nullptr && !pFBody->IsParamAndBodyScopeMerged ())
636602 {
637- uint slotArrayCount = slotArray. GetCount ( );
603+ Assert (pFBody-> paramScopeSlotArraySize > 0 );
638604 pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New (arena, slotArrayCount);
639605
640- DebuggerScope *formalScope = GetScopeWhenHaltAtFormals ();
606+ for (ulong i = 0 ; i < slotArrayCount; i++)
607+ {
608+ Js::DebuggerScopeProperty scopeProperty = formalScope->scopeProperties ->Item (i);
609+
610+ Var value = slotArray.Get (i);
611+ bool isInDeadZone = pFrame->GetScriptContext ()->IsUndeclBlockVar (value);
612+
613+ DebuggerPropertyDisplayInfo *pair = AllocateNewPropertyDisplayInfo (
614+ scopeProperty.propId ,
615+ value,
616+ false /* isConst*/ ,
617+ isInDeadZone);
618+
619+ Assert (pair != nullptr );
620+ pMembersList->Add (pair);
621+ }
622+ }
623+ else if (pFBody->GetPropertyIdsForScopeSlotArray () != nullptr )
624+ {
625+ pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New (arena, slotArrayCount);
641626
642627 for (ulong i = 0 ; i < slotArrayCount; i++)
643628 {
@@ -970,7 +955,7 @@ namespace Js
970955 Js::DebuggerScope *debuggerScope = pScopeObjectChain->pScopeChain ->Item (i);
971956 bool isScopeInRange = debuggerScope->IsOffsetInScope (bytecodeOffset);
972957 if (isScopeInRange
973- && debuggerScope->scopeType != DiagParamScope
958+ && ! debuggerScope->IsParamScope ()
974959 && (debuggerScope->IsOwnScope () || (debuggerScope->scopeType == DiagBlockScopeDirect && debuggerScope->HasProperties ())))
975960 {
976961 switch (debuggerScope->scopeType )
@@ -1107,27 +1092,46 @@ namespace Js
11071092 pVarWalkers->Add (Anew (arena, RootObjectVariablesWalker, pFrame, pFrame->GetRootObject (), UIGroupType_None));
11081093 }
11091094
1110- DWORD localsType = GetCurrentFramesLocalsType (pFrame);
1111- if (localsType & FramesLocalType::LocalType_Reg)
1112- {
1113- pVarWalkers->Add (Anew (arena, RegSlotVariablesWalker, pFrame, nullptr /* not debugger scope*/ , UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
1114- }
1115- if (localsType & FramesLocalType::LocalType_InObject)
1116- {
1117- Assert (scopeCount > 0 );
1118- pVarWalker = Anew (arena, ObjectVariablesWalker, pFrame, pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1119- }
1120- else if (localsType & FramesLocalType::LocalType_InSlot)
1095+ DebuggerScope *formalScope = GetScopeWhenHaltAtFormals (pFrame);
1096+
1097+ // If we are halted at formal place, and param and body scopes are splitted we need to make use of formal debugger scope to walk those variables.
1098+ if (!pFBody->IsParamAndBodyScopeMerged () && formalScope != nullptr )
11211099 {
11221100 Assert (scopeCount > 0 );
1123- pVarWalker = Anew (arena, SlotArrayVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1101+ if (formalScope->scopeType == Js::DiagParamScopeInObject)
1102+ {
1103+ pVarWalker = Anew (arena, ObjectVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1104+ }
1105+ else
1106+ {
1107+ Assert (pFBody->paramScopeSlotArraySize > 0 );
1108+ pVarWalker = Anew (arena, SlotArrayVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1109+ }
11241110 }
1125- else if (scopeCount > 0 && pFBody-> GetFrameDisplayRegister () != 0 )
1111+ else
11261112 {
1127- Assert ((Var)pDisplay->GetItem (0 ) == pFrame->GetScriptContext ()->GetLibrary ()->GetNull ());
1113+ DWORD localsType = GetCurrentFramesLocalsType (pFrame);
1114+ if (localsType & FramesLocalType::LocalType_Reg)
1115+ {
1116+ pVarWalkers->Add (Anew (arena, RegSlotVariablesWalker, pFrame, nullptr /* not debugger scope*/ , UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
1117+ }
1118+ if (localsType & FramesLocalType::LocalType_InObject)
1119+ {
1120+ Assert (scopeCount > 0 );
1121+ pVarWalker = Anew (arena, ObjectVariablesWalker, pFrame, pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1122+ }
1123+ else if (localsType & FramesLocalType::LocalType_InSlot)
1124+ {
1125+ Assert (scopeCount > 0 );
1126+ pVarWalker = Anew (arena, SlotArrayVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem (nextStartIndex++), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
1127+ }
1128+ else if (scopeCount > 0 && pFBody->GetFrameDisplayRegister () != 0 )
1129+ {
1130+ Assert ((Var)pDisplay->GetItem (0 ) == pFrame->GetScriptContext ()->GetLibrary ()->GetNull () || !pFBody->IsParamAndBodyScopeMerged ());
11281131
1129- // A dummy scope with nullptr register is created. Skip this.
1130- nextStartIndex++;
1132+ // A dummy scope with nullptr register is created. Skip this.
1133+ nextStartIndex++;
1134+ }
11311135 }
11321136
11331137 if (pVarWalker)
@@ -1366,6 +1370,55 @@ namespace Js
13661370 return totalLocalsCount;
13671371 }
13681372
1373+ /* static*/
1374+ DebuggerScope * LocalsWalker::GetScopeWhenHaltAtFormals (DiagStackFrame* frame)
1375+ {
1376+ Js::ScopeObjectChain * scopeObjectChain = frame->GetJavascriptFunction ()->GetFunctionBody ()->GetScopeObjectChain ();
1377+
1378+ if (scopeObjectChain != nullptr && scopeObjectChain->pScopeChain != nullptr )
1379+ {
1380+ int currentOffset = GetAdjustedByteCodeOffset (frame);
1381+ for (int i = 0 ; i < scopeObjectChain->pScopeChain ->Count (); i++)
1382+ {
1383+ Js::DebuggerScope * scope = scopeObjectChain->pScopeChain ->Item (i);
1384+ if (scope->IsParamScope () && scope->GetEnd () > currentOffset)
1385+ {
1386+ return scope;
1387+ }
1388+ }
1389+ }
1390+
1391+ return nullptr ;
1392+ }
1393+
1394+ // Gets an adjusted offset for the current bytecode location based on which stack frame we're in.
1395+ // If we're in the top frame (leaf node), then the byte code offset should remain as is, to reflect
1396+ // the current position of the instruction pointer. If we're not in the top frame, we need to subtract
1397+ // 1 as the byte code location will be placed at the next statement to be executed at the top frame.
1398+ // In the case of block scoping, this is an inaccurate location for viewing variables since the next
1399+ // statement could be beyond the current block scope. For inspection, we want to remain in the
1400+ // current block that the function was called from.
1401+ // An example is this:
1402+ // function foo() { ... } // Frame 0 (with breakpoint inside)
1403+ // function bar() { // Frame 1
1404+ // {
1405+ // let a = 0;
1406+ // foo(); // <-- Inspecting here, foo is already evaluated.
1407+ // }
1408+ // foo(); // <-- Byte code offset is now here, so we need to -1 to get back in the block scope.
1409+ int LocalsWalker::GetAdjustedByteCodeOffset (DiagStackFrame* frame)
1410+ {
1411+ int offset = frame->GetByteCodeOffset ();
1412+ if (!frame->IsTopFrame () && frame->IsInterpreterFrame ())
1413+ {
1414+ // Native frames are already adjusted so just need to adjust interpreted
1415+ // frames that are not the top frame.
1416+ --offset;
1417+ }
1418+
1419+ return offset;
1420+ }
1421+
13691422 /* static*/
13701423 DWORD LocalsWalker::GetCurrentFramesLocalsType (DiagStackFrame* frame)
13711424 {
0 commit comments