Bug 1511958 - part 2, runtime flag for Wasm BigInt<->I64 draft
authorAsumu Takikawa <asumu@igalia.com>
Thu, 05 Dec 2019 02:52:18 +0000
changeset 2517406 9927fec5044538633d2546939d2dda0a07d98cf5
parent 2513214 3c08edf74d039af79f9daad8ff5b57ffb64fdab6
child 2517407 c12cd9a18b984531ad2e6c5d0ff5b3f81c71e52d
push id460517
push userreviewbot
push dateThu, 05 Dec 2019 02:52:52 +0000
treeherdertry@1b2d78f9463f [default view] [failures only]
bugs1511958
milestone73.0a1
Bug 1511958 - part 2, runtime flag for Wasm BigInt<->I64 This adds a runtime flag for conversion between BigInts and I64s for Wasm's JS interoperation API. Differential Diff: PHID-DIFF-ewmuhc7jzrssc3srv5i5
js/public/ContextOptions.h
js/src/builtin/TestingFunctions.cpp
js/src/shell/js.cpp
js/src/shell/jsshell.h
js/src/wasm/AsmJS.cpp
js/src/wasm/WasmCode.cpp
js/src/wasm/WasmCode.h
js/src/wasm/WasmCompile.cpp
js/src/wasm/WasmCompile.h
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmJS.cpp
js/src/wasm/WasmJS.h
js/src/wasm/WasmStubs.cpp
js/src/wasm/WasmStubs.h
js/src/wasm/WasmValidate.cpp
js/src/wasm/WasmValidate.h
--- a/js/public/ContextOptions.h
+++ b/js/public/ContextOptions.h
@@ -22,16 +22,19 @@ class JS_PUBLIC_API ContextOptions {
         wasm_(true),
         wasmForTrustedPrinciples_(true),
         wasmVerbose_(false),
         wasmBaseline_(true),
         wasmIon_(true),
         wasmCranelift_(false),
         wasmGc_(false),
         testWasmAwaitTier2_(false),
+#ifdef ENABLE_WASM_BIGINT
+        enableWasmBigInt_(false),
+#endif
         throwOnAsmJSValidationFailure_(false),
         asyncStack_(true),
         throwOnDebuggeeWouldRun_(true),
         dumpStackOnDebuggeeWouldRun_(false),
         werror_(false),
         strictMode_(false),
         extraWarnings_(false),
         fuzzing_(false) {}
@@ -85,16 +88,24 @@ class JS_PUBLIC_API ContextOptions {
   ContextOptions& setWasmCranelift(bool flag);
 
   bool testWasmAwaitTier2() const { return testWasmAwaitTier2_; }
   ContextOptions& setTestWasmAwaitTier2(bool flag) {
     testWasmAwaitTier2_ = flag;
     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);
 
   bool throwOnAsmJSValidationFailure() const {
     return throwOnAsmJSValidationFailure_;
   }
   ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) {
@@ -173,16 +184,19 @@ class JS_PUBLIC_API ContextOptions {
   bool wasm_ : 1;
   bool wasmForTrustedPrinciples_ : 1;
   bool wasmVerbose_ : 1;
   bool wasmBaseline_ : 1;
   bool wasmIon_ : 1;
   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;
   bool dumpStackOnDebuggeeWouldRun_ : 1;
   bool werror_ : 1;
   bool strictMode_ : 1;
   bool extraWarnings_ : 1;
   bool fuzzing_ : 1;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -790,16 +790,22 @@ static bool WasmGcEnabled(JSContext* cx,
 }
 
 static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setBoolean(wasm::HasMultiValueSupport(cx));
   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() &&
                          wasm::BaselineCanCompile());
   return true;
 }
 
 static bool WasmCompileMode(JSContext* cx, unsigned argc, Value* vp) {
@@ -6636,16 +6642,20 @@ gc::ZealModeHelpText),
     JS_FN_HELP("wasmGcEnabled", WasmGcEnabled, 1, 0,
 "wasmGcEnabled()",
 "  Returns a boolean indicating whether the WebAssembly GC types proposal is enabled."),
 
     JS_FN_HELP("wasmMultiValueEnabled", WasmMultiValueEnabled, 1, 0,
 "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."),
 
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -481,16 +481,19 @@ bool shell::enableSharedMemory = SHARED_
 bool shell::enableWasmBaseline = false;
 bool shell::enableWasmIon = false;
 bool shell::enableWasmCranelift = false;
 #ifdef ENABLE_WASM_GC
 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;
 bool shell::enableBYOBStreamReaders = false;
 bool shell::enableWritableStreams = false;
 bool shell::enableFields = false;
 bool shell::enableAwaitFix = false;
 bool shell::enableWeakRefs = false;
@@ -10223,16 +10226,19 @@ static bool SetContextOptions(JSContext*
 #endif
   enableWasmVerbose = op.getBoolOption("wasm-verbose");
   enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
   enableAsyncStacks = !op.getBoolOption("no-async-stacks");
   enableStreams = !op.getBoolOption("no-streams");
   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");
 
   JS::ContextOptionsRef(cx)
       .setAsmJS(enableAsmJS)
       .setWasm(enableWasm)
       .setWasmForTrustedPrinciples(enableWasm)
@@ -10241,16 +10247,19 @@ static bool SetContextOptions(JSContext*
 #ifdef ENABLE_WASM_CRANELIFT
       .setWasmCranelift(enableWasmCranelift)
 #endif
 #ifdef ENABLE_WASM_GC
       .setWasmGc(enableWasmGc)
 #endif
       .setWasmVerbose(enableWasmVerbose)
       .setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
+#ifdef ENABLE_WASM_BIGINT
+      .setWasmBigIntEnabled(enableWasmBigInt)
+#endif
       .setAsyncStack(enableAsyncStacks);
 
   if (const char* str = op.getStringOption("cache-ir-stubs")) {
     if (strcmp(str, "on") == 0) {
       jit::JitOptions.disableCacheIR = false;
     } else if (strcmp(str, "off") == 0) {
       jit::JitOptions.disableCacheIR = true;
     } else {
@@ -10566,16 +10575,19 @@ static void SetWorkerContextOptions(JSCo
       .setWasmBaseline(enableWasmBaseline)
       .setWasmIon(enableWasmIon)
 #ifdef ENABLE_WASM_CRANELIFT
       .setWasmCranelift(enableWasmCranelift)
 #endif
 #ifdef ENABLE_WASM_GC
       .setWasmGc(enableWasmGc)
 #endif
+#ifdef ENABLE_WASM_BIGINT
+      .setWasmBigIntEnabled(enableWasmBigInt)
+#endif
       .setWasmVerbose(enableWasmVerbose)
       .setTestWasmAwaitTier2(enableTestWasmAwaitTier2);
 
   cx->runtime()->setOffthreadIonCompilationEnabled(offthreadCompilation);
   cx->runtime()->profilingScripts =
       enableCodeCoverage || enableDisassemblyDumps;
 
 #ifdef JS_GC_ZEAL
@@ -10973,16 +10985,22 @@ int main(int argc, char** argv, char** e
       !op.addStringOption(
           '\0', "wasm-compiler", "[option]",
           "Choose to enable a subset of the wasm compilers (valid options are "
           "none/baseline/ion/cranelift/baseline+ion/baseline+cranelift)") ||
       !op.addBoolOption('\0', "wasm-verbose",
                         "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") ||
 #ifdef ENABLE_WASM_GC
       !op.addBoolOption('\0', "wasm-gc",
                         "Enable experimental wasm GC features") ||
 #else
       !op.addBoolOption('\0', "wasm-gc", "No-op") ||
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -107,16 +107,19 @@ extern bool enableSharedMemory;
 extern bool enableWasmBaseline;
 extern bool enableWasmIon;
 extern bool enableWasmCranelift;
 #ifdef ENABLE_WASM_GC
 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;
 extern bool enableBYOBStreamReaders;
 extern bool enableWritableStreams;
 extern bool enableFields;
 extern bool enableAwaitFix;
 extern bool enableWeakRefs;
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -1347,17 +1347,18 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED Modu
         funcDefs_(cx),
         tables_(cx),
         globalMap_(cx),
         sigSet_(cx),
         funcImportMap_(cx),
         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);
   }
 
  protected:
   MOZ_MUST_USE bool addStandardLibraryMathInfo() {
     static constexpr struct {
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -663,28 +663,30 @@ bool LazyStubTier::createMany(const Uint
   TempAllocator alloc(&lifo);
   JitContext jitContext(&alloc);
   WasmMacroAssembler masm(alloc);
 
   const MetadataTier& metadata = codeTier.metadata();
   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) {
     const FuncExport& fe = funcExports[funcExportIndex];
     numExpectedRanges +=
         fe.funcType().temporarilyUnsupportedReftypeForEntry() ? 1 : 2;
     void* calleePtr =
         moduleSegmentBase + metadata.codeRange(fe).funcNormalEntry();
     Maybe<ImmPtr> callee;
     callee.emplace(calleePtr, ImmPtr::NoCheckToken());
     if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee,
-                            /* asmjs */ false, &codeRanges)) {
+                            /* asmjs */ false, bigIntEnabled, &codeRanges)) {
       return false;
     }
   }
   MOZ_ASSERT(codeRanges.length() == numExpectedRanges,
              "incorrect number of entries per function");
 
   masm.finish();
 
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -350,16 +350,19 @@ struct Metadata : public ShareableBase<M
   NameVector funcNames;
 
   // Debug-enabled code is not serialized.
   bool debugEnabled;
   FuncArgTypesVector debugFuncArgTypes;
   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() {}
 
   MetadataCacheablePod& pod() { return *this; }
   const MetadataCacheablePod& pod() const { return *this; }
 
   bool usesMemory() const { return memoryUsage != MemoryUsage::None; }
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -87,16 +87,22 @@ SharedCompileArgs CompileArgs::build(JSC
 #endif
 
 #ifdef ENABLE_WASM_GC
   bool gc = cx->options().wasmGc();
 #else
   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
   // is open.
   bool debug = cx->realm()->debuggerObservesAsmJS();
 
   bool sharedMemory =
       cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
@@ -140,16 +146,17 @@ SharedCompileArgs CompileArgs::build(JSC
   target->baselineEnabled = baseline;
   target->ionEnabled = ion;
   target->craneliftEnabled = cranelift;
   target->debugEnabled = debug;
   target->sharedMemoryEnabled = sharedMemory;
   target->forceTiering = forceTiering;
   target->gcEnabled = gc;
   target->hugeMemory = wasm::IsHugeMemoryEnabled();
+  target->bigIntEnabled = bigInt;
 
   return target;
 }
 
 // Classify the current system as one of a set of recognizable classes.  This
 // really needs to get our tier-1 systems right.
 //
 // TODO: We don't yet have a good measure of how fast a system is.  We
@@ -436,26 +443,27 @@ static bool TieringBeneficial(uint32_t c
 CompilerEnvironment::CompilerEnvironment(const CompileArgs& args)
     : state_(InitialWithArgs), args_(&args) {}
 
 CompilerEnvironment::CompilerEnvironment(CompileMode mode, Tier tier,
                                          OptimizedBackend optimizedBackend,
                                          DebugEnabled debugEnabled,
                                          bool refTypesConfigured,
                                          bool gcTypesConfigured,
-                                         bool hugeMemory)
+                                         bool hugeMemory, bool bigIntConfigured)
     : state_(InitialWithModeTierDebug),
       mode_(mode),
       tier_(tier),
       optimizedBackend_(optimizedBackend),
       debug_(debugEnabled),
       refTypes_(refTypesConfigured),
       gcTypes_(gcTypesConfigured),
       multiValues_(true),
-      hugeMemory_(hugeMemory) {}
+      hugeMemory_(hugeMemory),
+      bigInt_(bigIntConfigured) {}
 
 void CompilerEnvironment::computeParameters(bool gcFeatureOptIn) {
   MOZ_ASSERT(state_ == InitialWithModeTierDebug);
 
   if (gcTypes_) {
     gcTypes_ = gcFeatureOptIn;
   }
   state_ = Computed;
@@ -471,16 +479,17 @@ void CompilerEnvironment::computeParamet
 
   bool gcEnabled = args_->gcEnabled && gcFeatureOptIn;
   bool baselineEnabled = args_->baselineEnabled;
   bool ionEnabled = args_->ionEnabled;
   bool debugEnabled = args_->debugEnabled;
   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);
   MOZ_ASSERT_IF(forceTiering, baselineEnabled && hasSecondTier);
 
   // HasCompilerSupport() should prevent failure here
   MOZ_RELEASE_ASSERT(baselineEnabled || ionEnabled || craneliftEnabled);
 
@@ -503,16 +512,17 @@ void CompilerEnvironment::computeParamet
   optimizedBackend_ =
       craneliftEnabled ? OptimizedBackend::Cranelift : OptimizedBackend::Ion;
 
   debug_ = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
   gcTypes_ = gcEnabled;
   refTypes_ = !craneliftEnabled;
   multiValues_ = !craneliftEnabled;
   hugeMemory_ = hugeMemory;
+  bigInt_ = bigIntEnabled && !craneliftEnabled;
   state_ = Computed;
 }
 
 template <class DecoderT>
 static bool DecodeFunctionBody(DecoderT& d, ModuleGenerator& mg,
                                uint32_t funcIndex) {
   uint32_t bodySize;
   if (!d.readVarU32(&bodySize)) {
@@ -603,24 +613,25 @@ SharedModule wasm::CompileBuffer(const C
 
 void wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode,
                         const Module& module, Atomic<bool>* cancelled) {
   UniqueChars error;
   Decoder d(bytecode, 0, &error);
 
   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;
 
   CompilerEnvironment compilerEnv(CompileMode::Tier2, Tier::Optimized,
                                   optimizedBackend, DebugEnabled::False,
                                   refTypesConfigured, gcTypesConfigured,
-                                  args.hugeMemory);
+                                  args.hugeMemory, bigIntConfigured);
 
   ModuleEnvironment env(&compilerEnv, args.sharedMemoryEnabled
                                           ? Shareable::True
                                           : Shareable::False);
   if (!DecodeModuleEnvironment(d, &env)) {
     return;
   }
 
--- a/js/src/wasm/WasmCompile.h
+++ b/js/src/wasm/WasmCompile.h
@@ -53,16 +53,17 @@ struct CompileArgs : ShareableBase<Compi
   bool baselineEnabled;
   bool ionEnabled;
   bool craneliftEnabled;
   bool debugEnabled;
   bool sharedMemoryEnabled;
   bool forceTiering;
   bool gcEnabled;
   bool hugeMemory;
+  bool bigIntEnabled;
 
   // CompileArgs has two constructors:
   //
   // - one through a factory function `build`, which checks that flags are
   // consistent with each other.
   // - one that gives complete access to underlying fields.
   //
   // You should use the first one in general, unless you have a very good
@@ -75,17 +76,18 @@ struct CompileArgs : ShareableBase<Compi
       : scriptedCaller(std::move(scriptedCaller)),
         baselineEnabled(false),
         ionEnabled(false),
         craneliftEnabled(false),
         debugEnabled(false),
         sharedMemoryEnabled(false),
         forceTiering(false),
         gcEnabled(false),
-        hugeMemory(false) {}
+        hugeMemory(false),
+        bigIntEnabled(false) {}
 };
 
 // Return the estimated compiled (machine) code size for the given bytecode size
 // compiled at the given tier.
 
 double EstimateCompiledCodeSize(Tier tier, size_t bytecodeSize);
 
 // Compile the given WebAssembly bytecode with the given arguments into a
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -1081,16 +1081,17 @@ SharedMetadata ModuleGenerator::finishMe
   metadata_->maxMemoryLength = env_->maxMemoryLength;
   metadata_->startFuncIndex = env_->startFuncIndex;
   metadata_->tables = std::move(env_->tables);
   metadata_->globals = std::move(env_->globals);
   metadata_->nameCustomSectionIndex = env_->nameCustomSectionIndex;
   metadata_->moduleName = env_->moduleName;
   metadata_->funcNames = std::move(env_->funcNames);
   metadata_->omitsBoundsChecks = env_->hugeMemoryEnabled();
+  metadata_->bigIntEnabled = env_->bigIntEnabled();
 
   // Copy over additional debug information.
 
   if (env_->debugEnabled()) {
     metadata_->debugEnabled = true;
 
     const size_t numFuncTypes = env_->funcTypes.length();
     if (!metadata_->debugFuncArgTypes.resize(numFuncTypes)) {
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -98,16 +98,29 @@ bool wasm::HasMultiValueSupport(JSContex
 #endif
 #ifdef ENABLE_WASM_MULTI_VALUE
   return true;
 #else
   return false;
 #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;
 #endif
 
   if (gc::SystemPageSize() > wasm::PageSize) {
     return false;
   }
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -68,16 +68,21 @@ bool HasReftypesSupport(JSContext* cx);
 
 bool HasGcSupport(JSContext* cx);
 
 // Returns true if WebAssembly as configured by compile-time flags and run-time
 // options can support multi-value block and function returns (evolving).
 
 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.
 
 MOZ_MUST_USE bool Eval(JSContext* cx, Handle<TypedArrayObject*> code,
                        HandleObject importObj,
                        MutableHandleWasmInstanceObject instanceObj);
 
 // Extracts the various imports from the given import object into the given
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -833,17 +833,17 @@ static void GenerateJitEntryThrow(MacroA
 // Generate a stub that enters wasm from a jit code caller via the jit ABI.
 //
 // ARM64 note: This does not save the PseudoStackPointer so we must be sure to
 // recompute it on every return path, be it normal return or exception return.
 // The JIT code we return to assumes it is correct.
 
 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();
 
   GenerateJitEntryPrologue(masm, offsets);
 
   // The jit caller has set up the following stack layout (sp grows to the
   // left):
@@ -865,17 +865,17 @@ static bool GenerateJitEntry(MacroAssemb
                                              masm.framePushed(), bytesNeeded);
 
   // Reserve stack space for wasm ABI arguments, set up like this:
   // <-- ABI args | padding
   masm.reserveStack(frameSize);
 
   GenerateJitEntryLoadTls(masm, frameSize);
 
-  if (fe.funcType().hasI64ArgOrRet()) {
+  if (fe.funcType().hasI64ArgOrRet() && !bigIntEnabled) {
     CallSymbolicAddress(masm, !fe.hasEagerStubs(),
                         SymbolicAddress::ReportInt64JSCall);
     GenerateJitEntryThrow(masm, frameSize);
     return FinishOffsets(masm, offsets);
   }
 
   FloatRegister scratchF = ABINonArgDoubleReg;
   Register scratchG = ScratchIonEntry;
@@ -2456,34 +2456,36 @@ static bool GenerateDebugTrapStub(MacroA
 
   GenerateExitEpilogue(masm, 0, ExitReason::Fixed::DebugTrap, offsets);
 
   return FinishOffsets(masm, offsets);
 }
 
 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());
 
   Offsets offsets;
   if (!GenerateInterpEntry(masm, fe, callee, &offsets)) {
     return false;
   }
   if (!codeRanges->emplaceBack(CodeRange::InterpEntry, fe.funcIndex(),
                                offsets)) {
     return false;
   }
 
   if (isAsmJS || fe.funcType().temporarilyUnsupportedReftypeForEntry()) {
     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)) {
     return false;
   }
 
   return true;
 }
@@ -2534,17 +2536,17 @@ bool wasm::GenerateStubs(const ModuleEnv
 
   Maybe<ImmPtr> noAbsolute;
   for (size_t i = 0; i < exports.length(); i++) {
     const FuncExport& fe = exports[i];
     if (!fe.hasEagerStubs()) {
       continue;
     }
     if (!GenerateEntryStubs(masm, i, fe, noAbsolute, env.isAsmJS(),
-                            &code->codeRanges)) {
+                            env.bigIntEnabled(), &code->codeRanges)) {
       return false;
     }
   }
 
   JitSpew(JitSpew_Codegen, "# Emitting wasm exit stubs");
 
   Offsets offsets;
 
--- a/js/src/wasm/WasmStubs.h
+++ b/js/src/wasm/WasmStubs.h
@@ -254,17 +254,17 @@ extern bool GenerateImportFunctions(cons
 extern bool GenerateStubs(const ModuleEnvironment& env,
                           const FuncImportVector& imports,
                           const FuncExportVector& exports, CompiledCode* code);
 
 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);
 
 // A value that is written into the trap exit frame, which is useful for
 // cross-checking during garbage collection.
 static constexpr uintptr_t TrapExitDummyValue = 1337;
 
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -2961,20 +2961,22 @@ bool wasm::DecodeModuleTail(Decoder& d, 
 
 bool wasm::Validate(JSContext* cx, const ShareableBytes& bytecode,
                     UniqueChars* error) {
   Decoder d(bytecode.bytes, 0, error);
 
   bool gcTypesConfigured = HasGcSupport(cx);
   bool refTypesConfigured = HasReftypesSupport(cx);
   bool hugeMemory = false;
-
-  CompilerEnvironment compilerEnv(
-      CompileMode::Once, Tier::Optimized, OptimizedBackend::Ion,
-      DebugEnabled::False, refTypesConfigured, gcTypesConfigured, hugeMemory);
+  bool bigIntConfigured = HasI64BigIntSupport(cx);
+
+  CompilerEnvironment compilerEnv(CompileMode::Once, Tier::Optimized,
+                                  OptimizedBackend::Ion, DebugEnabled::False,
+                                  refTypesConfigured, gcTypesConfigured,
+                                  hugeMemory, bigIntConfigured);
   ModuleEnvironment env(
       &compilerEnv,
       cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
           ? Shareable::True
           : Shareable::False);
   if (!DecodeModuleEnvironment(d, &env)) {
     return false;
   }
--- a/js/src/wasm/WasmValidate.h
+++ b/js/src/wasm/WasmValidate.h
@@ -68,31 +68,33 @@ struct CompilerEnvironment {
       CompileMode mode_;
       Tier tier_;
       OptimizedBackend optimizedBackend_;
       DebugEnabled debug_;
       bool refTypes_;
       bool gcTypes_;
       bool multiValues_;
       bool hugeMemory_;
+      bool bigInt_;
     };
   };
 
  public:
   // Retain a reference to the CompileArgs. A subsequent computeParameters()
   // will compute all parameters from the CompileArgs and additional values.
   explicit CompilerEnvironment(const CompileArgs& args);
 
   // Save the provided values for mode, tier, and debug, and the initial value
   // for gcTypes/refTypes. A subsequent computeParameters() will compute the
   // final value of gcTypes/refTypes.
   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);
 
   // Compute any remaining compilation parameters.  Only use this method if
   // the CompilerEnvironment was created with values for mode, tier, and
   // debug.
   void computeParameters(bool gcFeatureOptIn);
@@ -125,16 +127,20 @@ struct CompilerEnvironment {
   bool multiValues() const {
     MOZ_ASSERT(isComputed());
     return multiValues_;
   }
   bool hugeMemory() const {
     MOZ_ASSERT(isComputed());
     return hugeMemory_;
   }
+  bool bigInt() const {
+    MOZ_ASSERT(isComputed());
+    return bigInt_;
+  }
 };
 
 // ModuleEnvironment contains all the state necessary to process or render
 // functions, and all of the state necessary to validate all aspects of the
 // functions.
 //
 // A ModuleEnvironment is created by decoding all the sections before the wasm
 // code section and then used immutably during. When compiling a module using a
@@ -210,16 +216,17 @@ struct ModuleEnvironment {
   size_t numFuncs() const { return funcTypes.length(); }
   size_t numFuncImports() const { return funcImportGlobalDataOffsets.length(); }
   size_t numFuncDefs() const {
     return funcTypes.length() - funcImportGlobalDataOffsets.length();
   }
   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; }
   bool debugEnabled() const {
     return compilerEnv->debug() == DebugEnabled::True;
   }
   bool hugeMemoryEnabled() const {
     return !isAsmJS() && compilerEnv->hugeMemory();