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