Repository: tetratelabs/wazero
Pull request #391 (2022-03-18 01:15:53)

jit: make compiler implementations build-tag free
This commit makes compiler implementations build tag free.
Notably, now the arm64 and amd64 compilers are compilable 
on any architecture. Anything arch-specific is isolated in files
named with `arch_*` prefixes.

This reduces the pain to make some broad change across
multiple architectures and allow developers to notice errors
on whichever architecture they are working on.

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>


Patch:
diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml
index 0415e442..37dde081 100644
--- a/.github/workflows/commit.yaml
+++ b/.github/workflows/commit.yaml
@@ -70,12 +70,8 @@ jobs:
 
       - run: make test
 
-  test_non_amd64:
-    # Only amd64 is viable with "make test" because other architectures require emulation:
-    # the process of installing depedencies and building the project through an emulator is unacceptably slow.
-    # Instead, we build cross-platform test binaries on our amd64 runner, which limits what is emulated to
-    # only executing the tests. This is why below uses "bash -c 'testbin test.v'" (running test binary) instead of make.
-    name: ${{ matrix.target.arch }}, ubuntu, Go-${{ matrix.go-version }}
+  test_scratch:
+    name: ${{ matrix.arch }}, Linux (scratch), Go-${{ matrix.go-version }}
     runs-on: ubuntu-20.04
     strategy:
       fail-fast: false  # don't fail fast as sometimes failures are arch/OS specific
@@ -83,11 +79,10 @@ jobs:
         go-version:
         - "1.17"  # == ${{ env.GO_VERSION }} because matrix cannot expand env variables
         - "1.18"
-        target:
-        - arch: arm64
-          image: arm64v8/ubuntu
-        - arch: riscv64
-          image: riscv64/ubuntu
+        arch:
+        - "amd64"
+        - "arm64"
+        - "riscv64"
 
     steps:
       - uses: actions/setup-go@v2
@@ -101,20 +96,28 @@ jobs:
           path: |
             ~/.cache/go-build
             ~/go/pkg/mod
-          key: test-${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}-${{ matrix.target.arch }}
+          key: test-${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}-${{ matrix.arch }}
 
       - name: Build test binaries
         run: go list ./... | xargs -Ipkg go test pkg -c
         env:
-          GOARCH: ${{ matrix.target.arch }}
+          GOARCH: ${{ matrix.arch }}
+          CGO_ENABLED: 0
 
       - name: Set up QEMU
+        if: ${{ matrix.arch != 'amd64' }}
         uses: docker/setup-qemu-action@v1
         with:
-          platforms: ${{ matrix.target.arch }}
+          platforms: ${{ matrix.arch }}
+
+      - name: Build scratch container
+        run: |
+          echo 'FROM scratch' >> Dockerfile
+          echo 'CMD ["/test"]' >> Dockerfile
+          docker buildx build -t wazero:test --platform linux/${{ matrix.arch }} .
 
       - name: Run built test binaries
-        run: docker run -w /tmp/wazero -v $(pwd):/tmp/wazero --rm -t ${{ matrix.target.image }} /bin/bash -c 'find . -name "*.test" | xargs -Itestbin bash -c "testbin test.v"'
+        run: find . -name "*.test" | xargs -Itestbin docker run -v $(pwd)/testbin:/test --rm -t wazero:test
 
   bench:
     name: Benchmark
diff --git a/README.md b/README.md
index 7c378540..8e91dbf2 100644
--- a/README.md
+++ b/README.md
@@ -97,10 +97,10 @@ We currently test ubuntu-20.04, macos-11 and windows-2022 as packaged by
 [GitHub Actions](https://github.com/actions/virtual-environments).
 
 * Interpreter
-  * Ubuntu is tested on amd64 (native) as well arm64 and riscv64 via emulation.
+  * Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
   * MacOS and Windows are only tested on amd64.
 * JIT
-  * Ubuntu is tested on amd64 (native) as well arm64 via emulation.
+  * Linux is tested on amd64 (native) as well arm64 via emulation.
   * MacOS and Windows are only tested on amd64.
 
 wazero has no dependencies and doesn't require CGO. This means it can also be
diff --git a/internal/wasm/jit/arch.go b/internal/wasm/jit/arch.go
index c683f0b0..7c337cac 100644
--- a/internal/wasm/jit/arch.go
+++ b/internal/wasm/jit/arch.go
@@ -1,30 +1,47 @@
 package jit
 
 import (
+	"fmt"
+	"runtime"
+
 	wasm "github.com/tetratelabs/wazero/internal/wasm"
-	"github.com/tetratelabs/wazero/internal/wasm/jit/asm"
 	"github.com/tetratelabs/wazero/internal/wazeroir"
 )
 
-// Following variables must be initialized in init() function in architecture-specific arch_*.go file which
-// is guarded by build tag. This file exists as build-tag free in order to provide documentation interface
-// over these per-architecture definitions of the following symbols.
 var (
 	// newArchContext returns a new archContext which is architecture-specific type to be embedded in callEngine.
+	// This must be initialized in init() function in architecture-specific arch_*.go file which is guarded by build tag.
 	newArchContext func() archContext
+)
 
-	// jitcall is used by callEngine.execWasmFunction and the entrypoint to enter the JITed native code.
-	// codeSegment is the pointer to the initial instruction of the compiled native code.
-	// ce is "*callEngine" as uintptr.
-	jitcall func(codeSegment, ce uintptr)
-
-	// newCompiler returns a new compiler interface which can be used to compile the given function instance.
-	// Note: ir param can be nil for host functions.
-	newCompiler func(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (compiler, error)
+// jitcall is used by callEngine.execWasmFunction and the entrypoint to enter the JITed native code.
+// codeSegment is the pointer to the initial instruction of the compiled native code.
+// ce is "*callEngine" as uintptr.
+//
+// Note: this is implemented in per-arch Go assembler file. For example, arch_amd64.s implements this for amd64.
+func jitcall(codeSegment, ce uintptr)
 
-	// unreservedGeneralPurposeIntRegisters contains unreserved general purpose registers of integer type.
-	unreservedGeneralPurposeIntRegisters []asm.Register
+func init() {
+	switch runtime.GOARCH {
+	case "arm64":
+		unreservedGeneralPurposeIntRegisters = arm64UnreservedGeneralPurposeIntRegisters
+		unreservedGeneralPurposeFloatRegisters = arm64UnreservedGeneralPurposeFloatRegisters
+	case "amd64":
+		unreservedGeneralPurposeIntRegisters = amd64UnreservedGeneralPurposeIntRegisters
+		unreservedGeneralPurposeFloatRegisters = amd64UnreservedGeneralPurposeFloatRegisters
+	}
+}
 
-	// unreservedGeneralPurposeFloatRegisters contains unreserved general purpose registers of scalar float type.
-	unreservedGeneralPurposeFloatRegisters []asm.Register
-)
+// newCompiler returns a new compiler interface which can be used to compile the given function instance.
+// Note: ir param can be nil for host functions.
+func newCompiler(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (c compiler, err error) {
+	switch arch := runtime.GOARCH; arch {
+	case "arm64":
+		c, err = newArm64Compiler(f, ir)
+	case "amd64":
+		c, err = newAmd64Compiler(f, ir)
+	default:
+		err = fmt.Errorf("unsupported GOARCH %s", arch)
+	}
+	return
+}
diff --git a/internal/wasm/jit/arch_amd64.go b/internal/wasm/jit/arch_amd64.go
index f5cf7b8f..74546c58 100644
--- a/internal/wasm/jit/arch_amd64.go
+++ b/internal/wasm/jit/arch_amd64.go
@@ -1,54 +1,8 @@
 package jit
 
-import (
-	wasm "github.com/tetratelabs/wazero/internal/wasm"
-	"github.com/tetratelabs/wazero/internal/wasm/jit/asm"
-	"github.com/tetratelabs/wazero/internal/wasm/jit/asm/amd64"
-	"github.com/tetratelabs/wazero/internal/wazeroir"
-)
-
 // init initializes variables for the amd64 architecture
 func init() {
-	jitcall = jitcallImpl
-	newCompiler = newCompilerImpl
 	newArchContext = newArchContextImpl
-	unreservedGeneralPurposeFloatRegisters = []asm.Register{
-		amd64.REG_X0, amd64.REG_X1, amd64.REG_X2, amd64.REG_X3,
-		amd64.REG_X4, amd64.REG_X5, amd64.REG_X6, amd64.REG_X7,
-		amd64.REG_X8, amd64.REG_X9, amd64.REG_X10, amd64.REG_X11,
-		amd64.REG_X12, amd64.REG_X13, amd64.REG_X14, amd64.REG_X15,
-	}
-	// Note that we never invoke "call" instruction,
-	// so we don't need to care about the calling convention.
-	// TODO: Maybe it is safe just save rbp, rsp somewhere
-	// in Go-allocated variables, and reuse these registers
-	// in JITed functions and write them back before returns.
-	unreservedGeneralPurposeIntRegisters = []asm.Register{
-		amd64.REG_AX, amd64.REG_CX, amd64.REG_DX, amd64.REG_BX,
-		amd64.REG_SI, amd64.REG_DI, amd64.REG_R8, amd64.REG_R9,
-		amd64.REG_R10, amd64.REG_R11, amd64.REG_R12,
-	}
-}
-
-// jitcallImpl implements jitcall for amd64 architecture.
-// Note: this function's body is defined in arch_amd64.s
-func jitcallImpl(codeSegment, ce uintptr)
-
-// newCompilerImpl implements newCompiler for amd64 architecture.
-func newCompilerImpl(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (compiler, error) {
-	b, err := amd64.NewAssembler()
-	if err != nil {
-		return nil, err
-	}
-	compiler := &amd64Compiler{
-		f:             f,
-		assembler:     b,
-		locationStack: newValueLocationStack(),
-		currentLabel:  wazeroir.EntrypointLabel,
-		ir:            ir,
-		labels:        map[string]*labelInfo{},
-	}
-	return compiler, nil
 }
 
 // archContext is embedded in callEngine in order to store architecture-specific data.
diff --git a/internal/wasm/jit/arch_amd64.s b/internal/wasm/jit/arch_amd64.s
index 404890d4..8cda8954 100644
--- a/internal/wasm/jit/arch_amd64.s
+++ b/internal/wasm/jit/arch_amd64.s
@@ -1,8 +1,8 @@
 #include "funcdata.h"
 #include "textflag.h"
 
-// jitcallImpl(codeSegment, ce)
-TEXT ·jitcallImpl(SB),NOSPLIT|NOFRAME,$0-16
+// jitcall(codeSegment, ce)
+TEXT ·jitcall(SB),NOSPLIT|NOFRAME,$0-16
         MOVQ codeSegment+0(FP),AX  // Load the address of native code.
         MOVQ ce+8(FP),R13          // Load the address of *callEngine.
         JMP AX                     // Jump to native code.
diff --git a/internal/wasm/jit/arch_arm64.go b/internal/wasm/jit/arch_arm64.go
index 5ecb8ccc..9119d9db 100644
--- a/internal/wasm/jit/arch_arm64.go
+++ b/internal/wasm/jit/arch_arm64.go
@@ -2,57 +2,11 @@ package jit
 
 import (
 	"math"
-
-	wasm "github.com/tetratelabs/wazero/internal/wasm"
-	"github.com/tetratelabs/wazero/internal/wasm/jit/asm"
-	"github.com/tetratelabs/wazero/internal/wasm/jit/asm/arm64"
-	"github.com/tetratelabs/wazero/internal/wazeroir"
 )
 
 // init initializes variables for the arm64 architecture
 func init() {
-	jitcall = jitcallImpl
-	newCompiler = newCompilerImpl
 	newArchContext = newArchContextImpl
-	unreservedGeneralPurposeFloatRegisters = []asm.Register{
-		arm64.REG_F0, arm64.REG_F1, arm64.REG_F2, arm64.REG_F3,
-		arm64.REG_F4, arm64.REG_F5, arm64.REG_F6, arm64.REG_F7, arm64.REG_F8,
-		arm64.REG_F9, arm64.REG_F10, arm64.REG_F11, arm64.REG_F12, arm64.REG_F13,
-		arm64.REG_F14, arm64.REG_F15, arm64.REG_F16, arm64.REG_F17, arm64.REG_F18,
-		arm64.REG_F19, arm64.REG_F20, arm64.REG_F21, arm64.REG_F22, arm64.REG_F23,
-		arm64.REG_F24, arm64.REG_F25, arm64.REG_F26, arm64.REG_F27, arm64.REG_F28,
-		arm64.REG_F29, arm64.REG_F30, arm64.REG_F31,
-	}
-	// Note (see arm64 section in https://go.dev/doc/asm):
-	// * REG_R18 is reserved as a platform register, and we don't use it in JIT.
-	// * REG_R28 is reserved for Goroutine by Go runtime, and we don't use it in JIT.
-	unreservedGeneralPurposeIntRegisters = []asm.Register{
-		arm64.REG_R4, arm64.REG_R5, arm64.REG_R6, arm64.REG_R7, arm64.REG_R8,
-		arm64.REG_R9, arm64.REG_R10, arm64.REG_R11, arm64.REG_R12, arm64.REG_R13,
-		arm64.REG_R14, arm64.REG_R15, arm64.REG_R16, arm64.REG_R17, arm64.REG_R19,
-		arm64.REG_R20, arm64.REG_R21, arm64.REG_R22, arm64.REG_R23, arm64.REG_R24,
-		arm64.REG_R25, arm64.REG_R26, arm64.REG_R27, arm64.REG_R29, arm64.REG_R30,
-	}
-}
-
-// jitcallImpl implements jitcallfor arm64 architecture.
-// Note: this function's body is defined in arch_arm64.s
-func jitcallImpl(codeSegment, ce uintptr)
-
-// newCompilerImpl implements newCompiler for amd64 architecture.
-func newCompilerImpl(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (compiler, error) {
-	a, err := arm64.NewAssembler(reservedRegisterForTemporary)
-	if err != nil {
-		return nil, err
-	}
-	compiler := &arm64Compiler{
-		f:             f,
-		assembler:     a,
-		locationStack: newValueLocationStack(),
-		ir:            ir,
-		labels:        map[string]*labelInfo{},
-	}
-	return compiler, nil
 }
 
 // archContext is embedded in callEngine in order to store architecture-specific data.
@@ -77,15 +31,6 @@ type archContext struct {
 	minimum64BitSignedInt int64
 }
 
-const (
-	// callEngineArchContextJITCallReturnAddressOffset is the offset of archContext.jitCallReturnAddress in callEngine.
-	callEngineArchContextJITCallReturnAddressOffset = 120
-	// callEngineArchContextMinimum32BitSignedIntOffset is the offset of archContext.minimum32BitSignedIntAddress in callEngine.
-	callEngineArchContextMinimum32BitSignedIntOffset = 128
-	// callEngineArchContextMinimum64BitSignedIntOffset is the offset of archContext.minimum64BitSignedIntAddress in callEngine.
-	callEngineArchContextMinimum64BitSignedIntOffset = 136
-)
-
 // newArchContextImpl implements newArchContext for amd64 architecture.
 func newArchContextImpl() archContext {
 	return archContext{
diff --git a/internal/wasm/jit/arch_arm64.s b/internal/wasm/jit/arch_arm64.s
index 5efe398f..74fb73f1 100644
--- a/internal/wasm/jit/arch_arm64.s
+++ b/internal/wasm/jit/arch_arm64.s
@@ -1,8 +1,8 @@
 #include "funcdata.h"
 #include "textflag.h"
 
-// jitcallImpl(codeSegment, ce)
-TEXT ·jitcallImpl(SB),NOSPLIT|NOFRAME,$0-16
+// jitcall(codeSegment, ce)
+TEXT ·jitcall(SB),NOSPLIT|NOFRAME,$0-16
         // Load the address of native code.
         MOVD codeSegment+0(FP),R1
         // Load the address of *callEngine.
diff --git a/internal/wasm/jit/arch_other.s b/internal/wasm/jit/arch_other.s
new file mode 100644
index 00000000..17dd7167
--- /dev/null
+++ b/internal/wasm/jit/arch_other.s
@@ -0,0 +1,3 @@
+//go:build !arm64 && !amd64
+
+TEXT ·jitcall(SB),$0-16
diff --git a/internal/wasm/jit/jit_amd64.go b/internal/wasm/jit/jit_amd64_impl.go
similarity index 95%
rename from internal/wasm/jit/jit_amd64.go
rename to internal/wasm/jit/jit_amd64_impl.go
index 831e76bc..d31e3fb0 100644
--- a/internal/wasm/jit/jit_amd64.go
+++ b/internal/wasm/jit/jit_amd64_impl.go
@@ -71,12 +71,31 @@ func init() {
 }
 
 var (
-	// reservedRegisterForCallEngine: pointer to callEngine (i.e. *callEngine as uintptr)
-	reservedRegisterForCallEngine = amd64.REG_R13
-	// reservedRegisterForStackBasePointerAddress: stack base pointer's address (callEngine.stackBasePointer) in the current function call.
-	reservedRegisterForStackBasePointerAddress = amd64.REG_R14
-	// reservedRegisterForMemory: pointer to the memory slice's data (i.e. &memory.Buffer[0] as uintptr).
-	reservedRegisterForMemory = amd64.REG_R15
+	// amd64ReservedRegisterForCallEngine: pointer to callEngine (i.e. *callEngine as uintptr)
+	amd64ReservedRegisterForCallEngine = amd64.REG_R13
+	// amd64ReservedRegisterForStackBasePointerAddress: stack base pointer's address (callEngine.stackBasePointer) in the current function call.
+	amd64ReservedRegisterForStackBasePointerAddress = amd64.REG_R14
+	// amd64ReservedRegisterForMemory: pointer to the memory slice's data (i.e. &memory.Buffer[0] as uintptr).
+	amd64ReservedRegisterForMemory = amd64.REG_R15
+)
+
+var (
+	amd64UnreservedGeneralPurposeFloatRegisters = []asm.Register{
+		amd64.REG_X0, amd64.REG_X1, amd64.REG_X2, amd64.REG_X3,
+		amd64.REG_X4, amd64.REG_X5, amd64.REG_X6, amd64.REG_X7,
+		amd64.REG_X8, amd64.REG_X9, amd64.REG_X10, amd64.REG_X11,
+		amd64.REG_X12, amd64.REG_X13, amd64.REG_X14, amd64.REG_X15,
+	}
+	// Note that we never invoke "call" instruction,
+	// so we don't need to care about the calling convention.
+	// TODO: Maybe it is safe just save rbp, rsp somewhere
+	// in Go-allocated variables, and reuse these registers
+	// in JITed functions and write them back before returns.
+	amd64UnreservedGeneralPurposeIntRegisters = []asm.Register{
+		amd64.REG_AX, amd64.REG_CX, amd64.REG_DX, amd64.REG_BX,
+		amd64.REG_SI, amd64.REG_DI, amd64.REG_R8, amd64.REG_R9,
+		amd64.REG_R10, amd64.REG_R11, amd64.REG_R12,
+	}
 )
 
 func (c *amd64Compiler) String() string {
@@ -91,7 +110,7 @@ type amd64Compiler struct {
 	// and each item is either placed in register or the actual memory stack.
 	locationStack *valueLocationStack
 	// labels hold per wazeroir label specific information in this function.
-	labels map[string]*labelInfo
+	labels map[string]*amd64LabelInfo
 	// stackPointerCeil is the greatest stack pointer value (from valueLocationStack) seen during compilation.
 	stackPointerCeil uint64
 	// currentLabel holds a currently compiled wazeroir label key. For debugging only.
@@ -101,6 +120,22 @@ type amd64Compiler struct {
 	staticData                           compiledFunctionStaticData
 }
 
+func newAmd64Compiler(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (compiler, error) {
+	b, err := amd64.NewAssembler()
+	if err != nil {
+		return nil, err
+	}
+	c := &amd64Compiler{
+		f:             f,
+		assembler:     b,
+		locationStack: newValueLocationStack(),
+		currentLabel:  wazeroir.EntrypointLabel,
+		ir:            ir,
+		labels:        map[string]*amd64LabelInfo{},
+	}
+	return c, nil
+}
+
 // setLocationStack sets the given valueLocationStack to .locationStack field,
 // while allowing us to track valueLocationStack.stackPointerCeil across multiple stacks.
 // This is called when we branch into different block.
@@ -121,7 +156,7 @@ func (c *amd64Compiler) pushValueLocationOnRegister(reg asm.Register) (ret *valu
 	return
 }
 
-type labelInfo struct {
+type amd64LabelInfo struct {
 	// initialInstruction is the initial instruction for this label so other block can jump into it.
 	initialInstruction asm.Node
 	// initialStack is the initial value location stack from which we start compiling this label.
@@ -130,12 +165,12 @@ type labelInfo struct {
 	labelBeginningCallbacks []func(asm.Node)
 }
 
-func (c *amd64Compiler) label(labelKey string) *labelInfo {
+func (c *amd64Compiler) label(labelKey string) *amd64LabelInfo {
 	ret, ok := c.labels[labelKey]
 	if ok {
 		return ret
 	}
-	c.labels[labelKey] = &labelInfo{}
+	c.labels[labelKey] = &amd64LabelInfo{}
 	return c.labels[labelKey]
 }
 
@@ -297,7 +332,7 @@ func (c *amd64Compiler) compileGlobalGet(o *wazeroir.OperationGlobalGet) error {
 	}
 
 	// First, move the pointer to the global slice into the allocated register.
-	c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset, intReg)
+	c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset, intReg)
 
 	// Then, get the memory location of the target global instance's pointer.
 	c.assembler.CompileConstToRegister(amd64.ADDQ, 8*int64(o.Index), intReg)
@@ -345,7 +380,7 @@ func (c *amd64Compiler) compileGlobalSet(o *wazeroir.OperationGlobalSet) error {
 	}
 
 	// First, move the pointer to the global slice into the allocated register.
-	c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset, intReg)
+	c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset, intReg)
 
 	// Then, get the memory location of the target global instance's pointer.
 	c.assembler.CompileConstToRegister(amd64.ADDQ, 8*int64(o.Index), intReg)
@@ -477,9 +512,9 @@ func (c *amd64Compiler) compileBrIf(o *wazeroir.OperationBrIf) error {
 		// Set the initial stack of the target label, so we can start compiling the label
 		// with the appropriate value locations. Note we clone the stack here as we maybe
 		// manipulate the stack before compiler reaches the label.
-		labelInfo := c.label(elseLabelKey)
-		if labelInfo.initialStack == nil {
-			labelInfo.initialStack = c.locationStack
+		amd64LabelInfo := c.label(elseLabelKey)
+		if amd64LabelInfo.initialStack == nil {
+			amd64LabelInfo.initialStack = c.locationStack
 		}
 
 		elseJmp := c.assembler.CompileJump(amd64.JMP)
@@ -505,9 +540,9 @@ func (c *amd64Compiler) compileBrIf(o *wazeroir.OperationBrIf) error {
 		// Set the initial stack of the target label, so we can start compiling the label
 		// with the appropriate value locations. Note we clone the stack here as we maybe
 		// manipulate the stack before compiler reaches the label.
-		labelInfo := c.label(thenLabelKey)
-		if labelInfo.initialStack == nil {
-			labelInfo.initialStack = c.locationStack
+		amd64LabelInfo := c.label(thenLabelKey)
+		if amd64LabelInfo.initialStack == nil {
+			amd64LabelInfo.initialStack = c.locationStack
 		}
 		thenJmp := c.assembler.CompileJump(amd64.JMP)
 		c.assignJumpTarget(thenLabelKey, thenJmp)
@@ -652,10 +687,10 @@ func (c *amd64Compiler) compileLabel(o *wazeroir.OperationLabel) (skipLabel bool
 	}
 
 	labelKey := o.Label.String()
-	labelInfo := c.label(labelKey)
+	amd64LabelInfo := c.label(labelKey)
 
 	// If initialStack is not set, that means this label has never been reached.
-	if labelInfo.initialStack == nil {
+	if amd64LabelInfo.initialStack == nil {
 		skipLabel = true
 		c.currentLabel = ""
 		return
@@ -666,19 +701,19 @@ func (c *amd64Compiler) compileLabel(o *wazeroir.OperationLabel) (skipLabel bool
 
 	// Save the instructions so that backward branching
 	// instructions can jump to this label.
-	labelInfo.initialInstruction = labelBegin
+	amd64LabelInfo.initialInstruction = labelBegin
 
 	// Set the initial stack.
-	c.setLocationStack(labelInfo.initialStack)
+	c.setLocationStack(amd64LabelInfo.initialStack)
 
 	// Invoke callbacks to notify the forward branching
 	// instructions can properly jump to this label.
-	for _, cb := range labelInfo.labelBeginningCallbacks {
+	for _, cb := range amd64LabelInfo.labelBeginningCallbacks {
 		cb(labelBegin)
 	}
 
-	// Clear for debugging purpose. See the comment in "len(labelInfo.labelBeginningCallbacks) > 0" block above.
-	labelInfo.labelBeginningCallbacks = nil
+	// Clear for debugging purpose. See the comment in "len(amd64LabelInfo.labelBeginningCallbacks) > 0" block above.
+	amd64LabelInfo.labelBeginningCallbacks = nil
 
 	if buildoptions.IsDebugMode {
 		fmt.Printf("[label %s (num callers=%d)]\n%s\n", labelKey, c.ir.LabelCallers[labelKey], c.locationStack)
@@ -725,7 +760,7 @@ func (c *amd64Compiler) compileCallIndirect(o *wazeroir.OperationCallIndirect) e
 	}
 
 	// First, we need to check if the offset doesn't exceed the length of table.
-	c.assembler.CompileMemoryToRegister(amd64.CMPQ, reservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset, offset.register)
+	c.assembler.CompileMemoryToRegister(amd64.CMPQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset, offset.register)
 	notLengthExceedJump := c.assembler.CompileJump(amd64.JHI)
 
 	// If it exceeds, we return the function with jitCallStatusCodeInvalidTableAccess.
@@ -740,7 +775,7 @@ func (c *amd64Compiler) compileCallIndirect(o *wazeroir.OperationCallIndirect) e
 
 	// Adds the address of wasm.Table[0] stored as callEngine.tableElement0Address to the offset.
 	c.assembler.CompileMemoryToRegister(amd64.ADDQ,
-		reservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset, offset.register)
+		amd64ReservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset, offset.register)
 
 	// "offset = (*offset) + interfaceDataOffset (== table[offset] + interfaceDataOffset == *compiledFunction type)"
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ, offset.register, interfaceDataOffset, offset.register)
@@ -915,7 +950,7 @@ func (c *amd64Compiler) compilePick(o *wazeroir.OperationPick) error {
 	} else if pickTarget.onStack() {
 		// Copy the value from the stack.
 		// Note: stack pointers are ensured not to exceed 2^27 so this offset never exceeds 32-bit range.
-		c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForStackBasePointerAddress, int64(pickTarget.stackPointer)*8, reg)
+		c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForStackBasePointerAddress, int64(pickTarget.stackPointer)*8, reg)
 	}
 	// Now we already placed the picked value on the register,
 	// so push the location onto the stack.
@@ -1650,7 +1685,7 @@ func (c *amd64Compiler) compileShiftOp(instruction asm.Instruction, is32Bit bool
 	} else {
 		// Shift target can be placed on a memory location.
 		// Note: stack pointers are ensured not to exceed 2^27 so this offset never exceeds 32-bit range.
-		c.assembler.CompileRegisterToMemory(instruction, x2.register, reservedRegisterForStackBasePointerAddress, int64(x1.stackPointer)*8)
+		c.assembler.CompileRegisterToMemory(instruction, x2.register, amd64ReservedRegisterForStackBasePointerAddress, int64(x1.stackPointer)*8)
 	}
 
 	// We consumed x2 register after the operation here,
@@ -2934,7 +2969,7 @@ func (c *amd64Compiler) compileLoad(o *wazeroir.OperationLoad) error {
 		// and store the value to the int register.
 		c.assembler.CompileMemoryWithIndexToRegister(movInst,
 			// we access memory as memory.Buffer[ceil-targetSizeInBytes: ceil].
-			reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+			amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 			reg)
 		top := c.pushValueLocationOnRegister(reg)
 		top.setRegisterType(generalPurposeRegisterTypeInt)
@@ -2946,7 +2981,7 @@ func (c *amd64Compiler) compileLoad(o *wazeroir.OperationLoad) error {
 		}
 		c.assembler.CompileMemoryWithIndexToRegister(movInst,
 			// we access memory as memory.Buffer[ceil-targetSizeInBytes: ceil].
-			reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+			amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 			floatReg)
 		top := c.pushValueLocationOnRegister(floatReg)
 		top.setRegisterType(generalPurposeRegisterTypeFloat)
@@ -2980,7 +3015,7 @@ func (c *amd64Compiler) compileLoad8(o *wazeroir.OperationLoad8) error {
 
 	c.assembler.CompileMemoryWithIndexToRegister(inst,
 		// we access memory as memory.Buffer[ceil-targetSizeInBytes: ceil].
-		reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+		amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 		reg)
 
 	top := c.pushValueLocationOnRegister(reg)
@@ -3013,7 +3048,7 @@ func (c *amd64Compiler) compileLoad16(o *wazeroir.OperationLoad16) error {
 	}
 	c.assembler.CompileMemoryWithIndexToRegister(inst,
 		// we access memory as memory.Buffer[ceil-targetSizeInBytes: ceil].
-		reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+		amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 		reg)
 
 	top := c.pushValueLocationOnRegister(reg)
@@ -3039,7 +3074,7 @@ func (c *amd64Compiler) compileLoad32(o *wazeroir.OperationLoad32) error {
 	}
 	c.assembler.CompileMemoryWithIndexToRegister(inst,
 		// We access memory as memory.Buffer[ceil-targetSizeInBytes: ceil].
-		reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+		amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 		reg)
 	top := c.pushValueLocationOnRegister(reg)
 
@@ -3070,7 +3105,7 @@ func (c *amd64Compiler) compileMemoryAccessCeilSetup(offsetArg uint32, targetSiz
 	}
 
 	// Now we compare the value with the memory length which is held by callEngine.
-	c.assembler.CompileMemoryToRegister(amd64.CMPQ, reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset, result)
+	c.assembler.CompileMemoryToRegister(amd64.CMPQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset, result)
 
 	// Jump if the value is within the memory length.
 	okJmp := c.assembler.CompileJump(amd64.JCC)
@@ -3127,7 +3162,7 @@ func (c *amd64Compiler) compileStoreImpl(offsetConst uint32, inst asm.Instructio
 
 	c.assembler.CompileRegisterToMemoryWithIndex(
 		inst, val.register,
-		reservedRegisterForMemory, -targetSizeInBytes, reg, 1,
+		amd64ReservedRegisterForMemory, -targetSizeInBytes, reg, 1,
 	)
 
 	// We no longer need both the value and base registers.
@@ -3161,7 +3196,7 @@ func (c *amd64Compiler) compileMemorySize() error {
 	}
 	loc := c.pushValueLocationOnRegister(reg)
 
-	c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset, loc.register)
+	c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset, loc.register)
 
 	// WebAssembly's memory.size returns the page size (65536) of memory region.
 	// That is equivalent to divide the len of memory slice by 65536 and
@@ -3250,7 +3285,7 @@ func (c *amd64Compiler) compileLoadValueOnStackToRegister(loc *valueLocation) {
 	// Copy the value from the stack.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
 		// Note: stack pointers are ensured not to exceed 2^27 so this offset never exceeds 32-bit range.
-		reservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8,
+		amd64ReservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8,
 		loc.register)
 }
 
@@ -3271,9 +3306,6 @@ func (c *amd64Compiler) maybeCompileMoveTopConditionalToFreeGeneralPurposeRegist
 
 // loadConditionalRegisterToGeneralPurposeRegister saves the conditional register value
 // to a general purpose register.
-//
-// We use CSET instruction to set 1 on the register if the condition satisfies:
-// https://developer.arm.com/documentation/100076/0100/a64-instruction-set-reference/a64-general-instructions/cset
 func (c *amd64Compiler) compileLoadConditionalRegisterToGeneralPurposeRegister(loc *valueLocation) {
 	// Get the free register.
 	reg, _ := c.locationStack.takeFreeRegister(generalPurposeRegisterTypeInt)
@@ -3378,12 +3410,12 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 
 	// First, we read the current call frame stack pointer.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		callFrameStackPointerRegister)
 
 	// And compare it with the underlying slice length.
 	c.assembler.CompileMemoryToRegister(amd64.CMPQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackLenOffset, callFrameStackPointerRegister)
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackLenOffset, callFrameStackPointerRegister)
 
 	// If they do not equal, then we don't have to grow the call frame stack.
 	jmpIfNotCallFrameStackNeedsGrow := c.assembler.CompileJump(amd64.JNE)
@@ -3414,14 +3446,14 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 
 	// Also we have to re-read the call frame stack pointer into callFrameStackPointerRegister.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		callFrameStackPointerRegister)
 
 	// Now that call-frame stack is enough length, we are ready to create a new call frame
 	// for the function call we are about to make.
 	c.assembler.SetJumpTargetOnNext(jmpIfNotCallFrameStackNeedsGrow)
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
 		tmpRegister)
 
 	// Since call frame stack pointer is the index for callEngine.callFrameStack slice,
@@ -3465,7 +3497,7 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 	{
 		// We must save the current stack base pointer (which lives on callEngine.valueStackContext.stackPointer)
 		// to the call frame stack. In the example, this is equivalent to writing the value into "rb.1".
-		c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset, tmpRegister)
+		c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset, tmpRegister)
 
 		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister,
 			// "rb.1" is BELOW the top address. See the above example for detail.
@@ -3481,7 +3513,7 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 		c.assembler.CompileConstToRegister(amd64.ADDQ, offset, tmpRegister)
 
 		// Write the calculated value to callEngine.valueStackContext.stackBasePointer.
-		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
+		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
 	}
 
 	// 3) Set rc.next to specify which function is executed on the current call frame (needs to make builtin function calls).
@@ -3492,7 +3524,7 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 			//
 			// First, we read the address of the first item of callEngine.compiledFunctions slice (= &callEngine.compiledFunctions[0])
 			// into tmpRegister.
-			c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset, tmpRegister)
+			c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset, tmpRegister)
 
 			// Next, read the address of the target function (= &callEngine.compiledFunctions[offset])
 			// into targetAddressRegister.
@@ -3526,7 +3558,7 @@ func (c *amd64Compiler) compileCallFunctionImpl(index wasm.Index, compiledFuncti
 
 	// Every preparation (1 to 5 in the description above) is done to enter into the target function.
 	// So we increment the call frame stack pointer.
-	c.assembler.CompileNoneToMemory(amd64.INCQ, reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
+	c.assembler.CompileNoneToMemory(amd64.INCQ, amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
 
 	// And jump into the initial address of the target function.
 	c.assembler.CompileJumpToMemory(amd64.JMP, targetAddressRegister, compiledFunctionCodeInitialAddressOffset)
@@ -3573,11 +3605,11 @@ func (c *amd64Compiler) compileReturnFunction() error {
 	decrementedCallFrameStackPointerRegister, callFrameStackTopAddressRegister, tmpRegister := regs[0], regs[1], regs[2]
 
 	// Since we return from the function, we need to decement the callframe stack pointer.
-	c.assembler.CompileNoneToMemory(amd64.DECQ, reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
+	c.assembler.CompileNoneToMemory(amd64.DECQ, amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
 
 	// Next, get the decremented callframe stack pointer into decrementedCallFrameStackPointerRegister.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		decrementedCallFrameStackPointerRegister)
 
 	// We have to exit if the decremented stack pointer equals zero.
@@ -3599,7 +3631,7 @@ func (c *amd64Compiler) compileReturnFunction() error {
 	c.assembler.CompileConstToRegister(amd64.SHLQ, int64(callFrameDataSizeMostSignificantSetBit), decrementedCallFrameStackPointerRegister)
 
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset, tmpRegister)
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset, tmpRegister)
 
 	c.assembler.CompileMemoryWithIndexToRegister(amd64.LEAQ,
 		tmpRegister, 0, decrementedCallFrameStackPointerRegister, 1,
@@ -3634,7 +3666,7 @@ func (c *amd64Compiler) compileReturnFunction() error {
 		tmpRegister,
 	)
 	c.assembler.CompileRegisterToMemory(amd64.MOVQ,
-		tmpRegister, reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
+		tmpRegister, amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
 
 	// 2) Jump into the address of "ra.caller".
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
@@ -3656,7 +3688,7 @@ func (c *amd64Compiler) compileCallHostFunction() error {
 
 func (c *amd64Compiler) compileCallBuiltinFunction(index wasm.Index) error {
 	// Set the functionAddress to the callEngine.exitContext functionCallAddress.
-	c.assembler.CompileConstToMemory(amd64.MOVL, int64(index), reservedRegisterForCallEngine, callEngineExitContextBuiltinFunctionCallAddressOffset)
+	c.assembler.CompileConstToMemory(amd64.MOVL, int64(index), amd64ReservedRegisterForCallEngine, callEngineExitContextBuiltinFunctionCallAddressOffset)
 	return c.compileCallGoFunction(jitCallStatusCodeCallBuiltInFunction)
 }
 
@@ -3677,13 +3709,13 @@ func (c *amd64Compiler) compileCallGoFunction(jitStatus jitCallStatusCode) error
 
 	// We need to store the address of the current callFrame's return address.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset, currentCallFrameAddressRegister)
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset, currentCallFrameAddressRegister)
 
 	// Next we shift the stack pointer so we get the actual offset from the address of stack's initial item.
 	c.assembler.CompileConstToRegister(amd64.SHLQ, int64(callFrameDataSizeMostSignificantSetBit), currentCallFrameAddressRegister)
 
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset, tmpRegister)
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset, tmpRegister)
 
 	// Now we can get the current call frame's address, which is equivalent to get &callEngine.callFrameStack[callEngine.callStackFramePointer-1].returnAddress.
 	c.assembler.CompileMemoryWithIndexToRegister(
@@ -3731,17 +3763,17 @@ func (c *amd64Compiler) compileReleaseRegisterToStack(loc *valueLocation) {
 	// Push value.
 	c.assembler.CompileRegisterToMemory(amd64.MOVQ, loc.register,
 		// Note: stack pointers are ensured not to exceed 2^27 so this offset never exceeds 32-bit range.
-		reservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8)
+		amd64ReservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8)
 
 	// Mark the register is free.
 	c.locationStack.releaseRegister(loc)
 }
 
 func (c *amd64Compiler) compileExitFromNativeCode(status jitCallStatusCode) {
-	c.assembler.CompileConstToMemory(amd64.MOVB, int64(status), reservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
+	c.assembler.CompileConstToMemory(amd64.MOVB, int64(status), amd64ReservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
 
 	// Write back the cached SP to the actual eng.stackPointer.
-	c.assembler.CompileConstToMemory(amd64.MOVQ, int64(c.locationStack.sp), reservedRegisterForCallEngine, callEngineValueStackContextStackPointerOffset)
+	c.assembler.CompileConstToMemory(amd64.MOVQ, int64(c.locationStack.sp), amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackPointerOffset)
 
 	c.assembler.CompileStandAlone(amd64.RET)
 }
@@ -3772,8 +3804,8 @@ func (c *amd64Compiler) compilePreamble() (err error) {
 func (c *amd64Compiler) compileReservedStackBasePointerInitialization() {
 	// First, make reservedRegisterForStackBasePointer point to the beginning of the slice backing array.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineGlobalContextValueStackElement0AddressOffset,
-		reservedRegisterForStackBasePointerAddress)
+		amd64ReservedRegisterForCallEngine, callEngineGlobalContextValueStackElement0AddressOffset,
+		amd64ReservedRegisterForStackBasePointerAddress)
 
 	// Since initializeReservedRegisters is called at the beginning of function
 	// calls (or right after they return), we have free registers at this point.
@@ -3781,22 +3813,22 @@ func (c *amd64Compiler) compileReservedStackBasePointerInitialization() {
 
 	// Next we move the base pointer (callEngine.stackBasePointer) to the tmp register.
 	c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-		reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
+		amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
 		tmpReg,
 	)
 
 	c.assembler.CompileMemoryWithIndexToRegister(
 		amd64.LEAQ,
-		reservedRegisterForStackBasePointerAddress, 0, tmpReg, 8,
-		reservedRegisterForStackBasePointerAddress,
+		amd64ReservedRegisterForStackBasePointerAddress, 0, tmpReg, 8,
+		amd64ReservedRegisterForStackBasePointerAddress,
 	)
 }
 
 func (c *amd64Compiler) compileReservedMemoryPointerInitialization() {
 	if c.f.Module.Memory != nil {
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ,
-			reservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
-			reservedRegisterForMemory,
+			amd64ReservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
+			amd64ReservedRegisterForMemory,
 		)
 	}
 }
@@ -3807,8 +3839,8 @@ func (c *amd64Compiler) compileReservedMemoryPointerInitialization() {
 func (c *amd64Compiler) compileMaybeGrowValueStack() error {
 	tmpRegister, _ := c.allocateRegister(generalPurposeRegisterTypeInt)
 
-	c.assembler.CompileMemoryToRegister(amd64.MOVQ, reservedRegisterForCallEngine, callEngineGlobalContextValueStackLenOffset, tmpRegister)
-	c.assembler.CompileMemoryToRegister(amd64.SUBQ, reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset, tmpRegister)
+	c.assembler.CompileMemoryToRegister(amd64.MOVQ, amd64ReservedRegisterForCallEngine, callEngineGlobalContextValueStackLenOffset, tmpRegister)
+	c.assembler.CompileMemoryToRegister(amd64.SUBQ, amd64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset, tmpRegister)
 
 	// If stack base pointer + max stack pointer > valueStackLen, we need to grow the stack.
 	cmpWithStackPointerCeil := c.assembler.CompileRegisterToConst(amd64.CMPQ, tmpRegister, 0)
@@ -3852,13 +3884,13 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 	// binaries. As a result, this cmp and jmp instruction sequence below must be easy for
 	// x64 CPU to do branch prediction since almost 100% jump happens across function calls.
 	c.assembler.CompileMemoryToRegister(amd64.CMPQ,
-		reservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset, moduleInstanceAddressRegister)
+		amd64ReservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset, moduleInstanceAddressRegister)
 	jmpIfModuleNotChange := c.assembler.CompileJump(amd64.JEQ)
 
 	// Otherwise, we need to update fields.
 	// First, save the read module instance address to callEngine.moduleInstanceAddress
 	c.assembler.CompileRegisterToMemory(amd64.MOVQ, moduleInstanceAddressRegister,
-		reservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset)
+		amd64ReservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset)
 
 	// Otherwise, we have to update the following fields:
 	// * callEngine.moduleContext.globalElement0Address
@@ -3879,7 +3911,7 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 		// See https://go.dev/blog/slices-intro if unfamiliar.
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, moduleInstanceAddressRegister, moduleInstanceGlobalsOffset, tmpRegister)
 
-		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, reservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset)
+		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, amd64ReservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset)
 	}
 
 	// Update tableElement0Address and tableSliceLen.
@@ -3897,7 +3929,7 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, tmpRegister, tableInstanceTableOffset, tmpRegister2)
 
 		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister2,
-			reservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset)
+			amd64ReservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset)
 
 		// Finally, read the length of table and update tableSliceLen accordingly.
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, tmpRegister, tableInstanceTableLenOffset, tmpRegister2)
@@ -3905,7 +3937,7 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 		// And put the length into tableSliceLen.
 
 		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister2,
-			reservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset)
+			amd64ReservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset)
 	}
 
 	// Update memoryElement0Address and memorySliceLen.
@@ -3919,12 +3951,12 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 		// Set length.
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, tmpRegister, memoryInstanceBufferLenOffset, tmpRegister2)
 		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister2,
-			reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset)
+			amd64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset)
 
 		// Set elemnt zero address.
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, tmpRegister, memoryInstanceBufferOffset, tmpRegister2)
 		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister2,
-			reservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset)
+			amd64ReservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset)
 	}
 
 	// Update moduleContext.compiledFunctionsElement0Address
@@ -3943,7 +3975,7 @@ func (c *amd64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileMemoryToRegister(amd64.MOVQ, tmpRegister, moduleEngineCompiledFunctionsOffset, tmpRegister)
 
 		// "callEngine.moduleContext.compiledFunctionsElement0Address = tmpRegister".
-		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, reservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset)
+		c.assembler.CompileRegisterToMemory(amd64.MOVQ, tmpRegister, amd64ReservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset)
 	}
 
 	c.locationStack.markRegisterUnused(regs...)
diff --git a/internal/wasm/jit/jit_arm64.go b/internal/wasm/jit/jit_arm64_impl.go
similarity index 91%
rename from internal/wasm/jit/jit_arm64.go
rename to internal/wasm/jit/jit_arm64_impl.go
index 7bed1c67..a1068f8f 100644
--- a/internal/wasm/jit/jit_arm64.go
+++ b/internal/wasm/jit/jit_arm64_impl.go
@@ -27,8 +27,8 @@ type arm64Compiler struct {
 	// locationStack holds the state of wazeroir virtual stack.
 	// and each item is either placed in register or the actual memory stack.
 	locationStack *valueLocationStack
-	// labels maps a label (Ex. ".L1_then") to *labelInfo.
-	labels map[string]*labelInfo
+	// labels maps a label (Ex. ".L1_then") to *arm64LabelInfo.
+	labels map[string]*arm64LabelInfo
 	// stackPointerCeil is the greatest stack pointer value (from valueLocationStack) seen during compilation.
 	stackPointerCeil uint64
 	// onStackPointerCeilDeterminedCallBack hold a callback which are called when the ceil of stack pointer is determined before generating native code.
@@ -38,14 +38,61 @@ type arm64Compiler struct {
 	staticData compiledFunctionStaticData
 }
 
+func newArm64Compiler(f *wasm.FunctionInstance, ir *wazeroir.CompilationResult) (compiler, error) {
+	b, err := arm64.NewAssembler(arm64ReservedRegisterForTemporary)
+	if err != nil {
+		return nil, err
+	}
+	c := &arm64Compiler{
+		f:             f,
+		assembler:     b,
+		locationStack: newValueLocationStack(),
+		ir:            ir,
+		labels:        map[string]*arm64LabelInfo{},
+	}
+	return c, nil
+}
+
+var (
+	arm64UnreservedGeneralPurposeFloatRegisters = []asm.Register{
+		arm64.REG_F0, arm64.REG_F1, arm64.REG_F2, arm64.REG_F3,
+		arm64.REG_F4, arm64.REG_F5, arm64.REG_F6, arm64.REG_F7, arm64.REG_F8,
+		arm64.REG_F9, arm64.REG_F10, arm64.REG_F11, arm64.REG_F12, arm64.REG_F13,
+		arm64.REG_F14, arm64.REG_F15, arm64.REG_F16, arm64.REG_F17, arm64.REG_F18,
+		arm64.REG_F19, arm64.REG_F20, arm64.REG_F21, arm64.REG_F22, arm64.REG_F23,
+		arm64.REG_F24, arm64.REG_F25, arm64.REG_F26, arm64.REG_F27, arm64.REG_F28,
+		arm64.REG_F29, arm64.REG_F30, arm64.REG_F31,
+	}
+
+	// Note (see arm64 section in https://go.dev/doc/asm):
+	// * REG_R18 is reserved as a platform register, and we don't use it in JIT.
+	// * REG_R28 is reserved for Goroutine by Go runtime, and we don't use it in JIT.
+	arm64UnreservedGeneralPurposeIntRegisters = []asm.Register{
+		arm64.REG_R4, arm64.REG_R5, arm64.REG_R6, arm64.REG_R7, arm64.REG_R8,
+		arm64.REG_R9, arm64.REG_R10, arm64.REG_R11, arm64.REG_R12, arm64.REG_R13,
+		arm64.REG_R14, arm64.REG_R15, arm64.REG_R16, arm64.REG_R17, arm64.REG_R19,
+		arm64.REG_R20, arm64.REG_R21, arm64.REG_R22, arm64.REG_R23, arm64.REG_R24,
+		arm64.REG_R25, arm64.REG_R26, arm64.REG_R27, arm64.REG_R29, arm64.REG_R30,
+	}
+)
+
+const (
+	// arm64ReservedRegisterForCallEngine holds the pointer to callEngine instance (i.e. *callEngine as uintptr)
+	arm64ReservedRegisterForCallEngine asm.Register = arm64.REG_R0
+	// arm64ReservedRegisterForStackBasePointerAddress holds stack base pointer's address (callEngine.stackBasePointer) in the current function call.
+	arm64ReservedRegisterForStackBasePointerAddress asm.Register = arm64.REG_R1
+	// arm64ReservedRegisterForMemory holds the pointer to the memory slice's data (i.e. &memory.Buffer[0] as uintptr).
+	arm64ReservedRegisterForMemory    asm.Register = arm64.REG_R2
+	arm64ReservedRegisterForTemporary asm.Register = arm64.REG_R3
+)
+
 const (
-	// reservedRegisterForCallEngine holds the pointer to callEngine instance (i.e. *callEngine as uintptr)
-	reservedRegisterForCallEngine asm.Register = arm64.REG_R0
-	// reservedRegisterForStackBasePointerAddress holds stack base pointer's address (callEngine.stackBasePointer) in the current function call.
-	reservedRegisterForStackBasePointerAddress asm.Register = arm64.REG_R1
-	// reservedRegisterForMemory holds the pointer to the memory slice's data (i.e. &memory.Buffer[0] as uintptr).
-	reservedRegisterForMemory    asm.Register = arm64.REG_R2
-	reservedRegisterForTemporary asm.Register = arm64.REG_R3
+	// arm64CallEngineArchContextJITCallReturnAddressOffset is the offset of archContext.jitCallReturnAddress in callEngine.
+	arm64CallEngineArchContextJITCallReturnAddressOffset = 120
+	// arm64CallEngineArchContextMinimum32BitSignedIntOffset is the offset of archContext.minimum32BitSignedIntAddress in callEngine.
+	arm64CallEngineArchContextMinimum32BitSignedIntOffset = 128
+	// arm64CallEngineArchContextMinimum64BitSignedIntOffset is the offset of archContext.minimum64BitSignedIntAddress in callEngine.
+	arm64CallEngineArchContextMinimum64BitSignedIntOffset = 136
 )
 
 func isZeroRegister(r asm.Register) bool {
@@ -87,8 +134,8 @@ func (c *arm64Compiler) compile() (code []byte, staticData compiledFunctionStati
 	return
 }
 
-// labelInfo holds a wazeroir label specific information in this function.
-type labelInfo struct {
+// arm64LabelInfo holds a wazeroir label specific information in this function.
+type arm64LabelInfo struct {
 	// initialInstruction is the initial instruction for this label so other block can branch into it.
 	initialInstruction asm.Node
 	// initialStack is the initial value location stack from which we start compiling this label.
@@ -97,12 +144,12 @@ type labelInfo struct {
 	labelBeginningCallbacks []func(asm.Node)
 }
 
-func (c *arm64Compiler) label(labelKey string) *labelInfo {
+func (c *arm64Compiler) label(labelKey string) *arm64LabelInfo {
 	ret, ok := c.labels[labelKey]
 	if ok {
 		return ret
 	}
-	c.labels[labelKey] = &labelInfo{}
+	c.labels[labelKey] = &arm64LabelInfo{}
 	return c.labels[labelKey]
 }
 
@@ -183,14 +230,14 @@ func (c *arm64Compiler) compileMaybeGrowValueStack() error {
 	// "tmpX = len(ce.valueStack)"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextValueStackLenOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextValueStackLenOffset,
 		tmpX,
 	)
 
 	// "tmpY = ce.stackBasePointer"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
 		tmpY,
 	)
 
@@ -245,9 +292,9 @@ func (c *arm64Compiler) compileReturnFunction() error {
 	callFramePointerReg, callFrameStackTopAddressRegister, tmpReg := tmpRegs[0], tmpRegs[1], tmpRegs[2]
 
 	// First we decrement the call-frame stack pointer.
-	c.assembler.CompileMemoryToRegister(arm64.MOVD, reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset, callFramePointerReg)
+	c.assembler.CompileMemoryToRegister(arm64.MOVD, arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset, callFramePointerReg)
 	c.assembler.CompileConstToRegister(arm64.SUBS, 1, callFramePointerReg)
-	c.assembler.CompileRegisterToMemory(arm64.MOVD, callFramePointerReg, reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
+	c.assembler.CompileRegisterToMemory(arm64.MOVD, callFramePointerReg, arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
 
 	// Next we compare the decremented call frame stack pointer with zero.
 	c.assembler.CompileTwoRegistersToNone(arm64.CMP, callFramePointerReg, arm64.REGZERO)
@@ -263,7 +310,7 @@ func (c *arm64Compiler) compileReturnFunction() error {
 	//
 	// "tmpReg = &ce.callFrameStack[0]"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
 		tmpReg,
 	)
 	// "callFrameStackTopAddressRegister = tmpReg + callFramePointerReg << ${callFrameDataSizeMostSignificantSetBit}"
@@ -297,7 +344,7 @@ func (c *arm64Compiler) compileReturnFunction() error {
 		tmpReg)
 	c.assembler.CompileRegisterToMemory(arm64.MOVD,
 		tmpReg,
-		reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
+		arm64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
 
 	// 2) Branch into the address of "ra.caller".
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
@@ -313,24 +360,24 @@ func (c *arm64Compiler) compileReturnFunction() error {
 // compileExitFromNativeCode adds instructions to give the control back to ce.exec with the given status code.
 func (c *arm64Compiler) compileExitFromNativeCode(status jitCallStatusCode) {
 	// Write the current stack pointer to the ce.stackPointer.
-	c.assembler.CompileConstToRegister(arm64.MOVD, int64(c.locationStack.sp), reservedRegisterForTemporary)
-	c.assembler.CompileRegisterToMemory(arm64.MOVD, reservedRegisterForTemporary, reservedRegisterForCallEngine,
+	c.assembler.CompileConstToRegister(arm64.MOVD, int64(c.locationStack.sp), arm64ReservedRegisterForTemporary)
+	c.assembler.CompileRegisterToMemory(arm64.MOVD, arm64ReservedRegisterForTemporary, arm64ReservedRegisterForCallEngine,
 		callEngineValueStackContextStackPointerOffset)
 
 	if status != 0 {
-		c.assembler.CompileConstToRegister(arm64.MOVW, int64(status), reservedRegisterForTemporary)
-		c.assembler.CompileRegisterToMemory(arm64.MOVW, reservedRegisterForTemporary, reservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
+		c.assembler.CompileConstToRegister(arm64.MOVW, int64(status), arm64ReservedRegisterForTemporary)
+		c.assembler.CompileRegisterToMemory(arm64.MOVW, arm64ReservedRegisterForTemporary, arm64ReservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
 	} else {
 		// If the status == 0, we use zero register to store zero.
-		c.assembler.CompileRegisterToMemory(arm64.MOVW, arm64.REGZERO, reservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
+		c.assembler.CompileRegisterToMemory(arm64.MOVW, arm64.REGZERO, arm64ReservedRegisterForCallEngine, callEngineExitContextJITCallStatusCodeOffset)
 	}
 
 	// The return address to the Go code is stored in archContext.jitReturnAddress which
 	// is embedded in ce. We load the value to the tmpRegister, and then
 	// invoke RET with that register.
-	c.assembler.CompileMemoryToRegister(arm64.MOVD, reservedRegisterForCallEngine, callEngineArchContextJITCallReturnAddressOffset, reservedRegisterForTemporary)
+	c.assembler.CompileMemoryToRegister(arm64.MOVD, arm64ReservedRegisterForCallEngine, arm64CallEngineArchContextJITCallReturnAddressOffset, arm64ReservedRegisterForTemporary)
 
-	c.assembler.CompileJumpToRegister(arm64.RET, reservedRegisterForTemporary)
+	c.assembler.CompileJumpToRegister(arm64.RET, arm64ReservedRegisterForTemporary)
 }
 
 // compileHostFunction implements compiler.compileHostFunction for the arm64 architecture.
@@ -361,10 +408,10 @@ func (c *arm64Compiler) setLocationStack(newStack *valueLocationStack) {
 // arm64Compiler implements compiler.arm64Compiler for the arm64 architecture.
 func (c *arm64Compiler) compileLabel(o *wazeroir.OperationLabel) (skipThisLabel bool) {
 	labelKey := o.Label.String()
-	labelInfo := c.label(labelKey)
+	arm64LabelInfo := c.label(labelKey)
 
 	// If initialStack is not set, that means this label has never been reached.
-	if labelInfo.initialStack == nil {
+	if arm64LabelInfo.initialStack == nil {
 		skipThisLabel = true
 		return
 	}
@@ -375,14 +422,14 @@ func (c *arm64Compiler) compileLabel(o *wazeroir.OperationLabel) (skipThisLabel
 
 	// Save the instructions so that backward branching
 	// instructions can branch to this label.
-	labelInfo.initialInstruction = labelBegin
+	arm64LabelInfo.initialInstruction = labelBegin
 
 	// Set the initial stack.
-	c.setLocationStack(labelInfo.initialStack)
+	c.setLocationStack(arm64LabelInfo.initialStack)
 
 	// Invoke callbacks to notify the forward branching
 	// instructions can properly branch to this label.
-	for _, cb := range labelInfo.labelBeginningCallbacks {
+	for _, cb := range arm64LabelInfo.labelBeginningCallbacks {
 		cb(labelBegin)
 	}
 	return false
@@ -509,17 +556,17 @@ func (c *arm64Compiler) compileReadGlobalAddress(globalIndex uint32) (destinatio
 		arm64.MOVD, int64(globalIndex)*8, destinationRegister,
 	)
 
-	// "reservedRegisterForTemporary = &globals[0]"
+	// "arm64ReservedRegisterForTemporary = &globals[0]"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset,
-		reservedRegisterForTemporary,
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset,
+		arm64ReservedRegisterForTemporary,
 	)
 
-	// "destinationRegister = [reservedRegisterForTemporary + destinationRegister] (== globals[globalIndex])".
+	// "destinationRegister = [arm64ReservedRegisterForTemporary + destinationRegister] (== globals[globalIndex])".
 	c.assembler.CompileMemoryWithRegisterOffsetToRegister(
 		arm64.MOVD,
-		reservedRegisterForTemporary, destinationRegister,
+		arm64ReservedRegisterForTemporary, destinationRegister,
 		destinationRegister,
 	)
 	return
@@ -815,12 +862,12 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 	//
 	// "callFrameStackPointerRegister = ce.callFrameStackPointer"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		callFrameStackPointerRegister)
 	// "tmp = len(ce.callFrameStack)"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackLenOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackLenOffset,
 		tmp,
 	)
 	// Compare tmp(len(ce.callFrameStack)) with callFrameStackPointerRegister(ce.callFrameStackPointer).
@@ -854,7 +901,7 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 	// On the function return, we again have to set ce.callFrameStackPointer into callFrameStackPointerRegister.
 	// "callFrameStackPointerRegister = ce.callFrameStackPointer"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		callFrameStackPointerRegister)
 
 	// Now that we ensured callFrameStack length is enough.
@@ -884,7 +931,7 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 
 	// 1) Set rb.current so that we can return back to this function properly.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
 		oldStackBasePointer)
 	c.assembler.CompileRegisterToMemory(arm64.MOVD,
 		oldStackBasePointer,
@@ -900,7 +947,7 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 		c.assembler.CompileConstToRegister(arm64.ADD, offset, oldStackBasePointer)
 		c.assembler.CompileRegisterToMemory(arm64.MOVD,
 			oldStackBasePointer,
-			reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
+			arm64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset)
 	}
 
 	// 3) Set rc.next to specify which function is executed on the current call frame.
@@ -908,7 +955,7 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 	// First, we read the address of the first item of ce.compiledFunctions slice (= &ce.compiledFunctions[0])
 	// into tmp.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset,
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset,
 		tmp)
 
 	// Next, read the index of the target function (= &ce.compiledFunctions[offset])
@@ -940,12 +987,12 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 
 	// Everything is done to make function call now: increment the call-frame stack pointer.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		tmp)
 	c.assembler.CompileConstToRegister(arm64.ADD, 1, tmp)
 	c.assembler.CompileRegisterToMemory(arm64.MOVD,
 		tmp,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset)
 
 	// Then, br into the target function's initial address.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
@@ -989,7 +1036,7 @@ func (c *arm64Compiler) compileCallImpl(index wasm.Index, compiledFunctionAddres
 func (c *arm64Compiler) compileCalcCallFrameStackTopAddress(callFrameStackPointerRegister, destinationRegister asm.Register) {
 	// "destinationRegister = &ce.callFrameStack[0]"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackElement0AddressOffset,
 		destinationRegister)
 	// "destinationRegister += callFrameStackPointerRegister << $callFrameDataSizeMostSignificantSetBit"
 	c.assembler.CompileLeftShiftedRegisterToRegister(
@@ -1026,7 +1073,7 @@ func (c *arm64Compiler) compileCallIndirect(o *wazeroir.OperationCallIndirect) e
 	// First, we need to check if the offset doesn't exceed the length of table.
 	// "tmp = len(table)"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset,
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset,
 		tmp,
 	)
 	// "cmp tmp, offset"
@@ -1043,7 +1090,7 @@ func (c *arm64Compiler) compileCallIndirect(o *wazeroir.OperationCallIndirect) e
 	// "tmp = &table[0]"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset,
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset,
 		tmp,
 	)
 	// "offset = tmp + (offset << 4) (== &table[offset])"
@@ -1077,11 +1124,11 @@ func (c *arm64Compiler) compileCallIndirect(o *wazeroir.OperationCallIndirect) e
 		arm64.MOVW, tmp, functionInstanceTypeIDOffset,
 		tmp,
 	)
-	// "reservedRegisterForTemporary = targetFunctionType.TypeID"
-	c.assembler.CompileConstToRegister(arm64.MOVW, int64(targetFunctionType.TypeID), reservedRegisterForTemporary)
+	// "arm64ReservedRegisterForTemporary = targetFunctionType.TypeID"
+	c.assembler.CompileConstToRegister(arm64.MOVW, int64(targetFunctionType.TypeID), arm64ReservedRegisterForTemporary)
 
 	// Compare these two values, and if they equal, we are ready to make function call.
-	c.assembler.CompileTwoRegistersToNone(arm64.CMPW, tmp, reservedRegisterForTemporary)
+	c.assembler.CompileTwoRegistersToNone(arm64.CMPW, tmp, arm64ReservedRegisterForTemporary)
 	brIfTypeMatched := c.assembler.CompileJump(arm64.BEQ)
 	c.compileExitFromNativeCode(jitCallStatusCodeTypeMismatchOnIndirectCall)
 
@@ -1511,11 +1558,11 @@ func (c *arm64Compiler) compileIntegerDivPrecheck(is32Bit, isSigned bool, divide
 	if is32Bit {
 		cmpInst = arm64.CMPW
 		movInst = arm64.MOVW
-		minValueOffsetInVM = callEngineArchContextMinimum32BitSignedIntOffset
+		minValueOffsetInVM = arm64CallEngineArchContextMinimum32BitSignedIntOffset
 	} else {
 		cmpInst = arm64.CMP
 		movInst = arm64.MOVD
-		minValueOffsetInVM = callEngineArchContextMinimum64BitSignedIntOffset
+		minValueOffsetInVM = arm64CallEngineArchContextMinimum64BitSignedIntOffset
 	}
 	c.assembler.CompileTwoRegistersToNone(cmpInst, arm64.REGZERO, divisor)
 
@@ -1532,8 +1579,8 @@ func (c *arm64Compiler) compileIntegerDivPrecheck(is32Bit, isSigned bool, divide
 		// case which results in the overflow.
 
 		// First, we compare the divisor with -1.
-		c.assembler.CompileConstToRegister(movInst, -1, reservedRegisterForTemporary)
-		c.assembler.CompileTwoRegistersToNone(cmpInst, reservedRegisterForTemporary, divisor)
+		c.assembler.CompileConstToRegister(movInst, -1, arm64ReservedRegisterForTemporary)
+		c.assembler.CompileTwoRegistersToNone(cmpInst, arm64ReservedRegisterForTemporary, divisor)
 
 		// If they not equal, we skip the following check.
 		brIfDivisorNonMinusOne := c.assembler.CompileJump(arm64.BNE)
@@ -1541,10 +1588,10 @@ func (c *arm64Compiler) compileIntegerDivPrecheck(is32Bit, isSigned bool, divide
 		// Otherwise, we further check if the dividend equals math.MinInt32 or MinInt64.
 		c.assembler.CompileMemoryToRegister(
 			movInst,
-			reservedRegisterForCallEngine, minValueOffsetInVM,
-			reservedRegisterForTemporary,
+			arm64ReservedRegisterForCallEngine, minValueOffsetInVM,
+			arm64ReservedRegisterForTemporary,
 		)
-		c.assembler.CompileTwoRegistersToNone(cmpInst, reservedRegisterForTemporary, dividend)
+		c.assembler.CompileTwoRegistersToNone(cmpInst, arm64ReservedRegisterForTemporary, dividend)
 
 		// If they not equal, we are safe to execute the division.
 		brIfDividendNotMinInt := c.assembler.CompileJump(arm64.BNE)
@@ -1930,10 +1977,10 @@ func (c *arm64Compiler) compileCopysign(o *wazeroir.OperationCopysign) error {
 	var minValueOffsetInVM int64
 	if o.Type == wazeroir.Float32 {
 		fmov = arm64.FMOVS
-		minValueOffsetInVM = callEngineArchContextMinimum32BitSignedIntOffset
+		minValueOffsetInVM = arm64CallEngineArchContextMinimum32BitSignedIntOffset
 	} else {
 		fmov = arm64.FMOVD
-		minValueOffsetInVM = callEngineArchContextMinimum64BitSignedIntOffset
+		minValueOffsetInVM = arm64CallEngineArchContextMinimum64BitSignedIntOffset
 	}
 
 	c.markRegisterUsed(x1.register, x2.register)
@@ -1951,7 +1998,7 @@ func (c *arm64Compiler) compileCopysign(o *wazeroir.OperationCopysign) error {
 	// "mov freg, -9223372036854775808 (stored at ce.minimum64BitSignedInt)"
 	c.assembler.CompileMemoryToRegister(
 		fmov,
-		reservedRegisterForCallEngine, minValueOffsetInVM,
+		arm64ReservedRegisterForCallEngine, minValueOffsetInVM,
 		freg,
 	)
 
@@ -2016,10 +2063,10 @@ func (c *arm64Compiler) compileITruncFromF(o *wazeroir.OperationITruncFromF) err
 
 	// Obtain the floating point status register value into the general purpose register,
 	// so that we can check if the conversion resulted in undefined behavior.
-	c.assembler.CompileRegisterToRegister(arm64.MRS, arm64.REG_FPSR, reservedRegisterForTemporary)
+	c.assembler.CompileRegisterToRegister(arm64.MRS, arm64.REG_FPSR, arm64ReservedRegisterForTemporary)
 	// Check if the conversion was undefined by comparing the status with 1.
 	// See https://developer.arm.com/documentation/ddi0595/2020-12/AArch64-Registers/FPSR--Floating-point-Status-Register
-	c.assembler.CompileRegisterAndConstSourceToNone(arm64.CMP, reservedRegisterForTemporary, 1)
+	c.assembler.CompileRegisterAndConstSourceToNone(arm64.CMP, arm64ReservedRegisterForTemporary, 1)
 
 	brOK := c.assembler.CompileJump(arm64.BNE)
 
@@ -2474,11 +2521,11 @@ func (c *arm64Compiler) compileLoadImpl(offsetArg uint32, loadInst asm.Instructi
 		}
 	}
 
-	// "resultRegister = [reservedRegisterForMemory + offsetReg]"
+	// "resultRegister = [arm64ReservedRegisterForMemory + offsetReg]"
 	// In other words, "resultRegister = memory.Buffer[offset: offset+targetSizeInBytes]"
 	c.assembler.CompileMemoryWithRegisterOffsetToRegister(
 		loadInst,
-		reservedRegisterForMemory, offsetReg,
+		arm64ReservedRegisterForMemory, offsetReg,
 		resultRegister,
 	)
 
@@ -2536,11 +2583,11 @@ func (c *arm64Compiler) compileStoreImpl(offsetArg uint32, storeInst asm.Instruc
 		return err
 	}
 
-	// "[reservedRegisterForMemory + offsetReg] = val.register"
+	// "[arm64ReservedRegisterForMemory + offsetReg] = val.register"
 	// In other words, "memory.Buffer[offset: offset+targetSizeInBytes] = val.register"
 	c.assembler.CompileRegisterToMemoryWithRegisterOffset(
 		storeInst, val.register,
-		reservedRegisterForMemory, offsetReg,
+		arm64ReservedRegisterForMemory, offsetReg,
 	)
 
 	c.markRegisterUnused(val.register)
@@ -2577,13 +2624,13 @@ func (c *arm64Compiler) compileMemoryAccessOffsetSetup(offsetArg uint32, targetS
 		return
 	}
 
-	// "reservedRegisterForTemporary = len(memory.Buffer)"
+	// "arm64ReservedRegisterForTemporary = len(memory.Buffer)"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
-		reservedRegisterForTemporary)
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
+		arm64ReservedRegisterForTemporary)
 
 	// Check if offsetRegister(= base+offsetArg+targetSizeInBytes) > len(memory.Buffer).
-	c.assembler.CompileTwoRegistersToNone(arm64.CMP, reservedRegisterForTemporary, offsetRegister)
+	c.assembler.CompileTwoRegistersToNone(arm64.CMP, arm64ReservedRegisterForTemporary, offsetRegister)
 	boundsOK := c.assembler.CompileJump(arm64.BLS)
 
 	// If offsetRegister(= base+offsetArg+targetSizeInBytes) exceeds the memory length,
@@ -2622,7 +2669,7 @@ func (c *arm64Compiler) compileMemorySize() error {
 	// "reg = len(memory.Buffer)"
 	c.assembler.CompileMemoryToRegister(
 		arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
+		arm64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
 		reg,
 	)
 
@@ -2665,12 +2712,12 @@ func (c *arm64Compiler) compileCallGoFunction(jitStatus jitCallStatusCode, built
 			int64(builtinFunction),
 			tmp,
 		)
-		// "[reservedRegisterForCallEngine + callEngineExitContextFunctionCallAddressOffset] = tmp"
+		// "[arm64ReservedRegisterForCallEngine + callEngineExitContextFunctionCallAddressOffset] = tmp"
 		// In other words, "ce.functionCallAddress = tmp (== $addr)"
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVW,
 			tmp,
-			reservedRegisterForCallEngine, callEngineExitContextBuiltinFunctionCallAddressOffset,
+			arm64ReservedRegisterForCallEngine, callEngineExitContextBuiltinFunctionCallAddressOffset,
 		)
 	}
 
@@ -2678,7 +2725,7 @@ func (c *arm64Compiler) compileCallGoFunction(jitStatus jitCallStatusCode, built
 	//
 	// "currentCallFrameStackPointerRegister = ce.callFrameStackPointer"
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextCallFrameStackPointerOffset,
 		currentCallFrameStackPointerRegister)
 
 	// Set the address of callFrameStack[ce.callFrameStackPointer] into currentCallFrameTopAddressRegister.
@@ -2762,7 +2809,7 @@ func (c *arm64Compiler) compileFloatConstant(is32bit bool, value uint64) error {
 
 	tmpReg := arm64.REGZERO
 	if value != 0 {
-		tmpReg = reservedRegisterForTemporary
+		tmpReg = arm64ReservedRegisterForTemporary
 		var inst asm.Instruction
 		if is32bit {
 			inst = arm64.MOVW
@@ -2889,7 +2936,7 @@ func (c *arm64Compiler) compileLoadValueOnStackToRegister(loc *valueLocation) {
 	case generalPurposeRegisterTypeFloat:
 		inst = arm64.FMOVD
 	}
-	c.assembler.CompileMemoryToRegister(inst, reservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8, loc.register)
+	c.assembler.CompileMemoryToRegister(inst, arm64ReservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8, loc.register)
 }
 
 // allocateRegister returns an unused register of the given type. The register will be taken
@@ -2942,40 +2989,40 @@ func (c *arm64Compiler) compileReleaseRegisterToStack(loc *valueLocation) {
 		inst = arm64.FMOVD
 	}
 
-	c.assembler.CompileRegisterToMemory(inst, loc.register, reservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8)
+	c.assembler.CompileRegisterToMemory(inst, loc.register, arm64ReservedRegisterForStackBasePointerAddress, int64(loc.stackPointer)*8)
 
 	// Mark the register is free.
 	c.locationStack.releaseRegister(loc)
 }
 
-// compileReservedStackBasePointerRegisterInitialization adds instructions to initialize reservedRegisterForStackBasePointerAddress
+// compileReservedStackBasePointerRegisterInitialization adds instructions to initialize arm64ReservedRegisterForStackBasePointerAddress
 // so that it points to the absolute address of the stack base for this function.
 func (c *arm64Compiler) compileReservedStackBasePointerRegisterInitialization() {
-	// First, load the address of the first element in the value stack into reservedRegisterForStackBasePointerAddress temporarily.
+	// First, load the address of the first element in the value stack into arm64ReservedRegisterForStackBasePointerAddress temporarily.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineGlobalContextValueStackElement0AddressOffset,
-		reservedRegisterForStackBasePointerAddress)
+		arm64ReservedRegisterForCallEngine, callEngineGlobalContextValueStackElement0AddressOffset,
+		arm64ReservedRegisterForStackBasePointerAddress)
 
-	// Next we move the base pointer (ce.stackBasePointer) to reservedRegisterForTemporary.
+	// Next we move the base pointer (ce.stackBasePointer) to arm64ReservedRegisterForTemporary.
 	c.assembler.CompileMemoryToRegister(arm64.MOVD,
-		reservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
-		reservedRegisterForTemporary)
+		arm64ReservedRegisterForCallEngine, callEngineValueStackContextStackBasePointerOffset,
+		arm64ReservedRegisterForTemporary)
 
-	// Finally, we calculate "reservedRegisterForStackBasePointerAddress + reservedRegisterForTemporary << 3"
+	// Finally, we calculate "arm64ReservedRegisterForStackBasePointerAddress + arm64ReservedRegisterForTemporary << 3"
 	// where we shift tmpReg by 3 because stack pointer is an index in the []uint64
 	// so we must multiply the value by the size of uint64 = 8 bytes.
 	c.assembler.CompileLeftShiftedRegisterToRegister(
-		reservedRegisterForTemporary, 3, reservedRegisterForStackBasePointerAddress,
-		reservedRegisterForStackBasePointerAddress)
+		arm64ReservedRegisterForTemporary, 3, arm64ReservedRegisterForStackBasePointerAddress,
+		arm64ReservedRegisterForStackBasePointerAddress)
 }
 
 func (c *arm64Compiler) compileReservedMemoryRegisterInitialization() {
 	if c.f.Module.Memory != nil {
-		// "reservedRegisterForMemory = ce.MemoryElement0Address"
+		// "arm64ReservedRegisterForMemory = ce.MemoryElement0Address"
 		c.assembler.CompileMemoryToRegister(
 			arm64.MOVD,
-			reservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
-			reservedRegisterForMemory,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
+			arm64ReservedRegisterForMemory,
 		)
 	}
 }
@@ -2998,7 +3045,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 	c.assembler.CompileConstToRegister(arm64.MOVD, int64(uintptr(unsafe.Pointer(c.f.Module))), moduleInstanceAddressRegister)
 
 	// "tmpX = ce.ModuleInstanceAddress"
-	c.assembler.CompileMemoryToRegister(arm64.MOVD, reservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset, tmpX)
+	c.assembler.CompileMemoryToRegister(arm64.MOVD, arm64ReservedRegisterForCallEngine, callEngineModuleContextModuleInstanceAddressOffset, tmpX)
 
 	// If the module instance address stays the same, we could skip the entire code below.
 	c.assembler.CompileTwoRegistersToNone(arm64.CMP, moduleInstanceAddressRegister, tmpX)
@@ -3027,7 +3074,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		// "ce.GlobalElement0Address = tmpX (== &moduleInstance.Globals[0])"
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD, tmpX,
-			reservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextGlobalElement0AddressOffset,
 		)
 	}
 
@@ -3056,7 +3103,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD,
 			tmpY,
-			reservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextMemorySliceLenOffset,
 		)
 
 		// Next write ce.memoryElement0Address.
@@ -3071,7 +3118,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD,
 			tmpY,
-			reservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextMemoryElement0AddressOffset,
 		)
 	}
 
@@ -3099,7 +3146,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD,
 			tmpY,
-			reservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextTableElement0AddressOffset,
 		)
 
 		// Update ce.tableSliceLen.
@@ -3113,7 +3160,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD,
 			tmpY,
-			reservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextTableSliceLenOffset,
 		)
 	}
 
@@ -3144,7 +3191,7 @@ func (c *arm64Compiler) compileModuleContextInitialization() error {
 		c.assembler.CompileRegisterToMemory(
 			arm64.MOVD,
 			tmpY,
-			reservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset,
+			arm64ReservedRegisterForCallEngine, callEngineModuleContextCompiledFunctionsElement0AddressOffset,
 		)
 	}
 
diff --git a/internal/wasm/jit/jit_value_location.go b/internal/wasm/jit/jit_value_location.go
index 03ffe57d..2c02d26e 100644
--- a/internal/wasm/jit/jit_value_location.go
+++ b/internal/wasm/jit/jit_value_location.go
@@ -7,6 +7,14 @@ import (
 	"github.com/tetratelabs/wazero/internal/wasm/jit/asm"
 )
 
+var (
+	// unreservedGeneralPurposeIntRegisters contains unreserved general purpose registers of integer type.
+	unreservedGeneralPurposeIntRegisters []asm.Register
+
+	// unreservedGeneralPurposeFloatRegisters contains unreserved general purpose registers of scalar float type.
+	unreservedGeneralPurposeFloatRegisters []asm.Register
+)
+
 func isNilRegister(r asm.Register) bool {
 	return r == asm.NilRegister
 }


Test patch:
diff --git a/internal/wasm/jit/arch_arm64_test.go b/internal/wasm/jit/arch_arm64_test.go
index 25fae6b2..5c41c0d0 100644
--- a/internal/wasm/jit/arch_arm64_test.go
+++ b/internal/wasm/jit/arch_arm64_test.go
@@ -9,7 +9,7 @@ import (
 
 func TestArchContextOffsetInArm64Engine(t *testing.T) {
 	var ctx callEngine
-	require.Equal(t, int(unsafe.Offsetof(ctx.jitCallReturnAddress)), callEngineArchContextJITCallReturnAddressOffset, "fix consts in jit_arm64.s")
-	require.Equal(t, int(unsafe.Offsetof(ctx.minimum32BitSignedInt)), callEngineArchContextMinimum32BitSignedIntOffset)
-	require.Equal(t, int(unsafe.Offsetof(ctx.minimum64BitSignedInt)), callEngineArchContextMinimum64BitSignedIntOffset)
+	require.Equal(t, int(unsafe.Offsetof(ctx.jitCallReturnAddress)), arm64CallEngineArchContextJITCallReturnAddressOffset, "fix consts in jit_arm64.s")
+	require.Equal(t, int(unsafe.Offsetof(ctx.minimum32BitSignedInt)), arm64CallEngineArchContextMinimum32BitSignedIntOffset)
+	require.Equal(t, int(unsafe.Offsetof(ctx.minimum64BitSignedInt)), arm64CallEngineArchContextMinimum64BitSignedIntOffset)
 }
diff --git a/internal/wasm/jit/jit_amd64_test.go b/internal/wasm/jit/jit_amd64_impl_test.go
similarity index 93%
rename from internal/wasm/jit/jit_amd64_test.go
rename to internal/wasm/jit/jit_amd64_impl_test.go
index 596eb848..e5be00f1 100644
--- a/internal/wasm/jit/jit_amd64_test.go
+++ b/internal/wasm/jit/jit_amd64_impl_test.go
@@ -1,6 +1,7 @@
 package jit
 
 import (
+	"runtime"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -10,27 +11,15 @@ import (
 	"github.com/tetratelabs/wazero/internal/wazeroir"
 )
 
-// compile implements compilerImpl.valueLocationStack for the amd64 architecture.
-func (c *amd64Compiler) valueLocationStack() *valueLocationStack {
-	return c.locationStack
-}
-
-// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
-func (c *amd64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
-	return c.onStackPointerCeilDeterminedCallBack
-}
-
-// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
-func (c *amd64Compiler) setStackPointerCeil(v uint64) {
-	c.stackPointerCeil = v
-}
-
-// compile implements compilerImpl.setValueLocationStack for the amd64 architecture.
-func (c *amd64Compiler) setValueLocationStack(s *valueLocationStack) {
-	c.locationStack = s
+func requireAMD64(t *testing.T) {
+	if runtime.GOARCH != "amd64" {
+		t.Skip()
+	}
 }
 
 func TestAmd64Compiler_compile_Mul_Div_Rem(t *testing.T) {
+	requireAMD64(t)
+
 	for _, kind := range []wazeroir.OperationKind{
 		wazeroir.OperationKindMul,
 		wazeroir.OperationKindDiv,
@@ -291,6 +280,8 @@ func TestAmd64Compiler_compile_Mul_Div_Rem(t *testing.T) {
 }
 
 func TestAmd64Compiler_readInstructionAddress(t *testing.T) {
+	requireAMD64(t)
+
 	t.Run("invalid", func(t *testing.T) {
 		env := newJITEnvironment()
 		compiler := env.requireNewCompiler(t, nil).(*amd64Compiler)
diff --git a/internal/wasm/jit/jit_arm64_test.go b/internal/wasm/jit/jit_arm64_impl_test.go
similarity index 71%
rename from internal/wasm/jit/jit_arm64_test.go
rename to internal/wasm/jit/jit_arm64_impl_test.go
index 4595862d..488b43bb 100644
--- a/internal/wasm/jit/jit_arm64_test.go
+++ b/internal/wasm/jit/jit_arm64_impl_test.go
@@ -1,6 +1,7 @@
 package jit
 
 import (
+	"runtime"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -9,27 +10,10 @@ import (
 	"github.com/tetratelabs/wazero/internal/wazeroir"
 )
 
-// compile implements compilerImpl.valueLocationStack for the amd64 architecture.
-func (c *arm64Compiler) valueLocationStack() *valueLocationStack {
-	return c.locationStack
-}
-
-// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
-func (c *arm64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
-	return c.onStackPointerCeilDeterminedCallBack
-}
-
-// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
-func (c *arm64Compiler) setStackPointerCeil(v uint64) {
-	c.stackPointerCeil = v
-}
-
-// compile implements compilerImpl.setValueLocationStack for the amd64 architecture.
-func (c *arm64Compiler) setValueLocationStack(s *valueLocationStack) {
-	c.locationStack = s
-}
-
 func TestArm64Compiler_readInstructionAddress(t *testing.T) {
+	if runtime.GOARCH != "arm64" {
+		t.Skip()
+	}
 	t.Run("target instruction not found", func(t *testing.T) {
 		env := newJITEnvironment()
 		compiler := env.requireNewCompiler(t, nil).(*arm64Compiler)
@@ -38,7 +22,7 @@ func TestArm64Compiler_readInstructionAddress(t *testing.T) {
 		require.NoError(t, err)
 
 		// Set the acquisition target instruction to the one after JMP.
-		compiler.assembler.CompileReadInstructionAddress(reservedRegisterForTemporary, arm64.B)
+		compiler.assembler.CompileReadInstructionAddress(arm64ReservedRegisterForTemporary, arm64.B)
 
 		compiler.compileExitFromNativeCode(jitCallStatusCodeReturned)
 
@@ -56,7 +40,7 @@ func TestArm64Compiler_readInstructionAddress(t *testing.T) {
 		require.NoError(t, err)
 
 		// Set the acquisition target instruction to the one after RET.
-		compiler.assembler.CompileReadInstructionAddress(reservedRegisterForTemporary, arm64.RET)
+		compiler.assembler.CompileReadInstructionAddress(arm64ReservedRegisterForTemporary, arm64.RET)
 
 		// Add many instruction between the target and compileReadInstructionAddress.
 		for i := 0; i < 100; i++ {
@@ -64,7 +48,7 @@ func TestArm64Compiler_readInstructionAddress(t *testing.T) {
 			require.NoError(t, err)
 		}
 
-		compiler.assembler.CompileJumpToRegister(arm64.RET, reservedRegisterForTemporary)
+		compiler.assembler.CompileJumpToRegister(arm64.RET, arm64ReservedRegisterForTemporary)
 
 		err = compiler.compileReturnFunction()
 		require.NoError(t, err)
@@ -84,7 +68,7 @@ func TestArm64Compiler_readInstructionAddress(t *testing.T) {
 
 		// Set the acquisition target instruction to the one after RET,
 		// and read the absolute address into destinationRegister.
-		const addressReg = reservedRegisterForTemporary
+		const addressReg = arm64ReservedRegisterForTemporary
 		compiler.assembler.CompileReadInstructionAddress(addressReg, arm64.RET)
 
 		// Branch to the instruction after RET below via the absolute
diff --git a/internal/wasm/jit/jit_test.go b/internal/wasm/jit/jit_test.go
index 71d8b992..b724a9c9 100644
--- a/internal/wasm/jit/jit_test.go
+++ b/internal/wasm/jit/jit_test.go
@@ -171,6 +171,46 @@ type compilerImpl interface {
 	compileModuleContextInitialization() error
 }
 
+// compile implements compilerImpl.valueLocationStack for the amd64 architecture.
+func (c *arm64Compiler) valueLocationStack() *valueLocationStack {
+	return c.locationStack
+}
+
+// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
+func (c *arm64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
+	return c.onStackPointerCeilDeterminedCallBack
+}
+
+// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
+func (c *arm64Compiler) setStackPointerCeil(v uint64) {
+	c.stackPointerCeil = v
+}
+
+// compile implements compilerImpl.setValueLocationStack for the amd64 architecture.
+func (c *arm64Compiler) setValueLocationStack(s *valueLocationStack) {
+	c.locationStack = s
+}
+
+// compile implements compilerImpl.valueLocationStack for the amd64 architecture.
+func (c *amd64Compiler) valueLocationStack() *valueLocationStack {
+	return c.locationStack
+}
+
+// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
+func (c *amd64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
+	return c.onStackPointerCeilDeterminedCallBack
+}
+
+// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
+func (c *amd64Compiler) setStackPointerCeil(v uint64) {
+	c.stackPointerCeil = v
+}
+
+// compile implements compilerImpl.setValueLocationStack for the amd64 architecture.
+func (c *amd64Compiler) setValueLocationStack(s *valueLocationStack) {
+	c.locationStack = s
+}
+
 const defaultMemoryPageNumInTest = 1
 
 func newJITEnvironment() *jitEnv {