From 5f04c30325785f4212624f26f85f7d6899f9522a Mon Sep 17 00:00:00 2001
From: Lars T Hansen <lhansen@mozilla.com>
Date: Thu, 9 Sep 2021 11:12:19 +0000
Subject: [PATCH] Bug 1728549 - Remove some platform dependencies in
 WasmBCMemory. r=jseward

Remove platform dependencies that depend only on whether the platform
has a HeapReg or not, by introducing a properly named #define for this
and rewriting the code slightly.

Introduce a RegIntptr alias to express integer-representing-pointer
appropriately on different platforms.

Introduce a templated move() method for register-to-register moves.

Drive-by cleanup:

Replace the overloaded free() methods for freeing registers with a
templated variant to match what we have for push, pop, need, and move.

Document the internal #defines that control the compiler.

Differential Revision: https://phabricator.services.mozilla.com/D124642
---
 js/src/wasm/WasmBCClass.h       |  22 +++----
 js/src/wasm/WasmBCCodegen-inl.h |  32 ++++++++++
 js/src/wasm/WasmBCDefs.h        |  45 +++++++++++++-
 js/src/wasm/WasmBCMemory.cpp    | 105 ++++++++++++++++----------------
 js/src/wasm/WasmBCRegDefs.h     |   8 +++
 js/src/wasm/WasmBCRegMgmt-inl.h |  50 ++++++++++++---
 6 files changed, 185 insertions(+), 77 deletions(-)

diff --git a/js/src/wasm/WasmBCClass.h b/js/src/wasm/WasmBCClass.h
index 898e13947463c..83805d44bd041 100644
--- a/js/src/wasm/WasmBCClass.h
+++ b/js/src/wasm/WasmBCClass.h
@@ -431,13 +431,8 @@ struct BaseCompiler final {
   inline void freeV128(RegV128 r);
 #endif
 
-  inline void free(RegI32 r);
-  inline void free(RegI64 r);
-  inline void free(RegF32 r);
-  inline void free(RegF64 r);
-#ifdef ENABLE_WASM_SIMD
-  inline void free(RegV128 r);
-#endif
+  template <typename RegType>
+  inline void free(RegType r);
 
   // Free r if it is not invalid.
   inline void maybeFree(RegI32 r);
@@ -945,6 +940,9 @@ struct BaseCompiler final {
   inline void moveV128(RegV128 src, RegV128 dest);
 #endif
 
+  template <typename RegType>
+  inline void move(RegType src, RegType dest);
+
   //////////////////////////////////////////////////////////////////////
   //
   // Immediate-to-register moves.
@@ -1053,17 +1051,13 @@ struct BaseCompiler final {
   void prepareMemoryAccess(MemoryAccessDesc* access, AccessCheck* check,
                            RegI32 tls, RegI32 ptr);
 
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
-    defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS64)
+#if defined(RABALDR_HAS_HEAPREG)
   BaseIndex prepareAtomicMemoryAccess(MemoryAccessDesc* access,
                                       AccessCheck* check, RegI32 tls,
                                       RegI32 ptr);
-#elif defined(JS_CODEGEN_X86)
-  // Some consumers depend on the address not retaining tls, as tls may be the
-  // scratch register.
-  Address prepareAtomicMemoryAccess(MemoryAccessDesc* access,
-                                    AccessCheck* check, RegI32 tls, RegI32 ptr);
 #else
+  // Some consumers depend on the returned Address not incorporating tls, as tls
+  // may be the scratch register.
   Address prepareAtomicMemoryAccess(MemoryAccessDesc* access,
                                     AccessCheck* check, RegI32 tls, RegI32 ptr);
 #endif
diff --git a/js/src/wasm/WasmBCCodegen-inl.h b/js/src/wasm/WasmBCCodegen-inl.h
index a6f49dab5f2bf..ef2e86107958a 100644
--- a/js/src/wasm/WasmBCCodegen-inl.h
+++ b/js/src/wasm/WasmBCCodegen-inl.h
@@ -71,6 +71,38 @@ void BaseCompiler::moveV128(RegV128 src, RegV128 dest) {
 }
 #endif
 
+template <>
+inline void BaseCompiler::move<RegI32>(RegI32 src, RegI32 dest) {
+  moveI32(src, dest);
+}
+
+template <>
+inline void BaseCompiler::move<RegI64>(RegI64 src, RegI64 dest) {
+  moveI64(src, dest);
+}
+
+template <>
+inline void BaseCompiler::move<RegF32>(RegF32 src, RegF32 dest) {
+  moveF32(src, dest);
+}
+
+template <>
+inline void BaseCompiler::move<RegF64>(RegF64 src, RegF64 dest) {
+  moveF64(src, dest);
+}
+
+template <>
+inline void BaseCompiler::move<RegRef>(RegRef src, RegRef dest) {
+  moveRef(src, dest);
+}
+
+#ifdef ENABLE_WASM_SIMD
+template <>
+inline void BaseCompiler::move<RegV128>(RegV128 src, RegV128 dest) {
+  moveV128(src, dest);
+}
+#endif
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // Constant loads.
diff --git a/js/src/wasm/WasmBCDefs.h b/js/src/wasm/WasmBCDefs.h
index d0cfc847c22ad..7f70902d9bed0 100644
--- a/js/src/wasm/WasmBCDefs.h
+++ b/js/src/wasm/WasmBCDefs.h
@@ -105,10 +105,47 @@ enum class UseABI { Wasm, Builtin, System };
 enum class InterModule { False = false, True = true };
 enum class RhsDestOp { True = true };
 
-// Misc config
+// Compiler configuration.
+//
+// The following internal configuration #defines are used.  The configuration is
+// partly below in this file, partly in WasmBCRegDefs.h.
+//
+// RABALDR_HAS_HEAPREG
+//   The platform has a dedicated HeapReg.
+//
+// RABALDR_CHUNKY_STACK
+//   The platform must allocate the CPU stack in chunks and not word-at-a-time
+//   due to SP alignment requirements (ARM64 for now).
+//
+// RABALDR_INT_DIV_I64_CALLOUT
+//   The platform calls out to the runtime to divide i64/u64.
+//
+// RABALDR_I64_TO_FLOAT_CALLOUT
+//   The platform calls out to the runtime for i64 -> fXX conversions.
+//
+// RABALDR_FLOAT_TO_I64_CALLOUT
+//   The platform calls out to the runtime for fXX -> i64 conversions.
+//
+// RABALDR_SCRATCH_<TypeName>
+//   The baseline compiler has its own scratch registers for the given type, it
+//   does not use the MacroAssembler's scratch.  This is really an anachronism -
+//   the baseline compiler should never use the MacroAssembler's scratches.
+//
+// RABALDR_SCRATCH_F32_ALIASES_F64
+//   On a platform where the baseline compiler has its own F32 and F64
+//   scratches, these are the same register.
+
+#ifdef JS_CODEGEN_X64
+#  define RABALDR_HAS_HEAPREG
+#endif
 
 #ifdef JS_CODEGEN_ARM64
 #  define RABALDR_CHUNKY_STACK
+#  define RABALDR_HAS_HEAPREG
+#endif
+
+#ifdef JS_CODEGEN_MIPS64
+#  define RABALDR_HAS_HEAPREG
 #endif
 
 #ifdef JS_CODEGEN_X86
@@ -116,11 +153,17 @@ enum class RhsDestOp { True = true };
 #endif
 
 #ifdef JS_CODEGEN_ARM
+#  define RABALDR_HAS_HEAPREG
 #  define RABALDR_INT_DIV_I64_CALLOUT
 #  define RABALDR_I64_TO_FLOAT_CALLOUT
 #  define RABALDR_FLOAT_TO_I64_CALLOUT
 #endif
 
+#ifdef JS_CODEGEN_NONE
+// Easier this way
+#  define RABALDR_HAS_HEAPREG
+#endif
+
 // Max number of pushes onto the value stack for any opcode or emitter that
 // does not push a variable, unbounded amount (anything with multiple
 // results).  This includes also intermediate pushes such as values pushed as
diff --git a/js/src/wasm/WasmBCMemory.cpp b/js/src/wasm/WasmBCMemory.cpp
index 509894464b6b1..97833f861bf6b 100644
--- a/js/src/wasm/WasmBCMemory.cpp
+++ b/js/src/wasm/WasmBCMemory.cpp
@@ -33,6 +33,14 @@
 namespace js {
 namespace wasm {
 
+#ifndef RABALDR_HAS_HEAPREG
+#  ifdef JS_CODEGEN_X86
+using ScratchAtomicNoHeapReg = ScratchEBX;
+#  else
+#    error "Unimplemented porting interface"
+#  endif
+#endif
+
 template <size_t Count>
 void Atomic32Temps<Count>::allocate(BaseCompiler* bc, size_t allocate) {
   static_assert(Count != 0);
@@ -179,25 +187,20 @@ RegI32 BaseCompiler::popMemory32Access(MemoryAccessDesc* access,
   return popI32();
 }
 
+#ifdef RABALDR_HAS_HEAPREG
 void BaseCompiler::pushHeapBase() {
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64) || \
-    defined(JS_CODEGEN_MIPS64)
-  RegI64 heapBase = needI64();
-  moveI64(RegI64(Register64(HeapReg)), heapBase);
-  pushI64(heapBase);
-#elif defined(JS_CODEGEN_ARM)
-  RegI32 heapBase = needI32();
-  moveI32(RegI32(HeapReg), heapBase);
-  pushI32(heapBase);
-#elif defined(JS_CODEGEN_X86)
-  RegI32 heapBase = needI32();
+  RegIntptr heapBase = need<RegIntptr>();
+  move(RegIntptr(RegIntptrRegister(HeapReg)), heapBase);
+  push(heapBase);
+}
+#else
+void BaseCompiler::pushHeapBase() {
+  RegIntptr heapBase = need<RegIntptr>();
   fr.loadTlsPtr(heapBase);
   masm.loadPtr(Address(heapBase, offsetof(TlsData, memoryBase)), heapBase);
-  pushI32(heapBase);
-#else
-  MOZ_CRASH("BaseCompiler platform hook: pushHeapBase");
-#endif
+  push(heapBase);
 }
+#endif
 
 void BaseCompiler::prepareMemoryAccess(MemoryAccessDesc* access,
                                        AccessCheck* check, RegI32 tls,
@@ -295,8 +298,7 @@ void BaseCompiler::prepareMemoryAccess(MemoryAccessDesc* access,
   }
 }
 
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
-    defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS64)
+#ifdef RABALDR_HAS_HEAPREG
 BaseIndex BaseCompiler::prepareAtomicMemoryAccess(MemoryAccessDesc* access,
                                                   AccessCheck* check,
                                                   RegI32 tls, RegI32 ptr) {
@@ -304,10 +306,9 @@ BaseIndex BaseCompiler::prepareAtomicMemoryAccess(MemoryAccessDesc* access,
   prepareMemoryAccess(access, check, tls, ptr);
   return BaseIndex(HeapReg, ptr, TimesOne, access->offset());
 }
-#elif defined(JS_CODEGEN_X86)
-// Some consumers depend on the address not retaining tls, as tls may be the
-// scratch register.
-
+#else
+// Some consumers depend on the returned Address not incorporating tls, as tls
+// may be the scratch register.
 Address BaseCompiler::prepareAtomicMemoryAccess(MemoryAccessDesc* access,
                                                 AccessCheck* check, RegI32 tls,
                                                 RegI32 ptr) {
@@ -316,12 +317,6 @@ Address BaseCompiler::prepareAtomicMemoryAccess(MemoryAccessDesc* access,
   masm.addPtr(Address(tls, offsetof(TlsData, memoryBase)), ptr);
   return Address(ptr, access->offset());
 }
-#else
-Address BaseCompiler::prepareAtomicMemoryAccess(MemoryAccessDesc* access,
-                                                AccessCheck* check, RegI32 tls,
-                                                RegI32 ptr) {
-  MOZ_CRASH("BaseCompiler platform hook: prepareAtomicMemoryAccess");
-}
 #endif
 
 void BaseCompiler::computeEffectiveAddress(MemoryAccessDesc* access) {
@@ -1175,16 +1170,16 @@ bool BaseCompiler::atomicCmpXchg(MemoryAccessDesc* access, ValType type) {
   AccessCheck check;
   RegI32 rp = popMemory32Access(access, &check);
 
-#ifdef JS_CODEGEN_X86
-  ScratchEBX ebx(*this);
-  RegI32 tls = maybeLoadTlsForAccess(check, ebx);
-  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
-  regs.atomicCmpXchg64(*access, memaddr, ebx);
-#else
+#ifdef RABALDR_HAS_HEAPREG
   RegI32 tls = maybeLoadTlsForAccess(check);
   auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
   regs.atomicCmpXchg64(*access, memaddr);
   maybeFree(tls);
+#else
+  ScratchAtomicNoHeapReg scratch(*this);
+  RegI32 tls = maybeLoadTlsForAccess(check, scratch);
+  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
+  regs.atomicCmpXchg64(*access, memaddr, scratch);
 #endif
 
   freeI32(rp);
@@ -1209,16 +1204,16 @@ bool BaseCompiler::atomicLoad(MemoryAccessDesc* access, ValType type) {
   AccessCheck check;
   RegI32 rp = popMemory32Access(access, &check);
 
-#  ifdef JS_CODEGEN_X86
-  ScratchEBX ebx(*this);
-  RegI32 tls = maybeLoadTlsForAccess(check, ebx);
-  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
-  regs.atomicLoad64(*access, memaddr, ebx);
-#  else
+#  ifdef RABALDR_HAS_HEAPREG
   RegI32 tls = maybeLoadTlsForAccess(check);
   auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
   regs.atomicLoad64(*access, memaddr);
   maybeFree(tls);
+#  else
+  ScratchAtomicNoHeapReg scratch(*this);
+  RegI32 tls = maybeLoadTlsForAccess(check, scratch);
+  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
+  regs.atomicLoad64(*access, memaddr, scratch);
 #  endif
 
   freeI32(rp);
@@ -1260,23 +1255,25 @@ bool BaseCompiler::atomicRMW(MemoryAccessDesc* access, ValType type,
   AccessCheck check;
   RegI32 rp = popMemory32Access(access, &check);
 
-#ifdef JS_CODEGEN_X86
-  ScratchEBX ebx(*this);
-  RegI32 tls = maybeLoadTlsForAccess(check, ebx);
+#if defined(RABALDR_HAS_HEAPREG)
+  RegI32 tls = maybeLoadTlsForAccess(check);
+  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
+  regs.atomicRMW64(*access, memaddr, op);
+  maybeFree(tls);
+#elif !defined(JS_64BIT)
+  ScratchAtomicNoHeapReg scratch(*this);
+  RegI32 tls = maybeLoadTlsForAccess(check, scratch);
 
   fr.pushGPR(regs.valueHigh());
   fr.pushGPR(regs.valueLow());
-  Address value(esp, 0);
+  Address value(StackPointer, 0);
 
   auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
-  regs.atomicRMW64(*access, memaddr, op, value, ebx);
+  regs.atomicRMW64(*access, memaddr, op, value, scratch);
 
   fr.popBytes(8);
 #else
-  RegI32 tls = maybeLoadTlsForAccess(check);
-  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
-  regs.atomicRMW64(*access, memaddr, op);
-  maybeFree(tls);
+  MOZ_CRASH("Unexpected combination");
 #endif
 
   freeI32(rp);
@@ -1339,16 +1336,16 @@ void BaseCompiler::emitAtomicXchg64(MemoryAccessDesc* access,
   AccessCheck check;
   RegI32 rp = popMemory32Access(access, &check);
 
-#ifdef JS_CODEGEN_X86
-  ScratchEBX ebx(*this);
-  RegI32 tls = maybeLoadTlsForAccess(check, ebx);
-  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
-  regs.atomicXchg64(*access, memaddr, ebx);
-#else
+#ifdef RABALDR_HAS_HEAPREG
   RegI32 tls = maybeLoadTlsForAccess(check);
   auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
   regs.atomicXchg64(*access, memaddr);
   maybeFree(tls);
+#else
+  ScratchAtomicNoHeapReg scratch(*this);
+  RegI32 tls = maybeLoadTlsForAccess(check, scratch);
+  auto memaddr = prepareAtomicMemoryAccess(access, &check, tls, rp);
+  regs.atomicXchg64(*access, memaddr, scratch);
 #endif
 
   freeI32(rp);
diff --git a/js/src/wasm/WasmBCRegDefs.h b/js/src/wasm/WasmBCRegDefs.h
index 7b36a543e3d0e..79b12e46971dd 100644
--- a/js/src/wasm/WasmBCRegDefs.h
+++ b/js/src/wasm/WasmBCRegDefs.h
@@ -330,6 +330,14 @@ struct AnyReg {
   }
 };
 
+#ifdef JS_64BIT
+using RegIntptr = RegI64;
+using RegIntptrRegister = Register64;
+#else
+using RegIntptr = RegI32;
+using RegIntptrRegister = Register;
+#endif
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // Platform-specific registers.
diff --git a/js/src/wasm/WasmBCRegMgmt-inl.h b/js/src/wasm/WasmBCRegMgmt-inl.h
index 87c6fce2b4f98..8311f4f667956 100644
--- a/js/src/wasm/WasmBCRegMgmt-inl.h
+++ b/js/src/wasm/WasmBCRegMgmt-inl.h
@@ -69,14 +69,6 @@ void BaseCompiler::freeF64(RegF64 r) { ra.freeF64(r); }
 void BaseCompiler::freeV128(RegV128 r) { ra.freeV128(r); }
 #endif
 
-void BaseCompiler::free(RegI32 r) { freeI32(r); }
-void BaseCompiler::free(RegI64 r) { freeI64(r); }
-void BaseCompiler::free(RegF32 r) { freeF32(r); }
-void BaseCompiler::free(RegF64 r) { freeF64(r); }
-#ifdef ENABLE_WASM_SIMD
-void BaseCompiler::free(RegV128 r) { freeV128(r); }
-#endif
-
 void BaseCompiler::freeAny(AnyReg r) {
   switch (r.tag) {
     case AnyReg::I32:
@@ -104,6 +96,48 @@ void BaseCompiler::freeAny(AnyReg r) {
   }
 }
 
+template <>
+inline void BaseCompiler::free<RegI32>(RegI32 r) {
+  freeI32(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegI64>(RegI64 r) {
+  freeI64(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegRef>(RegRef r) {
+  freeRef(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegPtr>(RegPtr r) {
+  freePtr(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegF32>(RegF32 r) {
+  freeF32(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegF64>(RegF64 r) {
+  freeF64(r);
+}
+
+#ifdef ENABLE_WASM_SIMD
+template <>
+inline void BaseCompiler::free<RegV128>(RegV128 r) {
+  freeV128(r);
+}
+#endif
+
+template <>
+inline void BaseCompiler::free<AnyReg>(AnyReg r) {
+  freeAny(r);
+}
+
 void BaseCompiler::freeI64Except(RegI64 r, RegI32 except) {
 #ifdef JS_PUNBOX64
   MOZ_ASSERT(r.reg == except);
-- 
GitLab