]> 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 71b9d1f1649f040a705d9cbfafb179731d6bda83..6e82dcc5eb2758e7ab960b022a7dbaf58ce0736f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012 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>
 
 #if ENABLE(ASSEMBLER)
 
-
-#if PLATFORM(QT)
-#define ENABLE_JIT_CONSTANT_BLINDING 0
-#endif
-
-#ifndef ENABLE_JIT_CONSTANT_BLINDING
-#define ENABLE_JIT_CONSTANT_BLINDING 1
-#endif
-
 namespace JSC {
 
-inline bool isARMv7s()
+inline bool isARMv7IDIVSupported()
 {
-#if CPU(APPLE_ARMV7S)
+#if HAVE(ARM_IDIV_INSTRUCTIONS)
     return true;
 #else
     return false;
@@ -72,7 +66,21 @@ inline bool isX86()
 #endif
 }
 
-class JumpReplacementWatchpoint;
+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;
@@ -80,10 +88,11 @@ 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;
@@ -92,6 +101,13 @@ 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
     //
@@ -104,6 +120,13 @@ public:
         TimesFour,
         TimesEight,
     };
+    
+    static Scale timesPtr()
+    {
+        if (sizeof(void*) == 4)
+            return TimesFour;
+        return TimesEight;
+    }
 
     // Address:
     //
@@ -114,7 +137,12 @@ public:
             , offset(offset)
         {
         }
-
+        
+        Address withOffset(int32_t additionalOffset)
+        {
+            return Address(base, offset + additionalOffset);
+        }
+        
         RegisterID base;
         int32_t offset;
     };
@@ -177,6 +205,11 @@ public:
         RegisterID index;
         Scale scale;
         int32_t offset;
+        
+        BaseIndex withOffset(int32_t additionalOffset)
+        {
+            return BaseIndex(base, index, scale, offset + additionalOffset);
+        }
     };
 
     // AbsoluteAddress:
@@ -226,12 +259,7 @@ public:
         const void* m_value;
     };
 
-    struct ImmPtr : 
-#if ENABLE(JIT_CONSTANT_BLINDING)
-        private TrustedImmPtr 
-#else
-        public TrustedImmPtr
-#endif
+    struct ImmPtr : private TrustedImmPtr
     {
         explicit ImmPtr(const void* value)
             : TrustedImmPtr(value)
@@ -266,13 +294,7 @@ public:
     };
 
 
-    struct Imm32 : 
-#if ENABLE(JIT_CONSTANT_BLINDING)
-        private TrustedImm32 
-#else
-        public TrustedImm32
-#endif
-    {
+    struct Imm32 : private TrustedImm32 {
         explicit Imm32(int32_t value)
             : TrustedImm32(value)
         {
@@ -311,12 +333,7 @@ public:
         int64_t m_value;
     };
 
-    struct Imm64 : 
-#if ENABLE(JIT_CONSTANT_BLINDING)
-        private TrustedImm64 
-#else
-        public TrustedImm64
-#endif
+    struct Imm64 : private TrustedImm64
     {
         explicit Imm64(int64_t value)
             : TrustedImm64(value)
@@ -344,11 +361,10 @@ 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 JumpReplacementWatchpoint;
         friend class MacroAssemblerCodeRef;
         friend class LinkBuffer;
         friend class Watchpoint;
@@ -358,7 +374,7 @@ public:
         {
         }
 
-        Label(AbstractMacroAssembler<AssemblerType>* masm)
+        Label(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
             masm->invalidateAllTempRegisters();
@@ -380,7 +396,7 @@ public:
     //
     // addPtr(TrustedImmPtr(i), a, b)
     class ConvertibleLoadLabel {
-        template<class TemplateAssemblerType>
+        template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
         friend class AbstractMacroAssembler;
         friend class LinkBuffer;
         
@@ -389,7 +405,7 @@ public:
         {
         }
         
-        ConvertibleLoadLabel(AbstractMacroAssembler<AssemblerType>* masm)
+        ConvertibleLoadLabel(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.labelIgnoringWatchpoints())
         {
         }
@@ -404,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:
@@ -412,7 +428,7 @@ public:
         {
         }
 
-        DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelPtr(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -425,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:
@@ -436,7 +452,7 @@ public:
         {
         }
 
-        DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabel32(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -452,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:
@@ -460,7 +476,7 @@ public:
         {
         }
         
-        DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelCompact(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -470,6 +486,8 @@ public:
         {
         }
 
+        AssemblerLabel label() const { return m_label; }
+
     private:
         AssemblerLabel m_label;
     };
@@ -481,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:
@@ -525,7 +543,7 @@ 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;
@@ -590,7 +608,7 @@ public:
             return result;
         }
 
-        void link(AbstractMacroAssembler<AssemblerType>* masm) const
+        void link(AbstractMacroAssemblerType* masm) const
         {
             masm->invalidateAllTempRegisters();
 
@@ -614,7 +632,7 @@ public:
 #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);
@@ -682,10 +700,11 @@ public:
         
         JumpList(Jump jump)
         {
-            append(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)
@@ -693,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)
@@ -775,7 +794,7 @@ public:
         {
         }
 
-        void check(unsigned low, unsigned high)
+        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);
         }
@@ -801,7 +820,7 @@ public:
 
         size_t size = m_registerAllocationForOffsets.size();
         for (size_t i = 0; i < size; ++i)
-            m_registerAllocationForOffsets[i].check(offset1, offset2);
+            m_registerAllocationForOffsets[i].checkOffsets(offset1, offset2);
     }
 #endif
 
@@ -822,14 +841,198 @@ public:
     {
         AssemblerType::cacheFlush(code, size);
     }
+
+#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)
+    {
+        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
+    }
+
+    // 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)
+    {
+        printInternal(static_cast<MacroAssemblerType*>(this), args...);
+    }
+
+    // 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())
     {
+        invalidateAllTempRegisters();
     }
 
-    AssemblerType m_assembler;
-    
     uint32_t random()
     {
         return m_randomSource.getUint32();
@@ -841,11 +1044,18 @@ protected:
     Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
 #endif
 
-#if ENABLE(JIT_CONSTANT_BLINDING)
-    static bool scratchRegisterForBlinding() { return false; }
-    static bool shouldBlindForSpecificArch(uint32_t) { return true; }
-    static bool shouldBlindForSpecificArch(uint64_t) { return true; }
-#endif
+    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;
@@ -855,7 +1065,7 @@ protected:
         friend class Label;
 
     public:
-        CachedTempRegister(AbstractMacroAssembler<AssemblerType>* masm, RegisterID registerID)
+        CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
             : m_masm(masm)
             , m_registerID(registerID)
             , m_value(0)
@@ -883,7 +1093,7 @@ protected:
         ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
 
     private:
-        AbstractMacroAssembler<AssemblerType>* m_masm;
+        AbstractMacroAssemblerType* m_masm;
         RegisterID m_registerID;
         intptr_t m_value;
         unsigned m_validBit;
@@ -973,7 +1183,143 @@ protected:
     {
         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