Skip to content

Commit 361df65

Browse files
committed
[1.10>master] [MERGE #5581 @pleath] OS#15992595: On debug reparse, update entry points associated with all parsed functions, not just the ones associated with function objects
Merge pull request #5581 from pleath:15992595 Object may evolve after reparse and use types that are not referenced at reparse time.
2 parents 72c274f + 3a7377d commit 361df65

File tree

7 files changed

+70
-66
lines changed

7 files changed

+70
-66
lines changed

lib/Runtime/Base/FunctionBody.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,17 +2438,10 @@ namespace Js
24382438

24392439
if (isDebugOrAsmJsReparse)
24402440
{
2441-
grfscr &= ~fscrWillDeferFncParse; // Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
2442-
}
2443-
2444-
if (isDebugOrAsmJsReparse)
2445-
{
2446-
grfscr |= fscrNoAsmJs; // Disable asm.js when debugging or if linking failed
2447-
}
2448-
2449-
if (isDebugOrAsmJsReparse)
2450-
{
2451-
grfscr &= ~fscrCreateParserState; // Disable parser state cache if we're debugging or reparsing asm.js
2441+
// Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
2442+
// Disable asm.js when debugging or if linking failed
2443+
// Disable parser state cache if we're debugging or reparsing asm.js
2444+
grfscr = fscrNoAsmJs | (grfscr & ~(fscrWillDeferFncParse | fscrCreateParserState));
24522445
}
24532446

24542447
BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
@@ -3555,6 +3548,23 @@ namespace Js
35553548
#endif
35563549
}
35573550

3551+
void FunctionBody::UpdateEntryPointsOnDebugReparse()
3552+
{
3553+
// Update all function types associated with this function body. Note that we can't rely on updating
3554+
// types pointed to by function objects, because the type may evolve to one that is not currently referenced.
3555+
3556+
ProxyEntryPointInfo * entryPointInfo = this->GetDefaultFunctionEntryPointInfo();
3557+
JavascriptMethod newEntryPoint = this->GetDirectEntryPoint(entryPointInfo);
3558+
bool isAsmJS = this->GetIsAsmjsMode();
3559+
3560+
auto updateOneType = [&](ScriptFunctionType* functionType) {
3561+
// Note that the ScriptFunctionType method will handle cross-site thunks correctly.
3562+
functionType->ChangeEntryPoint(entryPointInfo, newEntryPoint, isAsmJS);
3563+
};
3564+
3565+
this->MapFunctionObjectTypes(updateOneType);
3566+
}
3567+
35583568
void FunctionProxy::Finalize(bool isShutdown)
35593569
{
35603570
this->CleanupFunctionProxyCounters();
@@ -5227,10 +5237,6 @@ namespace Js
52275237
}
52285238

52295239
this->SetOriginalEntryPoint(DefaultDeferredParsingThunk);
5230-
5231-
// Abandon the shared type so a new function will get a new one
5232-
this->deferredPrototypeType = nullptr;
5233-
this->undeferredFunctionType = nullptr;
52345240
this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
52355241
}
52365242

lib/Runtime/Base/FunctionBody.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,6 +3216,8 @@ namespace Js
32163216
void ClearEntryPoints();
32173217
void ResetEntryPoint();
32183218
void CleanupToReparseHelper();
3219+
void UpdateEntryPointsOnDebugReparse();
3220+
32193221
void AddDeferParseAttribute();
32203222
void RemoveDeferParseAttribute();
32213223
#if DBG

lib/Runtime/Base/ScriptContext.cpp

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4101,7 +4101,6 @@ namespace Js
41014101
// Wrapped function are not allocated with the EnumClass bit
41024102
Assert(pFunction->GetFunctionInfo() != &JavascriptExternalFunction::EntryInfo::WrappedFunctionThunk);
41034103

4104-
JavascriptMethod entryPoint = pFunction->GetEntryPoint();
41054104
FunctionInfo * info = pFunction->GetFunctionInfo();
41064105
FunctionProxy * proxy = info->GetFunctionProxy();
41074106

@@ -4173,26 +4172,13 @@ namespace Js
41734172
}
41744173
#endif
41754174

4176-
ScriptFunction * scriptFunction = ScriptFunction::FromVar(pFunction);
4177-
41784175
#ifdef ASMJS_PLAT
4176+
ScriptFunction * scriptFunction = ScriptFunction::FromVar(pFunction);
41794177
scriptContext->TransitionEnvironmentForDebugger(scriptFunction);
41804178
#endif
4181-
4182-
JavascriptMethod newEntryPoint;
4183-
if (CrossSite::IsThunk(entryPoint))
4184-
{
4185-
// Can't change from cross-site to non-cross-site, but still need to update the e.p.info on ScriptFunctionType.
4186-
newEntryPoint = entryPoint;
4187-
}
4188-
else
4189-
{
4190-
newEntryPoint = pBody->GetDirectEntryPoint(pBody->GetDefaultFunctionEntryPointInfo());
4191-
}
4192-
4193-
scriptFunction->ChangeEntryPoint(pBody->GetDefaultFunctionEntryPointInfo(), newEntryPoint);
41944179
}
4195-
#endif
4180+
4181+
#endif // ENABLE_SCRIPT_DEBUGGING
41964182

41974183
#if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
41984184
void ScriptContext::RecyclerEnumClassEnumeratorCallback(void *address, size_t size)

lib/Runtime/Debug/DebugContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,10 @@ namespace Js
238238
{
239239
pFuncBody->ReinitializeExecutionModeAndLimits();
240240
}
241+
pFuncBody->UpdateEntryPointsOnDebugReparse();
241242
});
242243
}
244+
243245
return false;
244246
}
245247

@@ -330,6 +332,7 @@ namespace Js
330332
{
331333
pFuncBody->ReinitializeExecutionModeAndLimits();
332334
}
335+
pFuncBody->UpdateEntryPointsOnDebugReparse();
333336
});
334337
}
335338

lib/Runtime/Library/ScriptFunction.cpp

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -210,48 +210,15 @@ using namespace Js;
210210

211211
void ScriptFunction::ChangeEntryPoint(ProxyEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint)
212212
{
213-
Assert(entryPoint != nullptr);
214213
Assert(this->GetTypeId() == TypeIds_Function);
215214
#if ENABLE_NATIVE_CODEGEN
216215
Assert(!IsCrossSiteObject() || entryPoint != (Js::JavascriptMethod)checkCodeGenThunk);
217216
#endif
218217

219218
Assert((entryPointInfo != nullptr && this->GetFunctionProxy() != nullptr));
220-
if (this->GetEntryPoint() == entryPoint && this->GetScriptFunctionType()->GetEntryPointInfo() == entryPointInfo)
221-
{
222-
return;
223-
}
224219

225220
bool isAsmJS = HasFunctionBody() && this->GetFunctionBody()->GetIsAsmjsMode();
226-
227-
// ASMJS:- for asmjs we don't need to update the entry point here as it updates the types entry point
228-
if (!isAsmJS)
229-
{
230-
// We can't go from cross-site to non-cross-site. Update only in the non-cross site case
231-
if (!CrossSite::IsThunk(this->GetEntryPoint()))
232-
{
233-
this->SetEntryPoint(entryPoint);
234-
}
235-
}
236-
// instead update the address in the function entrypoint info
237-
else
238-
{
239-
entryPointInfo->jsMethod = entryPoint;
240-
}
241-
242-
ProxyEntryPointInfo* oldEntryPointInfo = this->GetScriptFunctionType()->GetEntryPointInfo();
243-
if (oldEntryPointInfo
244-
&& oldEntryPointInfo != entryPointInfo
245-
&& oldEntryPointInfo->SupportsExpiration())
246-
{
247-
// The old entry point could be executing so we need root it to make sure
248-
// it isn't prematurely collected. The rooting is done by queuing it up on the threadContext
249-
ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
250-
251-
threadContext->QueueFreeOldEntryPointInfoIfInScript((FunctionEntryPointInfo*)oldEntryPointInfo);
252-
}
253-
254-
this->GetScriptFunctionType()->SetEntryPointInfo(entryPointInfo);
221+
this->GetScriptFunctionType()->ChangeEntryPoint(entryPointInfo, entryPoint, isAsmJS);
255222
}
256223

257224
FunctionProxy * ScriptFunction::GetFunctionProxy() const

lib/Runtime/Types/ScriptFunctionType.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,43 @@ namespace Js
3434
library->ScriptFunctionTypeHandler(!proxy->IsConstructor(), proxy->GetIsAnonymousFunction()),
3535
isShared, isShared);
3636
}
37+
38+
void ScriptFunctionType::ChangeEntryPoint(ProxyEntryPointInfo * entryPointInfo, JavascriptMethod entryPoint, bool isAsmJS)
39+
{
40+
Assert(entryPoint != nullptr);
41+
Assert(entryPointInfo != nullptr);
42+
if (this->GetEntryPoint() == entryPoint && this->GetEntryPointInfo() == entryPointInfo)
43+
{
44+
return;
45+
}
46+
47+
// ASMJS:- for asmjs we don't need to update the entry point here as it updates the types entry point
48+
if (!isAsmJS)
49+
{
50+
// We can't go from cross-site to non-cross-site. Update only in the non-cross site case
51+
if (!CrossSite::IsThunk(this->GetEntryPoint()))
52+
{
53+
this->SetEntryPoint(entryPoint);
54+
}
55+
}
56+
// instead update the address in the function entrypoint info
57+
else
58+
{
59+
entryPointInfo->jsMethod = entryPoint;
60+
}
61+
62+
ProxyEntryPointInfo* oldEntryPointInfo = this->GetEntryPointInfo();
63+
if (oldEntryPointInfo
64+
&& oldEntryPointInfo != entryPointInfo
65+
&& oldEntryPointInfo->SupportsExpiration())
66+
{
67+
// The old entry point could be executing so we need root it to make sure
68+
// it isn't prematurely collected. The rooting is done by queuing it up on the threadContext
69+
ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
70+
71+
threadContext->QueueFreeOldEntryPointInfoIfInScript((FunctionEntryPointInfo*)oldEntryPointInfo);
72+
}
73+
74+
this->SetEntryPointInfo(entryPointInfo);
75+
}
3776
};

lib/Runtime/Types/ScriptFunctionType.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Js
1313
static DWORD GetEntryPointInfoOffset() { return offsetof(ScriptFunctionType, entryPointInfo); }
1414
ProxyEntryPointInfo * GetEntryPointInfo() const { return entryPointInfo; }
1515
void SetEntryPointInfo(ProxyEntryPointInfo * entryPointInfo) { this->entryPointInfo = entryPointInfo; }
16+
void ChangeEntryPoint(ProxyEntryPointInfo * entryPointInfo, JavascriptMethod entryPoint, bool isAsmJS);
1617
private:
1718
ScriptFunctionType(ScriptFunctionType * type);
1819
ScriptFunctionType(ScriptContext* scriptContext, RecyclableObject* prototype,

0 commit comments

Comments
 (0)