Bug 1439403 - General SpiderMonkey support for wasm on ARM64. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Fri, 23 Feb 2018 12:43:06 +0100
changeset 461302 a2507d4da91b3539dbd80b2d9e6c33d82c861cbc
parent 461301 ade8e3e4fbaf9a886c2454e8f5bc3202360e3af5
child 461303 f15ab7984211cc4252982b3e61bc75543e70a9a3
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1439403
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1439403 - General SpiderMonkey support for wasm on ARM64. r=bbouvier We introduce a few things to round out ARM64 support for wasm - add flags so as to support GetCPUID() - enable WASM_HUGE_MEMORY - remove the definition of HeapLenReg, it is not used except by a disused bounds checking method, which we also remove - add stubbed-out disassembler support so as to allow the signal handler code to compile and link when huge memory is enabled (stubs, because it is only required to work for asm.js, which is not supported by the baseline compiler)
js/src/jit/RegisterAllocator.h
js/src/jit/arm64/Architecture-arm64.cpp
js/src/jit/arm64/Architecture-arm64.h
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/arm64/Disassembler-arm64.cpp
js/src/jit/arm64/MacroAssembler-arm64.h
js/src/moz.build
js/src/wasm/WasmSignalHandlers.cpp
js/src/wasm/WasmTypes.cpp
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -351,22 +351,19 @@ class RegisterAllocator
         return outputOf(ins);
     }
 
     void dumpInstructions();
 
   public:
     template<typename TakeableSet>
     static void takeWasmRegisters(TakeableSet& regs) {
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
     defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
             regs.take(HeapReg);
-#elif defined(JS_CODEGEN_ARM64)
-            regs.take(HeapReg);
-            regs.take(HeapLenReg);
 #endif
             regs.take(FramePointer);
     }
 };
 
 static inline AnyRegister
 GetFixedRegister(const LDefinition* def, const LUse* use)
 {
--- a/js/src/jit/arm64/Architecture-arm64.cpp
+++ b/js/src/jit/arm64/Architecture-arm64.cpp
@@ -66,10 +66,16 @@ FloatRegister::GetPushSizeInBytes(const 
 
 uint32_t
 FloatRegister::getRegisterDumpOffsetInBytes()
 {
     // Although registers are 128-bits wide, only the first 64 need saving per ABI.
     return encoding() * sizeof(double);
 }
 
+uint32_t
+GetARM64Flags()
+{
+    return 0;
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm64/Architecture-arm64.h
+++ b/js/src/jit/arm64/Architecture-arm64.h
@@ -486,12 +486,14 @@ hasUnaliasedDouble()
 // ARM prior to ARMv8 also has doubles that alias multiple floats.
 // Again, ARMv8 is in the clear.
 inline bool
 hasMultiAlias()
 {
     return false;
 }
 
+uint32_t GetARM64Flags();
+
 } // namespace jit
 } // namespace js
 
 #endif // jit_arm64_Architecture_arm64_h
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -82,17 +82,16 @@ static constexpr Register IntArgReg0 { R
 static constexpr Register IntArgReg1 { Registers::x1 };
 static constexpr Register IntArgReg2 { Registers::x2 };
 static constexpr Register IntArgReg3 { Registers::x3 };
 static constexpr Register IntArgReg4 { Registers::x4 };
 static constexpr Register IntArgReg5 { Registers::x5 };
 static constexpr Register IntArgReg6 { Registers::x6 };
 static constexpr Register IntArgReg7 { Registers::x7 };
 static constexpr Register HeapReg { Registers::x21 };
-static constexpr Register HeapLenReg { Registers::x22 };
 
 // Define unsized Registers.
 #define DEFINE_UNSIZED_REGISTERS(N)  \
 static constexpr Register r##N { Registers::x##N };
 REGISTER_CODE_LIST(DEFINE_UNSIZED_REGISTERS)
 #undef DEFINE_UNSIZED_REGISTERS
 static constexpr Register ip0 { Registers::x16 };
 static constexpr Register ip1 { Registers::x16 };
new file mode 100644
--- /dev/null
+++ b/js/src/jit/arm64/Disassembler-arm64.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2018 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jit/Disassembler.h"
+
+MOZ_COLD uint8_t*
+js::jit::Disassembler::DisassembleHeapAccess(uint8_t*, js::jit::Disassembler::HeapAccess*)
+{
+    MOZ_CRASH("NYI - asm.js not supported yet on this platform");
+}
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -2022,39 +2022,16 @@ class MacroAssemblerCompat : public vixl
         const ARMRegister scratch32 = temps.AcquireW();
         MOZ_ASSERT(scratch32.asUnsized() != addr.base);
 
         load32(addr, scratch32.asUnsized());
         Add(scratch32, scratch32, Operand(1));
         store32(scratch32.asUnsized(), addr);
     }
 
-    void BoundsCheck(Register ptrReg, Label* onFail, vixl::CPURegister zeroMe = vixl::NoReg) {
-        // use tst rather than Tst to *ensure* that a single instrution is generated.
-        Cmp(ARMRegister(ptrReg, 32), ARMRegister(HeapLenReg, 32));
-        if (!zeroMe.IsNone()) {
-            if (zeroMe.IsRegister()) {
-                Csel(ARMRegister(zeroMe),
-                     ARMRegister(zeroMe),
-                     Operand(zeroMe.Is32Bits() ? vixl::wzr : vixl::xzr),
-                     Assembler::Below);
-            } else if (zeroMe.Is32Bits()) {
-                vixl::UseScratchRegisterScope temps(this);
-                const ARMFPRegister scratchFloat = temps.AcquireS();
-                Fmov(scratchFloat, JS::GenericNaN());
-                Fcsel(ARMFPRegister(zeroMe), ARMFPRegister(zeroMe), scratchFloat, Assembler::Below);
-            } else {
-                vixl::UseScratchRegisterScope temps(this);
-                const ARMFPRegister scratchDouble = temps.AcquireD();
-                Fmov(scratchDouble, JS::GenericNaN());
-                Fcsel(ARMFPRegister(zeroMe), ARMFPRegister(zeroMe), scratchDouble, Assembler::Below);
-            }
-        }
-        B(onFail, Assembler::AboveOrEqual);
-    }
     void breakpoint();
 
     // Emits a simulator directive to save the current sp on an internal stack.
     void simulatorMarkSP() {
 #ifdef JS_SIMULATOR_ARM64
         svc(vixl::kMarkStackPointer);
 #endif
     }
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -514,16 +514,17 @@ elif CONFIG['JS_CODEGEN_ARM']:
         ]
 elif CONFIG['JS_CODEGEN_ARM64']:
     UNIFIED_SOURCES += [
         'jit/arm64/Architecture-arm64.cpp',
         'jit/arm64/Assembler-arm64.cpp',
         'jit/arm64/Bailouts-arm64.cpp',
         'jit/arm64/BaselineIC-arm64.cpp',
         'jit/arm64/CodeGenerator-arm64.cpp',
+        'jit/arm64/Disassembler-arm64.cpp',
         'jit/arm64/Lowering-arm64.cpp',
         'jit/arm64/MacroAssembler-arm64.cpp',
         'jit/arm64/MoveEmitter-arm64.cpp',
         'jit/arm64/SharedIC-arm64.cpp',
         'jit/arm64/Trampoline-arm64.cpp',
         'jit/arm64/vixl/Assembler-vixl.cpp',
         'jit/arm64/vixl/Cpu-vixl.cpp',
         'jit/arm64/vixl/Decoder-vixl.cpp',
@@ -676,17 +677,17 @@ if CONFIG['JS_BUILD_BINAST']:
         SOURCES['frontend/BinSource.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
         SOURCES['frontend/BinToken.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
         SOURCES['frontend/BinTokenReaderTester.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
 
 # Wasm code should use WASM_HUGE_MEMORY instead of JS_CODEGEN_X64
 # so that it is easy to use the huge-mapping optimization for other
 # 64-bit platforms in the future.
 
-if CONFIG['JS_CODEGEN_X64']:
+if CONFIG['JS_CODEGEN_X64'] or CONFIG['JS_CODEGEN_ARM64']:
     DEFINES['WASM_HUGE_MEMORY'] = True
 
 if CONFIG['MOZ_DEBUG'] or CONFIG['NIGHTLY_BUILD']:
     DEFINES['JS_CACHEIR_SPEW'] = True
 
 # Also set in shell/moz.build
 DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
 
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -620,16 +620,17 @@ StoreValueFromGPReg(SharedMem<void*> add
 
 MOZ_COLD static void
 StoreValueFromGPImm(SharedMem<void*> addr, size_t size, int32_t imm)
 {
     MOZ_RELEASE_ASSERT(size <= sizeof(imm));
     AtomicOperations::memcpySafeWhenRacy(addr, static_cast<void*>(&imm), size);
 }
 
+#if defined(JS_CODEGEN_X64)
 # if !defined(XP_DARWIN)
 MOZ_COLD static void*
 AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
 {
     switch (encoding) {
       case X86Encoding::xmm0:  return &XMM_sig(context, 0);
       case X86Encoding::xmm1:  return &XMM_sig(context, 1);
       case X86Encoding::xmm2:  return &XMM_sig(context, 2);
@@ -721,16 +722,29 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::r13: return &context->thread.__r13;
       case X86Encoding::r14: return &context->thread.__r14;
       case X86Encoding::r15: return &context->thread.__r15;
       default: break;
     }
     MOZ_CRASH();
 }
 # endif  // !XP_DARWIN
+#elif defined(JS_CODEGEN_ARM64)
+MOZ_COLD static void*
+AddressOfFPRegisterSlot(EMULATOR_CONTEXT* context, FloatRegisters::Encoding encoding)
+{
+    MOZ_CRASH("NYI - asm.js not supported yet on this platform");
+}
+
+MOZ_COLD static void*
+AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
+{
+    MOZ_CRASH("NYI - asm.js not supported yet on this platform");
+}
+#endif
 
 MOZ_COLD static void
 SetRegisterToCoercedUndefined(EMULATOR_CONTEXT* context, size_t size,
                               const Disassembler::OtherOperand& value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         SetFPRegToNaN(size, AddressOfFPRegisterSlot(context, value.fpr()));
     else
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -27,21 +27,28 @@
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
 
 using mozilla::IsPowerOfTwo;
 using mozilla::MakeEnumeratedRange;
 
-// A sanity check.  We have only tested WASM_HUGE_MEMORY on x64, and only tested
-// x64 with WASM_HUGE_MEMORY.
+// We have only tested x64 with WASM_HUGE_MEMORY.
+
+#if defined(JS_CODEGEN_X64) && !defined(WASM_HUGE_MEMORY)
+#    error "Not an expected configuration"
+#endif
 
-#if defined(WASM_HUGE_MEMORY) != defined(JS_CODEGEN_X64)
-#  error "Not an expected configuration"
+// We have only tested WASM_HUGE_MEMORY on x64 and arm64.
+
+#if defined(WASM_HUGE_MEMORY)
+#  if !(defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64))
+#    error "Not an expected configuration"
+#  endif
 #endif
 
 // Another sanity check.
 
 static_assert(MaxMemoryInitialPages <= ArrayBufferObject::MaxBufferByteLength / PageSize,
               "Memory sizing constraint");
 
 void
@@ -97,30 +104,32 @@ static uint32_t
 GetCPUID()
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
         ARM = 0x3,
         MIPS = 0x4,
         MIPS64 = 0x5,
+        ARM64 = 0x6,
         ARCH_BITS = 3
     };
 
 #if defined(JS_CODEGEN_X86)
     MOZ_ASSERT(uint32_t(jit::CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS));
     return X86 | (uint32_t(jit::CPUInfo::GetSSEVersion()) << ARCH_BITS);
 #elif defined(JS_CODEGEN_X64)
     MOZ_ASSERT(uint32_t(jit::CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS));
     return X64 | (uint32_t(jit::CPUInfo::GetSSEVersion()) << ARCH_BITS);
 #elif defined(JS_CODEGEN_ARM)
     MOZ_ASSERT(jit::GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     return ARM | (jit::GetARMFlags() << ARCH_BITS);
 #elif defined(JS_CODEGEN_ARM64)
-    MOZ_CRASH("not enabled");
+    MOZ_ASSERT(jit::GetARM64Flags() <= (UINT32_MAX >> ARCH_BITS));
+    return ARM64 | (jit::GetARM64Flags() << ARCH_BITS);
 #elif defined(JS_CODEGEN_MIPS32)
     MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
     return MIPS | (jit::GetMIPSFlags() << ARCH_BITS);
 #elif defined(JS_CODEGEN_MIPS64)
     MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
     return MIPS64 | (jit::GetMIPSFlags() << ARCH_BITS);
 #elif defined(JS_CODEGEN_NONE)
     return 0;