Verify the contents of AssemblerBuffer on arm64e
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Sep 2018 05:34:38 +0000 (05:34 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Sep 2018 05:34:38 +0000 (05:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190057
<rdar://problem/38916630>

Reviewed by Mark Lam.

JSTests:

* stress/regress-189132.js:

Source/JavaScriptCore:

* assembler/ARM64Assembler.h:
(JSC::ARM64Assembler::ARM64Assembler):
(JSC::ARM64Assembler::fillNops):
(JSC::ARM64Assembler::link):
(JSC::ARM64Assembler::linkJumpOrCall):
(JSC::ARM64Assembler::linkCompareAndBranch):
(JSC::ARM64Assembler::linkConditionalBranch):
(JSC::ARM64Assembler::linkTestAndBranch):
(JSC::ARM64Assembler::unlinkedCode): Deleted.
* assembler/ARMAssembler.h:
(JSC::ARMAssembler::fillNops):
* assembler/ARMv7Assembler.h:
(JSC::ARMv7Assembler::unlinkedCode): Deleted.
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::emitNops):
(JSC::AbstractMacroAssembler::AbstractMacroAssembler):
* assembler/AssemblerBuffer.h:
(JSC::ARM64EHash::ARM64EHash):
(JSC::ARM64EHash::update):
(JSC::ARM64EHash::hash const):
(JSC::ARM64EHash::randomSeed const):
(JSC::AssemblerBuffer::AssemblerBuffer):
(JSC::AssemblerBuffer::putShort):
(JSC::AssemblerBuffer::putIntUnchecked):
(JSC::AssemblerBuffer::putInt):
(JSC::AssemblerBuffer::hash const):
(JSC::AssemblerBuffer::data const):
(JSC::AssemblerBuffer::putIntegralUnchecked):
(JSC::AssemblerBuffer::append): Deleted.
* assembler/LinkBuffer.cpp:
(JSC::LinkBuffer::copyCompactAndLinkCode):
* assembler/MIPSAssembler.h:
(JSC::MIPSAssembler::fillNops):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::jumpsToLink):
(JSC::MacroAssemblerARM64::link):
(JSC::MacroAssemblerARM64::unlinkedCode): Deleted.
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::jumpsToLink):
(JSC::MacroAssemblerARMv7::unlinkedCode): Deleted.
* assembler/X86Assembler.h:
(JSC::X86Assembler::fillNops):

Source/WTF:

* wtf/PtrTag.h:
(WTF::tagInt):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236589 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
JSTests/ChangeLog
JSTests/stress/regress-189132.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/ARM64Assembler.h
Source/JavaScriptCore/assembler/ARMAssembler.h
Source/JavaScriptCore/assembler/ARMv7Assembler.h
Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
Source/JavaScriptCore/assembler/AssemblerBuffer.h
Source/JavaScriptCore/assembler/LinkBuffer.cpp
Source/JavaScriptCore/assembler/MIPSAssembler.h
Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/WTF/ChangeLog
Source/WTF/wtf/PtrTag.h

index eca4797..affb26e 100644 (file)
@@ -1,3 +1,13 @@
+2018-09-27  Saam barati  <sbarati@apple.com>
+
+        Verify the contents of AssemblerBuffer on arm64e
+        https://bugs.webkit.org/show_bug.cgi?id=190057
+        <rdar://problem/38916630>
+
+        Reviewed by Mark Lam.
+
+        * stress/regress-189132.js:
+
 2018-09-27  Dominik Infuehr  <dinfuehr@igalia.com>
 
         Disable test without LLInt on ARMv7
index dca0287..cd0e579 100644 (file)
@@ -1,3 +1,5 @@
+//@ skip if $memoryLimited
+
 try {
     var a0 = '\ud801';
     var a1 = [];
index f063ffc..4e5e8ab 100644 (file)
@@ -1,3 +1,54 @@
+2018-09-27  Saam barati  <sbarati@apple.com>
+
+        Verify the contents of AssemblerBuffer on arm64e
+        https://bugs.webkit.org/show_bug.cgi?id=190057
+        <rdar://problem/38916630>
+
+        Reviewed by Mark Lam.
+
+        * assembler/ARM64Assembler.h:
+        (JSC::ARM64Assembler::ARM64Assembler):
+        (JSC::ARM64Assembler::fillNops):
+        (JSC::ARM64Assembler::link):
+        (JSC::ARM64Assembler::linkJumpOrCall):
+        (JSC::ARM64Assembler::linkCompareAndBranch):
+        (JSC::ARM64Assembler::linkConditionalBranch):
+        (JSC::ARM64Assembler::linkTestAndBranch):
+        (JSC::ARM64Assembler::unlinkedCode): Deleted.
+        * assembler/ARMAssembler.h:
+        (JSC::ARMAssembler::fillNops):
+        * assembler/ARMv7Assembler.h:
+        (JSC::ARMv7Assembler::unlinkedCode): Deleted.
+        * assembler/AbstractMacroAssembler.h:
+        (JSC::AbstractMacroAssembler::emitNops):
+        (JSC::AbstractMacroAssembler::AbstractMacroAssembler):
+        * assembler/AssemblerBuffer.h:
+        (JSC::ARM64EHash::ARM64EHash):
+        (JSC::ARM64EHash::update):
+        (JSC::ARM64EHash::hash const):
+        (JSC::ARM64EHash::randomSeed const):
+        (JSC::AssemblerBuffer::AssemblerBuffer):
+        (JSC::AssemblerBuffer::putShort):
+        (JSC::AssemblerBuffer::putIntUnchecked):
+        (JSC::AssemblerBuffer::putInt):
+        (JSC::AssemblerBuffer::hash const):
+        (JSC::AssemblerBuffer::data const):
+        (JSC::AssemblerBuffer::putIntegralUnchecked):
+        (JSC::AssemblerBuffer::append): Deleted.
+        * assembler/LinkBuffer.cpp:
+        (JSC::LinkBuffer::copyCompactAndLinkCode):
+        * assembler/MIPSAssembler.h:
+        (JSC::MIPSAssembler::fillNops):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::jumpsToLink):
+        (JSC::MacroAssemblerARM64::link):
+        (JSC::MacroAssemblerARM64::unlinkedCode): Deleted.
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::jumpsToLink):
+        (JSC::MacroAssemblerARMv7::unlinkedCode): Deleted.
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::fillNops):
+
 2018-09-27  Mark Lam  <mark.lam@apple.com>
 
         ByValInfo should not use integer offsets.
index ff22362..db2c557 100644 (file)
@@ -322,9 +322,17 @@ protected:
     static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
 
 public:
-    ARM64Assembler()
+    ARM64Assembler(
+#if CPU(ARM64E)
+        unsigned randomNumber
+#endif 
+        )
         : m_indexOfLastWatchpoint(INT_MIN)
         , m_indexOfTailOfLastWatchpoint(INT_MIN)
+#if CPU(ARM64E)
+        , m_buffer(randomNumber)
+#endif
+        
     {
     }
     
@@ -1558,17 +1566,15 @@ public:
         insn(nopPseudo());
     }
     
-    static void fillNops(void* base, size_t size, bool isCopyingToExecutableMemory)
+    template <typename CopyFunction>
+    static void fillNops(void* base, size_t size, CopyFunction copy)
     {
         RELEASE_ASSERT(!(size % sizeof(int32_t)));
         size_t n = size / sizeof(int32_t);
         for (int32_t* ptr = static_cast<int32_t*>(base); n--;) {
             int insn = nopPseudo();
-            if (isCopyingToExecutableMemory) {
-                RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(ptr) == ptr);
-                performJITMemcpy(ptr++, &insn, sizeof(int));
-            } else
-                memcpy(ptr++, &insn, sizeof(int));
+            RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(ptr) == ptr);
+            copy(ptr++, &insn, sizeof(int));
         }
     }
     
@@ -2573,7 +2579,6 @@ public:
         return b.m_offset - a.m_offset;
     }
 
-    void* unlinkedCode() { return m_buffer.data(); }
     size_t codeSize() const { return m_buffer.codeSize(); }
 
     static unsigned getCallReturnOffset(AssemblerLabel call)
@@ -2611,13 +2616,6 @@ public:
         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, bitNumber, compareRegister));
     }
 
-    void linkJump(AssemblerLabel from, void* executableCode, AssemblerLabel to)
-    {
-        ASSERT(from.isSet());
-        ASSERT(to.isSet());
-        relinkJumpOrCall<false>(addressOf(from), addressOf(executableCode, from), addressOf(to));
-    }
-    
     static void linkJump(void* code, AssemblerLabel from, void* to)
     {
         ASSERT(from.isSet());
@@ -2977,30 +2975,32 @@ public:
         return m_jumpsToLink;
     }
 
-    static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction8, uint8_t* to)
+    typedef void* (*CopyFunction)(void*, const void*, size_t);
+
+    static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction8, uint8_t* to, CopyFunction copy)
     {
         const int* fromInstruction = reinterpret_cast<const int*>(fromInstruction8);
         switch (record.linkType()) {
         case LinkJumpNoCondition:
-            linkJumpOrCall<false>(reinterpret_cast<int*>(from), fromInstruction, to);
+            linkJumpOrCall<false>(reinterpret_cast<int*>(from), fromInstruction, to, copy);
             break;
         case LinkJumpConditionDirect:
-            linkConditionalBranch<true>(record.condition(), reinterpret_cast<int*>(from), fromInstruction, to);
+            linkConditionalBranch<true>(record.condition(), reinterpret_cast<int*>(from), fromInstruction, to, copy);
             break;
         case LinkJumpCondition:
-            linkConditionalBranch<false>(record.condition(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
+            linkConditionalBranch<false>(record.condition(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to, copy);
             break;
         case LinkJumpCompareAndBranchDirect:
-            linkCompareAndBranch<true>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
+            linkCompareAndBranch<true>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to, copy);
             break;
         case LinkJumpCompareAndBranch:
-            linkCompareAndBranch<false>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
+            linkCompareAndBranch<false>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to, copy);
             break;
         case LinkJumpTestBitDirect:
-            linkTestAndBranch<true>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
+            linkTestAndBranch<true>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to, copy);
             break;
         case LinkJumpTestBit:
-            linkTestAndBranch<false>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
+            linkTestAndBranch<false>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to, copy);
             break;
         default:
             ASSERT_NOT_REACHED();
@@ -3042,7 +3042,7 @@ protected:
     }
 
     template<bool isCall>
-    static void linkJumpOrCall(int* from, const int* fromInstruction, void* to)
+    static void linkJumpOrCall(int* from, const int* fromInstruction, void* to, CopyFunction copy = performJITMemcpy)
     {
         bool link;
         int imm26;
@@ -3059,11 +3059,11 @@ protected:
 
         int insn = unconditionalBranchImmediate(isCall, static_cast<int>(offset));
         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-        performJITMemcpy(from, &insn, sizeof(int));
+        copy(from, &insn, sizeof(int));
     }
 
     template<bool isDirect>
-    static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, const int* fromInstruction, void* to)
+    static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, const int* fromInstruction, void* to, CopyFunction copy = performJITMemcpy)
     {
         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
@@ -3076,22 +3076,22 @@ protected:
         if (useDirect || isDirect) {
             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, condition == ConditionNE, static_cast<int>(offset), rt);
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
+            copy(from, &insn, sizeof(int));
             if (!isDirect) {
                 insn = nopPseudo();
                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
-                performJITMemcpy(from + 1, &insn, sizeof(int));
+                copy(from + 1, &insn, sizeof(int));
             }
         } else {
             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, invert(condition) == ConditionNE, 2, rt);
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
-            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
+            copy(from, &insn, sizeof(int));
+            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to, copy);
         }
     }
 
     template<bool isDirect>
-    static void linkConditionalBranch(Condition condition, int* from, const int* fromInstruction, void* to)
+    static void linkConditionalBranch(Condition condition, int* from, const int* fromInstruction, void* to, CopyFunction copy = performJITMemcpy)
     {
         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
@@ -3104,22 +3104,22 @@ protected:
         if (useDirect || isDirect) {
             int insn = conditionalBranchImmediate(static_cast<int>(offset), condition);
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
+            copy(from, &insn, sizeof(int));
             if (!isDirect) {
                 insn = nopPseudo();
                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
-                performJITMemcpy(from + 1, &insn, sizeof(int));
+                copy(from + 1, &insn, sizeof(int));
             }
         } else {
             int insn = conditionalBranchImmediate(2, invert(condition));
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
-            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
+            copy(from, &insn, sizeof(int));
+            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to, copy);
         }
     }
 
     template<bool isDirect>
-    static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, const int* fromInstruction, void* to)
+    static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, const int* fromInstruction, void* to, CopyFunction copy = performJITMemcpy)
     {
         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
@@ -3133,17 +3133,17 @@ protected:
         if (useDirect || isDirect) {
             int insn = testAndBranchImmediate(condition == ConditionNE, static_cast<int>(bitNumber), static_cast<int>(offset), rt);
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
+            copy(from, &insn, sizeof(int));
             if (!isDirect) {
                 insn = nopPseudo();
                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
-                performJITMemcpy(from + 1, &insn, sizeof(int));
+                copy(from + 1, &insn, sizeof(int));
             }
         } else {
             int insn = testAndBranchImmediate(invert(condition) == ConditionNE, static_cast<int>(bitNumber), 2, rt);
             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
-            performJITMemcpy(from, &insn, sizeof(int));
-            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
+            copy(from, &insn, sizeof(int));
+            linkJumpOrCall<false>(from + 1, fromInstruction + 1, to, copy);
         }
     }
 
@@ -3201,11 +3201,6 @@ protected:
         return reinterpret_cast<int*>(static_cast<char*>(code) + label.m_offset);
     }
 
-    int* addressOf(AssemblerLabel label)
-    {
-        return addressOf(m_buffer.data(), label);
-    }
-
     static RegisterID disassembleXOrSp(int reg) { return reg == 31 ? ARM64Registers::sp : static_cast<RegisterID>(reg); }
     static RegisterID disassembleXOrZr(int reg) { return reg == 31 ? ARM64Registers::zr : static_cast<RegisterID>(reg); }
     static RegisterID disassembleXOrZrOrSp(bool useZr, int reg) { return reg == 31 ? (useZr ? ARM64Registers::zr : ARM64Registers::sp) : static_cast<RegisterID>(reg); }
@@ -3781,10 +3776,10 @@ protected:
 #endif
     }
 
-    AssemblerBuffer m_buffer;
     Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink;
     int m_indexOfLastWatchpoint;
     int m_indexOfTailOfLastWatchpoint;
+    AssemblerBuffer m_buffer;
 
 public:
     static constexpr ptrdiff_t MAX_POINTER_BITS = 48;
index 73cfbef..50b6dcb 100644 (file)
@@ -752,9 +752,10 @@ namespace JSC {
             m_buffer.putInt(NOP);
         }
 
-        static void fillNops(void* base, size_t size, bool isCopyingToExecutableMemory)
+        template <typename CopyFunction>
+        static void fillNops(void* base, size_t size, CopyFunction copy)
         {
-            UNUSED_PARAM(isCopyingToExecutableMemory);
+            UNUSED_PARAM(copy);
             RELEASE_ASSERT(!(size % sizeof(int32_t)));
 
             int32_t* ptr = static_cast<int32_t*>(base);
index 40d785e..5924032 100644 (file)
@@ -2057,7 +2057,8 @@ public:
         return OP_NOP_T2a | (OP_NOP_T2b << 16);
     }
 
-    static void fillNops(void* base, size_t size, bool isCopyingToExecutableMemory)
+    template <typename CopyFunction>
+    static void fillNops(void* base, size_t size, CopyFunction copy)
     {
         RELEASE_ASSERT(!(size % sizeof(int16_t)));
 
@@ -2065,10 +2066,7 @@ public:
         const size_t num32s = size / sizeof(int32_t);
         for (size_t i = 0; i < num32s; i++) {
             const int32_t insn = nopPseudo32();
-            if (isCopyingToExecutableMemory)
-                performJITMemcpy(ptr, &insn, sizeof(int32_t));
-            else
-                memcpy(ptr, &insn, sizeof(int32_t));
+            copy(ptr, &insn, sizeof(int32_t));
             ptr += sizeof(int32_t);
         }
 
@@ -2077,10 +2075,7 @@ public:
         ASSERT(num16s * sizeof(int16_t) + num32s * sizeof(int32_t) == size);
         if (num16s) {
             const int16_t insn = nopPseudo16();
-            if (isCopyingToExecutableMemory)
-                performJITMemcpy(ptr, &insn, sizeof(int16_t));
-            else
-                memcpy(ptr, &insn, sizeof(int16_t));
+            copy(ptr, &insn, sizeof(int16_t));
         }
     }
 
@@ -2247,7 +2242,6 @@ public:
         }
     }
 
-    void* unlinkedCode() { return m_formatter.data(); }
     size_t codeSize() const { return m_formatter.codeSize(); }
 
     static unsigned getCallReturnOffset(AssemblerLabel call)
index 9f4aaee..f46f244 100644 (file)
@@ -862,8 +862,6 @@ public:
         AssemblerType::cacheFlush(code, size);
     }
 
-    AssemblerType m_assembler;
-    
     template<PtrTag tag>
     static void linkJump(void* code, Jump jump, CodeLocationLabel<tag> target)
     {
@@ -962,13 +960,18 @@ public:
 
     void emitNops(size_t memoryToFillWithNopsInBytes)
     {
+#if CPU(ARM64)
+        RELEASE_ASSERT(memoryToFillWithNopsInBytes % 4 == 0);
+        for (unsigned i = 0; i < memoryToFillWithNopsInBytes / 4; ++i)
+            m_assembler.nop();
+#else
         AssemblerBuffer& buffer = m_assembler.buffer();
         size_t startCodeSize = buffer.codeSize();
         size_t targetCodeSize = startCodeSize + memoryToFillWithNopsInBytes;
         buffer.ensureSpace(memoryToFillWithNopsInBytes);
-        bool isCopyingToExecutableMemory = false;
-        AssemblerType::fillNops(static_cast<char*>(buffer.data()) + startCodeSize, memoryToFillWithNopsInBytes, isCopyingToExecutableMemory);
+        AssemblerType::fillNops(static_cast<char*>(buffer.data()) + startCodeSize, memoryToFillWithNopsInBytes, memcpy);
         buffer.setCodeSize(targetCodeSize);
+#endif
     }
 
     ALWAYS_INLINE void tagReturnAddress() { }
@@ -983,6 +986,11 @@ public:
 protected:
     AbstractMacroAssembler()
         : m_randomSource(0)
+#if CPU(ARM64E)
+        , m_assembler(random())
+#else
+        , m_assembler()
+#endif
     {
         invalidateAllTempRegisters();
     }
@@ -998,6 +1006,9 @@ protected:
 
     bool m_randomSourceIsInitialized { false };
     WeakRandom m_randomSource;
+public:
+    AssemblerType m_assembler;
+protected:
 
 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
     Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
index 54b2e9b..9796c3f 100644 (file)
 #include <string.h>
 #include <wtf/Assertions.h>
 #include <wtf/FastMalloc.h>
+#if CPU(ARM64E)
+#include <wtf/PtrTag.h>
+#endif
 #include <wtf/StdLibExtras.h>
 #include <wtf/UnalignedAccess.h>
 
 namespace JSC {
 
+    class LinkBuffer;
+
     struct AssemblerLabel {
         AssemblerLabel()
             : m_offset(std::numeric_limits<uint32_t>::max())
@@ -141,11 +146,37 @@ namespace JSC {
         unsigned m_capacity;
     };
 
+#if CPU(ARM64E)
+    class ARM64EHash {
+    public:
+        ARM64EHash(unsigned randomNumber)
+            : m_hash(randomNumber)
+            , m_randomSeed(randomNumber)
+        { }
+        ALWAYS_INLINE void update(unsigned value, uintptr_t index)
+        {
+            m_hash = tagInt((static_cast<uintptr_t>(value) + m_hash) ^ (m_hash >> 32), static_cast<PtrTag>(index));
+        }
+        uintptr_t hash() const { return m_hash; }
+        unsigned randomSeed() const { return m_randomSeed; }
+    private:
+        uintptr_t m_hash;
+        unsigned m_randomSeed;
+    };
+#endif
+
     class AssemblerBuffer {
     public:
-        AssemblerBuffer()
+        AssemblerBuffer(
+#if CPU(ARM64E)
+            unsigned randomNumber
+#endif
+        )
             : m_storage()
             , m_index(0)
+#if CPU(ARM64E)
+            , m_hash(randomNumber)
+#endif
         {
         }
 
@@ -165,25 +196,23 @@ namespace JSC {
             return !(m_index & (alignment - 1));
         }
 
+#if !CPU(ARM64)
         void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
         void putByte(int8_t value) { putIntegral(value); }
         void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
         void putShort(int16_t value) { putIntegral(value); }
-        void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
-        void putInt(int32_t value) { putIntegral(value); }
         void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
         void putInt64(int64_t value) { putIntegral(value); }
-
-        void* data() const
-        {
-            return m_storage.buffer();
-        }
+#endif
+        void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
+        void putInt(int32_t value) { putIntegral(value); }
 
         size_t codeSize() const
         {
             return m_index;
         }
 
+#if !CPU(ARM64)
         void setCodeSize(size_t index)
         {
             // Warning: Only use this if you know exactly what you are doing.
@@ -192,6 +221,7 @@ namespace JSC {
             m_index = index;
             ASSERT(m_index <= m_storage.capacity());
         }
+#endif
 
         AssemblerLabel label() const
         {
@@ -209,6 +239,7 @@ namespace JSC {
         //
         // LocalWriter *CANNOT* be mixed with other types of access to AssemblerBuffer.
         // AssemblerBuffer cannot be used until its LocalWriter goes out of scope.
+#if !CPU(ARM64) // If we ever need to use this on arm64e, we would need to make the checksum aware of this.
         class LocalWriter {
         public:
             LocalWriter(AssemblerBuffer& buffer, unsigned requiredSpace)
@@ -251,6 +282,16 @@ namespace JSC {
             unsigned m_requiredSpace;
 #endif
         };
+#endif // !CPU(ARM64)
+
+#if CPU(ARM64E)
+        ARM64EHash hash() const { return m_hash; }
+#endif
+
+#if !CPU(ARM64) // If we were to define this on arm64e, we'd need a way to update the hash as we write directly into the buffer.
+        void* data() const { return m_storage.buffer(); }
+#endif
+
 
     protected:
         template<typename IntegralType>
@@ -265,35 +306,38 @@ namespace JSC {
         template<typename IntegralType>
         void putIntegralUnchecked(IntegralType value)
         {
+#if CPU(ARM64)
+            static_assert(sizeof(value) == 4, "");
+#if CPU(ARM64E)
+            m_hash.update(value, m_index);
+#endif
+#endif
             ASSERT(isAvailable(sizeof(IntegralType)));
             WTF::unalignedStore<IntegralType>(m_storage.buffer() + m_index, value);
             m_index += sizeof(IntegralType);
         }
 
-        void append(const char* data, int size)
-        {
-            if (!isAvailable(size))
-                grow(size);
-
-            memcpy(m_storage.buffer() + m_index, data, size);
-            m_index += size;
-        }
-
+    private:
         void grow(int extraCapacity = 0)
         {
             m_storage.grow(extraCapacity);
         }
 
-    private:
         NEVER_INLINE void outOfLineGrow()
         {
             m_storage.grow();
         }
 
+#if !CPU(ARM64)
         friend LocalWriter;
+#endif
+        friend LinkBuffer;
 
         AssemblerData m_storage;
         unsigned m_index;
+#if CPU(ARM64E)
+        ARM64EHash m_hash;
+#endif
     };
 
 } // namespace JSC
index 2edc54b..6845de8 100644 (file)
@@ -109,10 +109,15 @@ void LinkBuffer::copyCompactAndLinkCode(MacroAssembler& macroAssembler, void* ow
     m_assemblerStorage = macroAssembler.m_assembler.buffer().releaseAssemblerData();
     uint8_t* inData = reinterpret_cast<uint8_t*>(m_assemblerStorage.buffer());
 
+    uint8_t* codeOutData = m_code.dataLocation<uint8_t*>();
+#if CPU(ARM64E)
+    const ARM64EHash assemblerBufferHash = macroAssembler.m_assembler.buffer().hash();
+    ARM64EHash verifyUncompactedHash(assemblerBufferHash.randomSeed());
+    uint8_t* outData = codeOutData;
+#else
     AssemblerData outBuffer(m_size);
-
     uint8_t* outData = reinterpret_cast<uint8_t*>(outBuffer.buffer());
-    uint8_t* codeOutData = m_code.dataLocation<uint8_t*>();
+#endif
 #if CPU(ARM64)
     RELEASE_ASSERT(roundUpToMultipleOf<sizeof(unsigned)>(outData) == outData);
     RELEASE_ASSERT(roundUpToMultipleOf<sizeof(unsigned)>(codeOutData) == codeOutData);
@@ -121,6 +126,11 @@ void LinkBuffer::copyCompactAndLinkCode(MacroAssembler& macroAssembler, void* ow
     int readPtr = 0;
     int writePtr = 0;
     unsigned jumpCount = jumpsToLink.size();
+
+#if CPU(ARM64E)
+    os_thread_self_restrict_rwx_to_rw();
+#endif
+
     if (m_shouldPerformBranchCompaction) {
         for (unsigned i = 0; i < jumpCount; ++i) {
             int offset = readPtr - writePtr;
@@ -134,8 +144,18 @@ void LinkBuffer::copyCompactAndLinkCode(MacroAssembler& macroAssembler, void* ow
             ASSERT(!(regionSize % 2));
             ASSERT(!(readPtr % 2));
             ASSERT(!(writePtr % 2));
-            while (copySource != copyEnd)
-                *copyDst++ = *copySource++;
+#if CPU(ARM64E)
+            unsigned index = readPtr;
+#endif
+            while (copySource != copyEnd) {
+                InstructionType insn = *copySource++;
+#if CPU(ARM64E)
+                static_assert(sizeof(InstructionType) == 4, "");
+                verifyUncompactedHash.update(insn, index);
+                index += sizeof(InstructionType);
+#endif
+                *copyDst++ = insn;
+            }
             recordLinkOffsets(m_assemblerStorage, readPtr, jumpsToLink[i].from(), offset);
             readPtr += regionSize;
             writePtr += regionSize;
@@ -166,29 +186,76 @@ void LinkBuffer::copyCompactAndLinkCode(MacroAssembler& macroAssembler, void* ow
                 ASSERT(!MacroAssembler::canCompact(jumpsToLink[i].type()));
         }
     }
+
     // Copy everything after the last jump
-    memcpy(outData + writePtr, inData + readPtr, initialSize - readPtr);
+    {
+        InstructionType* dst = bitwise_cast<InstructionType*>(outData + writePtr);
+        InstructionType* src = bitwise_cast<InstructionType*>(inData + readPtr);
+        size_t bytes = initialSize - readPtr;
+
+        RELEASE_ASSERT(bitwise_cast<uintptr_t>(dst) % sizeof(InstructionType) == 0);
+        RELEASE_ASSERT(bitwise_cast<uintptr_t>(src) % sizeof(InstructionType) == 0);
+        RELEASE_ASSERT(bytes % sizeof(InstructionType) == 0);
+
+#if CPU(ARM64E)
+        unsigned index = readPtr;
+#endif
+
+        for (size_t i = 0; i < bytes; i += sizeof(InstructionType)) {
+            InstructionType insn = *src++;
+#if CPU(ARM64E)
+            verifyUncompactedHash.update(insn, index);
+            index += sizeof(InstructionType);
+#endif
+            *dst++ = insn;
+        }
+    }
+
+#if CPU(ARM64E)
+    if (verifyUncompactedHash.hash() != assemblerBufferHash.hash()) {
+        dataLogLn("Hashes don't match: ", RawPointer(bitwise_cast<void*>(verifyUncompactedHash.hash())), " ", RawPointer(bitwise_cast<void*>(assemblerBufferHash.hash())));
+        dataLogLn("Crashing!");
+        CRASH();
+    }
+#endif
+
     recordLinkOffsets(m_assemblerStorage, readPtr, initialSize, readPtr - writePtr);
         
     for (unsigned i = 0; i < jumpCount; ++i) {
+#if CPU(ARM64E)
+        auto memcpyFunction = memcpy;
+#else
+        auto memcpyFunction = performJITMemcpy;
+#endif
+
         uint8_t* location = codeOutData + jumpsToLink[i].from();
         uint8_t* target = codeOutData + jumpsToLink[i].to() - executableOffsetFor(jumpsToLink[i].to());
-        MacroAssembler::link(jumpsToLink[i], outData + jumpsToLink[i].from(), location, target);
+        MacroAssembler::link(jumpsToLink[i], outData + jumpsToLink[i].from(), location, target, memcpyFunction);
     }
 
-    jumpsToLink.clear();
-
     size_t compactSize = writePtr + initialSize - readPtr;
+    if (!m_executableMemory) {
+        size_t nopSizeInBytes = initialSize - compactSize;
+        MacroAssembler::AssemblerType_T::fillNops(outData + compactSize, nopSizeInBytes, memcpy);
+    }
+
+#if CPU(ARM64E)
+    os_thread_self_restrict_rwx_to_rx();
+#endif
+
     if (m_executableMemory) {
         m_size = compactSize;
         m_executableMemory->shrink(m_size);
-    } else {
-        size_t nopSizeInBytes = initialSize - compactSize;
-        bool isCopyingToExecutableMemory = false;
-        MacroAssembler::AssemblerType_T::fillNops(outData + compactSize, nopSizeInBytes, isCopyingToExecutableMemory);
     }
 
+#if !CPU(ARM64E)
+    ASSERT(codeOutData != outData);
     performJITMemcpy(codeOutData, outData, m_size);
+#else
+    ASSERT(codeOutData == outData);
+#endif
+
+    jumpsToLink.clear();
 
 #if DUMP_LINK_STATISTICS
     dumpLinkStatistics(codeOutData, initialSize, m_size);
index edb2244..7e8e213 100644 (file)
@@ -266,9 +266,10 @@ public:
         emitInst(0x00000000);
     }
     
-    static void fillNops(void* base, size_t size, bool isCopyingToExecutableMemory)
+    template <typename CopyFunction>
+    static void fillNops(void* base, size_t size, CopyFunction copy)
     {
-        UNUSED_PARAM(isCopyingToExecutableMemory);
+        UNUSED_PARAM(copy);
         RELEASE_ASSERT(!(size % sizeof(int32_t)));
 
         int32_t* ptr = static_cast<int32_t*>(base);
index 78c33a6..2b21d68 100644 (file)
@@ -79,12 +79,12 @@ public:
     static const Assembler::JumpType DefaultJump = Assembler::JumpNoConditionFixedSize;
 
     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
-    void* unlinkedCode() { return m_assembler.unlinkedCode(); }
     static bool canCompact(JumpType jumpType) { return Assembler::canCompact(jumpType); }
     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return Assembler::computeJumpType(jumpType, from, to); }
     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return Assembler::computeJumpType(record, from, to); }
     static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return Assembler::jumpSizeDelta(jumpType, jumpLinkType); }
-    static void link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction, uint8_t* to) { return Assembler::link(record, from, fromInstruction, to); }
+    template <typename CopyFunction>
+    static void link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction, uint8_t* to, CopyFunction copy) { return Assembler::link(record, from, fromInstruction, to, copy); }
 
     static const Scale ScalePtr = TimesEight;
 
index 790a39d..69b2e90 100644 (file)
@@ -65,7 +65,6 @@ public:
     }
 
     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
-    void* unlinkedCode() { return m_assembler.unlinkedCode(); }
     static bool canCompact(JumpType jumpType) { return ARMv7Assembler::canCompact(jumpType); }
     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(jumpType, from, to); }
     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(record, from, to); }
index 6edba1a..d080e75 100644 (file)
@@ -3933,9 +3933,10 @@ public:
         m_formatter.oneByteOp(OP_NOP);
     }
 
-    static void fillNops(void* base, size_t size, bool isCopyingToExecutableMemory)
+    template <typename CopyFunction>
+    static void fillNops(void* base, size_t size, CopyFunction copy)
     {
-        UNUSED_PARAM(isCopyingToExecutableMemory);
+        UNUSED_PARAM(copy);
 #if CPU(X86_64)
         static const uint8_t nops[10][10] = {
             // nop
index 475b42d..e9b1dd1 100644 (file)
@@ -1,3 +1,14 @@
+2018-09-27  Saam barati  <sbarati@apple.com>
+
+        Verify the contents of AssemblerBuffer on arm64e
+        https://bugs.webkit.org/show_bug.cgi?id=190057
+        <rdar://problem/38916630>
+
+        Reviewed by Mark Lam.
+
+        * wtf/PtrTag.h:
+        (WTF::tagInt):
+
 2018-09-27  Jer Noble  <jer.noble@apple.com>
 
         MediaPlayer should have mediaPlayerWaitingForKeyChanged() / bool waitingForKey() accessor
index be2fa02..4aa97ff 100644 (file)
@@ -147,6 +147,13 @@ inline PtrType untagCFunctionPtr(PtrType ptr, PtrTag) { return ptr; }
 template<PtrTag, typename PtrType, typename = std::enable_if_t<std::is_pointer<PtrType>::value>>
 inline PtrType untagCFunctionPtr(PtrType ptr) { return ptr; }
 
+template <typename IntType>
+inline IntType tagInt(IntType ptrInt, PtrTag)
+{
+    static_assert(sizeof(IntType) == sizeof(uintptr_t), "");
+    return ptrInt;
+}
+
 template<typename PtrType> void assertIsCFunctionPtr(PtrType) { }
 template<typename PtrType> void assertIsNullOrCFunctionPtr(PtrType) { }
 
@@ -184,6 +191,7 @@ using WTF::retagCodePtr;
 using WTF::removeCodePtrTag;
 using WTF::tagCFunctionPtr;
 using WTF::untagCFunctionPtr;
+using WTF::tagInt;
 
 using WTF::assertIsCFunctionPtr;
 using WTF::assertIsNullOrCFunctionPtr;