Bug 1732362 part 3 - Add an API to disable the JIT backend completely. r=iain

This adds a mechanism to permanently disable the JIT backend for the process. This
lets us improve the sandbox for the socket process.

Depends on D136723

Differential Revision: https://phabricator.services.mozilla.com/D136724
This commit is contained in:
Jan de Mooij 2022-01-25 10:13:04 +00:00
parent 41b6a25500
commit 9a1036bf48
11 changed files with 84 additions and 25 deletions

View file

@ -144,6 +144,15 @@ JS_PUBLIC_API bool InitSelfHostedCode(JSContext* cx,
SelfHostedCache cache = nullptr,
SelfHostedWriter writer = nullptr);
/*
* Permanently disable the JIT backend for this process. This disables the JS
* Baseline Interpreter, JIT compilers, regular expression JIT and support for
* WebAssembly.
*
* If called, this *must* be called before JS_Init.
*/
JS_PUBLIC_API void DisableJitBackend();
} // namespace JS
/**

View file

@ -0,0 +1,19 @@
// |jit-test| --no-jit-backend
assertEq(wasmIsSupportedByHardware(), false);
assertEq(wasmIsSupported(), false);
assertEq(isAsmJSCompilationAvailable(), false);
function test() {
var sum = 0;
for (var i = 0; i < 15; i++) {
sum += i;
}
return sum;
}
assertEq(test(), 105);
var re = /[\d][a-z]{3}[\d]/;
for (var i = 0; i < 10; i++) {
assertEq(re.exec("123foo456")[0], "3foo4");
}

View file

@ -154,6 +154,10 @@ DefaultJitOptions::DefaultJitOptions() {
// Toggles whether functions may be entered at loop headers.
SET_DEFAULT(osr, true);
// Whether the JIT backend (used by JITs, Wasm, Baseline Interpreter) has been
// disabled for this process. See JS::DisableJitBackend.
SET_DEFAULT(disableJitBackend, false);
// Whether to enable extra code to perform dynamic validations.
SET_DEFAULT(runExtraChecks, false);

View file

@ -39,6 +39,7 @@ struct DefaultJitOptions {
#endif
bool checkRangeAnalysis;
bool runExtraChecks;
bool disableJitBackend;
bool disableAma;
bool disableEaa;
bool disableEdgeCaseAnalysis;
@ -136,14 +137,19 @@ struct DefaultJitOptions {
extern DefaultJitOptions JitOptions;
inline bool IsBaselineInterpreterEnabled() {
#ifdef JS_CODEGEN_NONE
inline bool HasJitBackend() {
#if defined(JS_CODEGEN_NONE)
return false;
#else
return JitOptions.baselineInterpreter && JitOptions.supportsFloatingPoint;
return !JitOptions.disableJitBackend;
#endif
}
inline bool IsBaselineInterpreterEnabled() {
return HasJitBackend() && JitOptions.baselineInterpreter &&
JitOptions.supportsFloatingPoint;
}
} // namespace jit
extern mozilla::Atomic<bool> fuzzingSafe;

View file

@ -23,6 +23,7 @@
# include "jit/arm64/vixl/Cpu-vixl.h"
#endif
#include "jit/FlushICache.h" // js::jit::FlushICache
#include "jit/JitOptions.h"
#include "threading/LockGuard.h"
#include "threading/Mutex.h"
#include "util/Memory.h"
@ -545,6 +546,7 @@ class ProcessExecutableMemory {
pages_.init();
MOZ_RELEASE_ASSERT(!initialized());
MOZ_RELEASE_ASSERT(HasJitBackend());
MOZ_RELEASE_ASSERT(gc::SystemPageSize() <= ExecutableCodePageSize);
void* p = ReserveProcessExecutableMemory(MaxCodeBytesPerProcess);
@ -603,6 +605,7 @@ void* ProcessExecutableMemory::allocate(size_t bytes,
ProtectionSetting protection,
MemCheckKind checkKind) {
MOZ_ASSERT(initialized());
MOZ_ASSERT(HasJitBackend());
MOZ_ASSERT(bytes > 0);
MOZ_ASSERT((bytes % ExecutableCodePageSize) == 0);

View file

@ -53,6 +53,7 @@
--no-warp-generator
--no-warp-async
--large-arraybuffers
--no-jit-backend
# GC-related
# These 2 flags can cause the shell to slow down

View file

@ -12245,6 +12245,9 @@ int main(int argc, char** argv) {
"Disable functions that cause "
"artificial OOMs") ||
!op.addBoolOption('\0', "no-threads", "Disable helper threads") ||
!op.addBoolOption(
'\0', "no-jit-backend",
"Disable the JIT backend completely for this process") ||
#ifdef DEBUG
!op.addBoolOption('\0', "dump-entrained-variables",
"Print variables which are "
@ -12345,6 +12348,11 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
// Note: DisableJitBackend must be called before JS_InitWithFailureDiagnostic.
if (op.getBoolOption("no-jit-backend")) {
JS::DisableJitBackend();
}
// Start the engine.
if (const char* message = JS_InitWithFailureDiagnostic()) {
fprintf(gErrFile->fp, "JS_Init failed: %s\n", message);

View file

@ -24,6 +24,7 @@
#include "jit/AtomicOperations.h"
#include "jit/Ion.h"
#include "jit/JitCommon.h"
#include "jit/JitOptions.h"
#include "jit/ProcessExecutableMemory.h"
#include "js/Utility.h"
#include "threading/ProtectedData.h" // js::AutoNoteSingleThreadedRegion
@ -175,7 +176,9 @@ JS_PUBLIC_API const char* JS::detail::InitWithFailureDiagnostic(
js::coverage::InitLCov();
RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory());
if (js::jit::HasJitBackend()) {
RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory());
}
RETURN_IF_FAIL(js::MemoryProtectionExceptionHandler::install());
@ -242,11 +245,11 @@ JS_PUBLIC_API bool JS::InitSelfHostedCode(JSContext* cx, SelfHostedCache cache,
return false;
}
#ifndef JS_CODEGEN_NONE
if (!rt->createJitRuntime(cx)) {
return false;
if (js::jit::HasJitBackend()) {
if (!rt->createJitRuntime(cx)) {
return false;
}
}
#endif
return true;
}
@ -304,7 +307,9 @@ JS_PUBLIC_API void JS_ShutDown(void) {
js::FinishDateTimeState();
if (!JSRuntime::hasLiveRuntimes()) {
js::jit::ReleaseProcessExecutableMemory();
if (js::jit::HasJitBackend()) {
js::jit::ReleaseProcessExecutableMemory();
}
MOZ_ASSERT(!js::LiveMappedBufferCount());
}
@ -333,3 +338,11 @@ JS_PUBLIC_API bool JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn,
(defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86))
void JS::SetAVXEnabled() { js::jit::CPUInfo::SetAVXEnabled(); }
#endif
JS_PUBLIC_API void JS::DisableJitBackend() {
MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
"DisableJitBackend must be called before JS_Init");
MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
"DisableJitBackend must be called before creating a JSContext");
js::jit::JitOptions.disableJitBackend = true;
}

View file

@ -2112,11 +2112,9 @@ void JSScript::relazify(JSRuntime* rt) {
js::Scope* scope = enclosingScope();
UniquePtr<PrivateScriptData> scriptData;
#ifndef JS_CODEGEN_NONE
// Any JIT compiles should have been released, so we already point to the
// interpreter trampoline which supports lazy scripts.
MOZ_ASSERT(isUsingInterpreterTrampoline(rt));
#endif
MOZ_ASSERT_IF(jit::HasJitBackend(), isUsingInterpreterTrampoline(rt));
// Without bytecode, the script counts are invalid so destroy them if they
// still exist.
@ -2363,11 +2361,10 @@ bool JSScript::fullyInitFromStencil(
// here will be released by the UniquePtr.
Rooted<UniquePtr<PrivateScriptData>> lazyData(cx);
#ifndef JS_CODEGEN_NONE
// Whether we are a newborn script or an existing lazy script, we should
// already be pointing to the interpreter trampoline.
MOZ_ASSERT(script->isUsingInterpreterTrampoline(cx->runtime()));
#endif
MOZ_ASSERT_IF(jit::HasJitBackend(),
script->isUsingInterpreterTrampoline(cx->runtime()));
// If we are using an existing lazy script, record enough info to be able to
// rollback on failure.
@ -3131,11 +3128,10 @@ BaseScript* BaseScript::New(JSContext* cx, JS::Handle<JSFunction*> function,
return nullptr;
}
#ifndef JS_CODEGEN_NONE
uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
#else
uint8_t* stubEntry = nullptr;
#endif
if (jit::HasJitBackend()) {
stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
}
MOZ_ASSERT_IF(function,
function->compartment() == sourceObject->compartment());

View file

@ -48,11 +48,7 @@ enum RegExpRunStatus : int32_t {
};
inline bool IsNativeRegExpEnabled() {
#ifdef JS_CODEGEN_NONE
return false;
#else
return jit::JitOptions.nativeRegExp;
#endif
return jit::HasJitBackend() && jit::JitOptions.nativeRegExp;
}
/*

View file

@ -382,10 +382,14 @@ bool wasm::ThreadsAvailable(JSContext* cx) {
}
bool wasm::HasPlatformSupport(JSContext* cx) {
#if !MOZ_LITTLE_ENDIAN() || defined(JS_CODEGEN_NONE) || defined(__wasi__)
#if !MOZ_LITTLE_ENDIAN()
return false;
#else
if (!HasJitBackend()) {
return false;
}
if (gc::SystemPageSize() > wasm::PageSize) {
return false;
}