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