From 489904c774e4fc24abdee417b9e87d478d407715 Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Wed, 13 Aug 2014 01:12:00 +1000 Subject: [PATCH] Bug 1050254 - OdinMonkey: Place NaN in the global data and load from here to free the NANReg. r=luke --- js/src/asmjs/AsmJSLink.cpp | 2 ++ js/src/asmjs/AsmJSModule.h | 32 ++++++++++++++++++++++---- js/src/asmjs/AsmJSValidate.cpp | 4 +--- js/src/jit/RegisterAllocator.h | 2 -- js/src/jit/arm/Assembler-arm.h | 2 -- js/src/jit/arm/CodeGenerator-arm.cpp | 4 ++-- js/src/jit/mips/Assembler-mips.h | 2 -- js/src/jit/mips/CodeGenerator-mips.cpp | 4 ++-- js/src/jit/shared/Assembler-shared.h | 6 +++-- 9 files changed, 39 insertions(+), 19 deletions(-) diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 2e52f41bb5c4..fc25b0aa71d3 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -342,6 +342,8 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module) for (unsigned i = 0; i < module.numExits(); i++) module.exitIndexToGlobalDatum(i).fun = &ffis[module.exit(i).ffiIndex()]->as(); + module.initGlobalNaN(); + return true; } diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 53d75d198ccc..291c97de303b 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -33,12 +33,15 @@ # include "jit/PerfSpewer.h" #endif #include "jit/RegisterSets.h" +#include "jit/shared/Assembler-shared.h" #include "vm/TypedArrayObject.h" namespace js { namespace frontend { class TokenStream; } +using JS::GenericNaN; + // These EcmaScript-defined coercions form the basis of the asm.js type system. enum AsmJSCoercion { @@ -1042,8 +1045,10 @@ class AsmJSModule // are laid out in this order: // 0. a pointer to the current AsmJSActivation // 1. a pointer to the heap that was linked to the module - // 2. global variable state (elements are sizeof(uint64_t)) - // 3. interleaved function-pointer tables and exits. These are allocated + // 2. the double float constant NaN. + // 3. the float32 constant NaN, padded to sizeof(double). + // 4. global variable state (elements are sizeof(uint64_t)) + // 5. interleaved function-pointer tables and exits. These are allocated // while type checking function bodies (as exits and uses of // function-pointer tables are encountered). size_t offsetOfGlobalData() const { @@ -1057,6 +1062,8 @@ class AsmJSModule size_t globalDataBytes() const { return sizeof(void*) + sizeof(void*) + + sizeof(double) + + sizeof(double) + pod.numGlobalVars_ * sizeof(uint64_t) + pod.funcPtrTableAndExitBytes_; } @@ -1077,9 +1084,26 @@ class AsmJSModule JS_ASSERT(isFinished()); return *(uint8_t**)(globalData() + heapGlobalDataOffset()); } + static unsigned nan64GlobalDataOffset() { + static_assert(jit::AsmJSNaN64GlobalDataOffset % sizeof(double) == 0, + "Global data NaN should be aligned"); + return heapGlobalDataOffset() + sizeof(void*); + } + static unsigned nan32GlobalDataOffset() { + static_assert(jit::AsmJSNaN32GlobalDataOffset % sizeof(double) == 0, + "Global data NaN should be aligned"); + return nan64GlobalDataOffset() + sizeof(double); + } + void initGlobalNaN() { + MOZ_ASSERT(jit::AsmJSNaN64GlobalDataOffset == nan64GlobalDataOffset()); + MOZ_ASSERT(jit::AsmJSNaN32GlobalDataOffset == nan32GlobalDataOffset()); + *(double *)(globalData() + nan64GlobalDataOffset()) = GenericNaN(); + *(float *)(globalData() + nan32GlobalDataOffset()) = GenericNaN(); + } unsigned globalVariableOffset() const { - static_assert((2 * sizeof(void*)) % sizeof(double) == 0, "Global data should be aligned"); - return 2 * sizeof(void*); + static_assert((2 * sizeof(void*) + 2 * sizeof(double)) % sizeof(double) == 0, + "Global data should be aligned"); + return 2 * sizeof(void*) + 2 * sizeof(double); } unsigned globalVarIndexToGlobalDataOffset(unsigned i) const { JS_ASSERT(isFinishedWithModulePrologue()); diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 679541e76f24..975727560872 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -5985,11 +5985,9 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) JS_ASSERT(masm.framePushed() == FramePushedAfterSave); // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative - // addressing, x86 uses immediates in effective addresses) and NaN register - // (used as part of the out-of-bounds handling in heap loads/stores). + // addressing, x86 uses immediates in effective addresses). #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) masm.movePtr(IntArgReg1, GlobalReg); - masm.loadConstantDouble(GenericNaN(), NANReg); #endif // ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in diff --git a/js/src/jit/RegisterAllocator.h b/js/src/jit/RegisterAllocator.h index 2bd155e6a4b9..1c528f6b0035 100644 --- a/js/src/jit/RegisterAllocator.h +++ b/js/src/jit/RegisterAllocator.h @@ -319,8 +319,6 @@ class RegisterAllocator #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) allRegisters_.take(AnyRegister(HeapReg)); allRegisters_.take(AnyRegister(GlobalReg)); - // Need to remove both NANReg, and its aliases. - allRegisters_.takeAllAliasedUnchecked(AnyRegister(NANReg)); #endif } else { if (FramePointer != InvalidReg && mir->instrumentedProfiling()) diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 6df011a92cbc..ab004a1f7d25 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -102,8 +102,6 @@ static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = InvalidFloatReg; static MOZ_CONSTEXPR_VAR FloatRegister ScratchUIntReg = { FloatRegisters::d15, VFPRegister::UInt }; static MOZ_CONSTEXPR_VAR FloatRegister ScratchIntReg = { FloatRegisters::d15, VFPRegister::Int }; -static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::d14, VFPRegister::Double }; - // Registers used in the GenerateFFIIonExit Enable Activation block. static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r4; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = r0; diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 4511f52760da..56479e70da78 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -1835,10 +1835,10 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) FloatRegister dst = ToFloatRegister(ins->output()); VFPRegister vd(dst); if (size == 32) { - masm.convertDoubleToFloat32(NANReg, dst, Assembler::AboveOrEqual); + masm.ma_vldr(Operand(GlobalReg, AsmJSNaN32GlobalDataOffset), vd.singleOverlay(), Assembler::AboveOrEqual); masm.ma_vldr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Below); } else { - masm.ma_vmov(NANReg, dst, Assembler::AboveOrEqual); + masm.ma_vldr(Operand(GlobalReg, AsmJSNaN64GlobalDataOffset), vd, Assembler::AboveOrEqual); masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Below); } } else { diff --git a/js/src/jit/mips/Assembler-mips.h b/js/src/jit/mips/Assembler-mips.h index 7f87a0df4d1e..f3b32b8bfc6f 100644 --- a/js/src/jit/mips/Assembler-mips.h +++ b/js/src/jit/mips/Assembler-mips.h @@ -116,8 +116,6 @@ static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 }; static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 }; static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 }; -static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 }; - // Registers used in the GenerateFFIIonExit Enable Activation block. static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = t0; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = a0; diff --git a/js/src/jit/mips/CodeGenerator-mips.cpp b/js/src/jit/mips/CodeGenerator-mips.cpp index f39c54701ecb..05d60bf49c2c 100644 --- a/js/src/jit/mips/CodeGenerator-mips.cpp +++ b/js/src/jit/mips/CodeGenerator-mips.cpp @@ -1954,9 +1954,9 @@ CodeGeneratorMIPS::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) // Offset is out of range. Load default values. if (isFloat) { if (size == 32) - masm.convertDoubleToFloat32(NANReg, ToFloatRegister(out)); + masm.loadFloat32(Address(GlobalReg, AsmJSNaN32GlobalDataOffset), ToFloatRegister(out)); else - masm.moveDouble(NANReg, ToFloatRegister(out)); + masm.loadDouble(Address(GlobalReg, AsmJSNaN64GlobalDataOffset), ToFloatRegister(out)); } else { masm.move32(Imm32(0), ToRegister(out)); } diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 324cd018bd32..038fd421b799 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -659,9 +659,11 @@ struct AsmJSFrame static_assert(sizeof(AsmJSFrame) == 2 * sizeof(void*), "?!"); static const uint32_t AsmJSFrameBytesAfterReturnAddress = sizeof(void*); -// A hoisting of AsmJSModule::activationGlobalDataOffset that avoids #including -// AsmJSModule everywhere. +// A hoisting of constants that would otherwise require #including AsmJSModule.h +// everywhere. Values are asserted in AsmJSModule.h. static const unsigned AsmJSActivationGlobalDataOffset = 0; +static const unsigned AsmJSNaN64GlobalDataOffset = 2 * sizeof(void*); +static const unsigned AsmJSNaN32GlobalDataOffset = 2 * sizeof(void*) + sizeof(double); // Summarizes a heap access made by asm.js code that needs to be patched later // and/or looked up by the asm.js signal handlers. Different architectures need