Skip to content

Commit b793fe4

Browse files
[MERGE chakra-core#4797 @digitalinfinity] Support disabling interpreter thunks in JSRT
Merge pull request chakra-core#4797 from digitalinfinity:jsrt_thunk_master JsRuntimeAttributeDisableNativeCodeGeneration is not sufficient to disable all allocation of executable memory. Added a new attribute with explicitly this intent so that hosts running in locked down processes can embed ChakraCore
2 parents ddce7f6 + 6464387 commit b793fe4

8 files changed

Lines changed: 57 additions & 1 deletion

File tree

bin/NativeTests/JsRTApiTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ namespace JsRTApiTest
6666
WithSetup(JsRuntimeAttributeAllowScriptInterrupt, handler);
6767
WithSetup(JsRuntimeAttributeEnableIdleProcessing, handler);
6868
WithSetup(JsRuntimeAttributeDisableNativeCodeGeneration, handler);
69+
WithSetup(JsRuntimeAttributeDisableExecutablePageAllocation, handler);
6970
WithSetup(JsRuntimeAttributeDisableEval, handler);
7071
WithSetup((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeAllowScriptInterrupt | JsRuntimeAttributeEnableIdleProcessing), handler);
7172
}

lib/Backend/InterpreterThunkEmitter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@ void* InterpreterThunkEmitter::ConvertToEntryPoint(PVOID dynamicInterpreterThunk
323323

324324
bool InterpreterThunkEmitter::NewThunkBlock()
325325
{
326+
if (this->scriptContext->GetConfig()->IsNoDynamicThunks())
327+
{
328+
return false;
329+
}
330+
326331
#ifdef ENABLE_OOP_NATIVE_CODEGEN
327332
if (CONFIG_FLAG(ForceStaticInterpreterThunk))
328333
{

lib/Jsrt/ChakraCommon.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,15 @@ typedef unsigned short uint16_t;
454454
/// Disable Failfast fatal error on OOM
455455
/// </summary>
456456
JsRuntimeAttributeDisableFatalOnOOM = 0x00000080,
457+
/// <summary>
458+
/// Runtime will not allocate executable code pages
459+
/// This also implies that Native Code generation will be turned off
460+
/// Note that this will break JavaScript stack decoding in tools
461+
// like WPA since they rely on allocation of unique thunks to
462+
// interpret each function and allocation of those thunks will be
463+
// disabled as well
464+
/// </summary>
465+
JsRuntimeAttributeDisableExecutablePageAllocation = 0x00000100,
457466

458467
} JsRuntimeAttributes;
459468

lib/Jsrt/Jsrt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
285285
JsRuntimeAttributeEnableIdleProcessing |
286286
JsRuntimeAttributeDisableEval |
287287
JsRuntimeAttributeDisableNativeCodeGeneration |
288+
JsRuntimeAttributeDisableExecutablePageAllocation |
288289
JsRuntimeAttributeEnableExperimentalFeatures |
289290
JsRuntimeAttributeDispatchSetExceptionsToDebugger |
290291
JsRuntimeAttributeDisableFatalOnOOM
@@ -339,6 +340,12 @@ JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
339340
threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
340341
}
341342

343+
if (attributes & JsRuntimeAttributeDisableExecutablePageAllocation)
344+
{
345+
threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
346+
threadContext->SetThreadContextFlag(ThreadContextFlagNoDynamicThunks);
347+
}
348+
342349
if (attributes & JsRuntimeAttributeDisableFatalOnOOM)
343350
{
344351
threadContext->SetThreadContextFlag(ThreadContextFlagDisableFatalOnOOM);

lib/Runtime/Base/FunctionBody.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3664,6 +3664,23 @@ namespace Js
36643664
{
36653665
this->SetOriginalEntryPoint((JavascriptMethod)InterpreterThunkEmitter::ConvertToEntryPoint(this->m_dynamicInterpreterThunk));
36663666
}
3667+
3668+
#if DBG
3669+
if (GetScriptContext()->GetThreadContext()->NoDynamicThunks())
3670+
{
3671+
Assert(this->m_dynamicInterpreterThunk == nullptr);
3672+
#ifdef ASMJS_PLAT
3673+
if (m_isAsmJsFunction)
3674+
{
3675+
Assert(this->GetOriginalEntryPoint_Unchecked() == (JavascriptMethod)&Js::InterpreterStackFrame::StaticInterpreterAsmThunk);
3676+
}
3677+
else
3678+
#endif
3679+
{
3680+
Assert(this->GetOriginalEntryPoint_Unchecked() == (JavascriptMethod)&Js::InterpreterStackFrame::StaticInterpreterThunk);
3681+
}
3682+
}
3683+
#endif
36673684
}
36683685

36693686
JavascriptMethod FunctionBody::EnsureDynamicInterpreterThunk(FunctionEntryPointInfo* entryPointInfo)
@@ -3673,7 +3690,6 @@ namespace Js
36733690
// We need to ensure dynamic profile info even if we didn't generate a dynamic interpreter thunk
36743691
// This happens when we go through CheckCodeGen thunk, to DelayDynamicInterpreterThunk, to here
36753692
// but the background codegen thread updated the entry point with the native entry point.
3676-
36773693
this->EnsureDynamicProfileInfo();
36783694

36793695
Assert(HasValidEntryPoint());

lib/Runtime/Base/ScriptContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ namespace Js
273273
WinRTConstructorAllowed(Configuration::Global.flags.WinRTConstructorAllowed),
274274
#endif
275275
NoNative(Configuration::Global.flags.NoNative),
276+
NoDynamicThunks(false),
276277
isOptimizedForManyInstances(isOptimizedForManyInstances),
277278
threadConfig(threadConfig)
278279
{
@@ -298,6 +299,9 @@ namespace Js
298299

299300
bool SupportsCollectGarbage() const { return true; }
300301

302+
void ForceNoDynamicThunks() { this->NoDynamicThunks = true; }
303+
bool IsNoDynamicThunks() const { return this->NoDynamicThunks; }
304+
301305
void ForceNoNative() { this->NoNative = true; }
302306
void ForceNative() { this->NoNative = false; }
303307
bool IsNoNative() const { return this->NoNative; }
@@ -341,6 +345,7 @@ namespace Js
341345

342346
// Per script configurations
343347
bool NoNative;
348+
bool NoDynamicThunks;
344349
BOOL fCanOptimizeGlobalLookup;
345350
const bool isOptimizedForManyInstances;
346351
const ThreadConfiguration * const threadConfig;
@@ -1056,6 +1061,7 @@ namespace Js
10561061
inline bool IsHeapEnumInProgress() { return GetRecycler()->IsHeapEnumInProgress(); }
10571062

10581063
bool IsInterpreted() { return config.IsNoNative(); }
1064+
void ForceNoDynamicThunks() { config.ForceNoDynamicThunks(); }
10591065
void ForceNoNative() { config.ForceNoNative(); }
10601066
void ForceNative() { config.ForceNative(); }
10611067
ScriptConfiguration const * GetConfig(void) const { return &config; }

lib/Runtime/Base/ThreadContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,6 +2415,12 @@ ThreadContext::RegisterScriptContext(Js::ScriptContext *scriptContext)
24152415
{
24162416
scriptContext->ForceNoNative();
24172417
}
2418+
2419+
if (NoDynamicThunks())
2420+
{
2421+
scriptContext->ForceNoDynamicThunks();
2422+
}
2423+
24182424
#if DBG || defined(RUNTIME_DATA_COLLECTION)
24192425
scriptContextCount++;
24202426
#endif

lib/Runtime/Base/ThreadContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum ThreadContextFlags
4444
ThreadContextFlagEvalDisabled = 0x00000002,
4545
ThreadContextFlagNoJIT = 0x00000004,
4646
ThreadContextFlagDisableFatalOnOOM = 0x00000008,
47+
ThreadContextFlagNoDynamicThunks = 0x00000010,
4748
};
4849

4950
const int LS_MAX_STACK_SIZE_KB = 300;
@@ -945,6 +946,11 @@ class ThreadContext sealed :
945946
return this->TestThreadContextFlag(ThreadContextFlagNoJIT);
946947
}
947948

949+
bool NoDynamicThunks() const
950+
{
951+
return this->TestThreadContextFlag(ThreadContextFlagNoDynamicThunks);
952+
}
953+
948954
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
949955
Js::Var GetMemoryStat(Js::ScriptContext* scriptContext);
950956
void SetAutoProxyName(LPCWSTR objectName);

0 commit comments

Comments
 (0)