Skip to content

Commit 1b75f1b

Browse files
committed
[MERGE #3391 @kfarnung] Report script loads from eval when debugging
Merge pull request #3391 from kfarnung:evaldebug * Added code to report the load of scripts on eval in order to support stepping into the eval code. * Added protections to prevent re-entrancy when reparsing scripts * Updated debugger test baselines
2 parents 804093e + 1c2d259 commit 1b75f1b

12 files changed

+407
-36
lines changed

lib/Jsrt/JsrtDebugManager.cpp

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,21 @@ HRESULT JsrtDebugManager::DbgRegisterFunction(Js::ScriptContext* scriptContext,
154154
{
155155
utf8SourceInfo->SetDebugDocument(debugDocument);
156156
}
157+
158+
// Raising events during the middle of a source reparse allows the host to reenter the
159+
// script context and cause memory race conditions. Suppressing these events during a
160+
// reparse prevents the issue. Since the host was already expected to call JsDiagGetScripts
161+
// once the attach is completed to get the list of parsed scripts, there is no change in
162+
// behavior.
163+
if (this->debugEventCallback != nullptr &&
164+
!scriptContext->GetDebugContext()->GetIsReparsingSource())
165+
{
166+
JsrtDebugEventObject debugEventObject(scriptContext);
167+
Js::DynamicObject* eventDataObject = debugEventObject.GetEventDataObject();
168+
JsrtDebugUtils::AddSourceMetadataToObject(eventDataObject, utf8SourceInfo);
169+
170+
this->CallDebugEventCallback(JsDiagDebugEventSourceCompile, eventDataObject, scriptContext, false /*isBreak*/);
171+
}
157172
}
158173

159174
return S_OK;
@@ -170,16 +185,8 @@ void JsrtDebugManager::ReportScriptCompile_TTD(Js::FunctionBody* body, Js::Utf8S
170185
Js::ScriptContext* scriptContext = utf8SourceInfo->GetScriptContext();
171186

172187
JsrtDebugEventObject debugEventObject(scriptContext);
173-
174188
Js::DynamicObject* eventDataObject = debugEventObject.GetEventDataObject();
175189

176-
JsrtDebugUtils::AddFileNameOrScriptTypeToObject(eventDataObject, utf8SourceInfo);
177-
JsrtDebugUtils::AddLineCountToObject(eventDataObject, utf8SourceInfo);
178-
JsrtDebugUtils::AddPropertyToObject(eventDataObject, JsrtDebugPropertyId::sourceLength, utf8SourceInfo->GetCchLength(), utf8SourceInfo->GetScriptContext());
179-
180-
JsDiagDebugEvent jsDiagDebugEvent = JsDiagDebugEventCompileError;
181-
182-
183190
JsrtDebugDocumentManager* debugDocumentManager = this->GetDebugDocumentManager();
184191
Assert(debugDocumentManager != nullptr);
185192

@@ -188,15 +195,13 @@ void JsrtDebugManager::ReportScriptCompile_TTD(Js::FunctionBody* body, Js::Utf8S
188195
if(debugDocument != nullptr)
189196
{
190197
utf8SourceInfo->SetDebugDocument(debugDocument);
191-
192-
// Only add scriptId if everything is ok as scriptId is used for other operations
193-
JsrtDebugUtils::AddScriptIdToObject(eventDataObject, utf8SourceInfo);
194198
}
195-
jsDiagDebugEvent = JsDiagDebugEventSourceCompile;
199+
200+
JsrtDebugUtils::AddSourceMetadataToObject(eventDataObject, utf8SourceInfo);
196201

197202
if(notify)
198203
{
199-
this->CallDebugEventCallback(jsDiagDebugEvent, eventDataObject, scriptContext, false /*isBreak*/);
204+
this->CallDebugEventCallback(JsDiagDebugEventSourceCompile, eventDataObject, scriptContext, false /*isBreak*/);
200205
}
201206
}
202207
#endif
@@ -208,13 +213,8 @@ void JsrtDebugManager::ReportScriptCompile(Js::JavascriptFunction* scriptFunctio
208213
Js::ScriptContext* scriptContext = utf8SourceInfo->GetScriptContext();
209214

210215
JsrtDebugEventObject debugEventObject(scriptContext);
211-
212216
Js::DynamicObject* eventDataObject = debugEventObject.GetEventDataObject();
213217

214-
JsrtDebugUtils::AddFileNameOrScriptTypeToObject(eventDataObject, utf8SourceInfo);
215-
JsrtDebugUtils::AddLineCountToObject(eventDataObject, utf8SourceInfo);
216-
JsrtDebugUtils::AddPropertyToObject(eventDataObject, JsrtDebugPropertyId::sourceLength, utf8SourceInfo->GetCchLength(), utf8SourceInfo->GetScriptContext());
217-
218218
JsDiagDebugEvent jsDiagDebugEvent = JsDiagDebugEventCompileError;
219219

220220
if (scriptFunction == nullptr)
@@ -235,13 +235,13 @@ void JsrtDebugManager::ReportScriptCompile(Js::JavascriptFunction* scriptFunctio
235235
if (debugDocument != nullptr)
236236
{
237237
utf8SourceInfo->SetDebugDocument(debugDocument);
238-
239-
// Only add scriptId if everything is ok as scriptId is used for other operations
240-
JsrtDebugUtils::AddScriptIdToObject(eventDataObject, utf8SourceInfo);
241238
}
239+
242240
jsDiagDebugEvent = JsDiagDebugEventSourceCompile;
243241
}
244242

243+
JsrtDebugUtils::AddSourceMetadataToObject(eventDataObject, utf8SourceInfo);
244+
245245
this->CallDebugEventCallback(jsDiagDebugEvent, eventDataObject, scriptContext, false /*isBreak*/);
246246
}
247247
}
@@ -460,11 +460,7 @@ void JsrtDebugManager::CallDebugEventCallbackForBreak(JsDiagDebugEvent debugEven
460460
Js::DynamicObject* JsrtDebugManager::GetScript(Js::Utf8SourceInfo* utf8SourceInfo)
461461
{
462462
Js::DynamicObject* scriptObject = utf8SourceInfo->GetScriptContext()->GetLibrary()->CreateObject();
463-
464-
JsrtDebugUtils::AddScriptIdToObject(scriptObject, utf8SourceInfo);
465-
JsrtDebugUtils::AddFileNameOrScriptTypeToObject(scriptObject, utf8SourceInfo);
466-
JsrtDebugUtils::AddLineCountToObject(scriptObject, utf8SourceInfo);
467-
JsrtDebugUtils::AddPropertyToObject(scriptObject, JsrtDebugPropertyId::sourceLength, utf8SourceInfo->GetCchLength(), utf8SourceInfo->GetScriptContext());
463+
JsrtDebugUtils::AddSourceMetadataToObject(scriptObject, utf8SourceInfo);
468464

469465
return scriptObject;
470466
}
@@ -542,11 +538,8 @@ Js::DynamicObject* JsrtDebugManager::GetSource(Js::ScriptContext* scriptContext,
542538
{
543539
sourceObject = (Js::DynamicObject*)Js::CrossSite::MarshalVar(utf8SourceInfo->GetScriptContext(), scriptContext->GetLibrary()->CreateObject());
544540

545-
JsrtDebugUtils::AddScriptIdToObject(sourceObject, utf8SourceInfo);
546-
JsrtDebugUtils::AddFileNameOrScriptTypeToObject(sourceObject, utf8SourceInfo);
547-
JsrtDebugUtils::AddLineCountToObject(sourceObject, utf8SourceInfo);
548-
JsrtDebugUtils::AddPropertyToObject(sourceObject, JsrtDebugPropertyId::sourceLength, utf8SourceInfo->GetCchLength(), utf8SourceInfo->GetScriptContext());
549-
JsrtDebugUtils::AddSouceToObject(sourceObject, utf8SourceInfo);
541+
JsrtDebugUtils::AddSourceMetadataToObject(sourceObject, utf8SourceInfo);
542+
JsrtDebugUtils::AddSourceToObject(sourceObject, utf8SourceInfo);
550543
}
551544

552545
return sourceObject;

lib/Jsrt/JsrtDebugUtils.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void JsrtDebugUtils::AddLineCountToObject(Js::DynamicObject * object, Js::Utf8So
8989
JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::lineCount, (uint32)utf8SourceInfo->GetLineCount(), utf8SourceInfo->GetScriptContext());
9090
}
9191

92-
void JsrtDebugUtils::AddSouceToObject(Js::DynamicObject * object, Js::Utf8SourceInfo * utf8SourceInfo)
92+
void JsrtDebugUtils::AddSourceToObject(Js::DynamicObject * object, Js::Utf8SourceInfo * utf8SourceInfo)
9393
{
9494
int32 cchLength = utf8SourceInfo->GetCchLength();
9595
AutoArrayPtr<char16> sourceContent(HeapNewNoThrowArray(char16, cchLength + 1), cchLength + 1);
@@ -107,6 +107,19 @@ void JsrtDebugUtils::AddSouceToObject(Js::DynamicObject * object, Js::Utf8Source
107107
}
108108
}
109109

110+
void JsrtDebugUtils::AddSourceMetadataToObject(Js::DynamicObject * object, Js::Utf8SourceInfo * utf8SourceInfo)
111+
{
112+
JsrtDebugUtils::AddFileNameOrScriptTypeToObject(object, utf8SourceInfo);
113+
JsrtDebugUtils::AddLineCountToObject(object, utf8SourceInfo);
114+
JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::sourceLength, utf8SourceInfo->GetCchLength(), utf8SourceInfo->GetScriptContext());
115+
116+
if (utf8SourceInfo->HasDebugDocument())
117+
{
118+
// Only add the script ID in cases where a debug document exists
119+
JsrtDebugUtils::AddScriptIdToObject(object, utf8SourceInfo);
120+
}
121+
}
122+
110123
void JsrtDebugUtils::AddVarPropertyToObject(Js::DynamicObject * object, const char16 * propertyName, Js::Var value, Js::ScriptContext * scriptContext)
111124
{
112125
const Js::PropertyRecord* propertyRecord;

lib/Jsrt/JsrtDebugUtils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class JsrtDebugUtils
2424
static void AddLineColumnToObject(Js::DynamicObject* object, Js::FunctionBody* functionBody, int byteCodeOffset);
2525
static void AddSourceLengthAndTextToObject(Js::DynamicObject* object, Js::FunctionBody* functionBody, int byteCodeOffset);
2626
static void AddLineCountToObject(Js::DynamicObject* object, Js::Utf8SourceInfo* utf8SourceInfo);
27-
static void AddSouceToObject(Js::DynamicObject* object, Js::Utf8SourceInfo* utf8SourceInfo);
27+
static void AddSourceToObject(Js::DynamicObject* object, Js::Utf8SourceInfo* utf8SourceInfo);
28+
static void AddSourceMetadataToObject(Js::DynamicObject* object, Js::Utf8SourceInfo* utf8SourceInfo);
2829

2930
static void AddVarPropertyToObject(Js::DynamicObject* object, const char16* propertyName, Js::Var value, Js::ScriptContext* scriptContext);
3031
static void AddPropertyToObject(Js::DynamicObject* object, JsrtDebugPropertyId propertyId, double value, Js::ScriptContext* scriptContext);

lib/Runtime/Debug/DebugContext.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace Js
1010
scriptContext(scriptContext),
1111
hostDebugContext(nullptr),
1212
diagProbesContainer(nullptr),
13-
debuggerMode(DebuggerMode::NotDebugging)
13+
debuggerMode(DebuggerMode::NotDebugging),
14+
isReparsingSource(false)
1415
{
1516
Assert(scriptContext != nullptr);
1617
}
@@ -141,6 +142,30 @@ namespace Js
141142

142143
HRESULT DebugContext::RundownSourcesAndReparse(bool shouldPerformSourceRundown, bool shouldReparseFunctions)
143144
{
145+
struct AutoRestoreIsReparsingSource
146+
{
147+
AutoRestoreIsReparsingSource(DebugContext* debugContext, bool shouldReparseFunctions)
148+
: debugContext(debugContext)
149+
, shouldReparseFunctions(shouldReparseFunctions)
150+
{
151+
if (this->shouldReparseFunctions)
152+
{
153+
this->debugContext->isReparsingSource = true;
154+
}
155+
}
156+
~AutoRestoreIsReparsingSource()
157+
{
158+
if (this->shouldReparseFunctions)
159+
{
160+
this->debugContext->isReparsingSource = false;
161+
}
162+
}
163+
164+
private:
165+
DebugContext* debugContext;
166+
bool shouldReparseFunctions;
167+
} autoRestoreIsReparsingSource(this, shouldReparseFunctions);
168+
144169
OUTPUT_TRACE(Js::DebuggerPhase, _u("DebugContext::RundownSourcesAndReparse scriptContext 0x%p, shouldPerformSourceRundown %d, shouldReparseFunctions %d\n"),
145170
this->scriptContext, shouldPerformSourceRundown, shouldReparseFunctions);
146171

lib/Runtime/Debug/DebugContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ namespace Js
6060

6161
HostDebugContext * GetHostDebugContext() const { return hostDebugContext; }
6262

63+
bool GetIsReparsingSource() const { return this->isReparsingSource; }
64+
6365
private:
6466
ScriptContext * scriptContext;
6567
HostDebugContext* hostDebugContext;
6668
DebuggerMode debuggerMode;
6769
ProbeContainer* diagProbesContainer;
70+
bool isReparsingSource;
6871

6972
// Private Functions
7073
void WalkAndAddUtf8SourceInfo(Js::Utf8SourceInfo* sourceInfo, JsUtil::List<Js::Utf8SourceInfo *, Recycler, false, Js::CopyRemovePolicy, RecyclerPointerComparer> *utf8SourceInfoList);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[
2+
{
3+
"this": "Object {...}",
4+
"locals": {
5+
"b": "string [Uninitialized block variable]"
6+
},
7+
"scopes0": "undefined undefined"
8+
}
9+
]

test/DebuggerCommon/blockScopeSlotArraySiblingTest.js.dbg.baseline

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,81 @@
11
[
22
{
33
"evaluate": {
4+
"level_0_identifier_0=='level0'": "boolean true"
5+
}
6+
},
7+
{
8+
"evaluate": {
9+
"level_0_identifier_1=='level0'": "boolean true"
10+
}
11+
},
12+
{
13+
"evaluate": {
14+
"level_0_identifier_2=='level0'": "boolean true"
15+
}
16+
},
17+
{
18+
"evaluate": {
19+
"level_1_identifier_0=='level1'": "boolean true"
20+
}
21+
},
22+
{
23+
"evaluate": {
24+
"arguments[0]=='level1'": "boolean true"
25+
}
26+
},
27+
{
28+
"evaluate": {
29+
"level_1_identifier_1[0]=='level1'": "boolean true"
30+
}
31+
},
32+
{
33+
"evaluate": {
34+
"level_1_identifier_2=='level1'": "boolean true"
35+
}
36+
},
37+
{
38+
"evaluate": {
39+
"level_1_identifier_3=='level1'": "boolean true"
40+
}
41+
},
42+
{
43+
"evaluate": {
44+
"level_1_identifier_4=='level1'": "boolean true"
45+
}
46+
},
47+
{
48+
"evaluate": {
49+
"level_1_identifier_0=='level1level1'": "boolean true"
50+
}
51+
},
52+
{
53+
"evaluate": {
54+
"arguments[0]=='level1level1'": "boolean true"
55+
}
56+
},
57+
{
58+
"evaluate": {
59+
"level_1_identifier_1[0]=='level1level1'": "boolean true"
60+
}
61+
},
62+
{
63+
"evaluate": {
64+
"level_1_identifier_2=='level1level1'": "boolean true"
65+
}
66+
},
67+
{
68+
"evaluate": {
69+
"level_1_identifier_3=='level1'": "boolean true"
70+
}
71+
},
72+
{
73+
"evaluate": {
74+
"level_1_identifier_4=='level1level1'": "boolean true"
75+
}
76+
},
77+
{
78+
"evaluate": {
479
"level_0_identifier_0=='level0level1'": "boolean true"
580
}
681
},

0 commit comments

Comments
 (0)