From 7c2c17a2e70caf8e28906b1938782f80ee56c6a8 Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Wed, 4 Dec 2019 13:30:06 +0200 Subject: [PATCH] =?UTF-8?q?Bug=201511958=20-=20Implement=20i64<>JavaScript?= =?UTF-8?q?=E2=80=99s=20BigInt=20conversions=20proposal=20(part=202,=20run?= =?UTF-8?q?time=20flag=20and=20testing=20function)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- js/public/ContextOptions.h | 14 ++++++++++++++ js/src/builtin/TestingFunctions.cpp | 10 ++++++++++ js/src/shell/js.cpp | 18 ++++++++++++++++++ js/src/shell/jsshell.h | 3 +++ js/src/wasm/AsmJS.cpp | 3 ++- js/src/wasm/WasmCode.cpp | 4 +++- js/src/wasm/WasmCode.h | 3 +++ js/src/wasm/WasmCompile.cpp | 17 ++++++++++++++--- js/src/wasm/WasmCompile.h | 4 +++- js/src/wasm/WasmGenerator.cpp | 1 + js/src/wasm/WasmJS.cpp | 13 +++++++++++++ js/src/wasm/WasmJS.h | 5 +++++ js/src/wasm/WasmStubs.cpp | 12 +++++++----- js/src/wasm/WasmStubs.h | 2 +- js/src/wasm/WasmValidate.cpp | 8 +++++--- js/src/wasm/WasmValidate.h | 9 ++++++++- 16 files changed, 110 insertions(+), 16 deletions(-) diff --git a/js/public/ContextOptions.h b/js/public/ContextOptions.h index d48470dd4dd4..2769a1110d53 100644 --- a/js/public/ContextOptions.h +++ b/js/public/ContextOptions.h @@ -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; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index f98b522be8dd..188bee4d440b 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -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."), diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 40cdaaf57748..4822b6272809 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -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") || diff --git a/js/src/shell/jsshell.h b/js/src/shell/jsshell.h index 1a7934e6ec7d..d1fcbe628624 100644 --- a/js/src/shell/jsshell.h +++ b/js/src/shell/jsshell.h @@ -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; diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 4748a503ee1f..4cd45e677f97 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -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); diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp index d40149fbb9f9..b04105766527 100644 --- a/js/src/wasm/WasmCode.cpp +++ b/js/src/wasm/WasmCode.cpp @@ -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 numExpectedRanges = 0; for (uint32_t funcExportIndex : funcExportIndices) { @@ -679,7 +681,7 @@ bool LazyStubTier::createMany(const Uint32Vector& funcExportIndices, Maybe callee; callee.emplace(calleePtr, ImmPtr::NoCheckToken()); if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee, - /* asmjs */ false, &codeRanges)) { + /* asmjs */ false, bigIntEnabled, &codeRanges)) { return false; } } diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h index 7949ff15cc7c..366dfb97dc32 100644 --- a/js/src/wasm/WasmCode.h +++ b/js/src/wasm/WasmCode.h @@ -355,6 +355,9 @@ struct Metadata : public ShareableBase, 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() {} diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp index 01a1438d07a3..cbc5096a36a2 100644 --- a/js/src/wasm/WasmCompile.cpp +++ b/js/src/wasm/WasmCompile.cpp @@ -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 diff --git a/js/src/wasm/WasmCompile.h b/js/src/wasm/WasmCompile.h index 10011c60207a..1490e69f1462 100644 --- a/js/src/wasm/WasmCompile.h +++ b/js/src/wasm/WasmCompile.h @@ -58,6 +58,7 @@ struct CompileArgs : ShareableBase { bool forceTiering; bool gcEnabled; bool hugeMemory; + bool bigIntEnabled; // CompileArgs has two constructors: // @@ -80,7 +81,8 @@ struct CompileArgs : ShareableBase { sharedMemoryEnabled(false), forceTiering(false), gcEnabled(false), - hugeMemory(false) {} + hugeMemory(false), + bigIntEnabled(false) {} }; // Return the estimated compiled (machine) code size for the given bytecode size diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index 3059c6b14772..792e5457349b 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -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. diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 41be2ef47004..ac9ff2d3c907 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -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; diff --git a/js/src/wasm/WasmJS.h b/js/src/wasm/WasmJS.h index 758866d7f31c..1168590ac9c5 100644 --- a/js/src/wasm/WasmJS.h +++ b/js/src/wasm/WasmJS.h @@ -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. diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp index 792148ff8e0f..65f727cf3a78 100644 --- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -838,7 +838,7 @@ static void GenerateJitEntryThrow(MacroAssembler& masm, unsigned frameSize) { static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex, const FuncExport& fe, const Maybe& 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& 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; } } diff --git a/js/src/wasm/WasmStubs.h b/js/src/wasm/WasmStubs.h index 3da998a33e9d..678e8ae8cb7b 100644 --- a/js/src/wasm/WasmStubs.h +++ b/js/src/wasm/WasmStubs.h @@ -259,7 +259,7 @@ extern bool GenerateEntryStubs(jit::MacroAssembler& masm, size_t funcExportIndex, const FuncExport& funcExport, const Maybe& callee, bool isAsmJS, - CodeRangeVector* codeRanges); + bool bigIntEnabled, CodeRangeVector* codeRanges); extern void GenerateTrapExitMachineState(jit::MachineState* machine, size_t* numWords); diff --git a/js/src/wasm/WasmValidate.cpp b/js/src/wasm/WasmValidate.cpp index 1b8cebc8547c..a7032fa0b799 100644 --- a/js/src/wasm/WasmValidate.cpp +++ b/js/src/wasm/WasmValidate.cpp @@ -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() diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h index cf82ef954666..81b66669c376 100644 --- a/js/src/wasm/WasmValidate.h +++ b/js/src/wasm/WasmValidate.h @@ -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; }