]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - assembler/LinkBuffer.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / assembler / LinkBuffer.h
index 47cac5ab63cc9ff952898df4c1dfa9b0ad974560..b48c7e9261258af7c5e29ccf97f2eac06b3e0ab5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(ASSEMBLER)
 
-#include <MacroAssembler.h>
+#define DUMP_LINK_STATISTICS 0
+#define DUMP_CODE 0
+
+#define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1))
+#define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2))
+
+#include "JITCompilationEffort.h"
+#include "MacroAssembler.h"
+#include <wtf/DataLog.h>
 #include <wtf/Noncopyable.h>
 
 namespace JSC {
 
+class VM;
+
 // LinkBuffer:
 //
 // This class assists in linking code generated by the macro assembler, once code generation
@@ -47,61 +57,87 @@ namespace JSC {
 //   * The address of a Label pointing into the code may be resolved.
 //   * The value referenced by a DataLabel may be set.
 //
-class LinkBuffer : public Noncopyable {
+class LinkBuffer {
+    WTF_MAKE_NONCOPYABLE(LinkBuffer);
     typedef MacroAssemblerCodeRef CodeRef;
+    typedef MacroAssemblerCodePtr CodePtr;
     typedef MacroAssembler::Label Label;
     typedef MacroAssembler::Jump Jump;
+    typedef MacroAssembler::PatchableJump PatchableJump;
     typedef MacroAssembler::JumpList JumpList;
     typedef MacroAssembler::Call Call;
+    typedef MacroAssembler::DataLabelCompact DataLabelCompact;
     typedef MacroAssembler::DataLabel32 DataLabel32;
     typedef MacroAssembler::DataLabelPtr DataLabelPtr;
+    typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
+#if ENABLE(BRANCH_COMPACTION)
+    typedef MacroAssembler::LinkRecord LinkRecord;
+    typedef MacroAssembler::JumpLinkType JumpLinkType;
+#endif
 
 public:
-    // Note: Initialization sequence is significant, since executablePool is a PassRefPtr.
-    //       First, executablePool is copied into m_executablePool, then the initialization of
-    //       m_code uses m_executablePool, *not* executablePool, since this is no longer valid.
-    LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool)
-        : m_executablePool(executablePool)
-        , m_code(masm->m_assembler.executableCopy(m_executablePool.get()))
-        , m_size(masm->m_assembler.size())
+    LinkBuffer(VM& vm, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+        : m_size(0)
+#if ENABLE(BRANCH_COMPACTION)
+        , m_initialSize(0)
+#endif
+        , m_code(0)
+        , m_assembler(masm)
+        , m_vm(&vm)
 #ifndef NDEBUG
         , m_completed(false)
+        , m_effort(effort)
 #endif
     {
+        linkCode(ownerUID, effort);
     }
 
     ~LinkBuffer()
     {
-        ASSERT(m_completed);
+        ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail));
+    }
+    
+    bool didFailToAllocate() const
+    {
+        return !m_executableMemory;
     }
 
+    bool isValid() const
+    {
+        return !didFailToAllocate();
+    }
+    
     // These methods are used to link or set values at code generation time.
 
     void link(Call call, FunctionPtr function)
     {
         ASSERT(call.isFlagSet(Call::Linkable));
+        call.m_label = applyOffset(call.m_label);
         MacroAssembler::linkCall(code(), call, function);
     }
     
     void link(Jump jump, CodeLocationLabel label)
     {
+        jump.m_label = applyOffset(jump.m_label);
         MacroAssembler::linkJump(code(), jump, label);
     }
 
     void link(JumpList list, CodeLocationLabel label)
     {
         for (unsigned i = 0; i < list.m_jumps.size(); ++i)
-            MacroAssembler::linkJump(code(), list.m_jumps[i], label);
+            link(list.m_jumps[i], label);
     }
 
     void patch(DataLabelPtr label, void* value)
     {
-        MacroAssembler::linkPointer(code(), label.m_label, value);
+        AssemblerLabel target = applyOffset(label.m_label);
+        MacroAssembler::linkPointer(code(), target, value);
     }
 
     void patch(DataLabelPtr label, CodeLocationLabel value)
     {
-        MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress());
+        AssemblerLabel target = applyOffset(label.m_label);
+        MacroAssembler::linkPointer(code(), target, value.executableAddress());
     }
 
     // These methods are used to obtain handles to allow the code to be relinked / repatched later.
@@ -110,82 +146,154 @@ public:
     {
         ASSERT(call.isFlagSet(Call::Linkable));
         ASSERT(!call.isFlagSet(Call::Near));
-        return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
+        return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label)));
     }
 
     CodeLocationNearCall locationOfNearCall(Call call)
     {
         ASSERT(call.isFlagSet(Call::Linkable));
         ASSERT(call.isFlagSet(Call::Near));
-        return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
+        return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label)));
+    }
+
+    CodeLocationLabel locationOf(PatchableJump jump)
+    {
+        return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump.m_jump.m_label)));
     }
 
     CodeLocationLabel locationOf(Label label)
     {
-        return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label));
+        return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
     }
 
     CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
     {
-        return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label));
+        return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
     }
 
     CodeLocationDataLabel32 locationOf(DataLabel32 label)
     {
-        return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label));
+        return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
+    }
+    
+    CodeLocationDataLabelCompact locationOf(DataLabelCompact label)
+    {
+        return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
+    }
+
+    CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label)
+    {
+        return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
     }
 
     // This method obtains the return address of the call, given as an offset from
     // the start of the code.
     unsigned returnAddressOffset(Call call)
     {
+        call.m_label = applyOffset(call.m_label);
         return MacroAssembler::getLinkerCallReturnOffset(call);
     }
 
-    // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
-    // once to complete generation of the code.  'finalizeCode()' is suited to situations
-    // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
-    // suited to adding to an existing allocation.
-    CodeRef finalizeCode()
+    uint32_t offsetOf(Label label)
     {
-        performFinalization();
-
-        return CodeRef(m_code, m_executablePool, m_size);
+        return applyOffset(label.m_label).m_offset;
     }
-    CodeLocationLabel finalizeCodeAddendum()
+
+    // Upon completion of all patching 'FINALIZE_CODE()' should be called once to
+    // complete generation of the code. Alternatively, call
+    // finalizeCodeWithoutDisassembly() directly if you have your own way of
+    // displaying disassembly.
+    
+    CodeRef finalizeCodeWithoutDisassembly();
+    CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+
+    CodePtr trampolineAt(Label label)
     {
-        performFinalization();
+        return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label)));
+    }
 
-        return CodeLocationLabel(code());
+    void* debugAddress()
+    {
+        return m_code;
+    }
+    
+    size_t debugSize()
+    {
+        return m_size;
     }
 
 private:
-    // Keep this private! - the underlying code should only be obtained externally via 
-    // finalizeCode() or finalizeCodeAddendum().
+    template <typename T> T applyOffset(T src)
+    {
+#if ENABLE(BRANCH_COMPACTION)
+        src.m_offset -= m_assembler->executableOffsetFor(src.m_offset);
+#endif
+        return src;
+    }
+    
+    // Keep this private! - the underlying code should only be obtained externally via finalizeCode().
     void* code()
     {
         return m_code;
     }
 
-    void performFinalization()
-    {
-#ifndef NDEBUG
-        ASSERT(!m_completed);
-        m_completed = true;
+    void linkCode(void* ownerUID, JITCompilationEffort);
+#if ENABLE(BRANCH_COMPACTION)
+    template <typename InstructionType>
+    void copyCompactAndLinkCode(void* ownerUID, JITCompilationEffort);
 #endif
 
-        ExecutableAllocator::makeExecutable(code(), m_size);
-        ExecutableAllocator::cacheFlush(code(), m_size);
-    }
+    void performFinalization();
 
-    RefPtr<ExecutablePool> m_executablePool;
-    void* m_code;
+#if DUMP_LINK_STATISTICS
+    static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize);
+#endif
+    
+#if DUMP_CODE
+    static void dumpCode(void* code, size_t);
+#endif
+    
+    RefPtr<ExecutableMemoryHandle> m_executableMemory;
     size_t m_size;
+#if ENABLE(BRANCH_COMPACTION)
+    size_t m_initialSize;
+#endif
+    void* m_code;
+    MacroAssembler* m_assembler;
+    VM* m_vm;
 #ifndef NDEBUG
     bool m_completed;
+    JITCompilationEffort m_effort;
 #endif
 };
 
+#define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading)  \
+    (UNLIKELY((condition))                                              \
+     ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \
+     : (linkBufferReference).finalizeCodeWithoutDisassembly())
+
+// Use this to finalize code, like so:
+//
+// CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number));
+//
+// Which, in disassembly mode, will print:
+//
+// Generated JIT code for my super thingy number 42:
+//     Code at [0x123456, 0x234567]:
+//         0x123456: mov $0, 0
+//         0x12345a: ret
+//
+// ... and so on.
+//
+// Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
+// is true, so you can hide expensive disassembly-only computations inside there.
+
+#define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading)  \
+    FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading)
+
+#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading)  \
+    FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
+
 } // namespace JSC
 
 #endif // ENABLE(ASSEMBLER)