1/* 2 * Copyright (C) 2009, 2010, 2012, 2013, 2014 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 26#ifndef LinkBuffer_h 27#define LinkBuffer_h 28 29#if ENABLE(ASSEMBLER) 30 31#define DUMP_LINK_STATISTICS 0 32#define DUMP_CODE 0 33 34#define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1)) 35#define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2)) 36#define CSS_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3)) 37 38#include "JITCompilationEffort.h" 39#include "MacroAssembler.h" 40#include <wtf/DataLog.h> 41#include <wtf/FastMalloc.h> 42#include <wtf/Noncopyable.h> 43 44namespace JSC { 45 46class CodeBlock; 47class VM; 48 49// LinkBuffer: 50// 51// This class assists in linking code generated by the macro assembler, once code generation 52// has been completed, and the code has been copied to is final location in memory. At this 53// time pointers to labels within the code may be resolved, and relative offsets to external 54// addresses may be fixed. 55// 56// Specifically: 57// * Jump objects may be linked to external targets, 58// * The address of Jump objects may taken, such that it can later be relinked. 59// * The return address of a Call may be acquired. 60// * The address of a Label pointing into the code may be resolved. 61// * The value referenced by a DataLabel may be set. 62// 63class LinkBuffer { 64 WTF_MAKE_NONCOPYABLE(LinkBuffer); WTF_MAKE_FAST_ALLOCATED; 65 66 typedef MacroAssemblerCodeRef CodeRef; 67 typedef MacroAssemblerCodePtr CodePtr; 68 typedef MacroAssembler::Label Label; 69 typedef MacroAssembler::Jump Jump; 70 typedef MacroAssembler::PatchableJump PatchableJump; 71 typedef MacroAssembler::JumpList JumpList; 72 typedef MacroAssembler::Call Call; 73 typedef MacroAssembler::DataLabelCompact DataLabelCompact; 74 typedef MacroAssembler::DataLabel32 DataLabel32; 75 typedef MacroAssembler::DataLabelPtr DataLabelPtr; 76 typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel; 77#if ENABLE(BRANCH_COMPACTION) 78 typedef MacroAssembler::LinkRecord LinkRecord; 79 typedef MacroAssembler::JumpLinkType JumpLinkType; 80#endif 81 82public: 83 LinkBuffer(VM& vm, MacroAssembler& macroAssembler, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) 84 : m_size(0) 85#if ENABLE(BRANCH_COMPACTION) 86 , m_initialSize(0) 87#endif 88 , m_didAllocate(false) 89 , m_code(0) 90 , m_vm(&vm) 91#ifndef NDEBUG 92 , m_completed(false) 93#endif 94 { 95 linkCode(macroAssembler, ownerUID, effort); 96 } 97 98 LinkBuffer(VM& vm, MacroAssembler& macroAssembler, void* code, size_t size) 99 : m_size(size) 100#if ENABLE(BRANCH_COMPACTION) 101 , m_initialSize(0) 102#endif 103 , m_didAllocate(false) 104 , m_code(code) 105 , m_vm(&vm) 106#ifndef NDEBUG 107 , m_completed(false) 108#endif 109 { 110 linkCode(macroAssembler, 0, JITCompilationCanFail); 111 } 112 113 ~LinkBuffer() 114 { 115 } 116 117 bool didFailToAllocate() const 118 { 119 return !m_didAllocate; 120 } 121 122 bool isValid() const 123 { 124 return !didFailToAllocate(); 125 } 126 127 // These methods are used to link or set values at code generation time. 128 129 void link(Call call, FunctionPtr function) 130 { 131 ASSERT(call.isFlagSet(Call::Linkable)); 132 call.m_label = applyOffset(call.m_label); 133 MacroAssembler::linkCall(code(), call, function); 134 } 135 136 void link(Call call, CodeLocationLabel label) 137 { 138 link(call, FunctionPtr(label.executableAddress())); 139 } 140 141 void link(Jump jump, CodeLocationLabel label) 142 { 143 jump.m_label = applyOffset(jump.m_label); 144 MacroAssembler::linkJump(code(), jump, label); 145 } 146 147 void link(JumpList list, CodeLocationLabel label) 148 { 149 for (unsigned i = 0; i < list.m_jumps.size(); ++i) 150 link(list.m_jumps[i], label); 151 } 152 153 void patch(DataLabelPtr label, void* value) 154 { 155 AssemblerLabel target = applyOffset(label.m_label); 156 MacroAssembler::linkPointer(code(), target, value); 157 } 158 159 void patch(DataLabelPtr label, CodeLocationLabel value) 160 { 161 AssemblerLabel target = applyOffset(label.m_label); 162 MacroAssembler::linkPointer(code(), target, value.executableAddress()); 163 } 164 165 // These methods are used to obtain handles to allow the code to be relinked / repatched later. 166 167 CodeLocationLabel entrypoint() 168 { 169 return CodeLocationLabel(code()); 170 } 171 172 CodeLocationCall locationOf(Call call) 173 { 174 ASSERT(call.isFlagSet(Call::Linkable)); 175 ASSERT(!call.isFlagSet(Call::Near)); 176 return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); 177 } 178 179 CodeLocationNearCall locationOfNearCall(Call call) 180 { 181 ASSERT(call.isFlagSet(Call::Linkable)); 182 ASSERT(call.isFlagSet(Call::Near)); 183 return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); 184 } 185 186 CodeLocationLabel locationOf(PatchableJump jump) 187 { 188 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump.m_jump.m_label))); 189 } 190 191 CodeLocationLabel locationOf(Label label) 192 { 193 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); 194 } 195 196 CodeLocationDataLabelPtr locationOf(DataLabelPtr label) 197 { 198 return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); 199 } 200 201 CodeLocationDataLabel32 locationOf(DataLabel32 label) 202 { 203 return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); 204 } 205 206 CodeLocationDataLabelCompact locationOf(DataLabelCompact label) 207 { 208 return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); 209 } 210 211 CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label) 212 { 213 return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); 214 } 215 216 // This method obtains the return address of the call, given as an offset from 217 // the start of the code. 218 unsigned returnAddressOffset(Call call) 219 { 220 call.m_label = applyOffset(call.m_label); 221 return MacroAssembler::getLinkerCallReturnOffset(call); 222 } 223 224 uint32_t offsetOf(Label label) 225 { 226 return applyOffset(label.m_label).m_offset; 227 } 228 229 unsigned offsetOf(PatchableJump jump) 230 { 231 return applyOffset(jump.m_jump.m_label).m_offset; 232 } 233 234 // Upon completion of all patching 'FINALIZE_CODE()' should be called once to 235 // complete generation of the code. Alternatively, call 236 // finalizeCodeWithoutDisassembly() directly if you have your own way of 237 // displaying disassembly. 238 239 JS_EXPORT_PRIVATE CodeRef finalizeCodeWithoutDisassembly(); 240 JS_EXPORT_PRIVATE CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); 241 242 CodePtr trampolineAt(Label label) 243 { 244 return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label))); 245 } 246 247 void* debugAddress() 248 { 249 return m_code; 250 } 251 252 // FIXME: this does not account for the AssemblerData size! 253 size_t size() 254 { 255 return m_size; 256 } 257 258private: 259#if ENABLE(BRANCH_COMPACTION) 260 int executableOffsetFor(int location) 261 { 262 if (!location) 263 return 0; 264 return bitwise_cast<int32_t*>(m_assemblerStorage.buffer())[location / sizeof(int32_t) - 1]; 265 } 266#endif 267 268 template <typename T> T applyOffset(T src) 269 { 270#if ENABLE(BRANCH_COMPACTION) 271 src.m_offset -= executableOffsetFor(src.m_offset); 272#endif 273 return src; 274 } 275 276 // Keep this private! - the underlying code should only be obtained externally via finalizeCode(). 277 void* code() 278 { 279 return m_code; 280 } 281 282 void allocate(size_t initialSize, void* ownerUID, JITCompilationEffort); 283 void shrink(size_t newSize); 284 285 JS_EXPORT_PRIVATE void linkCode(MacroAssembler&, void* ownerUID, JITCompilationEffort); 286#if ENABLE(BRANCH_COMPACTION) 287 template <typename InstructionType> 288 void copyCompactAndLinkCode(MacroAssembler&, void* ownerUID, JITCompilationEffort); 289#endif 290 291 void performFinalization(); 292 293#if DUMP_LINK_STATISTICS 294 static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize); 295#endif 296 297#if DUMP_CODE 298 static void dumpCode(void* code, size_t); 299#endif 300 301 RefPtr<ExecutableMemoryHandle> m_executableMemory; 302 size_t m_size; 303#if ENABLE(BRANCH_COMPACTION) 304 size_t m_initialSize; 305 AssemblerData m_assemblerStorage; 306#endif 307 bool m_didAllocate; 308 void* m_code; 309 VM* m_vm; 310#ifndef NDEBUG 311 bool m_completed; 312#endif 313}; 314 315#define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \ 316 (UNLIKELY((condition)) \ 317 ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \ 318 : (linkBufferReference).finalizeCodeWithoutDisassembly()) 319 320bool shouldShowDisassemblyFor(CodeBlock*); 321 322#define FINALIZE_CODE_FOR(codeBlock, linkBufferReference, dataLogFArgumentsForHeading) \ 323 FINALIZE_CODE_IF(shouldShowDisassemblyFor(codeBlock), linkBufferReference, dataLogFArgumentsForHeading) 324 325// Use this to finalize code, like so: 326// 327// CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number)); 328// 329// Which, in disassembly mode, will print: 330// 331// Generated JIT code for my super thingy number 42: 332// Code at [0x123456, 0x234567]: 333// 0x123456: mov $0, 0 334// 0x12345a: ret 335// 336// ... and so on. 337// 338// Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly 339// is true, so you can hide expensive disassembly-only computations inside there. 340 341#define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ 342 FINALIZE_CODE_IF(JSC::Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) 343 344#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ 345 FINALIZE_CODE_IF((JSC::Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading) 346 347} // namespace JSC 348 349#endif // ENABLE(ASSEMBLER) 350 351#endif // LinkBuffer_h 352