LinkBuffer.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Copyright (C) 2009, 2010, 2012 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef LinkBuffer_h
  26. #define LinkBuffer_h
  27. #if ENABLE(ASSEMBLER)
  28. #define DUMP_LINK_STATISTICS 0
  29. #define DUMP_CODE 0
  30. #define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1))
  31. #define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2))
  32. #include "JITCompilationEffort.h"
  33. #include "MacroAssembler.h"
  34. #include <wtf/DataLog.h>
  35. #include <wtf/Noncopyable.h>
  36. namespace JSC {
  37. class VM;
  38. // LinkBuffer:
  39. //
  40. // This class assists in linking code generated by the macro assembler, once code generation
  41. // has been completed, and the code has been copied to is final location in memory. At this
  42. // time pointers to labels within the code may be resolved, and relative offsets to external
  43. // addresses may be fixed.
  44. //
  45. // Specifically:
  46. // * Jump objects may be linked to external targets,
  47. // * The address of Jump objects may taken, such that it can later be relinked.
  48. // * The return address of a Call may be acquired.
  49. // * The address of a Label pointing into the code may be resolved.
  50. // * The value referenced by a DataLabel may be set.
  51. //
  52. class LinkBuffer {
  53. WTF_MAKE_NONCOPYABLE(LinkBuffer);
  54. typedef MacroAssemblerCodeRef CodeRef;
  55. typedef MacroAssemblerCodePtr CodePtr;
  56. typedef MacroAssembler::Label Label;
  57. typedef MacroAssembler::Jump Jump;
  58. typedef MacroAssembler::PatchableJump PatchableJump;
  59. typedef MacroAssembler::JumpList JumpList;
  60. typedef MacroAssembler::Call Call;
  61. typedef MacroAssembler::DataLabelCompact DataLabelCompact;
  62. typedef MacroAssembler::DataLabel32 DataLabel32;
  63. typedef MacroAssembler::DataLabelPtr DataLabelPtr;
  64. typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
  65. #if ENABLE(BRANCH_COMPACTION)
  66. typedef MacroAssembler::LinkRecord LinkRecord;
  67. typedef MacroAssembler::JumpLinkType JumpLinkType;
  68. #endif
  69. public:
  70. LinkBuffer(VM& vm, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
  71. : m_size(0)
  72. #if ENABLE(BRANCH_COMPACTION)
  73. , m_initialSize(0)
  74. #endif
  75. , m_code(0)
  76. , m_assembler(masm)
  77. , m_vm(&vm)
  78. #ifndef NDEBUG
  79. , m_completed(false)
  80. , m_effort(effort)
  81. #endif
  82. {
  83. linkCode(ownerUID, effort);
  84. }
  85. ~LinkBuffer()
  86. {
  87. ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail));
  88. }
  89. bool didFailToAllocate() const
  90. {
  91. return !m_executableMemory;
  92. }
  93. bool isValid() const
  94. {
  95. return !didFailToAllocate();
  96. }
  97. // These methods are used to link or set values at code generation time.
  98. void link(Call call, FunctionPtr function)
  99. {
  100. ASSERT(call.isFlagSet(Call::Linkable));
  101. call.m_label = applyOffset(call.m_label);
  102. MacroAssembler::linkCall(code(), call, function);
  103. }
  104. void link(Jump jump, CodeLocationLabel label)
  105. {
  106. jump.m_label = applyOffset(jump.m_label);
  107. MacroAssembler::linkJump(code(), jump, label);
  108. }
  109. void link(JumpList list, CodeLocationLabel label)
  110. {
  111. for (unsigned i = 0; i < list.m_jumps.size(); ++i)
  112. link(list.m_jumps[i], label);
  113. }
  114. void patch(DataLabelPtr label, void* value)
  115. {
  116. AssemblerLabel target = applyOffset(label.m_label);
  117. MacroAssembler::linkPointer(code(), target, value);
  118. }
  119. void patch(DataLabelPtr label, CodeLocationLabel value)
  120. {
  121. AssemblerLabel target = applyOffset(label.m_label);
  122. MacroAssembler::linkPointer(code(), target, value.executableAddress());
  123. }
  124. // These methods are used to obtain handles to allow the code to be relinked / repatched later.
  125. CodeLocationCall locationOf(Call call)
  126. {
  127. ASSERT(call.isFlagSet(Call::Linkable));
  128. ASSERT(!call.isFlagSet(Call::Near));
  129. return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label)));
  130. }
  131. CodeLocationNearCall locationOfNearCall(Call call)
  132. {
  133. ASSERT(call.isFlagSet(Call::Linkable));
  134. ASSERT(call.isFlagSet(Call::Near));
  135. return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label)));
  136. }
  137. CodeLocationLabel locationOf(PatchableJump jump)
  138. {
  139. return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump.m_jump.m_label)));
  140. }
  141. CodeLocationLabel locationOf(Label label)
  142. {
  143. return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
  144. }
  145. CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
  146. {
  147. return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
  148. }
  149. CodeLocationDataLabel32 locationOf(DataLabel32 label)
  150. {
  151. return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
  152. }
  153. CodeLocationDataLabelCompact locationOf(DataLabelCompact label)
  154. {
  155. return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
  156. }
  157. CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label)
  158. {
  159. return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
  160. }
  161. // This method obtains the return address of the call, given as an offset from
  162. // the start of the code.
  163. unsigned returnAddressOffset(Call call)
  164. {
  165. call.m_label = applyOffset(call.m_label);
  166. return MacroAssembler::getLinkerCallReturnOffset(call);
  167. }
  168. uint32_t offsetOf(Label label)
  169. {
  170. return applyOffset(label.m_label).m_offset;
  171. }
  172. // Upon completion of all patching 'FINALIZE_CODE()' should be called once to
  173. // complete generation of the code. Alternatively, call
  174. // finalizeCodeWithoutDisassembly() directly if you have your own way of
  175. // displaying disassembly.
  176. CodeRef finalizeCodeWithoutDisassembly();
  177. CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
  178. CodePtr trampolineAt(Label label)
  179. {
  180. return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label)));
  181. }
  182. void* debugAddress()
  183. {
  184. return m_code;
  185. }
  186. size_t debugSize()
  187. {
  188. return m_size;
  189. }
  190. private:
  191. template <typename T> T applyOffset(T src)
  192. {
  193. #if ENABLE(BRANCH_COMPACTION)
  194. src.m_offset -= m_assembler->executableOffsetFor(src.m_offset);
  195. #endif
  196. return src;
  197. }
  198. // Keep this private! - the underlying code should only be obtained externally via finalizeCode().
  199. void* code()
  200. {
  201. return m_code;
  202. }
  203. void linkCode(void* ownerUID, JITCompilationEffort);
  204. void performFinalization();
  205. #if DUMP_LINK_STATISTICS
  206. static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize);
  207. #endif
  208. #if DUMP_CODE
  209. static void dumpCode(void* code, size_t);
  210. #endif
  211. RefPtr<ExecutableMemoryHandle> m_executableMemory;
  212. size_t m_size;
  213. #if ENABLE(BRANCH_COMPACTION)
  214. size_t m_initialSize;
  215. #endif
  216. void* m_code;
  217. MacroAssembler* m_assembler;
  218. VM* m_vm;
  219. #ifndef NDEBUG
  220. bool m_completed;
  221. JITCompilationEffort m_effort;
  222. #endif
  223. };
  224. #if ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT
  225. #define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \
  226. (UNLIKELY((condition)) \
  227. ? ((linkBufferReference).finalizeCodeWithDisassembly ("")) \
  228. : (linkBufferReference).finalizeCodeWithoutDisassembly())
  229. #else
  230. #define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \
  231. (UNLIKELY((condition)) \
  232. ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \
  233. : (linkBufferReference).finalizeCodeWithoutDisassembly())
  234. #endif
  235. // Use this to finalize code, like so:
  236. //
  237. // CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number));
  238. //
  239. // Which, in disassembly mode, will print:
  240. //
  241. // Generated JIT code for my super thingy number 42:
  242. // Code at [0x123456, 0x234567]:
  243. // 0x123456: mov $0, 0
  244. // 0x12345a: ret
  245. //
  246. // ... and so on.
  247. //
  248. // Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
  249. // is true, so you can hide expensive disassembly-only computations inside there.
  250. #define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
  251. FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading)
  252. #define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
  253. FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
  254. } // namespace JSC
  255. #endif // ENABLE(ASSEMBLER)
  256. #endif // LinkBuffer_h