]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - assembler/AbstractMacroAssembler.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / assembler / AbstractMacroAssembler.h
index 7d9d0925c5ee42931c3f7568eec49d7dda05049f..6e82dcc5eb2758e7ab960b022a7dbaf58ce0736f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2014, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #ifndef AbstractMacroAssembler_h
 #define AbstractMacroAssembler_h
 
+#include "AbortReason.h"
+#include "AssemblerBuffer.h"
 #include "CodeLocation.h"
 #include "MacroAssemblerCodeRef.h"
+#include "Options.h"
+#include "WeakRandom.h"
+#include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/Noncopyable.h>
-#include <wtf/UnusedParam.h>
 
 #if ENABLE(ASSEMBLER)
 
 namespace JSC {
 
+inline bool isARMv7IDIVSupported()
+{
+#if HAVE(ARM_IDIV_INSTRUCTIONS)
+    return true;
+#else
+    return false;
+#endif
+}
+
+inline bool isARM64()
+{
+#if CPU(ARM64)
+    return true;
+#else
+    return false;
+#endif
+}
+
+inline bool isX86()
+{
+#if CPU(X86_64) || CPU(X86)
+    return true;
+#else
+    return false;
+#endif
+}
+
+inline bool optimizeForARMv7IDIVSupported()
+{
+    return isARMv7IDIVSupported() && Options::enableArchitectureSpecificOptimizations();
+}
+
+inline bool optimizeForARM64()
+{
+    return isARM64() && Options::enableArchitectureSpecificOptimizations();
+}
+
+inline bool optimizeForX86()
+{
+    return isX86() && Options::enableArchitectureSpecificOptimizations();
+}
+
 class LinkBuffer;
 class RepatchBuffer;
+class Watchpoint;
+namespace DFG {
+struct OSRExit;
+}
 
-template <class AssemblerType>
+template <class AssemblerType, class MacroAssemblerType>
 class AbstractMacroAssembler {
 public:
     friend class JITWriteBarrierBase;
+    typedef AbstractMacroAssembler<AssemblerType, MacroAssemblerType> AbstractMacroAssemblerType;
     typedef AssemblerType AssemblerType_T;
 
     typedef MacroAssemblerCodePtr CodePtr;
@@ -50,19 +101,32 @@ public:
     class Jump;
 
     typedef typename AssemblerType::RegisterID RegisterID;
+    typedef typename AssemblerType::FPRegisterID FPRegisterID;
+    
+    static RegisterID firstRegister() { return AssemblerType::firstRegister(); }
+    static RegisterID lastRegister() { return AssemblerType::lastRegister(); }
+
+    static FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); }
+    static FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); }
 
     // Section 1: MacroAssembler operand types
     //
     // The following types are used as operands to MacroAssembler operations,
     // describing immediate  and memory operands to the instructions to be planted.
 
-
     enum Scale {
         TimesOne,
         TimesTwo,
         TimesFour,
         TimesEight,
     };
+    
+    static Scale timesPtr()
+    {
+        if (sizeof(void*) == 4)
+            return TimesFour;
+        return TimesEight;
+    }
 
     // Address:
     //
@@ -73,7 +137,12 @@ public:
             , offset(offset)
         {
         }
-
+        
+        Address withOffset(int32_t additionalOffset)
+        {
+            return Address(base, offset + additionalOffset);
+        }
+        
         RegisterID base;
         int32_t offset;
     };
@@ -136,6 +205,11 @@ public:
         RegisterID index;
         Scale scale;
         int32_t offset;
+        
+        BaseIndex withOffset(int32_t additionalOffset)
+        {
+            return BaseIndex(base, index, scale, offset + additionalOffset);
+        }
     };
 
     // AbsoluteAddress:
@@ -157,10 +231,25 @@ public:
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
     struct TrustedImmPtr {
+        TrustedImmPtr() { }
+        
         explicit TrustedImmPtr(const void* value)
             : m_value(value)
         {
         }
+        
+        // This is only here so that TrustedImmPtr(0) does not confuse the C++
+        // overload handling rules.
+        explicit TrustedImmPtr(int value)
+            : m_value(0)
+        {
+            ASSERT_UNUSED(value, !value);
+        }
+
+        explicit TrustedImmPtr(size_t value)
+            : m_value(reinterpret_cast<void*>(value))
+        {
+        }
 
         intptr_t asIntptr()
         {
@@ -170,11 +259,14 @@ public:
         const void* m_value;
     };
 
-    struct ImmPtr : public TrustedImmPtr {
+    struct ImmPtr : private TrustedImmPtr
+    {
         explicit ImmPtr(const void* value)
             : TrustedImmPtr(value)
         {
         }
+
+        TrustedImmPtr asTrustedImmPtr() { return *this; }
     };
 
     // TrustedImm32:
@@ -184,39 +276,25 @@ public:
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
     struct TrustedImm32 {
+        TrustedImm32() { }
+        
         explicit TrustedImm32(int32_t value)
             : m_value(value)
-#if CPU(ARM) || CPU(MIPS)
-            , m_isPointer(false)
-#endif
         {
         }
 
 #if !CPU(X86_64)
         explicit TrustedImm32(TrustedImmPtr ptr)
             : m_value(ptr.asIntptr())
-#if CPU(ARM) || CPU(MIPS)
-            , m_isPointer(true)
-#endif
         {
         }
 #endif
 
         int32_t m_value;
-#if CPU(ARM) || CPU(MIPS)
-        // We rely on being able to regenerate code to recover exception handling
-        // information.  Since ARMv7 supports 16-bit immediates there is a danger
-        // that if pointer values change the layout of the generated code will change.
-        // To avoid this problem, always generate pointers (and thus Imm32s constructed
-        // from ImmPtrs) with a code sequence that is able  to represent  any pointer
-        // value - don't use a more compact form in these cases.
-        // Same for MIPS.
-        bool m_isPointer;
-#endif
     };
 
 
-    struct Imm32 : public TrustedImm32 {
+    struct Imm32 : private TrustedImm32 {
         explicit Imm32(int32_t value)
             : TrustedImm32(value)
         {
@@ -227,6 +305,47 @@ public:
         {
         }
 #endif
+        const TrustedImm32& asTrustedImm32() const { return *this; }
+
+    };
+    
+    // TrustedImm64:
+    //
+    // A 64bit immediate operand to an instruction - this is wrapped in a
+    // class requiring explicit construction in order to prevent RegisterIDs
+    // (which are implemented as an enum) from accidentally being passed as
+    // immediate values.
+    struct TrustedImm64 {
+        TrustedImm64() { }
+        
+        explicit TrustedImm64(int64_t value)
+            : m_value(value)
+        {
+        }
+
+#if CPU(X86_64) || CPU(ARM64)
+        explicit TrustedImm64(TrustedImmPtr ptr)
+            : m_value(ptr.asIntptr())
+        {
+        }
+#endif
+
+        int64_t m_value;
+    };
+
+    struct Imm64 : private TrustedImm64
+    {
+        explicit Imm64(int64_t value)
+            : TrustedImm64(value)
+        {
+        }
+#if CPU(X86_64) || CPU(ARM64)
+        explicit Imm64(TrustedImmPtr ptr)
+            : TrustedImm64(ptr)
+        {
+        }
+#endif
+        const TrustedImm64& asTrustedImm64() const { return *this; }
     };
     
     // Section 2: MacroAssembler code buffer handles
@@ -242,19 +361,52 @@ public:
     // A Label records a point in the generated instruction stream, typically such that
     // it may be used as a destination for a jump.
     class Label {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
+        friend struct DFG::OSRExit;
         friend class Jump;
         friend class MacroAssemblerCodeRef;
         friend class LinkBuffer;
+        friend class Watchpoint;
 
     public:
         Label()
         {
         }
 
-        Label(AbstractMacroAssembler<AssemblerType>* masm)
+        Label(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
+        {
+            masm->invalidateAllTempRegisters();
+        }
+
+        bool isSet() const { return m_label.isSet(); }
+    private:
+        AssemblerLabel m_label;
+    };
+    
+    // ConvertibleLoadLabel:
+    //
+    // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
+    // so that:
+    //
+    // loadPtr(Address(a, i), b)
+    //
+    // becomes:
+    //
+    // addPtr(TrustedImmPtr(i), a, b)
+    class ConvertibleLoadLabel {
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
+        friend class AbstractMacroAssembler;
+        friend class LinkBuffer;
+        
+    public:
+        ConvertibleLoadLabel()
+        {
+        }
+        
+        ConvertibleLoadLabel(AbstractMacroAssemblerType* masm)
+            : m_label(masm->m_assembler.labelIgnoringWatchpoints())
         {
         }
         
@@ -268,7 +420,7 @@ public:
     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
     // patched after the code has been generated.
     class DataLabelPtr {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
         friend class LinkBuffer;
     public:
@@ -276,11 +428,11 @@ public:
         {
         }
 
-        DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelPtr(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
-        
+
         bool isSet() const { return m_label.isSet(); }
         
     private:
@@ -289,10 +441,10 @@ public:
 
     // DataLabel32:
     //
-    // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
+    // A DataLabel32 is used to refer to a location in the code containing a 32-bit constant to be
     // patched after the code has been generated.
     class DataLabel32 {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
         friend class LinkBuffer;
     public:
@@ -300,7 +452,7 @@ public:
         {
         }
 
-        DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabel32(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -316,7 +468,7 @@ public:
     // A DataLabelCompact is used to refer to a location in the code containing a
     // compact immediate to be patched after the code has been generated.
     class DataLabelCompact {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
         friend class LinkBuffer;
     public:
@@ -324,16 +476,18 @@ public:
         {
         }
         
-        DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelCompact(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
-    
+
         DataLabelCompact(AssemblerLabel label)
             : m_label(label)
         {
         }
 
+        AssemblerLabel label() const { return m_label; }
+
     private:
         AssemblerLabel m_label;
     };
@@ -345,7 +499,7 @@ public:
     // relative offset such that when executed it will call to the desired
     // destination.
     class Call {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
 
     public:
@@ -362,7 +516,7 @@ public:
         }
         
         Call(AssemblerLabel jmp, Flags flags)
-            : m_jmp(jmp)
+            : m_label(jmp)
             , m_flags(flags)
         {
         }
@@ -374,10 +528,10 @@ public:
 
         static Call fromTailJump(Jump jump)
         {
-            return Call(jump.m_jmp, Linkable);
+            return Call(jump.m_label, Linkable);
         }
 
-        AssemblerLabel m_jmp;
+        AssemblerLabel m_label;
     private:
         Flags m_flags;
     };
@@ -389,9 +543,10 @@ public:
     // relative offset such that when executed it will jump to the desired
     // destination.
     class Jump {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
         friend class Call;
+        friend struct DFG::OSRExit;
         friend class LinkBuffer;
     public:
         Jump()
@@ -400,47 +555,137 @@ public:
         
 #if CPU(ARM_THUMB2)
         // Fixme: this information should be stored in the instruction stream, not in the Jump object.
-        Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
-            : m_jmp(jmp)
+        Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
+            : m_label(jmp)
+            , m_type(type)
+            , m_condition(condition)
+        {
+        }
+#elif CPU(ARM64)
+        Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid)
+            : m_label(jmp)
             , m_type(type)
             , m_condition(condition)
         {
         }
+
+        Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister)
+            : m_label(jmp)
+            , m_type(type)
+            , m_condition(condition)
+            , m_is64Bit(is64Bit)
+            , m_compareRegister(compareRegister)
+        {
+            ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize));
+        }
+
+        Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister)
+            : m_label(jmp)
+            , m_type(type)
+            , m_condition(condition)
+            , m_bitNumber(bitNumber)
+            , m_compareRegister(compareRegister)
+        {
+            ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize));
+        }
+#elif CPU(SH4)
+        Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
+            : m_label(jmp)
+            , m_type(type)
+        {
+        }
 #else
         Jump(AssemblerLabel jmp)    
-            : m_jmp(jmp)
+            : m_label(jmp)
         {
         }
 #endif
+        
+        Label label() const
+        {
+            Label result;
+            result.m_label = m_label;
+            return result;
+        }
 
-        void link(AbstractMacroAssembler<AssemblerType>* masm) const
+        void link(AbstractMacroAssemblerType* masm) const
         {
+            masm->invalidateAllTempRegisters();
+
+#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
+            masm->checkRegisterAllocationAgainstBranchRange(m_label.m_offset, masm->debugOffset());
+#endif
+
 #if CPU(ARM_THUMB2)
-            masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label(), m_type, m_condition);
+            masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
+#elif CPU(ARM64)
+            if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
+                masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
+            else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
+                masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
+            else
+                masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
+#elif CPU(SH4)
+            masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
 #else
-            masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
+            masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
 #endif
         }
         
-        void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
+        void linkTo(Label label, AbstractMacroAssemblerType* masm) const
         {
+#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
+            masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset);
+#endif
+
 #if CPU(ARM_THUMB2)
-            masm->m_assembler.linkJump(m_jmp, label.m_label, m_type, m_condition);
+            masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
+#elif CPU(ARM64)
+            if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
+                masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_is64Bit, m_compareRegister);
+            else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
+                masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_bitNumber, m_compareRegister);
+            else
+                masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
 #else
-            masm->m_assembler.linkJump(m_jmp, label.m_label);
+            masm->m_assembler.linkJump(m_label, label.m_label);
 #endif
         }
 
-        bool isSet() const { return m_jmp.isSet(); }
+        bool isSet() const { return m_label.isSet(); }
 
     private:
-        AssemblerLabel m_jmp;
+        AssemblerLabel m_label;
 #if CPU(ARM_THUMB2)
         ARMv7Assembler::JumpType m_type;
         ARMv7Assembler::Condition m_condition;
+#elif CPU(ARM64)
+        ARM64Assembler::JumpType m_type;
+        ARM64Assembler::Condition m_condition;
+        bool m_is64Bit;
+        unsigned m_bitNumber;
+        ARM64Assembler::RegisterID m_compareRegister;
+#endif
+#if CPU(SH4)
+        SH4Assembler::JumpType m_type;
 #endif
     };
 
+    struct PatchableJump {
+        PatchableJump()
+        {
+        }
+
+        explicit PatchableJump(Jump jump)
+            : m_jump(jump)
+        {
+        }
+
+        operator Jump&() { return m_jump; }
+
+        Jump m_jump;
+    };
+
     // JumpList:
     //
     // A JumpList is a set of Jump objects.
@@ -449,9 +694,17 @@ public:
         friend class LinkBuffer;
 
     public:
-        typedef Vector<Jump, 16> JumpVector;
+        typedef Vector<Jump, 2> JumpVector;
+        
+        JumpList() { }
+        
+        JumpList(Jump jump)
+        {
+            if (jump.isSet())
+                append(jump);
+        }
 
-        void link(AbstractMacroAssembler<AssemblerType>* masm)
+        void link(AbstractMacroAssemblerType* masm)
         {
             size_t size = m_jumps.size();
             for (size_t i = 0; i < size; ++i)
@@ -459,7 +712,7 @@ public:
             m_jumps.clear();
         }
         
-        void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
+        void linkTo(Label label, AbstractMacroAssemblerType* masm)
         {
             size_t size = m_jumps.size();
             for (size_t i = 0; i < size; ++i)
@@ -472,7 +725,7 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(JumpList& other)
+        void append(const JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
         }
@@ -487,7 +740,7 @@ public:
             m_jumps.clear();
         }
         
-        const JumpVector& jumps() { return m_jumps; }
+        const JumpVector& jumps() const { return m_jumps; }
 
     private:
         JumpVector m_jumps;
@@ -495,83 +748,385 @@ public:
 
 
     // Section 3: Misc admin methods
+#if ENABLE(DFG_JIT)
+    Label labelIgnoringWatchpoints()
+    {
+        Label result;
+        result.m_label = m_assembler.labelIgnoringWatchpoints();
+        return result;
+    }
+#else
+    Label labelIgnoringWatchpoints()
+    {
+        return label();
+    }
+#endif
+    
     Label label()
     {
         return Label(this);
     }
     
+    void padBeforePatch()
+    {
+        // Rely on the fact that asking for a label already does the padding.
+        (void)label();
+    }
+    
+    Label watchpointLabel()
+    {
+        Label result;
+        result.m_label = m_assembler.labelForWatchpoint();
+        return result;
+    }
+    
     Label align()
     {
         m_assembler.align(16);
         return Label(this);
     }
 
-    ptrdiff_t differenceBetween(Label from, Jump to)
+#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
+    class RegisterAllocationOffset {
+    public:
+        RegisterAllocationOffset(unsigned offset)
+            : m_offset(offset)
+        {
+        }
+
+        void checkOffsets(unsigned low, unsigned high)
+        {
+            RELEASE_ASSERT_WITH_MESSAGE(!(low <= m_offset && m_offset <= high), "Unsafe branch over register allocation at instruction offset %u in jump offset range %u..%u", m_offset, low, high);
+        }
+
+    private:
+        unsigned m_offset;
+    };
+
+    void addRegisterAllocationAtOffset(unsigned offset)
+    {
+        m_registerAllocationForOffsets.append(RegisterAllocationOffset(offset));
+    }
+
+    void clearRegisterAllocationOffsets()
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
+        m_registerAllocationForOffsets.clear();
     }
 
-    ptrdiff_t differenceBetween(Label from, Call to)
+    void checkRegisterAllocationAgainstBranchRange(unsigned offset1, unsigned offset2)
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
+        if (offset1 > offset2)
+            std::swap(offset1, offset2);
+
+        size_t size = m_registerAllocationForOffsets.size();
+        for (size_t i = 0; i < size; ++i)
+            m_registerAllocationForOffsets[i].checkOffsets(offset1, offset2);
     }
+#endif
 
-    ptrdiff_t differenceBetween(Label from, Label to)
+    template<typename T, typename U>
+    static ptrdiff_t differenceBetween(T from, U to)
     {
         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
     }
 
-    ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
+    static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+        return reinterpret_cast<ptrdiff_t>(b.executableAddress()) - reinterpret_cast<ptrdiff_t>(a.executableAddress());
     }
 
-    ptrdiff_t differenceBetween(Label from, DataLabel32 to)
+    unsigned debugOffset() { return m_assembler.debugOffset(); }
+
+    ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+        AssemblerType::cacheFlush(code, size);
     }
-    
-    ptrdiff_t differenceBetween(Label from, DataLabelCompact to)
+
+#if ENABLE(MASM_PROBE)
+
+    struct CPUState {
+        #define DECLARE_REGISTER(_type, _regName) \
+            _type _regName;
+        FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
+        #undef DECLARE_REGISTER
+
+        static const char* registerName(RegisterID regID)
+        {
+            switch (regID) {
+                #define DECLARE_REGISTER(_type, _regName) \
+                case RegisterID::_regName: \
+                    return #_regName;
+                FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER)
+                #undef DECLARE_REGISTER
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        static const char* registerName(FPRegisterID regID)
+        {
+            switch (regID) {
+                #define DECLARE_REGISTER(_type, _regName) \
+                case FPRegisterID::_regName: \
+                    return #_regName;
+                FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER)
+                #undef DECLARE_REGISTER
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        void* registerValue(RegisterID regID)
+        {
+            switch (regID) {
+                #define DECLARE_REGISTER(_type, _regName) \
+                case RegisterID::_regName: \
+                    return _regName;
+                FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER)
+                #undef DECLARE_REGISTER
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        double registerValue(FPRegisterID regID)
+        {
+            switch (regID) {
+                #define DECLARE_REGISTER(_type, _regName) \
+                case FPRegisterID::_regName: \
+                    return _regName;
+                FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER)
+                #undef DECLARE_REGISTER
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+    };
+
+    struct ProbeContext;
+    typedef void (*ProbeFunction)(struct ProbeContext*);
+
+    struct ProbeContext {
+        ProbeFunction probeFunction;
+        void* arg1;
+        void* arg2;
+        CPUState cpu;
+
+        void print(int indentation = 0)
+        {
+            #define INDENT MacroAssemblerType::printIndent(indentation)
+
+            INDENT, dataLogF("ProbeContext %p {\n", this);
+            indentation++;
+            {
+                INDENT, dataLogF("probeFunction: %p\n", probeFunction);
+                INDENT, dataLogF("arg1: %p %llu\n", arg1, reinterpret_cast<int64_t>(arg1));
+                INDENT, dataLogF("arg2: %p %llu\n", arg2, reinterpret_cast<int64_t>(arg2));
+                MacroAssemblerType::printCPU(cpu, indentation);
+            }
+            indentation--;
+            INDENT, dataLog("}\n");
+
+            #undef INDENT
+        }
+    };
+
+    static void printIndent(int indentation)
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+        for (; indentation > 0; indentation--)
+            dataLog("    ");
+    }
+
+    static void printCPU(CPUState& cpu, int indentation = 0)
+    {
+        #define INDENT printIndent(indentation)
+
+        INDENT, dataLog("cpu: {\n");
+        MacroAssemblerType::printCPURegisters(cpu, indentation + 1);
+        INDENT, dataLog("}\n");
+
+        #undef INDENT
     }
 
-    ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
+    // This is a marker type only used with print(). See print() below for details.
+    struct AllRegisters { };
+
+    // Emits code which will print debugging info at runtime. The type of values that
+    // can be printed is encapsulated in the PrintArg struct below. Here are some
+    // examples:
+    //
+    //      print("Hello world\n"); // Emits code to print the string.
+    //
+    //      CodeBlock* cb = ...;
+    //      print(cb);              // Emits code to print the pointer value.
+    //
+    //      RegisterID regID = ...;
+    //      print(regID);           // Emits code to print the register value (not the id).
+    //
+    //      // Emits code to print all registers.  Unlike other items, this prints
+    //      // multiple lines as follows:
+    //      //      cpu {
+    //      //          eax: 0x123456789
+    //      //          ebx: 0x000000abc
+    //      //          ...
+    //      //      }
+    //      print(AllRegisters());
+    //
+    //      // Print multiple things at once. This incurs the probe overhead only once
+    //      // to print all the items.
+    //      print("cb:", cb, " regID:", regID, " cpu:\n", AllRegisters());
+
+    template<typename... Arguments>
+    void print(Arguments... args)
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
+        printInternal(static_cast<MacroAssemblerType*>(this), args...);
     }
 
-    ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
+    // This function will be called by printCPU() to print the contents of the
+    // target specific registers which are saved away in the CPUState struct.
+    // printCPURegisters() should make use of printIndentation() to print the
+    // registers with the appropriate amount of indentation.
+    //
+    // Note: printCPURegisters() should be implemented by the target specific
+    // MacroAssembler. This prototype is only provided here to document the
+    // interface.
+
+    static void printCPURegisters(CPUState&, int indentation = 0);
+
+    // This function will be called by print() to print the contents of a
+    // specific register (from the CPUState) in line with other items in the
+    // print stream. Hence, no indentation is needed.
+    //
+    // Note: printRegister() should be implemented by the target specific
+    // MacroAssembler. These prototypes are only provided here to document their
+    // interface.
+
+    static void printRegister(CPUState&, RegisterID);
+    static void printRegister(CPUState&, FPRegisterID);
+
+    // This function emits code to preserve the CPUState (e.g. registers),
+    // call a user supplied probe function, and restore the CPUState before
+    // continuing with other JIT generated code.
+    //
+    // The user supplied probe function will be called with a single pointer to
+    // a ProbeContext struct (defined above) which contains, among other things,
+    // the preserved CPUState. This allows the user probe function to inspect
+    // the CPUState at that point in the JIT generated code.
+    //
+    // If the user probe function alters the register values in the ProbeContext,
+    // the altered values will be loaded into the CPU registers when the probe
+    // returns.
+    //
+    // The ProbeContext is stack allocated and is only valid for the duration
+    // of the call to the user probe function.
+    //
+    // Note: probe() should be implemented by the target specific MacroAssembler.
+    // This prototype is only provided here to document the interface.
+
+    void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
+
+#endif // ENABLE(MASM_PROBE)
+
+    AssemblerType m_assembler;
+    
+protected:
+    AbstractMacroAssembler()
+        : m_randomSource(cryptographicallyRandomNumber())
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+        invalidateAllTempRegisters();
     }
 
-    ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
+    uint32_t random()
     {
-        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
+        return m_randomSource.getUint32();
     }
 
-    // Temporary interface; likely to be removed, since may be hard to port to all architectures.
-#if CPU(X86) || CPU(X86_64)
-    void rewindToLabel(Label rewindTo) { m_assembler.rewindToLabel(rewindTo.m_label); }
+    WeakRandom m_randomSource;
+
+#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
+    Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
 #endif
 
-    void beginUninterruptedSequence() { }
-    void endUninterruptedSequence() { }
+    static bool haveScratchRegisterForBlinding()
+    {
+        return false;
+    }
+    static RegisterID scratchRegisterForBlinding()
+    {
+        UNREACHABLE_FOR_PLATFORM();
+        return firstRegister();
+    }
+    static bool canBlind() { return false; }
+    static bool shouldBlindForSpecificArch(uint32_t) { return false; }
+    static bool shouldBlindForSpecificArch(uint64_t) { return false; }
+
+    class CachedTempRegister {
+        friend class DataLabelPtr;
+        friend class DataLabel32;
+        friend class DataLabelCompact;
+        friend class Jump;
+        friend class Label;
 
-#ifndef NDEBUG
-    unsigned debugOffset() { return m_assembler.debugOffset(); }
-#endif
+    public:
+        CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
+            : m_masm(masm)
+            , m_registerID(registerID)
+            , m_value(0)
+            , m_validBit(1 << static_cast<unsigned>(registerID))
+        {
+            ASSERT(static_cast<unsigned>(registerID) < (sizeof(unsigned) * 8));
+        }
 
-protected:
-    AssemblerType m_assembler;
+        ALWAYS_INLINE RegisterID registerIDInvalidate() { invalidate(); return m_registerID; }
+
+        ALWAYS_INLINE RegisterID registerIDNoInvalidate() { return m_registerID; }
+
+        bool value(intptr_t& value)
+        {
+            value = m_value;
+            return m_masm->isTempRegisterValid(m_validBit);
+        }
+
+        void setValue(intptr_t value)
+        {
+            m_value = value;
+            m_masm->setTempRegisterValid(m_validBit);
+        }
+
+        ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
+
+    private:
+        AbstractMacroAssemblerType* m_masm;
+        RegisterID m_registerID;
+        intptr_t m_value;
+        unsigned m_validBit;
+    };
+
+    ALWAYS_INLINE void invalidateAllTempRegisters()
+    {
+        m_tempRegistersValidBits = 0;
+    }
+
+    ALWAYS_INLINE bool isTempRegisterValid(unsigned registerMask)
+    {
+        return (m_tempRegistersValidBits & registerMask);
+    }
+
+    ALWAYS_INLINE void clearTempRegisterValid(unsigned registerMask)
+    {
+        m_tempRegistersValidBits &=  ~registerMask;
+    }
+
+    ALWAYS_INLINE void setTempRegisterValid(unsigned registerMask)
+    {
+        m_tempRegistersValidBits |= registerMask;
+    }
+
+    unsigned m_tempRegistersValidBits;
 
     friend class LinkBuffer;
     friend class RepatchBuffer;
 
     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
     {
-        AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
+        AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
     }
 
     static void linkPointer(void* code, AssemblerLabel label, void* value)
@@ -586,7 +1141,7 @@ protected:
 
     static unsigned getLinkerCallReturnOffset(Call call)
     {
-        return AssemblerType::getCallReturnOffset(call.m_jmp);
+        return AssemblerType::getCallReturnOffset(call.m_label);
     }
 
     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
@@ -618,7 +1173,153 @@ protected:
     {
         return AssemblerType::readPointer(dataLabelPtr.dataLocation());
     }
-};
+    
+    static void replaceWithLoad(CodeLocationConvertibleLoad label)
+    {
+        AssemblerType::replaceWithLoad(label.dataLocation());
+    }
+    
+    static void replaceWithAddressComputation(CodeLocationConvertibleLoad label)
+    {
+        AssemblerType::replaceWithAddressComputation(label.dataLocation());
+    }
+
+private:
+
+#if ENABLE(MASM_PROBE)
+
+    struct PrintArg {
+    
+        enum class Type {
+            AllRegisters,
+            RegisterID,
+            FPRegisterID,
+            ConstCharPtr,
+            ConstVoidPtr,
+            IntptrValue,
+            UintptrValue,
+        };
+
+        PrintArg(AllRegisters&)
+            : type(Type::AllRegisters)
+        {
+        }
+
+        PrintArg(RegisterID regID)
+            : type(Type::RegisterID)
+        {
+            u.gpRegisterID = regID;
+        }
+
+        PrintArg(FPRegisterID regID)
+            : type(Type::FPRegisterID)
+        {
+            u.fpRegisterID = regID;
+        }
+
+        PrintArg(const char* ptr)
+            : type(Type::ConstCharPtr)
+        {
+            u.constCharPtr = ptr;
+        }
+
+        PrintArg(const void* ptr)
+            : type(Type::ConstVoidPtr)
+        {
+            u.constVoidPtr = ptr;
+        }
+
+        PrintArg(int value)
+            : type(Type::IntptrValue)
+        {
+            u.intptrValue = value;
+        }
+
+        PrintArg(unsigned value)
+            : type(Type::UintptrValue)
+        {
+            u.intptrValue = value;
+        }
+
+        PrintArg(intptr_t value)
+            : type(Type::IntptrValue)
+        {
+            u.intptrValue = value;
+        }
+
+        PrintArg(uintptr_t value)
+            : type(Type::UintptrValue)
+        {
+            u.uintptrValue = value;
+        }
+
+        Type type;
+        union {
+            RegisterID gpRegisterID;
+            FPRegisterID fpRegisterID;
+            const char* constCharPtr;
+            const void* constVoidPtr;
+            intptr_t intptrValue;
+            uintptr_t uintptrValue;
+        } u;
+    };
+
+    typedef Vector<PrintArg> PrintArgsList;
+
+    template<typename FirstArg, typename... Arguments>
+    static void appendPrintArg(PrintArgsList* argsList, FirstArg& firstArg, Arguments... otherArgs)
+    {
+        argsList->append(PrintArg(firstArg));
+        appendPrintArg(argsList, otherArgs...);
+    }
+
+    static void appendPrintArg(PrintArgsList*) { }
+
+    
+    template<typename... Arguments>
+    static void printInternal(MacroAssemblerType* masm, Arguments... args)
+    {
+        auto argsList = std::make_unique<PrintArgsList>();
+        appendPrintArg(argsList.get(), args...);
+        masm->probe(printCallback, argsList.release());
+    }
+
+    static void printCallback(ProbeContext* context)
+    {
+        typedef PrintArg Arg;
+        PrintArgsList& argsList =
+            *reinterpret_cast<PrintArgsList*>(context->arg1);
+        for (size_t i = 0; i < argsList.size(); i++) {
+            auto& arg = argsList[i];
+            switch (arg.type) {
+            case Arg::Type::AllRegisters:
+                MacroAssemblerType::printCPU(context->cpu);
+                break;
+            case Arg::Type::RegisterID:
+                MacroAssemblerType::printRegister(context->cpu, arg.u.gpRegisterID);
+                break;
+            case Arg::Type::FPRegisterID:
+                MacroAssemblerType::printRegister(context->cpu, arg.u.fpRegisterID);
+                break;
+            case Arg::Type::ConstCharPtr:
+                dataLog(arg.u.constCharPtr);
+                break;
+            case Arg::Type::ConstVoidPtr:
+                dataLogF("%p", arg.u.constVoidPtr);
+                break;
+            case Arg::Type::IntptrValue:
+                dataLog(arg.u.intptrValue);
+                break;
+            case Arg::Type::UintptrValue:
+                dataLog(arg.u.uintptrValue);
+                break;
+            }
+        }
+    }
+
+#endif // ENABLE(MASM_PROBE)
+
+}; // class AbstractMacroAssembler
 
 } // namespace JSC