Bug 1518210 - Wasm: Conditionally compile bounds checks based on wasm::IsHugeMemoryEnabled. r=lth

This commit allows us to conditionally compile bounds checks based on runtime
support for huge memory.

New flags to CompileArgs and CompilerEnvironment are added for whether we are
using huge memory or not, and computed based on the global flag.

Differential Revision: https://phabricator.services.mozilla.com/D41868

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ryan Hunt 2019-08-30 03:17:29 +00:00
Родитель 8764683823
Коммит e96ff8f380
15 изменённых файлов: 62 добавлений и 53 удалений

Просмотреть файл

@ -13286,9 +13286,6 @@ void CodeGenerator::visitWasmTrap(LWasmTrap* lir) {
}
void CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins) {
#ifdef WASM_HUGE_MEMORY
MOZ_CRASH("No wasm bounds check for huge memory");
#else
const MWasmBoundsCheck* mir = ins->mir();
Register ptr = ToRegister(ins->ptr());
Register boundsCheckLimit = ToRegister(ins->boundsCheckLimit());
@ -13296,7 +13293,6 @@ void CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins) {
masm.wasmBoundsCheck(Assembler::Below, ptr, boundsCheckLimit, &ok);
masm.wasmTrap(wasm::Trap::OutOfBounds, mir->bytecodeOffset());
masm.bind(&ok);
#endif
}
void CodeGenerator::visitWasmAlignmentCheck(LWasmAlignmentCheck* ins) {

Просмотреть файл

@ -4206,9 +4206,6 @@ void LIRGenerator::visitWasmLoadTls(MWasmLoadTls* ins) {
}
void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
#ifdef WASM_HUGE_MEMORY
MOZ_CRASH("No bounds checking on huge memory");
#else
MOZ_ASSERT(!ins->isRedundant());
MDefinition* index = ins->index();
@ -4226,7 +4223,6 @@ void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
add(lir, ins);
}
#endif
}
void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {

Просмотреть файл

@ -48,11 +48,6 @@ bool jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) {
// The payload of the MConstant will be Double if the constant
// result is above 2^31-1, but we don't care about that for BCE.
#ifndef WASM_HUGE_MEMORY
MOZ_ASSERT(wasm::MaxMemoryAccessSize < wasm::GuardSize,
"Guard page handles partial out-of-bounds");
#endif
if (addr->isConstant() &&
addr->toConstant()->type() == MIRType::Int32 &&
uint32_t(addr->toConstant()->toInt32()) <

Просмотреть файл

@ -1355,7 +1355,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidatorShared {
arrayViews_(cx),
compilerEnv_(CompileMode::Once, Tier::Optimized, OptimizedBackend::Ion,
DebugEnabled::False, /* ref types */ false,
/* gc types */ false),
/* gc types */ false, /* huge memory */ false),
env_(&compilerEnv_, Shareable::False, ModuleKind::AsmJS) {
compilerEnv_.computeParameters(/* gc types */ false);
env_.minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);

Просмотреть файл

@ -5292,11 +5292,11 @@ class BaseCompiler final : public BaseCompilerInterface {
// Ensure no tls if we don't need it.
#ifdef WASM_HUGE_MEMORY
// We have HeapReg and no bounds checking and need load neither
// memoryBase nor boundsCheckLimit from tls.
MOZ_ASSERT_IF(check->omitBoundsCheck, tls.isInvalid());
#endif
if (env_.hugeMemoryEnabled()) {
// We have HeapReg and no bounds checking and need load neither
// memoryBase nor boundsCheckLimit from tls.
MOZ_ASSERT_IF(check->omitBoundsCheck, tls.isInvalid());
}
#ifdef JS_CODEGEN_ARM
// We have HeapReg on ARM and don't need to load the memoryBase from tls.
MOZ_ASSERT_IF(check->omitBoundsCheck, tls.isInvalid());
@ -5304,8 +5304,7 @@ class BaseCompiler final : public BaseCompilerInterface {
// Bounds check if required.
#ifndef WASM_HUGE_MEMORY
if (!check->omitBoundsCheck) {
if (!env_.hugeMemoryEnabled() && !check->omitBoundsCheck) {
Label ok;
masm.wasmBoundsCheck(Assembler::Below, ptr,
Address(tls, offsetof(TlsData, boundsCheckLimit)),
@ -5313,7 +5312,6 @@ class BaseCompiler final : public BaseCompilerInterface {
masm.wasmTrap(Trap::OutOfBounds, bytecodeOffset());
masm.bind(&ok);
}
#endif
}
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
@ -5369,12 +5367,10 @@ class BaseCompiler final : public BaseCompilerInterface {
MOZ_MUST_USE bool needTlsForAccess(const AccessCheck& check) {
#if defined(JS_CODEGEN_X86)
// x86 requires Tls for memory base
return true;
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \
defined(JS_CODEGEN_MIPS64) || !defined(WASM_HUGE_MEMORY)
return !check.omitBoundsCheck;
#else
return false;
return !env_.hugeMemoryEnabled() && !check.omitBoundsCheck;
#endif
}

Просмотреть файл

@ -891,7 +891,8 @@ size_t Metadata::serializedSize() const {
return sizeof(pod()) + SerializedVectorSize(funcTypeIds) +
SerializedPodVectorSize(globals) + SerializedPodVectorSize(tables) +
sizeof(moduleName) + SerializedPodVectorSize(funcNames) +
filename.serializedSize() + sourceMapURL.serializedSize();
filename.serializedSize() + sourceMapURL.serializedSize() +
sizeof(uint8_t);
}
uint8_t* Metadata::serialize(uint8_t* cursor) const {
@ -905,10 +906,12 @@ uint8_t* Metadata::serialize(uint8_t* cursor) const {
cursor = SerializePodVector(cursor, funcNames);
cursor = filename.serialize(cursor);
cursor = sourceMapURL.serialize(cursor);
cursor = WriteScalar(cursor, uint8_t(omitsBoundsChecks));
return cursor;
}
/* static */ const uint8_t* Metadata::deserialize(const uint8_t* cursor) {
uint8_t scalarOmitsBoundsChecks = 0;
(cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
(cursor = DeserializeVector(cursor, &funcTypeIds)) &&
(cursor = DeserializePodVector(cursor, &globals)) &&
@ -916,10 +919,12 @@ uint8_t* Metadata::serialize(uint8_t* cursor) const {
(cursor = ReadBytes(cursor, &moduleName, sizeof(moduleName))) &&
(cursor = DeserializePodVector(cursor, &funcNames)) &&
(cursor = filename.deserialize(cursor)) &&
(cursor = sourceMapURL.deserialize(cursor));
(cursor = sourceMapURL.deserialize(cursor)) &&
(cursor = ReadScalar<uint8_t>(cursor, &scalarOmitsBoundsChecks));
debugEnabled = false;
debugFuncArgTypes.clear();
debugFuncReturnTypes.clear();
omitsBoundsChecks = !!scalarOmitsBoundsChecks;
return cursor;
}

Просмотреть файл

@ -339,6 +339,7 @@ struct Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod {
TableDescVector tables;
CacheableChars filename;
CacheableChars sourceMapURL;
bool omitsBoundsChecks;
// namePayload points at the name section's CustomSection::payload so that
// the Names (which are use payload-relative offsets) can be used

Просмотреть файл

@ -28,6 +28,7 @@
#include "wasm/WasmGenerator.h"
#include "wasm/WasmIonCompile.h"
#include "wasm/WasmOpIter.h"
#include "wasm/WasmProcess.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmValidate.h"
@ -141,6 +142,7 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
target->sharedMemoryEnabled = sharedMemory;
target->forceTiering = forceTiering;
target->gcEnabled = gc;
target->hugeMemory = wasm::IsHugeMemoryEnabled();
return target;
}
@ -436,14 +438,16 @@ CompilerEnvironment::CompilerEnvironment(CompileMode mode, Tier tier,
OptimizedBackend optimizedBackend,
DebugEnabled debugEnabled,
bool refTypesConfigured,
bool gcTypesConfigured)
bool gcTypesConfigured,
bool hugeMemory)
: state_(InitialWithModeTierDebug),
mode_(mode),
tier_(tier),
optimizedBackend_(optimizedBackend),
debug_(debugEnabled),
refTypes_(refTypesConfigured),
gcTypes_(gcTypesConfigured) {}
gcTypes_(gcTypesConfigured),
hugeMemory_(hugeMemory) {}
void CompilerEnvironment::computeParameters(bool gcFeatureOptIn) {
MOZ_ASSERT(state_ == InitialWithModeTierDebug);
@ -468,6 +472,7 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
bool debugEnabled = args_->debugEnabled;
bool craneliftEnabled = args_->craneliftEnabled;
bool forceTiering = args_->forceTiering;
bool hugeMemory = args_->hugeMemory;
bool hasSecondTier = ionEnabled || craneliftEnabled;
MOZ_ASSERT_IF(gcEnabled || debugEnabled, baselineEnabled);
@ -498,6 +503,7 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
debug_ = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
gcTypes_ = gcEnabled;
refTypes_ = !craneliftEnabled;
hugeMemory_ = hugeMemory;
state_ = Computed;
}
@ -604,7 +610,8 @@ void wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode,
CompilerEnvironment compilerEnv(CompileMode::Tier2, Tier::Optimized,
optimizedBackend, DebugEnabled::False,
refTypesConfigured, gcTypesConfigured);
refTypesConfigured, gcTypesConfigured,
args.hugeMemory);
ModuleEnvironment env(&compilerEnv, args.sharedMemoryEnabled
? Shareable::True

Просмотреть файл

@ -57,6 +57,7 @@ struct CompileArgs : ShareableBase<CompileArgs> {
bool sharedMemoryEnabled;
bool forceTiering;
bool gcEnabled;
bool hugeMemory;
// CompileArgs has two constructors:
//
@ -78,7 +79,8 @@ struct CompileArgs : ShareableBase<CompileArgs> {
debugEnabled(false),
sharedMemoryEnabled(false),
forceTiering(false),
gcEnabled(false) {}
gcEnabled(false),
hugeMemory(false) {}
};
// Return the estimated compiled (machine) code size for the given bytecode size

Просмотреть файл

@ -227,7 +227,17 @@ class AutoCranelift {
public:
explicit AutoCranelift(const ModuleEnvironment& env)
: env_(env), compiler_(nullptr) {}
: env_(env), compiler_(nullptr) {
#ifdef WASM_SUPPORTS_HUGE_MEMORY
if (env.hugeMemoryEnabled()) {
// In the huge memory configuration, we always reserve the full 4 GB
// index space for a heap.
staticEnv_.staticMemoryBound = HugeIndexRange;
}
#endif
// Otherwise, heap bounds are stored in the `boundsCheckLimit` field
// of TlsData.
}
bool init() {
compiler_ = cranelift_compiler_create(&staticEnv_, &env_);
return !!compiler_;
@ -247,10 +257,8 @@ CraneliftFuncCompileInput::CraneliftFuncCompileInput(
index(func.index),
offset_in_module(func.lineOrBytecode) {}
#ifndef WASM_HUGE_MEMORY
static_assert(offsetof(TlsData, boundsCheckLimit) == sizeof(size_t),
"fix make_heap() in wasm2clif.rs");
#endif
CraneliftStaticEnvironment::CraneliftStaticEnvironment()
:
@ -280,17 +288,7 @@ CraneliftStaticEnvironment::CraneliftStaticEnvironment()
#else
platformIsWindows(false),
#endif
staticMemoryBound(
#ifdef WASM_HUGE_MEMORY
// In the huge memory configuration, we always reserve the full 4 GB
// index space for a heap.
IndexRange
#else
// Otherwise, heap bounds are stored in the `boundsCheckLimit` field
// of TlsData.
0
#endif
),
staticMemoryBound(0),
memoryGuardSize(OffsetGuardLimit),
instanceTlsOffset(offsetof(TlsData, instance)),
interruptTlsOffset(offsetof(TlsData, interrupt)),

Просмотреть файл

@ -1075,6 +1075,7 @@ SharedMetadata ModuleGenerator::finishMetadata(const Bytes& bytecode) {
metadata_->nameCustomSectionIndex = env_->nameCustomSectionIndex;
metadata_->moduleName = env_->moduleName;
metadata_->funcNames = std::move(env_->funcNames);
metadata_->omitsBoundsChecks = env_->hugeMemoryEnabled();
// Copy over additional debug information.

Просмотреть файл

@ -575,11 +575,9 @@ class FunctionCompiler {
}
MWasmLoadTls* maybeLoadBoundsCheckLimit() {
#ifdef WASM_HUGE_MEMORY
if (!env_.isAsmJS()) {
if (env_.hugeMemoryEnabled()) {
return nullptr;
}
#endif
AliasSet aliases = env_.maxMemoryLength.isSome()
? AliasSet::None()
: AliasSet::Load(AliasSet::WasmHeapMeta);

Просмотреть файл

@ -41,6 +41,7 @@
#include "wasm/WasmInstance.h"
#include "wasm/WasmIonCompile.h"
#include "wasm/WasmModule.h"
#include "wasm/WasmProcess.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmStubs.h"
#include "wasm/WasmValidate.h"
@ -494,6 +495,10 @@ bool wasm::CompileAndSerialize(const ShareableBytes& bytecode,
compileArgs->baselineEnabled = false;
compileArgs->ionEnabled = true;
// The caller must ensure that huge memory support is configured the same in
// the receiving process of this serialized module.
compileArgs->hugeMemory = wasm::IsHugeMemoryEnabled();
SerializeListener listener(serialized);
UniqueChars error;

Просмотреть файл

@ -2901,10 +2901,11 @@ bool wasm::Validate(JSContext* cx, const ShareableBytes& bytecode,
bool gcTypesConfigured = HasGcSupport(cx);
bool refTypesConfigured = HasReftypesSupport(cx);
bool hugeMemory = false;
CompilerEnvironment compilerEnv(CompileMode::Once, Tier::Optimized,
OptimizedBackend::Ion, DebugEnabled::False,
refTypesConfigured, gcTypesConfigured);
CompilerEnvironment compilerEnv(
CompileMode::Once, Tier::Optimized, OptimizedBackend::Ion,
DebugEnabled::False, refTypesConfigured, gcTypesConfigured, hugeMemory);
ModuleEnvironment env(
&compilerEnv,
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()

Просмотреть файл

@ -71,6 +71,7 @@ struct CompilerEnvironment {
DebugEnabled debug_;
bool refTypes_;
bool gcTypes_;
bool hugeMemory_;
};
};
@ -85,7 +86,7 @@ struct CompilerEnvironment {
CompilerEnvironment(CompileMode mode, Tier tier,
OptimizedBackend optimizedBackend,
DebugEnabled debugEnabled, bool refTypesConfigured,
bool gcTypesConfigured);
bool gcTypesConfigured, bool hugeMemory);
// Compute any remaining compilation parameters.
void computeParameters(Decoder& d, bool gcFeatureOptIn);
@ -120,6 +121,10 @@ struct CompilerEnvironment {
MOZ_ASSERT(isComputed());
return refTypes_;
}
bool hugeMemory() const {
MOZ_ASSERT(isComputed());
return hugeMemory_;
}
};
// ModuleEnvironment contains all the state necessary to process or render
@ -210,6 +215,9 @@ struct ModuleEnvironment {
bool debugEnabled() const {
return compilerEnv->debug() == DebugEnabled::True;
}
bool hugeMemoryEnabled() const {
return !isAsmJS() && compilerEnv->hugeMemory();
}
bool funcIsImport(uint32_t funcIndex) const {
return funcIndex < funcImportGlobalDataOffsets.length();
}