1 /* 2 * Copyright (C) 2008 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 AbstractMacroAssembler_h 27 #define AbstractMacroAssembler_h 28 29 #include <wtf/Platform.h> 30 31 #include <MacroAssemblerCodeRef.h> 32 #include <CodeLocation.h> 33 #include <wtf/Noncopyable.h> 34 #include <wtf/UnusedParam.h> 35 36 #if ENABLE(ASSEMBLER) 37 38 namespace JSC { 39 40 class LinkBuffer; 41 class RepatchBuffer; 42 43 template <class AssemblerType> 44 class AbstractMacroAssembler { 45 public: 46 typedef AssemblerType AssemblerType_T; 47 48 typedef MacroAssemblerCodePtr CodePtr; 49 typedef MacroAssemblerCodeRef CodeRef; 50 51 class Jump; 52 53 typedef typename AssemblerType::RegisterID RegisterID; 54 typedef typename AssemblerType::FPRegisterID FPRegisterID; 55 typedef typename AssemblerType::JmpSrc JmpSrc; 56 typedef typename AssemblerType::JmpDst JmpDst; 57 58 59 // Section 1: MacroAssembler operand types 60 // 61 // The following types are used as operands to MacroAssembler operations, 62 // describing immediate and memory operands to the instructions to be planted. 63 64 65 enum Scale { 66 TimesOne, 67 TimesTwo, 68 TimesFour, 69 TimesEight, 70 }; 71 72 // Address: 73 // 74 // Describes a simple base-offset address. 75 struct Address { 76 explicit Address(RegisterID base, int32_t offset = 0) baseAddress77 : base(base) 78 , offset(offset) 79 { 80 } 81 82 RegisterID base; 83 int32_t offset; 84 }; 85 86 // ImplicitAddress: 87 // 88 // This class is used for explicit 'load' and 'store' operations 89 // (as opposed to situations in which a memory operand is provided 90 // to a generic operation, such as an integer arithmetic instruction). 91 // 92 // In the case of a load (or store) operation we want to permit 93 // addresses to be implicitly constructed, e.g. the two calls: 94 // 95 // load32(Address(addrReg), destReg); 96 // load32(addrReg, destReg); 97 // 98 // Are equivalent, and the explicit wrapping of the Address in the former 99 // is unnecessary. 100 struct ImplicitAddress { ImplicitAddressImplicitAddress101 ImplicitAddress(RegisterID base) 102 : base(base) 103 , offset(0) 104 { 105 } 106 ImplicitAddressImplicitAddress107 ImplicitAddress(Address address) 108 : base(address.base) 109 , offset(address.offset) 110 { 111 } 112 113 RegisterID base; 114 int32_t offset; 115 }; 116 117 // BaseIndex: 118 // 119 // Describes a complex addressing mode. 120 struct BaseIndex { 121 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0) baseBaseIndex122 : base(base) 123 , index(index) 124 , scale(scale) 125 , offset(offset) 126 { 127 } 128 129 RegisterID base; 130 RegisterID index; 131 Scale scale; 132 int32_t offset; 133 }; 134 135 // AbsoluteAddress: 136 // 137 // Describes an memory operand given by a pointer. For regular load & store 138 // operations an unwrapped void* will be used, rather than using this. 139 struct AbsoluteAddress { AbsoluteAddressAbsoluteAddress140 explicit AbsoluteAddress(void* ptr) 141 : m_ptr(ptr) 142 { 143 } 144 145 void* m_ptr; 146 }; 147 148 // ImmPtr: 149 // 150 // A pointer sized immediate operand to an instruction - this is wrapped 151 // in a class requiring explicit construction in order to differentiate 152 // from pointers used as absolute addresses to memory operations 153 struct ImmPtr { ImmPtrImmPtr154 explicit ImmPtr(void* value) 155 : m_value(value) 156 { 157 } 158 asIntptrImmPtr159 intptr_t asIntptr() 160 { 161 return reinterpret_cast<intptr_t>(m_value); 162 } 163 164 void* m_value; 165 }; 166 167 // Imm32: 168 // 169 // A 32bit immediate operand to an instruction - this is wrapped in a 170 // class requiring explicit construction in order to prevent RegisterIDs 171 // (which are implemented as an enum) from accidentally being passed as 172 // immediate values. 173 struct Imm32 { Imm32Imm32174 explicit Imm32(int32_t value) 175 : m_value(value) 176 #if PLATFORM(ARM) 177 , m_isPointer(false) 178 #endif 179 { 180 } 181 182 #if !PLATFORM(X86_64) Imm32Imm32183 explicit Imm32(ImmPtr ptr) 184 : m_value(ptr.asIntptr()) 185 #if PLATFORM(ARM) 186 , m_isPointer(true) 187 #endif 188 { 189 } 190 #endif 191 192 int32_t m_value; 193 #if PLATFORM(ARM) 194 // We rely on being able to regenerate code to recover exception handling 195 // information. Since ARMv7 supports 16-bit immediates there is a danger 196 // that if pointer values change the layout of the generated code will change. 197 // To avoid this problem, always generate pointers (and thus Imm32s constructed 198 // from ImmPtrs) with a code sequence that is able to represent any pointer 199 // value - don't use a more compact form in these cases. 200 bool m_isPointer; 201 #endif 202 }; 203 204 205 // Section 2: MacroAssembler code buffer handles 206 // 207 // The following types are used to reference items in the code buffer 208 // during JIT code generation. For example, the type Jump is used to 209 // track the location of a jump instruction so that it may later be 210 // linked to a label marking its destination. 211 212 213 // Label: 214 // 215 // A Label records a point in the generated instruction stream, typically such that 216 // it may be used as a destination for a jump. 217 class Label { 218 template<class TemplateAssemblerType> 219 friend class AbstractMacroAssembler; 220 friend class Jump; 221 friend class MacroAssemblerCodeRef; 222 friend class LinkBuffer; 223 224 public: Label()225 Label() 226 { 227 } 228 Label(AbstractMacroAssembler<AssemblerType> * masm)229 Label(AbstractMacroAssembler<AssemblerType>* masm) 230 : m_label(masm->m_assembler.label()) 231 { 232 } 233 isUsed()234 bool isUsed() const { return m_label.isUsed(); } used()235 void used() { m_label.used(); } 236 private: 237 JmpDst m_label; 238 }; 239 240 // DataLabelPtr: 241 // 242 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be 243 // patched after the code has been generated. 244 class DataLabelPtr { 245 template<class TemplateAssemblerType> 246 friend class AbstractMacroAssembler; 247 friend class LinkBuffer; 248 public: DataLabelPtr()249 DataLabelPtr() 250 { 251 } 252 DataLabelPtr(AbstractMacroAssembler<AssemblerType> * masm)253 DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm) 254 : m_label(masm->m_assembler.label()) 255 { 256 } 257 258 private: 259 JmpDst m_label; 260 }; 261 262 // DataLabel32: 263 // 264 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be 265 // patched after the code has been generated. 266 class DataLabel32 { 267 template<class TemplateAssemblerType> 268 friend class AbstractMacroAssembler; 269 friend class LinkBuffer; 270 public: DataLabel32()271 DataLabel32() 272 { 273 } 274 DataLabel32(AbstractMacroAssembler<AssemblerType> * masm)275 DataLabel32(AbstractMacroAssembler<AssemblerType>* masm) 276 : m_label(masm->m_assembler.label()) 277 { 278 } 279 280 private: 281 JmpDst m_label; 282 }; 283 284 // Call: 285 // 286 // A Call object is a reference to a call instruction that has been planted 287 // into the code buffer - it is typically used to link the call, setting the 288 // relative offset such that when executed it will call to the desired 289 // destination. 290 class Call { 291 template<class TemplateAssemblerType> 292 friend class AbstractMacroAssembler; 293 294 public: 295 enum Flags { 296 None = 0x0, 297 Linkable = 0x1, 298 Near = 0x2, 299 LinkableNear = 0x3, 300 }; 301 Call()302 Call() 303 : m_flags(None) 304 { 305 } 306 Call(JmpSrc jmp,Flags flags)307 Call(JmpSrc jmp, Flags flags) 308 : m_jmp(jmp) 309 , m_flags(flags) 310 { 311 } 312 isFlagSet(Flags flag)313 bool isFlagSet(Flags flag) 314 { 315 return m_flags & flag; 316 } 317 fromTailJump(Jump jump)318 static Call fromTailJump(Jump jump) 319 { 320 return Call(jump.m_jmp, Linkable); 321 } 322 enableLatePatch()323 void enableLatePatch() 324 { 325 m_jmp.enableLatePatch(); 326 } 327 328 JmpSrc m_jmp; 329 private: 330 Flags m_flags; 331 }; 332 333 // Jump: 334 // 335 // A jump object is a reference to a jump instruction that has been planted 336 // into the code buffer - it is typically used to link the jump, setting the 337 // relative offset such that when executed it will jump to the desired 338 // destination. 339 class Jump { 340 template<class TemplateAssemblerType> 341 friend class AbstractMacroAssembler; 342 friend class Call; 343 friend class LinkBuffer; 344 public: Jump()345 Jump() 346 { 347 } 348 Jump(JmpSrc jmp)349 Jump(JmpSrc jmp) 350 : m_jmp(jmp) 351 { 352 } 353 link(AbstractMacroAssembler<AssemblerType> * masm)354 void link(AbstractMacroAssembler<AssemblerType>* masm) 355 { 356 masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); 357 } 358 linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)359 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) 360 { 361 masm->m_assembler.linkJump(m_jmp, label.m_label); 362 } 363 enableLatePatch()364 void enableLatePatch() 365 { 366 m_jmp.enableLatePatch(); 367 } 368 369 private: 370 JmpSrc m_jmp; 371 }; 372 373 // JumpList: 374 // 375 // A JumpList is a set of Jump objects. 376 // All jumps in the set will be linked to the same destination. 377 class JumpList { 378 friend class LinkBuffer; 379 380 public: 381 typedef Vector<Jump, 16> JumpVector; 382 link(AbstractMacroAssembler<AssemblerType> * masm)383 void link(AbstractMacroAssembler<AssemblerType>* masm) 384 { 385 size_t size = m_jumps.size(); 386 for (size_t i = 0; i < size; ++i) 387 m_jumps[i].link(masm); 388 m_jumps.clear(); 389 } 390 linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)391 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) 392 { 393 size_t size = m_jumps.size(); 394 for (size_t i = 0; i < size; ++i) 395 m_jumps[i].linkTo(label, masm); 396 m_jumps.clear(); 397 } 398 append(Jump jump)399 void append(Jump jump) 400 { 401 m_jumps.append(jump); 402 } 403 append(JumpList & other)404 void append(JumpList& other) 405 { 406 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size()); 407 } 408 empty()409 bool empty() 410 { 411 return !m_jumps.size(); 412 } 413 jumps()414 const JumpVector& jumps() { return m_jumps; } 415 416 private: 417 JumpVector m_jumps; 418 }; 419 420 421 // Section 3: Misc admin methods 422 trampolineAt(CodeRef ref,Label label)423 static CodePtr trampolineAt(CodeRef ref, Label label) 424 { 425 return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); 426 } 427 size()428 size_t size() 429 { 430 return m_assembler.size(); 431 } 432 label()433 Label label() 434 { 435 return Label(this); 436 } 437 align()438 Label align() 439 { 440 m_assembler.align(16); 441 return Label(this); 442 } 443 differenceBetween(Label from,Jump to)444 ptrdiff_t differenceBetween(Label from, Jump to) 445 { 446 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 447 } 448 differenceBetween(Label from,Call to)449 ptrdiff_t differenceBetween(Label from, Call to) 450 { 451 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 452 } 453 differenceBetween(Label from,Label to)454 ptrdiff_t differenceBetween(Label from, Label to) 455 { 456 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 457 } 458 differenceBetween(Label from,DataLabelPtr to)459 ptrdiff_t differenceBetween(Label from, DataLabelPtr to) 460 { 461 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 462 } 463 differenceBetween(Label from,DataLabel32 to)464 ptrdiff_t differenceBetween(Label from, DataLabel32 to) 465 { 466 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 467 } 468 differenceBetween(DataLabelPtr from,Jump to)469 ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) 470 { 471 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 472 } 473 differenceBetween(DataLabelPtr from,DataLabelPtr to)474 ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) 475 { 476 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 477 } 478 differenceBetween(DataLabelPtr from,Call to)479 ptrdiff_t differenceBetween(DataLabelPtr from, Call to) 480 { 481 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 482 } 483 484 protected: 485 AssemblerType m_assembler; 486 487 friend class LinkBuffer; 488 friend class RepatchBuffer; 489 linkJump(void * code,Jump jump,CodeLocationLabel target)490 static void linkJump(void* code, Jump jump, CodeLocationLabel target) 491 { 492 AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); 493 } 494 linkPointer(void * code,typename AssemblerType::JmpDst label,void * value)495 static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) 496 { 497 AssemblerType::linkPointer(code, label, value); 498 } 499 getLinkerAddress(void * code,typename AssemblerType::JmpSrc label)500 static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) 501 { 502 return AssemblerType::getRelocatedAddress(code, label); 503 } 504 getLinkerAddress(void * code,typename AssemblerType::JmpDst label)505 static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) 506 { 507 return AssemblerType::getRelocatedAddress(code, label); 508 } 509 getLinkerCallReturnOffset(Call call)510 static unsigned getLinkerCallReturnOffset(Call call) 511 { 512 return AssemblerType::getCallReturnOffset(call.m_jmp); 513 } 514 repatchJump(CodeLocationJump jump,CodeLocationLabel destination)515 static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) 516 { 517 AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); 518 } 519 repatchNearCall(CodeLocationNearCall nearCall,CodeLocationLabel destination)520 static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) 521 { 522 AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); 523 } 524 repatchInt32(CodeLocationDataLabel32 dataLabel32,int32_t value)525 static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) 526 { 527 AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); 528 } 529 repatchPointer(CodeLocationDataLabelPtr dataLabelPtr,void * value)530 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) 531 { 532 AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); 533 } 534 repatchLoadPtrToLEA(CodeLocationInstruction instruction)535 static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) 536 { 537 AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); 538 } 539 }; 540 541 } // namespace JSC 542 543 #endif // ENABLE(ASSEMBLER) 544 545 #endif // AbstractMacroAssembler_h 546