Bug 1511958 - Implement i64<>JavaScript’s BigInt conversions proposal (part 2, runtime flag and testing function)

This is part 2 of a series of revs that split up D41710 (for Wasm I64 to BigInt conversion) into smaller revs. This rev depends on the compile-time flag added in D43177 and adds a runtime flag to JSContext options that will toggle whether I64 to BigInt conversion is used. The flag will get used mostly in WasmInstance.cpp, but it also needs to be used to toggle I64 error checks in both Ion inlining code and in Wasm stub generation code. To pass that information along, the flag is also put in CompileArgs for WasmCompile and then copied to wasm module metadata (so that it can be read from lazy stub generation code).

Differential Revision: https://phabricator.services.mozilla.com/D43179
This commit is contained in:
Asumu Takikawa 2019-12-04 13:30:06 +02:00
parent e77b837ae6
commit 7c2c17a2e7
16 changed files with 110 additions and 16 deletions

View File

@ -27,6 +27,9 @@ class JS_PUBLIC_API ContextOptions {
wasmCranelift_(false),
wasmGc_(false),
testWasmAwaitTier2_(false),
#ifdef ENABLE_WASM_BIGINT
enableWasmBigInt_(false),
#endif
throwOnAsmJSValidationFailure_(false),
asyncStack_(true),
throwOnDebuggeeWouldRun_(true),
@ -90,6 +93,14 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
#ifdef ENABLE_WASM_BIGINT
bool isWasmBigIntEnabled() const { return enableWasmBigInt_; }
ContextOptions& setWasmBigIntEnabled(bool flag) {
enableWasmBigInt_ = flag;
return *this;
}
#endif
bool wasmGc() const { return wasmGc_; }
// Defined out-of-line because it depends on a compile-time option
ContextOptions& setWasmGc(bool flag);
@ -178,6 +189,9 @@ class JS_PUBLIC_API ContextOptions {
bool wasmCranelift_ : 1;
bool wasmGc_ : 1;
bool testWasmAwaitTier2_ : 1;
#ifdef ENABLE_WASM_BIGINT
bool enableWasmBigInt_ : 1;
#endif
bool throwOnAsmJSValidationFailure_ : 1;
bool asyncStack_ : 1;
bool throwOnDebuggeeWouldRun_ : 1;

View File

@ -795,6 +795,12 @@ static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool WasmBigIntEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasI64BigIntSupport(cx));
return true;
}
static bool WasmDebugSupport(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(cx->options().wasmBaseline() &&
@ -6641,6 +6647,10 @@ gc::ZealModeHelpText),
"wasmMultiValueEnabled()",
" Returns a boolean indicating whether the WebAssembly multi-value proposal is enabled."),
JS_FN_HELP("wasmBigIntEnabled", WasmBigIntEnabled, 1, 0,
"wasmBigIntEnabled()",
" Returns a boolean indicating whether the WebAssembly I64 to BigInt proposal is enabled."),
JS_FN_HELP("wasmDebugSupport", WasmDebugSupport, 1, 0,
"wasmDebugSupport()",
" Returns a boolean indicating whether the WebAssembly compilers support debugging."),

View File

@ -486,6 +486,9 @@ bool shell::enableWasmGc = false;
#endif
bool shell::enableWasmVerbose = false;
bool shell::enableTestWasmAwaitTier2 = false;
#ifdef ENABLE_WASM_BIGINT
bool shell::enableWasmBigInt = false;
#endif
bool shell::enableAsyncStacks = false;
bool shell::enableStreams = false;
bool shell::enableReadableByteStreams = false;
@ -10228,6 +10231,9 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) {
enableReadableByteStreams = op.getBoolOption("enable-readable-byte-streams");
enableBYOBStreamReaders = op.getBoolOption("enable-byob-stream-readers");
enableWritableStreams = op.getBoolOption("enable-writable-streams");
#ifdef ENABLE_WASM_BIGINT
enableWasmBigInt = op.getBoolOption("wasm-bigint");
#endif
enableFields = !op.getBoolOption("disable-experimental-fields");
enableAwaitFix = op.getBoolOption("enable-experimental-await-fix");
enableWeakRefs = op.getBoolOption("enable-weak-refs");
@ -10246,6 +10252,9 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) {
#endif
.setWasmVerbose(enableWasmVerbose)
.setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
#ifdef ENABLE_WASM_BIGINT
.setWasmBigIntEnabled(enableWasmBigInt)
#endif
.setAsyncStack(enableAsyncStacks);
if (const char* str = op.getStringOption("cache-ir-stubs")) {
@ -10570,6 +10579,9 @@ static void SetWorkerContextOptions(JSContext* cx) {
#endif
#ifdef ENABLE_WASM_GC
.setWasmGc(enableWasmGc)
#endif
#ifdef ENABLE_WASM_BIGINT
.setWasmBigIntEnabled(enableWasmBigInt)
#endif
.setWasmVerbose(enableWasmVerbose)
.setTestWasmAwaitTier2(enableTestWasmAwaitTier2);
@ -10978,6 +10990,12 @@ int main(int argc, char** argv, char** envp) {
"Enable WebAssembly verbose logging") ||
!op.addBoolOption('\0', "disable-wasm-huge-memory",
"Disable WebAssembly huge memory") ||
#ifdef ENABLE_WASM_BIGINT
!op.addBoolOption('\0', "wasm-bigint",
"Enable WebAssembly BigInt conversions") ||
#else
!op.addBoolOption('\0', "wasm-bigint", "No-op") ||
#endif
!op.addBoolOption('\0', "test-wasm-await-tier2",
"Forcibly activate tiering and block "
"instantiation on completion of tier2") ||

View File

@ -112,6 +112,9 @@ extern bool enableWasmGc;
#endif
extern bool enableWasmVerbose;
extern bool enableTestWasmAwaitTier2;
#ifdef ENABLE_WASM_BIGINT
extern bool enableWasmBigInt;
#endif
extern bool enableAsyncStacks;
extern bool enableStreams;
extern bool enableReadableByteStreams;

View File

@ -1352,7 +1352,8 @@ 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, /* huge memory */ false),
/* gc types */ false, /* huge memory */ false,
/* bigint */ false),
env_(&compilerEnv_, Shareable::False, ModuleKind::AsmJS) {
compilerEnv_.computeParameters(/* gc types */ false);
env_.minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);

View File

@ -668,6 +668,8 @@ bool LazyStubTier::createMany(const Uint32Vector& funcExportIndices,
const FuncExportVector& funcExports = metadata.funcExports;
uint8_t* moduleSegmentBase = codeTier.segment().base();
bool bigIntEnabled = codeTier.code().metadata().bigIntEnabled;
CodeRangeVector codeRanges;
DebugOnly<uint32_t> numExpectedRanges = 0;
for (uint32_t funcExportIndex : funcExportIndices) {
@ -679,7 +681,7 @@ bool LazyStubTier::createMany(const Uint32Vector& funcExportIndices,
Maybe<ImmPtr> callee;
callee.emplace(calleePtr, ImmPtr::NoCheckToken());
if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee,
/* asmjs */ false, &codeRanges)) {
/* asmjs */ false, bigIntEnabled, &codeRanges)) {
return false;
}
}

View File

@ -355,6 +355,9 @@ struct Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod {
FuncReturnTypesVector debugFuncReturnTypes;
ModuleHash debugHash;
// Feature flag that gets copied from ModuleEnvironment for BigInt support.
bool bigIntEnabled;
explicit Metadata(ModuleKind kind = ModuleKind::Wasm)
: MetadataCacheablePod(kind), debugEnabled(false), debugHash() {}
virtual ~Metadata() {}

View File

@ -92,6 +92,12 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
bool gc = false;
#endif
#ifdef ENABLE_WASM_BIGINT
bool bigInt = cx->options().isWasmBigIntEnabled();
#else
bool bigInt = false;
#endif
// Debug information such as source view or debug traps will require
// additional memory and permanently stay in baseline code, so we try to
// only enable it when a developer actually cares: when the debugger tab
@ -145,6 +151,7 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
target->forceTiering = forceTiering;
target->gcEnabled = gc;
target->hugeMemory = wasm::IsHugeMemoryEnabled();
target->bigIntEnabled = bigInt;
return target;
}
@ -441,7 +448,7 @@ CompilerEnvironment::CompilerEnvironment(CompileMode mode, Tier tier,
DebugEnabled debugEnabled,
bool refTypesConfigured,
bool gcTypesConfigured,
bool hugeMemory)
bool hugeMemory, bool bigIntConfigured)
: state_(InitialWithModeTierDebug),
mode_(mode),
tier_(tier),
@ -450,7 +457,8 @@ CompilerEnvironment::CompilerEnvironment(CompileMode mode, Tier tier,
refTypes_(refTypesConfigured),
gcTypes_(gcTypesConfigured),
multiValues_(true),
hugeMemory_(hugeMemory) {}
hugeMemory_(hugeMemory),
bigInt_(bigIntConfigured) {}
void CompilerEnvironment::computeParameters(bool gcFeatureOptIn) {
MOZ_ASSERT(state_ == InitialWithModeTierDebug);
@ -476,6 +484,7 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
bool craneliftEnabled = args_->craneliftEnabled;
bool forceTiering = args_->forceTiering;
bool hugeMemory = args_->hugeMemory;
bool bigIntEnabled = args_->bigIntEnabled;
bool hasSecondTier = ionEnabled || craneliftEnabled;
MOZ_ASSERT_IF(gcEnabled || debugEnabled, baselineEnabled);
@ -508,6 +517,7 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
refTypes_ = !craneliftEnabled;
multiValues_ = !craneliftEnabled;
hugeMemory_ = hugeMemory;
bigInt_ = bigIntEnabled && !craneliftEnabled;
state_ = Computed;
}
@ -608,6 +618,7 @@ void wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode,
bool gcTypesConfigured = false; // No optimized backend support yet
bool refTypesConfigured = !args.craneliftEnabled;
bool bigIntConfigured = args.bigIntEnabled && !args.craneliftEnabled;
OptimizedBackend optimizedBackend = args.craneliftEnabled
? OptimizedBackend::Cranelift
: OptimizedBackend::Ion;
@ -615,7 +626,7 @@ void wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode,
CompilerEnvironment compilerEnv(CompileMode::Tier2, Tier::Optimized,
optimizedBackend, DebugEnabled::False,
refTypesConfigured, gcTypesConfigured,
args.hugeMemory);
args.hugeMemory, bigIntConfigured);
ModuleEnvironment env(&compilerEnv, args.sharedMemoryEnabled
? Shareable::True

View File

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

View File

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

View File

@ -103,6 +103,19 @@ bool wasm::HasMultiValueSupport(JSContext* cx) {
#endif
}
bool wasm::HasI64BigIntSupport(JSContext* cx) {
#ifdef ENABLE_WASM_CRANELIFT
if (cx->options().wasmCranelift()) {
return false;
}
#endif
#ifdef ENABLE_WASM_BIGINT
return cx->options().isWasmBigIntEnabled();
#else
return false;
#endif
}
bool wasm::HasCompilerSupport(JSContext* cx) {
#if !MOZ_LITTLE_ENDIAN || defined(JS_CODEGEN_NONE)
return false;

View File

@ -73,6 +73,11 @@ bool HasGcSupport(JSContext* cx);
bool HasMultiValueSupport(JSContext* cx);
// Returns true if WebAssembly as configured by compile-time flags and run-time
// options can support I64 to BigInt conversion.
bool HasI64BigIntSupport(JSContext* cx);
// Compiles the given binary wasm module given the ArrayBufferObject
// and links the module's imports with the given import object.

View File

@ -838,7 +838,7 @@ static void GenerateJitEntryThrow(MacroAssembler& masm, unsigned frameSize) {
static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
const FuncExport& fe, const Maybe<ImmPtr>& funcPtr,
Offsets* offsets) {
bool bigIntEnabled, Offsets* offsets) {
AssertExpectedSP(masm);
RegisterOrSP sp = masm.getStackPointer();
@ -870,7 +870,7 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
GenerateJitEntryLoadTls(masm, frameSize);
if (fe.funcType().hasI64ArgOrRet()) {
if (fe.funcType().hasI64ArgOrRet() && !bigIntEnabled) {
CallSymbolicAddress(masm, !fe.hasEagerStubs(),
SymbolicAddress::ReportInt64JSCall);
GenerateJitEntryThrow(masm, frameSize);
@ -2461,7 +2461,8 @@ static bool GenerateDebugTrapStub(MacroAssembler& masm, Label* throwLabel,
bool wasm::GenerateEntryStubs(MacroAssembler& masm, size_t funcExportIndex,
const FuncExport& fe, const Maybe<ImmPtr>& callee,
bool isAsmJS, CodeRangeVector* codeRanges) {
bool isAsmJS, bool bigIntEnabled,
CodeRangeVector* codeRanges) {
MOZ_ASSERT(!callee == fe.hasEagerStubs());
MOZ_ASSERT_IF(isAsmJS, fe.hasEagerStubs());
@ -2478,7 +2479,8 @@ bool wasm::GenerateEntryStubs(MacroAssembler& masm, size_t funcExportIndex,
return true;
}
if (!GenerateJitEntry(masm, funcExportIndex, fe, callee, &offsets)) {
if (!GenerateJitEntry(masm, funcExportIndex, fe, callee, bigIntEnabled,
&offsets)) {
return false;
}
if (!codeRanges->emplaceBack(CodeRange::JitEntry, fe.funcIndex(), offsets)) {
@ -2539,7 +2541,7 @@ bool wasm::GenerateStubs(const ModuleEnvironment& env,
continue;
}
if (!GenerateEntryStubs(masm, i, fe, noAbsolute, env.isAsmJS(),
&code->codeRanges)) {
env.bigIntEnabled(), &code->codeRanges)) {
return false;
}
}

View File

@ -259,7 +259,7 @@ extern bool GenerateEntryStubs(jit::MacroAssembler& masm,
size_t funcExportIndex,
const FuncExport& funcExport,
const Maybe<jit::ImmPtr>& callee, bool isAsmJS,
CodeRangeVector* codeRanges);
bool bigIntEnabled, CodeRangeVector* codeRanges);
extern void GenerateTrapExitMachineState(jit::MachineState* machine,
size_t* numWords);

View File

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

View File

@ -73,6 +73,7 @@ struct CompilerEnvironment {
bool gcTypes_;
bool multiValues_;
bool hugeMemory_;
bool bigInt_;
};
};
@ -87,7 +88,8 @@ struct CompilerEnvironment {
CompilerEnvironment(CompileMode mode, Tier tier,
OptimizedBackend optimizedBackend,
DebugEnabled debugEnabled, bool refTypesConfigured,
bool gcTypesConfigured, bool hugeMemory);
bool gcTypesConfigured, bool hugeMemory,
bool bigIntConfigured);
// Compute any remaining compilation parameters.
void computeParameters(Decoder& d, bool gcFeatureOptIn);
@ -130,6 +132,10 @@ struct CompilerEnvironment {
MOZ_ASSERT(isComputed());
return hugeMemory_;
}
bool bigInt() const {
MOZ_ASSERT(isComputed());
return bigInt_;
}
};
// ModuleEnvironment contains all the state necessary to process or render
@ -215,6 +221,7 @@ struct ModuleEnvironment {
bool gcTypesEnabled() const { return compilerEnv->gcTypes(); }
bool refTypesEnabled() const { return compilerEnv->refTypes(); }
bool multiValuesEnabled() const { return compilerEnv->multiValues(); }
bool bigIntEnabled() const { return compilerEnv->bigInt(); }
bool usesMemory() const { return memoryUsage != MemoryUsage::None; }
bool usesSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
bool isAsmJS() const { return kind == ModuleKind::AsmJS; }