Bug 1447578 part 2 - Refactor MacroAssembler, add AutoCheckCannotGC for stack-allocated assemblers. r=jonco,luke
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 21 Mar 2018 16:57:30 +0100
changeset 1460143 3d56f55622c6844c162aa5b65d98745eebf09530
parent 1460142 769fed48d30f053011e89ffa89b4e386cf78bc77
child 1460144 af5c036e68f4fa99b6c6fcd2c7d27de9b2dce200
push id260095
push userecoal95@gmail.com
push dateWed, 21 Mar 2018 17:01:50 +0000
treeherdertry@0c24a9ae2a68 [default view] [failures only]
reviewersjonco, luke
bugs1447578
milestone61.0a1
Bug 1447578 part 2 - Refactor MacroAssembler, add AutoCheckCannotGC for stack-allocated assemblers. r=jonco,luke
js/src/irregexp/NativeRegExpMacroAssembler.h
js/src/jit/BaselineDebugModeOSR.cpp
js/src/jit/CacheIRCompiler.h
js/src/jit/CodeGenerator.cpp
js/src/jit/Ion.cpp
js/src/jit/MacroAssembler.h
js/src/jit/SharedIC.cpp
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/arm64/Trampoline-arm64.cpp
js/src/jit/mips32/Trampoline-mips32.cpp
js/src/jit/mips64/Trampoline-mips64.cpp
js/src/jit/shared/BaselineCompiler-shared.h
js/src/jit/shared/CodeGenerator-shared.h
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86/Trampoline-x86.cpp
js/src/jsapi-tests/testAssemblerBuffer.cpp
js/src/jsapi-tests/testJitMacroAssembler.cpp
js/src/jsapi-tests/testJitMoveEmitterCycles-mips32.cpp
js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
js/src/vm/UnboxedObject.cpp
js/src/wasm/WasmBaselineCompile.cpp
js/src/wasm/WasmBuiltins.cpp
js/src/wasm/WasmCode.cpp
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmGenerator.h
js/src/wasm/WasmIonCompile.cpp
js/src/wasm/WasmStubs.cpp
--- a/js/src/irregexp/NativeRegExpMacroAssembler.h
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.h
@@ -167,17 +167,17 @@ class MOZ_STACK_CLASS NativeRegExpMacroA
     void PopBacktrack(jit::Register target);
 
     // Check whether we are exceeding the stack limit on the backtrack stack.
     void CheckBacktrackStackLimit();
 
     void LoadCurrentCharacterUnchecked(int cp_offset, int characters);
 
   private:
-    jit::MacroAssembler masm;
+    jit::StackMacroAssembler masm;
     RegExpShared::JitCodeTables& tables;
 
     JSContext* cx;
     Mode mode_;
     jit::Label entry_label_;
     jit::Label start_label_;
     jit::Label backtrack_label_;
     jit::Label success_label_;
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -1113,17 +1113,17 @@ EmitBaselineDebugModeOSRHandlerTail(Macr
     }
 
     masm.jump(target);
 }
 
 JitCode*
 JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(BaselineFrameReg);
     regs.take(ReturnReg);
     Register temp = regs.takeAny();
     Register syncedStackStart = regs.takeAny();
 
     // Pop the frame reg.
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -534,17 +534,17 @@ class MOZ_RAII CacheIRCompiler
   protected:
     friend class AutoOutputRegister;
 
     enum class Mode { Baseline, Ion };
 
     JSContext* cx_;
     CacheIRReader reader;
     const CacheIRWriter& writer_;
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 
     CacheRegisterAllocator allocator;
     Vector<FailurePath, 4, SystemAllocPolicy> failurePaths;
 
     // Float registers that are live. Registers not in this set can be
     // clobbered and don't need to be saved before performing a VM call.
     // Doing this for non-float registers is a bit more complicated because
     // the IC register allocator allocates GPRs.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1910,17 +1910,17 @@ JitCompartment::generateRegExpMatcherStu
     if (!templateObject)
         return nullptr;
 
     // The template object should have enough space for the maximum number of
     // pairs this stub can handle.
     MOZ_ASSERT(ObjectElements::VALUES_PER_HEADER + RegExpObject::MaxPairCount ==
                gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()));
 
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp5, inputOutputDataStartOffset,
                                  RegExpShared::Normal, &notFound, &oolEntry))
@@ -2216,17 +2216,17 @@ JitCompartment::generateRegExpSearcherSt
     regs.take(input);
     regs.take(regexp);
     regs.take(lastIndex);
 
     Register temp1 = regs.takeAny();
     Register temp2 = regs.takeAny();
     Register temp3 = regs.takeAny();
 
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp3, inputOutputDataStartOffset,
                                  RegExpShared::Normal, &notFound, &oolEntry))
@@ -2355,17 +2355,17 @@ static const int32_t RegExpTesterResultF
 JitCode*
 JitCompartment::generateRegExpTesterStub(JSContext* cx)
 {
     Register regexp = RegExpTesterRegExpReg;
     Register input = RegExpTesterStringReg;
     Register lastIndex = RegExpTesterLastIndexReg;
     Register result = ReturnReg;
 
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
 #ifdef JS_USE_LINK_REGISTER
     masm.pushReturnAddress();
 #endif
 
     // We are free to clobber all registers, as LRegExpTester is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input);
@@ -8385,17 +8385,17 @@ CodeGenerator::visitSubstr(LSubstr* lir)
     }
 
     masm.bind(done);
 }
 
 JitCode*
 JitCompartment::generateStringConcatStub(JSContext* cx)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     Register lhs = CallTempReg0;
     Register rhs = CallTempReg1;
     Register temp1 = CallTempReg2;
     Register temp2 = CallTempReg3;
     Register temp3 = CallTempReg4;
     Register output = CallTempReg5;
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -246,17 +246,17 @@ JitRuntime::initialize(JSContext* cx, Au
 
     if (!cx->compartment()->ensureJitCompartmentExists(cx))
         return false;
 
     functionWrappers_ = cx->new_<VMWrapperMap>(cx);
     if (!functionWrappers_ || !functionWrappers_->init())
         return false;
 
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 
     Label bailoutTail;
     JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
     generateBailoutTailStub(masm, &bailoutTail);
 
     if (cx->runtime()->jitSupportsFloatingPoint) {
         JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -330,17 +330,18 @@ class MacroAssembler : public MacroAssem
     mozilla::Maybe<AutoRooter> autoRooter_;
     mozilla::Maybe<JitContext> jitContext_;
     mozilla::Maybe<AutoJitContextAlloc> alloc_;
 
   private:
     // Labels for handling exceptions and failures.
     NonAssertingLabel failureLabel_;
 
-  public:
+  protected:
+    // Constructors are protected. Use one of the derived classes!
     MacroAssembler()
       : framePushed_(0),
 #ifdef DEBUG
         inCall_(false),
 #endif
         emitProfilingInstrumentation_(false)
     {
         JitContext* jcx = GetJitContext();
@@ -386,16 +387,17 @@ class MacroAssembler : public MacroAssem
         initWithAllocator();
         // Stubs + builtins + the baseline compiler all require the native SP,
         // not the PSP.
         SetStackPointer64(sp);
         armbuffer_.id = 0;
 #endif
     }
 
+  public:
 #ifdef DEBUG
     bool isRooted() const {
         return autoRooter_.isSome();
     }
 #endif
 
     void constructRoot(JSContext* cx) {
         autoRooter_.emplace(cx, this);
@@ -2692,16 +2694,52 @@ class MacroAssembler : public MacroAssem
     // later.
     JSObject* getSingletonAndDelayBarrier(const TypeSet* types, size_t i);
     ObjectGroup* getGroupAndDelayBarrier(const TypeSet* types, size_t i);
 
     Vector<JSObject*, 0, SystemAllocPolicy> pendingObjectReadBarriers_;
     Vector<ObjectGroup*, 0, SystemAllocPolicy> pendingObjectGroupReadBarriers_;
 };
 
+// StackMacroAssembler checks no GC will happen while it's on the stack.
+class MOZ_RAII StackMacroAssembler : public MacroAssembler
+{
+    JS::AutoCheckCannotGC nogc;
+
+  public:
+    StackMacroAssembler()
+      : MacroAssembler()
+    {}
+    explicit StackMacroAssembler(JSContext* cx)
+      : MacroAssembler(cx)
+    {}
+};
+
+// WasmMacroAssembler does not contain GC pointers, so it doesn't need the no-GC
+// checking StackMacroAssembler has.
+class MOZ_RAII WasmMacroAssembler : public MacroAssembler
+{
+  public:
+    explicit WasmMacroAssembler(TempAllocator& alloc)
+      : MacroAssembler(WasmToken(), alloc)
+    {}
+};
+
+// Heap-allocated MacroAssembler used for Ion off-thread code generation.
+// GC cancels off-thread compilations.
+class IonHeapMacroAssembler : public MacroAssembler
+{
+  public:
+    IonHeapMacroAssembler()
+      : MacroAssembler()
+    {
+        MOZ_ASSERT(CurrentThreadIsIonCompiling());
+    }
+};
+
 //{{{ check_macroassembler_style
 inline uint32_t
 MacroAssembler::framePushed() const
 {
     return framePushed_;
 }
 
 inline void
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -499,17 +499,17 @@ ICStubCompiler::getStubCode()
     // Check for existing cached stubcode.
     uint32_t stubKey = getKey();
     JitCode* stubCode = comp->getStubCode(stubKey);
     if (stubCode)
         return stubCode;
 
     // Compile new stubcode.
     JitContext jctx(cx, nullptr);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 #ifndef JS_USE_LINK_REGISTER
     // The first value contains the return addres,
     // which we pull into ICTailCallReg for tail calls.
     masm.adjustFrame(sizeof(intptr_t));
 #endif
 #ifdef JS_CODEGEN_ARM
     masm.setSecondScratchReg(BaselineSecondScratchReg);
 #endif
@@ -2754,17 +2754,17 @@ ICNewArray_Fallback::Compiler::generateS
 //
 
 // Unlike typical baseline IC stubs, the code for NewObject_WithTemplate is
 // specialized for the template object being allocated.
 static JitCode*
 GenerateNewObjectWithTemplateCode(JSContext* cx, JSObject* templateObject)
 {
     JitContext jctx(cx, nullptr);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 #ifdef JS_CODEGEN_ARM
     masm.setSecondScratchReg(BaselineSecondScratchReg);
 #endif
 
     Label failure;
     Register objReg = R0.scratchReg();
     Register tempReg = R1.scratchReg();
     masm.branchIfPretenuredGroup(templateObject->group(), tempReg, &failure);
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -947,17 +947,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 
     Register scratch1 = r0;
     Register scratch2 = r1;
 
     // Load BaselineFrame pointer in scratch1.
     masm.mov(r11, scratch1);
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -766,17 +766,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 #ifndef JS_USE_LINK_REGISTER
     // The first value contains the return addres,
     // which we pull into ICTailCallReg for tail calls.
     masm.setFramePushed(sizeof(intptr_t));
 #endif
 
     Register scratch1 = r0;
     Register scratch2 = r1;
--- a/js/src/jit/mips32/Trampoline-mips32.cpp
+++ b/js/src/jit/mips32/Trampoline-mips32.cpp
@@ -922,17 +922,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     Register scratch1 = t0;
     Register scratch2 = t1;
 
     // Load BaselineFrame pointer in scratch1.
     masm.movePtr(s5, scratch1);
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
--- a/js/src/jit/mips64/Trampoline-mips64.cpp
+++ b/js/src/jit/mips64/Trampoline-mips64.cpp
@@ -872,17 +872,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     Register scratch1 = t0;
     Register scratch2 = t1;
 
     // Load BaselineFrame pointer in scratch1.
     masm.movePtr(s5, scratch1);
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
--- a/js/src/jit/shared/BaselineCompiler-shared.h
+++ b/js/src/jit/shared/BaselineCompiler-shared.h
@@ -16,17 +16,17 @@ namespace js {
 namespace jit {
 
 class BaselineCompilerShared
 {
   protected:
     JSContext* cx;
     JSScript* script;
     jsbytecode* pc;
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     bool ionCompileable_;
     bool compileDebugInstrumentation_;
 
     TempAllocator& alloc_;
     BytecodeAnalysis analysis_;
     FrameInfo frame;
 
     FallbackICStubSpace stubSpace_;
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -61,17 +61,17 @@ struct NativeToTrackedOptimizations
     const TrackedOptimizations* optimizations;
 };
 
 class CodeGeneratorShared : public LElementVisitor
 {
     js::Vector<OutOfLineCode*, 0, SystemAllocPolicy> outOfLineCode_;
 
     MacroAssembler& ensureMasm(MacroAssembler* masm);
-    mozilla::Maybe<MacroAssembler> maybeMasm_;
+    mozilla::Maybe<IonHeapMacroAssembler> maybeMasm_;
 
   public:
     MacroAssembler& masm;
 
   protected:
     MIRGenerator* gen;
     LIRGraph& graph;
     LBlock* current;
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -827,17 +827,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 #ifndef JS_USE_LINK_REGISTER
     // The first value contains the return addres,
     // which we pull into ICTailCallReg for tail calls.
     masm.setFramePushed(sizeof(intptr_t));
 #endif
 
     Register scratch1 = rax;
     Register scratch2 = rcx;
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -848,17 +848,17 @@ JitRuntime::generatePreBarrier(JSContext
 
 typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
 static const VMFunction HandleDebugTrapInfo =
     FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
 
 JitCode*
 JitRuntime::generateDebugTrapHandler(JSContext* cx)
 {
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 #ifndef JS_USE_LINK_REGISTER
     // The first value contains the return addres,
     // which we pull into ICTailCallReg for tail calls.
     masm.setFramePushed(sizeof(intptr_t));
 #endif
 
     Register scratch1 = eax;
     Register scratch2 = ecx;
--- a/js/src/jsapi-tests/testAssemblerBuffer.cpp
+++ b/js/src/jsapi-tests/testAssemblerBuffer.cpp
@@ -514,17 +514,17 @@ END_TEST(testAssemblerBuffer_AssemblerBu
 BEGIN_TEST(testAssemblerBuffer_ARM64)
 {
     using namespace js::jit;
 
     js::LifoAlloc lifo(4096);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 
     // Branches to an unbound label.
     Label lab1;
     masm.branch(Assembler::Equal, &lab1);
     masm.branch(Assembler::LessThan, &lab1);
     masm.bind(&lab1);
     masm.branch(Assembler::Equal, &lab1);
 
--- a/js/src/jsapi-tests/testJitMacroAssembler.cpp
+++ b/js/src/jsapi-tests/testJitMacroAssembler.cpp
@@ -47,24 +47,25 @@ static bool Execute(JSContext* cx, Macro
 
     Linker linker(masm);
     JitCode* code = linker.newCode(cx, CodeKind::Other);
     if (!code)
         return false;
     if (!ExecutableAllocator::makeExecutable(code->raw(), code->bufferSize()))
         return false;
 
+    JS::AutoSuppressGCAnalysis suppress;
     EnterTest test = code->as<EnterTest>();
     test();
     return true;
 }
 
 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
     FloatRegister input = allFloatRegs.takeAny();
 #ifdef JS_NUNBOX32
@@ -102,17 +103,17 @@ BEGIN_TEST(testJitMacroAssembler_truncat
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_truncateDoubleToInt64)
 
 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
     FloatRegister input = allFloatRegs.takeAny();
     FloatRegister floatTemp = allFloatRegs.takeAny();
@@ -154,17 +155,17 @@ BEGIN_TEST(testJitMacroAssembler_truncat
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
 
 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
     FloatRegister input = allFloatRegs.takeAny();
 #ifdef JS_NUNBOX32
@@ -208,17 +209,17 @@ BEGIN_TEST(testJitMacroAssembler_branchD
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
 
 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
     FloatRegister input = allFloatRegs.takeAny();
 #ifdef JS_NUNBOX32
@@ -265,17 +266,17 @@ BEGIN_TEST(testJitMacroAssembler_branchD
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
 
 BEGIN_TEST(testJitMacroAssembler_lshift64)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
 #if defined(JS_CODEGEN_X86)
     Register shift = ecx;
@@ -334,17 +335,17 @@ BEGIN_TEST(testJitMacroAssembler_lshift6
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_lshift64)
 
 BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
 #if defined(JS_CODEGEN_X86)
     Register shift = ecx;
@@ -402,17 +403,17 @@ BEGIN_TEST(testJitMacroAssembler_rshift6
     masm.freeStack(sizeof(int32_t));
 
     return Execute(cx, masm);
 }
 END_TEST(testJitMacroAssembler_rshift64Arithmetic)
 
 BEGIN_TEST(testJitMacroAssembler_rshift64)
 {
-    MacroAssembler masm(cx);
+    StackMacroAssembler masm(cx);
 
     if (!Prepare(masm))
         return false;
 
     AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
     AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
 #if defined(JS_CODEGEN_X86)
     Register shift = ecx;
--- a/js/src/jsapi-tests/testJitMoveEmitterCycles-mips32.cpp
+++ b/js/src/jsapi-tests/testJitMoveEmitterCycles-mips32.cpp
@@ -85,17 +85,17 @@ BEGIN_TEST(testJitMoveEmitterCycles_simp
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     AutoFlushICache afc("test");
 
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(double0), MoveOperand(double2), MoveOp::DOUBLE));
     sim->setFpuRegisterDouble(double0.id(), 2.0);
     TRY(mr.addMove(MoveOperand(double3), MoveOperand(double1), MoveOp::DOUBLE));
     sim->setFpuRegisterDouble(double3.id(), 1.0);
@@ -126,17 +126,17 @@ END_TEST(testJitMoveEmitterCycles_simple
 BEGIN_TEST(testJitMoveEmitterCycles_autogen)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     AutoFlushICache afc("test");
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     sim->setFpuRegisterDouble(double9.id(), 9.0);
     TRY(mr.addMove(MoveOperand(single24), MoveOperand(single25), MoveOp::FLOAT32));
     sim->setFpuRegisterFloat(single24.id(), 24.0f);
     TRY(mr.addMove(MoveOperand(double3), MoveOperand(double0), MoveOp::DOUBLE));
@@ -213,17 +213,17 @@ END_TEST(testJitMoveEmitterCycles_autoge
 BEGIN_TEST(testJitMoveEmitterCycles_autogen2)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     AutoFlushICache afc("test");
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(double10), MoveOperand(double0), MoveOp::DOUBLE));
     sim->setFpuRegisterDouble(double10.id(), 10.0);
     TRY(mr.addMove(MoveOperand(single15), MoveOperand(single3), MoveOp::FLOAT32));
     sim->setFpuRegisterFloat(single15.id(), 15.0f);
@@ -312,17 +312,17 @@ END_TEST(testJitMoveEmitterCycles_autoge
 BEGIN_TEST(testJitMoveEmitterCycles_autogen3)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     AutoFlushICache afc("test");
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(single0), MoveOperand(single21), MoveOp::FLOAT32));
     sim->setFpuRegisterFloat(single0.id(), 0.0f);
     TRY(mr.addMove(MoveOperand(single2), MoveOperand(single26), MoveOp::FLOAT32));
     sim->setFpuRegisterFloat(single2.id(), 2.0f);
--- a/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
+++ b/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
@@ -68,17 +68,17 @@ linkAndAllocate(JSContext* cx, js::jit::
 BEGIN_TEST(testJitMoveEmitterCycles_simple)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(d0), MoveOperand(d2), MoveOp::DOUBLE));
     sim->set_d_register_from_double(0, 2);
     TRY(mr.addMove(MoveOperand(d3), MoveOperand(d1), MoveOp::DOUBLE));
     sim->set_d_register_from_double(3, 1);
@@ -117,17 +117,17 @@ END_TEST(testJitMoveEmitterCycles_simple
 BEGIN_TEST(testJitMoveEmitterCycles_autogen)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(d9), MoveOperand(d14), MoveOp::DOUBLE));
     sim->set_d_register_from_double(9, 9);
     TRY(mr.addMove(MoveOperand(s24), MoveOperand(s25), MoveOp::FLOAT32));
     sim->set_s_register_from_float(24, 24);
@@ -244,17 +244,17 @@ END_TEST(testJitMoveEmitterCycles_autoge
 BEGIN_TEST(testJitMoveEmitterCycles_autogen2)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(d10), MoveOperand(d0), MoveOp::DOUBLE));
     sim->set_d_register_from_double(10, 10);
     TRY(mr.addMove(MoveOperand(s15), MoveOperand(s3), MoveOp::FLOAT32));
     sim->set_s_register_from_float(15, 15);
@@ -389,17 +389,17 @@ END_TEST(testJitMoveEmitterCycles_autoge
 BEGIN_TEST(testJitMoveEmitterCycles_autogen3)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     TRY(mr.addMove(MoveOperand(s0), MoveOperand(s21), MoveOp::FLOAT32));
     sim->set_s_register_from_float(0, 0);
     TRY(mr.addMove(MoveOperand(s2), MoveOperand(s26), MoveOp::FLOAT32));
     sim->set_s_register_from_float(2, 2);
@@ -532,17 +532,17 @@ END_TEST(testJitMoveEmitterCycles_autoge
 BEGIN_TEST(testJitMoveEmitterCycles_bug1299147_1)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     // S2 -> S0
     // S2 -> S6
     // S3 -> S1
     // S3 -> S7
@@ -584,17 +584,17 @@ END_TEST(testJitMoveEmitterCycles_bug129
 BEGIN_TEST(testJitMoveEmitterCycles_bug1299147)
 {
     using namespace js;
     using namespace js::jit;
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jc(cx, &alloc);
     cx->runtime()->getJitRuntime(cx);
-    MacroAssembler masm;
+    StackMacroAssembler masm;
     MoveEmitter mover(masm);
     MoveResolver mr;
     mr.setAllocator(alloc);
     Simulator* sim = Simulator::Current();
     // S2 -> S5
     // S2 -> S6
     // D0 -> D1
     TRY(mr.addMove(MoveOperand(s2), MoveOperand(s5), MoveOp::FLOAT32));
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -76,17 +76,17 @@ UnboxedLayout::makeConstructorCode(JSCon
     MOZ_ASSERT(!layout.constructorCode());
 
     UnboxedPlainObject* templateObject = UnboxedPlainObject::create(cx, group, TenuredObject);
     if (!templateObject)
         return false;
 
     JitContext jitContext(cx, nullptr);
 
-    MacroAssembler masm;
+    StackMacroAssembler masm;
 
     Register propertiesReg, newKindReg;
 #ifdef JS_CODEGEN_X86
     propertiesReg = eax;
     newKindReg = ecx;
     masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg);
     masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg);
 #else
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -9872,17 +9872,17 @@ js::wasm::BaselineCompileFunctions(const
     MOZ_ASSERT(env.tier == Tier::Baseline);
     MOZ_ASSERT(env.kind == ModuleKind::Wasm);
 
     // The MacroAssembler will sometimes access the jitContext.
 
     TempAllocator alloc(&lifo);
     JitContext jitContext(&alloc);
     MOZ_ASSERT(IsCompilingWasm());
-    MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
+    WasmMacroAssembler masm(alloc);
 
     // Swap in already-allocated empty vectors to avoid malloc/free.
     MOZ_ASSERT(code->empty());
     if (!code->swap(masm))
         return false;
 
     for (const FuncCompileInput& func : inputs) {
         Decoder d(func.begin, func.end, func.lineOrBytecode, error);
--- a/js/src/wasm/WasmBuiltins.cpp
+++ b/js/src/wasm/WasmBuiltins.cpp
@@ -931,17 +931,17 @@ wasm::EnsureBuiltinThunksInitialized()
         return true;
 
     auto thunks = MakeUnique<BuiltinThunks>();
     if (!thunks)
         return false;
 
     LifoAlloc lifo(BUILTIN_THUNK_LIFO_SIZE);
     TempAllocator tempAlloc(&lifo);
-    MacroAssembler masm(MacroAssembler::WasmToken(), tempAlloc);
+    WasmMacroAssembler masm(tempAlloc);
 
     for (auto sym : MakeEnumeratedRange(SymbolicAddress::Limit)) {
         if (!NeedsBuiltinThunk(sym)) {
             thunks->symbolicAddressToCodeRange[sym] = UINT32_MAX;
             continue;
         }
 
         uint32_t codeRangeIndex = thunks->codeRanges.length();
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -673,17 +673,17 @@ bool
 LazyStubTier::createMany(const Uint32Vector& funcExportIndices, const CodeTier& codeTier,
                          size_t* stubSegmentIndex)
 {
     MOZ_ASSERT(funcExportIndices.length());
 
     LifoAlloc lifo(LAZY_STUB_LIFO_DEFAULT_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     JitContext jitContext(&alloc);
-    MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
+    WasmMacroAssembler masm(alloc);
 
     const CodeRangeVector& moduleRanges = codeTier.metadata().codeRanges;
     const FuncExportVector& funcExports = codeTier.metadata().funcExports;
     uint8_t* moduleSegmentBase = codeTier.segment().base();
 
     CodeRangeVector codeRanges;
     for (uint32_t funcExportIndex : funcExportIndices) {
         const FuncExport& fe = funcExports[funcExportIndex];
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -72,17 +72,17 @@ ModuleGenerator::ModuleGenerator(const C
     error_(error),
     cancelled_(cancelled),
     env_(env),
     linkDataTier_(nullptr),
     metadataTier_(nullptr),
     taskState_(mutexid::WasmCompileTaskState),
     lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
     masmAlloc_(&lifo_),
-    masm_(MacroAssembler::WasmToken(), masmAlloc_),
+    masm_(masmAlloc_),
     oldTrapCodeOffsets_(),
     debugTrapCodeOffset_(),
     lastPatchedCallSite_(0),
     startOfUnpatchedCallsites_(0),
     parallel_(false),
     outstanding_(0),
     currentTask_(nullptr),
     batchedBytecode_(0),
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -163,17 +163,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     UniqueMetadataTier              metadataTier_;
     MutableMetadata                 metadata_;
 
     // Data scoped to the ModuleGenerator's lifetime
     ExclusiveCompileTaskState       taskState_;
     LifoAlloc                       lifo_;
     jit::JitContext                 jcx_;
     jit::TempAllocator              masmAlloc_;
-    jit::MacroAssembler             masm_;
+    jit::WasmMacroAssembler         masm_;
     Uint32Vector                    funcToCodeRange_;
     OldTrapOffsetArray              oldTrapCodeOffsets_;
     uint32_t                        debugTrapCodeOffset_;
     OldTrapFarJumpVector            oldTrapFarJumps_;
     CallFarJumpVector               callFarJumps_;
     CallSiteTargetVector            callSiteTargets_;
     uint32_t                        lastPatchedCallSite_;
     uint32_t                        startOfUnpatchedCallsites_;
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -4366,17 +4366,17 @@ wasm::IonCompileFunctions(const ModuleEn
                           const FuncCompileInputVector& inputs, CompiledCode* code,
                           UniqueChars* error)
 {
     MOZ_ASSERT(env.tier == Tier::Ion);
 
     TempAllocator alloc(&lifo);
     JitContext jitContext(&alloc);
     MOZ_ASSERT(IsCompilingWasm());
-    MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
+    WasmMacroAssembler masm(alloc);
 
     // Swap in already-allocated empty vectors to avoid malloc/free.
     MOZ_ASSERT(code->empty());
     if (!code->swap(masm))
         return false;
 
     for (const FuncCompileInput& func : inputs) {
         Decoder d(func.begin, func.end, func.lineOrBytecode, error);
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -1005,17 +1005,17 @@ GenerateImportFunction(jit::MacroAssembl
 static const unsigned STUBS_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
 
 bool
 wasm::GenerateImportFunctions(const ModuleEnvironment& env, const FuncImportVector& imports,
                               CompiledCode* code)
 {
     LifoAlloc lifo(STUBS_LIFO_DEFAULT_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
-    MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
+    WasmMacroAssembler masm(alloc);
 
     for (uint32_t funcIndex = 0; funcIndex < imports.length(); funcIndex++) {
         const FuncImport& fi = imports[funcIndex];
 
         FuncOffsets offsets;
         if (!GenerateImportFunction(masm, fi, env.funcSigs[funcIndex]->id, &offsets))
             return false;
         if (!code->codeRanges.emplaceBack(funcIndex, /* bytecodeOffset = */ 0, offsets))
@@ -1767,17 +1767,17 @@ wasm::GenerateEntryStubs(MacroAssembler&
 }
 
 bool
 wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& imports,
                     const FuncExportVector& exports, CompiledCode* code)
 {
     LifoAlloc lifo(STUBS_LIFO_DEFAULT_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
-    MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
+    WasmMacroAssembler masm(alloc);
 
     // Swap in already-allocated empty vectors to avoid malloc/free.
     if (!code->swap(masm))
         return false;
 
     Label throwLabel;
 
     JitSpew(JitSpew_Codegen, "# Emitting wasm import stubs");