Skip to content

Commit 3a7377d

Browse files
committed
[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 4a6c0ec + 7c5a6bf commit 3a7377d

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
@@ -2406,17 +2406,10 @@ namespace Js
24062406

24072407
if (isDebugOrAsmJsReparse)
24082408
{
2409-
grfscr &= ~fscrWillDeferFncParse; // Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
2410-
}
2411-
2412-
if (isDebugOrAsmJsReparse)
2413-
{
2414-
grfscr |= fscrNoAsmJs; // Disable asm.js when debugging or if linking failed
2415-
}
2416-
2417-
if (isDebugOrAsmJsReparse)
2418-
{
2419-
grfscr &= ~fscrCreateParserState; // Disable parser state cache if we're debugging or reparsing asm.js
2409+
// Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
2410+
// Disable asm.js when debugging or if linking failed
2411+
// Disable parser state cache if we're debugging or reparsing asm.js
2412+
grfscr = fscrNoAsmJs | (grfscr & ~(fscrWillDeferFncParse | fscrCreateParserState));
24202413
}
24212414

24222415
BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
@@ -3520,6 +3513,23 @@ namespace Js
35203513
#endif
35213514
}
35223515

3516+
void FunctionBody::UpdateEntryPointsOnDebugReparse()
3517+
{
3518+
// Update all function types associated with this function body. Note that we can't rely on updating
3519+
// types pointed to by function objects, because the type may evolve to one that is not currently referenced.
3520+
3521+
ProxyEntryPointInfo * entryPointInfo = this->GetDefaultFunctionEntryPointInfo();
3522+
JavascriptMethod newEntryPoint = this->GetDirectEntryPoint(entryPointInfo);
3523+
bool isAsmJS = this->GetIsAsmjsMode();
3524+
3525+
auto updateOneType = [&](ScriptFunctionType* functionType) {
3526+
// Note that the ScriptFunctionType method will handle cross-site thunks correctly.
3527+
functionType->ChangeEntryPoint(entryPointInfo, newEntryPoint, isAsmJS);
3528+
};
3529+
3530+
this->MapFunctionObjectTypes(updateOneType);
3531+
}
3532+
35233533
void FunctionProxy::Finalize(bool isShutdown)
35243534
{
35253535
this->CleanupFunctionProxyCounters();
@@ -5188,10 +5198,6 @@ namespace Js
51885198
}
51895199

51905200
this->SetOriginalEntryPoint(DefaultDeferredParsingThunk);
5191-
5192-
// Abandon the shared type so a new function will get a new one
5193-
this->deferredPrototypeType = nullptr;
5194-
this->undeferredFunctionType = nullptr;
51955201
this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
51965202
}
51975203

lib/Runtime/Base/FunctionBody.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,8 @@ namespace Js
32133213
void ClearEntryPoints();
32143214
void ResetEntryPoint();
32153215
void CleanupToReparseHelper();
3216+
void UpdateEntryPointsOnDebugReparse();
3217+
32163218
void AddDeferParseAttribute();
32173219
void RemoveDeferParseAttribute();
32183220
#if DBG

lib/Runtime/Base/ScriptContext.cpp

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

4024-
JavascriptMethod entryPoint = pFunction->GetEntryPoint();
40254024
FunctionInfo * info = pFunction->GetFunctionInfo();
40264025
FunctionProxy * proxy = info->GetFunctionProxy();
40274026

@@ -4093,26 +4092,13 @@ namespace Js
40934092
}
40944093
#endif
40954094

4096-
ScriptFunction * scriptFunction = ScriptFunction::FromVar(pFunction);
4097-
40984095
#ifdef ASMJS_PLAT
4096+
ScriptFunction * scriptFunction = ScriptFunction::FromVar(pFunction);
40994097
scriptContext->TransitionEnvironmentForDebugger(scriptFunction);
41004098
#endif
4101-
4102-
JavascriptMethod newEntryPoint;
4103-
if (CrossSite::IsThunk(entryPoint))
4104-
{
4105-
// Can't change from cross-site to non-cross-site, but still need to update the e.p.info on ScriptFunctionType.
4106-
newEntryPoint = entryPoint;
4107-
}
4108-
else
4109-
{
4110-
newEntryPoint = pBody->GetDirectEntryPoint(pBody->GetDefaultFunctionEntryPointInfo());
4111-
}
4112-
4113-
scriptFunction->ChangeEntryPoint(pBody->GetDefaultFunctionEntryPointInfo(), newEntryPoint);
41144099
}
4115-
#endif
4100+
4101+
#endif // ENABLE_SCRIPT_DEBUGGING
41164102

41174103
#if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
41184104
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)