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 CPU(ARM) 177 , m_isPointer(false) 178 #endif 179 { 180 } 181 182 #if !CPU(X86_64) Imm32Imm32183 explicit Imm32(ImmPtr ptr) 184 : m_value(ptr.asIntptr()) 185 #if CPU(ARM) 186 , m_isPointer(true) 187 #endif 188 { 189 } 190 #endif 191 192 int32_t m_value; 193 #if CPU(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 323 JmpSrc m_jmp; 324 private: 325 Flags m_flags; 326 }; 327 328 // Jump: 329 // 330 // A jump object is a reference to a jump instruction that has been planted 331 // into the code buffer - it is typically used to link the jump, setting the 332 // relative offset such that when executed it will jump to the desired 333 // destination. 334 class Jump { 335 template<class TemplateAssemblerType> 336 friend class AbstractMacroAssembler; 337 friend class Call; 338 friend class LinkBuffer; 339 public: Jump()340 Jump() 341 { 342 } 343 Jump(JmpSrc jmp)344 Jump(JmpSrc jmp) 345 : m_jmp(jmp) 346 { 347 } 348 link(AbstractMacroAssembler<AssemblerType> * masm)349 void link(AbstractMacroAssembler<AssemblerType>* masm) 350 { 351 masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); 352 } 353 linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)354 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) 355 { 356 masm->m_assembler.linkJump(m_jmp, label.m_label); 357 } 358 359 private: 360 JmpSrc m_jmp; 361 }; 362 363 // JumpList: 364 // 365 // A JumpList is a set of Jump objects. 366 // All jumps in the set will be linked to the same destination. 367 class JumpList { 368 friend class LinkBuffer; 369 370 public: 371 typedef Vector<Jump, 16> JumpVector; 372 link(AbstractMacroAssembler<AssemblerType> * masm)373 void link(AbstractMacroAssembler<AssemblerType>* masm) 374 { 375 size_t size = m_jumps.size(); 376 for (size_t i = 0; i < size; ++i) 377 m_jumps[i].link(masm); 378 m_jumps.clear(); 379 } 380 linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)381 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) 382 { 383 size_t size = m_jumps.size(); 384 for (size_t i = 0; i < size; ++i) 385 m_jumps[i].linkTo(label, masm); 386 m_jumps.clear(); 387 } 388 append(Jump jump)389 void append(Jump jump) 390 { 391 m_jumps.append(jump); 392 } 393 append(JumpList & other)394 void append(JumpList& other) 395 { 396 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size()); 397 } 398 empty()399 bool empty() 400 { 401 return !m_jumps.size(); 402 } 403 jumps()404 const JumpVector& jumps() { return m_jumps; } 405 406 private: 407 JumpVector m_jumps; 408 }; 409 410 411 // Section 3: Misc admin methods 412 trampolineAt(CodeRef ref,Label label)413 static CodePtr trampolineAt(CodeRef ref, Label label) 414 { 415 return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); 416 } 417 size()418 size_t size() 419 { 420 return m_assembler.size(); 421 } 422 label()423 Label label() 424 { 425 return Label(this); 426 } 427 align()428 Label align() 429 { 430 m_assembler.align(16); 431 return Label(this); 432 } 433 differenceBetween(Label from,Jump to)434 ptrdiff_t differenceBetween(Label from, Jump to) 435 { 436 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 437 } 438 differenceBetween(Label from,Call to)439 ptrdiff_t differenceBetween(Label from, Call to) 440 { 441 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 442 } 443 differenceBetween(Label from,Label to)444 ptrdiff_t differenceBetween(Label from, Label to) 445 { 446 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 447 } 448 differenceBetween(Label from,DataLabelPtr to)449 ptrdiff_t differenceBetween(Label from, DataLabelPtr to) 450 { 451 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 452 } 453 differenceBetween(Label from,DataLabel32 to)454 ptrdiff_t differenceBetween(Label from, DataLabel32 to) 455 { 456 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 457 } 458 differenceBetween(DataLabelPtr from,Jump to)459 ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) 460 { 461 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 462 } 463 differenceBetween(DataLabelPtr from,DataLabelPtr to)464 ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) 465 { 466 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); 467 } 468 differenceBetween(DataLabelPtr from,Call to)469 ptrdiff_t differenceBetween(DataLabelPtr from, Call to) 470 { 471 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); 472 } 473 474 protected: 475 AssemblerType m_assembler; 476 477 friend class LinkBuffer; 478 friend class RepatchBuffer; 479 linkJump(void * code,Jump jump,CodeLocationLabel target)480 static void linkJump(void* code, Jump jump, CodeLocationLabel target) 481 { 482 AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); 483 } 484 linkPointer(void * code,typename AssemblerType::JmpDst label,void * value)485 static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) 486 { 487 AssemblerType::linkPointer(code, label, value); 488 } 489 getLinkerAddress(void * code,typename AssemblerType::JmpSrc label)490 static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) 491 { 492 return AssemblerType::getRelocatedAddress(code, label); 493 } 494 getLinkerAddress(void * code,typename AssemblerType::JmpDst label)495 static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) 496 { 497 return AssemblerType::getRelocatedAddress(code, label); 498 } 499 getLinkerCallReturnOffset(Call call)500 static unsigned getLinkerCallReturnOffset(Call call) 501 { 502 return AssemblerType::getCallReturnOffset(call.m_jmp); 503 } 504 repatchJump(CodeLocationJump jump,CodeLocationLabel destination)505 static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) 506 { 507 AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); 508 } 509 repatchNearCall(CodeLocationNearCall nearCall,CodeLocationLabel destination)510 static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) 511 { 512 AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); 513 } 514 repatchInt32(CodeLocationDataLabel32 dataLabel32,int32_t value)515 static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) 516 { 517 AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); 518 } 519 repatchPointer(CodeLocationDataLabelPtr dataLabelPtr,void * value)520 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) 521 { 522 AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); 523 } 524 repatchLoadPtrToLEA(CodeLocationInstruction instruction)525 static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) 526 { 527 AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); 528 } 529 }; 530 531 } // namespace JSC 532 533 #endif // ENABLE(ASSEMBLER) 534 535 #endif // AbstractMacroAssembler_h 536