]> 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 a20990072fa058ba5cbb1e55a7a85b0da5600e49..6e82dcc5eb2758e7ab960b022a7dbaf58ce0736f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012, 2014 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
@@ -39,9 +39,9 @@
 
 namespace JSC {
 
-inline bool isARMv7s()
+inline bool isARMv7IDIVSupported()
 {
-#if CPU(APPLE_ARMV7S)
+#if HAVE(ARM_IDIV_INSTRUCTIONS)
     return true;
 #else
     return false;
@@ -66,9 +66,9 @@ inline bool isX86()
 #endif
 }
 
-inline bool optimizeForARMv7s()
+inline bool optimizeForARMv7IDIVSupported()
 {
-    return isARMv7s() && Options::enableArchitectureSpecificOptimizations();
+    return isARMv7IDIVSupported() && Options::enableArchitectureSpecificOptimizations();
 }
 
 inline bool optimizeForARM64()
@@ -88,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;
@@ -204,6 +205,11 @@ public:
         RegisterID index;
         Scale scale;
         int32_t offset;
+        
+        BaseIndex withOffset(int32_t additionalOffset)
+        {
+            return BaseIndex(base, index, scale, offset + additionalOffset);
+        }
     };
 
     // AbsoluteAddress:
@@ -355,7 +361,7 @@ 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;
@@ -368,7 +374,7 @@ public:
         {
         }
 
-        Label(AbstractMacroAssembler<AssemblerType>* masm)
+        Label(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
             masm->invalidateAllTempRegisters();
@@ -390,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;
         
@@ -399,7 +405,7 @@ public:
         {
         }
         
-        ConvertibleLoadLabel(AbstractMacroAssembler<AssemblerType>* masm)
+        ConvertibleLoadLabel(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.labelIgnoringWatchpoints())
         {
         }
@@ -414,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:
@@ -422,7 +428,7 @@ public:
         {
         }
 
-        DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelPtr(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -438,7 +444,7 @@ public:
     // 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:
@@ -446,7 +452,7 @@ public:
         {
         }
 
-        DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabel32(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -462,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:
@@ -470,7 +476,7 @@ public:
         {
         }
         
-        DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
+        DataLabelCompact(AbstractMacroAssemblerType* masm)
             : m_label(masm->m_assembler.label())
         {
         }
@@ -493,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:
@@ -537,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;
@@ -602,7 +608,7 @@ public:
             return result;
         }
 
-        void link(AbstractMacroAssembler<AssemblerType>* masm) const
+        void link(AbstractMacroAssemblerType* masm) const
         {
             masm->invalidateAllTempRegisters();
 
@@ -626,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);
@@ -698,7 +704,7 @@ public:
                 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)
@@ -706,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)
@@ -836,6 +842,188 @@ 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:
@@ -877,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)
@@ -905,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;
@@ -995,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