tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 1ab1eb6ce51b15cc04140d297bfb664985a28683
parent f8b8182ee6960e6ebc5d883ca30cc27a56a12fba
Author: Ryan Hunt <rhunt@eqrion.net>
Date:   Thu, 18 Dec 2025 16:45:28 +0000

Bug 2002625 - wasm: Simplify codegen after merging data and suspender. r=yury

Now that they are actually the same thing, simplify their codegen.

This uncovered some latent issues:
  1. SuspenderReg could sometimes be the ReturnReg, when we start using
     SuspenderReg more often in the JIT functions this lead to a segfault.
  2. InstanceReg is not pinned inside of Ion and must be manually provided.

InstanceReg is now manually provided to all the MIR functions.
ContinueOnSuspendable's register allocation is reworked to avoid the
segfault hazard. The other's will be improved in another bug, but don't
seem to have the hazard right now.

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

Diffstat:
Mjs/src/jit/CodeGenerator.cpp | 131++++++++++++++++++++++++++++---------------------------------------------------
Mjs/src/jit/Lowering.cpp | 9++++++---
Mjs/src/jit/MIROps.yaml | 14+++++++++-----
Mjs/src/wasm/WasmIonCompile.cpp | 9++++++---
4 files changed, 68 insertions(+), 95 deletions(-)

diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp @@ -10569,7 +10569,6 @@ void CodeGenerator::visitWasmStackSwitchToSuspendable( const Register SuspenderReg = lir->suspender()->toGeneralReg()->reg(); const Register FnReg = lir->fn()->toGeneralReg()->reg(); const Register DataReg = lir->data()->toGeneralReg()->reg(); - const Register SuspenderDataReg = ABINonArgReg3; # ifdef JS_CODEGEN_ARM64 vixl::UseScratchRegisterScope temps(&masm); @@ -10610,18 +10609,16 @@ void CodeGenerator::visitWasmStackSwitchToSuspendable( masm.framePushed() - sizeof(wasm::Frame), WasmStackAlignment); masm.reserveStack(reserve); - masm.movePtr(SuspenderReg, SuspenderDataReg); - // Switch stacks to suspendable, keep original FP to maintain // frames chain between main and suspendable stack segments. masm.storeStackPtrToPrivateValue( - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainSP())); + Address(SuspenderReg, wasm::SuspenderObject::offsetOfMainSP())); masm.storePrivateValue( FramePointer, - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainFP())); + Address(SuspenderReg, wasm::SuspenderObject::offsetOfMainFP())); - masm.loadStackPtrFromPrivateValue(Address( - SuspenderDataReg, wasm::SuspenderObject::offsetOfSuspendableSP())); + masm.loadStackPtrFromPrivateValue( + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableSP())); masm.assertStackAlignment(WasmStackAlignment); @@ -10654,7 +10651,7 @@ void CodeGenerator::visitWasmStackSwitchToSuspendable( Address(masm.getStackPointer(), -int32_t(sizeof(wasm::Frame))), ScratchReg2); masm.storePrivateValue( - ScratchReg2, Address(SuspenderDataReg, + ScratchReg2, Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableExitFP())); masm.mov(&returnCallsite, ReturnAddressReg); @@ -10717,7 +10714,6 @@ void CodeGenerator::visitWasmStackSwitchToMain(LWasmStackSwitchToMain* lir) { const Register SuspenderReg = lir->suspender()->toGeneralReg()->reg(); const Register FnReg = lir->fn()->toGeneralReg()->reg(); const Register DataReg = lir->data()->toGeneralReg()->reg(); - const Register SuspenderDataReg = ABINonArgReg3; # ifdef JS_CODEGEN_ARM64 vixl::UseScratchRegisterScope temps(&masm); @@ -10759,40 +10755,27 @@ void CodeGenerator::visitWasmStackSwitchToMain(LWasmStackSwitchToMain* lir) { masm.framePushed() - sizeof(wasm::Frame), WasmStackAlignment); masm.reserveStack(reserve); - masm.movePtr(SuspenderReg, SuspenderDataReg); + masm.movePtr(SuspenderReg, SuspenderReg); // Switch stacks to main. - masm.storeStackPtrToPrivateValue(Address( - SuspenderDataReg, wasm::SuspenderObject::offsetOfSuspendableSP())); + masm.storeStackPtrToPrivateValue( + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableSP())); masm.storePrivateValue( - FramePointer, Address(SuspenderDataReg, - wasm::SuspenderObject::offsetOfSuspendableFP())); + FramePointer, + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableFP())); masm.loadStackPtrFromPrivateValue( - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainSP())); + Address(SuspenderReg, wasm::SuspenderObject::offsetOfMainSP())); masm.loadPrivate( - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainFP()), + Address(SuspenderReg, wasm::SuspenderObject::offsetOfMainFP()), FramePointer); // Set main_ra field to returnCallsite. -# ifdef JS_CODEGEN_X86 - // SuspenderDataReg is also ScratchReg1, use DataReg as a scratch register. - MOZ_ASSERT(ScratchReg1 == SuspenderDataReg); - masm.push(DataReg); - masm.mov(&returnCallsite, DataReg); - masm.storePrivateValue( - DataReg, - Address(SuspenderDataReg, - wasm::SuspenderObject::offsetOfSuspendedReturnAddress())); - masm.pop(DataReg); -# else - MOZ_ASSERT(ScratchReg1 != SuspenderDataReg); masm.mov(&returnCallsite, ScratchReg1); masm.storePrivateValue( ScratchReg1, - Address(SuspenderDataReg, + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendedReturnAddress())); -# endif masm.assertStackAlignment(WasmStackAlignment); @@ -10826,12 +10809,12 @@ void CodeGenerator::visitWasmStackSwitchToMain(LWasmStackSwitchToMain* lir) { ScratchReg2); masm.storePrivateValue( ScratchReg2, - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainExitFP())); + Address(SuspenderReg, wasm::SuspenderObject::offsetOfMainExitFP())); // Load InstanceReg from suspendable stack exit frame. - masm.loadPrivate(Address(SuspenderDataReg, - wasm::SuspenderObject::offsetOfSuspendableExitFP()), - ScratchReg2); + masm.loadPrivate( + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableExitFP()), + ScratchReg2); masm.loadPtr( Address(ScratchReg2, wasm::FrameWithInstances::callerInstanceOffset()), ScratchReg2); @@ -10839,9 +10822,9 @@ void CodeGenerator::visitWasmStackSwitchToMain(LWasmStackSwitchToMain* lir) { WasmCallerInstanceOffsetBeforeCall)); // Load RA from suspendable stack exit frame. - masm.loadPrivate(Address(SuspenderDataReg, - wasm::SuspenderObject::offsetOfSuspendableExitFP()), - ScratchReg1); + masm.loadPrivate( + Address(SuspenderReg, wasm::SuspenderObject::offsetOfSuspendableExitFP()), + ScratchReg1); masm.loadPtr(Address(ScratchReg1, wasm::Frame::returnAddressOffset()), ReturnAddressReg); @@ -10911,29 +10894,13 @@ void CodeGenerator::visitWasmStackSwitchToMain(LWasmStackSwitchToMain* lir) { void CodeGenerator::visitWasmStackContinueOnSuspendable( LWasmStackContinueOnSuspendable* lir) { #ifdef ENABLE_WASM_JSPI - const Register SuspenderReg = lir->suspender()->toGeneralReg()->reg(); - const Register ResultReg = lir->result()->toGeneralReg()->reg(); - const Register SuspenderDataReg = ABINonArgReg3; - -# ifdef JS_CODEGEN_ARM64 - vixl::UseScratchRegisterScope temps(&masm); - const Register ScratchReg1 = temps.AcquireX().asUnsized(); -# elif defined(JS_CODEGEN_X86) - const Register ScratchReg1 = ABINonArgReturnReg1; -# elif defined(JS_CODEGEN_X64) - const Register ScratchReg1 = ScratchReg; -# elif defined(JS_CODEGEN_ARM) - const Register ScratchReg1 = ABINonArgReturnVolatileReg; -# elif defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64) || \ - defined(JS_CODEGEN_MIPS64) - UseScratchRegisterScope temps(masm); - const Register ScratchReg1 = temps.Acquire(); -# else -# error "NYI: scratch register" -# endif - const Register ScratchReg2 = ABINonArgReg1; + MOZ_ASSERT(ToRegister(lir->instance()) == InstanceReg); + Register suspender = ToRegister(lir->suspender()); + Register result = ToRegister(lir->result()); + Register temp1 = ToRegister(lir->temp0()); + Register temp2 = ToRegister(lir->temp1()); - masm.Push(SuspenderReg); + masm.Push(suspender); int32_t framePushedAtSuspender = masm.framePushed(); masm.Push(InstanceReg); @@ -10945,35 +10912,32 @@ void CodeGenerator::visitWasmStackContinueOnSuspendable( masm.framePushed() - sizeof(wasm::Frame), WasmStackAlignment); masm.reserveStack(reserve); - masm.movePtr(SuspenderReg, SuspenderDataReg); masm.storeStackPtrToPrivateValue( - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainSP())); + Address(suspender, wasm::SuspenderObject::offsetOfMainSP())); masm.storePrivateValue( FramePointer, - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfMainFP())); + Address(suspender, wasm::SuspenderObject::offsetOfMainFP())); // Adjust exit frame FP. - masm.loadPrivate(Address(SuspenderDataReg, - wasm::SuspenderObject::offsetOfSuspendableExitFP()), - ScratchReg1); - masm.storePtr(FramePointer, - Address(ScratchReg1, wasm::Frame::callerFPOffset())); + masm.loadPrivate( + Address(suspender, wasm::SuspenderObject::offsetOfSuspendableExitFP()), + temp1); + masm.storePtr(FramePointer, Address(temp1, wasm::Frame::callerFPOffset())); // Adjust exit frame RA. - masm.mov(&returnCallsite, ScratchReg2); + masm.mov(&returnCallsite, temp2); - masm.storePtr(ScratchReg2, - Address(ScratchReg1, wasm::Frame::returnAddressOffset())); + masm.storePtr(temp2, Address(temp1, wasm::Frame::returnAddressOffset())); // Adjust exit frame caller instance slot. masm.storePtr( InstanceReg, - Address(ScratchReg1, wasm::FrameWithInstances::callerInstanceOffset())); + Address(temp1, wasm::FrameWithInstances::callerInstanceOffset())); // Switch stacks to suspendable. - masm.loadStackPtrFromPrivateValue(Address( - SuspenderDataReg, wasm::SuspenderObject::offsetOfSuspendableSP())); + masm.loadStackPtrFromPrivateValue( + Address(suspender, wasm::SuspenderObject::offsetOfSuspendableSP())); masm.loadPrivate( - Address(SuspenderDataReg, wasm::SuspenderObject::offsetOfSuspendableFP()), + Address(suspender, wasm::SuspenderObject::offsetOfSuspendableFP()), FramePointer); masm.assertStackAlignment(WasmStackAlignment); @@ -11001,16 +10965,16 @@ void CodeGenerator::visitWasmStackContinueOnSuspendable( masm.assertStackAlignment(WasmStackAlignment); // Transfer results to ReturnReg so it will appear at SwitchToMain return. - masm.mov(ResultReg, ReturnReg); - - const Register ReturnAddressReg = ScratchReg1; + // temp2 is fixed to be the ReturnReg, and so use it here. + MOZ_ASSERT(temp2 == ReturnReg); + masm.mov(result, temp2); // Pretend we just returned from the function. masm.loadPrivate( - Address(SuspenderDataReg, + Address(suspender, wasm::SuspenderObject::offsetOfSuspendedReturnAddress()), - ReturnAddressReg); - masm.jump(ReturnAddressReg); + temp1); + masm.jump(temp1); // About to use valid FramePointer -- restore framePushed. masm.setFramePushed(framePushed); @@ -11036,13 +11000,12 @@ void CodeGenerator::visitWasmStackContinueOnSuspendable( masm.freeStack(reserve); masm.Pop(InstanceReg); - masm.Pop(SuspenderReg); + masm.Pop(suspender); - // Using SuspenderDataReg and ABINonArgReg2 as temps. - masm.switchToWasmInstanceRealm(SuspenderDataReg, ABINonArgReg2); + masm.switchToWasmInstanceRealm(temp1, temp2); callWasmUpdateSuspenderState(wasm::UpdateSuspenderStateAction::Leave, - SuspenderReg, ScratchReg1); + suspender, temp1); #else MOZ_CRASH("NYI"); #endif // ENABLE_WASM_JSPI diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp @@ -7335,6 +7335,7 @@ void LIRGenerator::visitWasmStackSwitchToSuspendable( MWasmStackSwitchToSuspendable* ins) { #ifdef ENABLE_WASM_JSPI auto* lir = new (alloc()) LWasmStackSwitchToSuspendable( + useFixedAtStart(ins->instance(), InstanceReg), useFixedAtStart(ins->suspender(), ABINonArgReg0), useFixedAtStart(ins->fn(), ABINonArgReg1), useFixedAtStart(ins->data(), ABINonArgReg2)); @@ -7349,7 +7350,8 @@ void LIRGenerator::visitWasmStackSwitchToSuspendable( void LIRGenerator::visitWasmStackSwitchToMain(MWasmStackSwitchToMain* ins) { #ifdef ENABLE_WASM_JSPI auto* lir = new (alloc()) - LWasmStackSwitchToMain(useFixedAtStart(ins->suspender(), ABINonArgReg0), + LWasmStackSwitchToMain(useFixedAtStart(ins->instance(), InstanceReg), + useFixedAtStart(ins->suspender(), ABINonArgReg0), useFixedAtStart(ins->fn(), ABINonArgReg1), useFixedAtStart(ins->data(), ABINonArgReg2)); @@ -7364,8 +7366,9 @@ void LIRGenerator::visitWasmStackContinueOnSuspendable( MWasmStackContinueOnSuspendable* ins) { #ifdef ENABLE_WASM_JSPI auto* lir = new (alloc()) LWasmStackContinueOnSuspendable( - useFixedAtStart(ins->suspender(), ABINonArgReg0), - useFixedAtStart(ins->result(), ABINonArgReg2)); + useFixedAtStart(ins->instance(), InstanceReg), + useRegisterAtStart(ins->suspender()), useRegisterAtStart(ins->result()), + tempFixed(ABINonArgReturnReg0), tempFixed(ReturnReg)); add(lir, ins); assignWasmSafepoint(lir); diff --git a/js/src/jit/MIROps.yaml b/js/src/jit/MIROps.yaml @@ -4386,8 +4386,9 @@ - name: WasmStackSwitchToMain operands: - suspender: Object - fn: Object + instance: WasmAnyRef + suspender: WasmAnyRef + fn: WasmAnyRef data: WasmAnyRef result_type: WasmAnyRef type_policy: none @@ -4396,8 +4397,9 @@ - name: WasmStackSwitchToSuspendable operands: - suspender: Object - fn: Object + instance: WasmAnyRef + suspender: WasmAnyRef + fn: WasmAnyRef data: WasmAnyRef type_policy: none possibly_calls: true @@ -4405,11 +4407,13 @@ - name: WasmStackContinueOnSuspendable operands: - suspender: Object + instance: WasmAnyRef + suspender: WasmAnyRef result: WasmAnyRef type_policy: none possibly_calls: true generate_lir: true + lir_temps: 2 - name: WasmBinarySimd128 gen_boilerplate: false diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp @@ -3291,13 +3291,16 @@ class FunctionCompiler { MInstruction* ins; switch (kind) { case StackSwitchKind::SwitchToMain: - ins = MWasmStackSwitchToMain::New(alloc(), suspender, fn, data); + ins = MWasmStackSwitchToMain::New(alloc(), instancePointer_, suspender, + fn, data); break; case StackSwitchKind::SwitchToSuspendable: - ins = MWasmStackSwitchToSuspendable::New(alloc(), suspender, fn, data); + ins = MWasmStackSwitchToSuspendable::New(alloc(), instancePointer_, + suspender, fn, data); break; case StackSwitchKind::ContinueOnSuspendable: - ins = MWasmStackContinueOnSuspendable::New(alloc(), suspender, data); + ins = MWasmStackContinueOnSuspendable::New(alloc(), instancePointer_, + suspender, data); break; } if (!ins) {