]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/AbstractMacroAssembler.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / assembler / AbstractMacroAssembler.h
CommitLineData
ba379fdc
A
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
6fe7ccc8 29#include "AssemblerBuffer.h"
14957cd0
A
30#include "CodeLocation.h"
31#include "MacroAssemblerCodeRef.h"
6fe7ccc8 32#include <wtf/CryptographicallyRandomNumber.h>
ba379fdc
A
33#include <wtf/Noncopyable.h>
34#include <wtf/UnusedParam.h>
35
36#if ENABLE(ASSEMBLER)
37
6fe7ccc8
A
38
39#if PLATFORM(QT)
40#define ENABLE_JIT_CONSTANT_BLINDING 0
41#endif
42
43#ifndef ENABLE_JIT_CONSTANT_BLINDING
44#define ENABLE_JIT_CONSTANT_BLINDING 1
45#endif
46
ba379fdc
A
47namespace JSC {
48
49class LinkBuffer;
50class RepatchBuffer;
6fe7ccc8
A
51namespace DFG {
52class CorrectableJumpPoint;
53}
ba379fdc
A
54
55template <class AssemblerType>
56class AbstractMacroAssembler {
57public:
14957cd0 58 friend class JITWriteBarrierBase;
ba379fdc
A
59 typedef AssemblerType AssemblerType_T;
60
61 typedef MacroAssemblerCodePtr CodePtr;
62 typedef MacroAssemblerCodeRef CodeRef;
63
64 class Jump;
65
66 typedef typename AssemblerType::RegisterID RegisterID;
ba379fdc
A
67
68 // Section 1: MacroAssembler operand types
69 //
70 // The following types are used as operands to MacroAssembler operations,
71 // describing immediate and memory operands to the instructions to be planted.
72
73
74 enum Scale {
75 TimesOne,
76 TimesTwo,
77 TimesFour,
78 TimesEight,
79 };
80
81 // Address:
82 //
83 // Describes a simple base-offset address.
84 struct Address {
85 explicit Address(RegisterID base, int32_t offset = 0)
86 : base(base)
87 , offset(offset)
88 {
89 }
90
91 RegisterID base;
92 int32_t offset;
93 };
94
4e4e5a6f
A
95 struct ExtendedAddress {
96 explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
97 : base(base)
98 , offset(offset)
99 {
100 }
101
102 RegisterID base;
103 intptr_t offset;
104 };
105
ba379fdc
A
106 // ImplicitAddress:
107 //
108 // This class is used for explicit 'load' and 'store' operations
109 // (as opposed to situations in which a memory operand is provided
110 // to a generic operation, such as an integer arithmetic instruction).
111 //
112 // In the case of a load (or store) operation we want to permit
113 // addresses to be implicitly constructed, e.g. the two calls:
114 //
115 // load32(Address(addrReg), destReg);
116 // load32(addrReg, destReg);
117 //
118 // Are equivalent, and the explicit wrapping of the Address in the former
119 // is unnecessary.
120 struct ImplicitAddress {
121 ImplicitAddress(RegisterID base)
122 : base(base)
123 , offset(0)
124 {
125 }
126
127 ImplicitAddress(Address address)
128 : base(address.base)
129 , offset(address.offset)
130 {
131 }
132
133 RegisterID base;
134 int32_t offset;
135 };
136
137 // BaseIndex:
138 //
139 // Describes a complex addressing mode.
140 struct BaseIndex {
141 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
142 : base(base)
143 , index(index)
144 , scale(scale)
145 , offset(offset)
146 {
147 }
148
149 RegisterID base;
150 RegisterID index;
151 Scale scale;
152 int32_t offset;
153 };
154
155 // AbsoluteAddress:
156 //
157 // Describes an memory operand given by a pointer. For regular load & store
158 // operations an unwrapped void* will be used, rather than using this.
159 struct AbsoluteAddress {
14957cd0 160 explicit AbsoluteAddress(const void* ptr)
ba379fdc
A
161 : m_ptr(ptr)
162 {
163 }
164
14957cd0 165 const void* m_ptr;
ba379fdc
A
166 };
167
14957cd0 168 // TrustedImmPtr:
ba379fdc
A
169 //
170 // A pointer sized immediate operand to an instruction - this is wrapped
171 // in a class requiring explicit construction in order to differentiate
172 // from pointers used as absolute addresses to memory operations
14957cd0
A
173 struct TrustedImmPtr {
174 explicit TrustedImmPtr(const void* value)
ba379fdc
A
175 : m_value(value)
176 {
177 }
6fe7ccc8
A
178
179 // This is only here so that TrustedImmPtr(0) does not confuse the C++
180 // overload handling rules.
181 explicit TrustedImmPtr(int value)
182 : m_value(0)
183 {
184 ASSERT_UNUSED(value, !value);
185 }
186
187 explicit TrustedImmPtr(size_t value)
188 : m_value(reinterpret_cast<void*>(value))
189 {
190 }
ba379fdc
A
191
192 intptr_t asIntptr()
193 {
194 return reinterpret_cast<intptr_t>(m_value);
195 }
196
4e4e5a6f 197 const void* m_value;
ba379fdc
A
198 };
199
6fe7ccc8
A
200 struct ImmPtr :
201#if ENABLE(JIT_CONSTANT_BLINDING)
202 private TrustedImmPtr
203#else
204 public TrustedImmPtr
205#endif
206 {
14957cd0
A
207 explicit ImmPtr(const void* value)
208 : TrustedImmPtr(value)
209 {
210 }
6fe7ccc8
A
211
212 TrustedImmPtr asTrustedImmPtr() { return *this; }
14957cd0
A
213 };
214
215 // TrustedImm32:
ba379fdc
A
216 //
217 // A 32bit immediate operand to an instruction - this is wrapped in a
218 // class requiring explicit construction in order to prevent RegisterIDs
219 // (which are implemented as an enum) from accidentally being passed as
220 // immediate values.
14957cd0
A
221 struct TrustedImm32 {
222 explicit TrustedImm32(int32_t value)
ba379fdc 223 : m_value(value)
4e4e5a6f 224#if CPU(ARM) || CPU(MIPS)
ba379fdc
A
225 , m_isPointer(false)
226#endif
227 {
228 }
229
f9bf01c6 230#if !CPU(X86_64)
14957cd0 231 explicit TrustedImm32(TrustedImmPtr ptr)
ba379fdc 232 : m_value(ptr.asIntptr())
4e4e5a6f 233#if CPU(ARM) || CPU(MIPS)
ba379fdc
A
234 , m_isPointer(true)
235#endif
236 {
237 }
238#endif
239
240 int32_t m_value;
4e4e5a6f 241#if CPU(ARM) || CPU(MIPS)
ba379fdc
A
242 // We rely on being able to regenerate code to recover exception handling
243 // information. Since ARMv7 supports 16-bit immediates there is a danger
244 // that if pointer values change the layout of the generated code will change.
245 // To avoid this problem, always generate pointers (and thus Imm32s constructed
246 // from ImmPtrs) with a code sequence that is able to represent any pointer
247 // value - don't use a more compact form in these cases.
4e4e5a6f 248 // Same for MIPS.
ba379fdc
A
249 bool m_isPointer;
250#endif
251 };
252
253
6fe7ccc8
A
254 struct Imm32 :
255#if ENABLE(JIT_CONSTANT_BLINDING)
256 private TrustedImm32
257#else
258 public TrustedImm32
259#endif
260 {
14957cd0
A
261 explicit Imm32(int32_t value)
262 : TrustedImm32(value)
263 {
264 }
265#if !CPU(X86_64)
266 explicit Imm32(TrustedImmPtr ptr)
267 : TrustedImm32(ptr)
268 {
269 }
270#endif
6fe7ccc8
A
271 const TrustedImm32& asTrustedImm32() const { return *this; }
272
14957cd0
A
273 };
274
ba379fdc
A
275 // Section 2: MacroAssembler code buffer handles
276 //
277 // The following types are used to reference items in the code buffer
278 // during JIT code generation. For example, the type Jump is used to
279 // track the location of a jump instruction so that it may later be
280 // linked to a label marking its destination.
281
282
283 // Label:
284 //
285 // A Label records a point in the generated instruction stream, typically such that
286 // it may be used as a destination for a jump.
287 class Label {
288 template<class TemplateAssemblerType>
289 friend class AbstractMacroAssembler;
6fe7ccc8 290 friend class DFG::CorrectableJumpPoint;
ba379fdc
A
291 friend class Jump;
292 friend class MacroAssemblerCodeRef;
293 friend class LinkBuffer;
294
295 public:
296 Label()
297 {
298 }
299
300 Label(AbstractMacroAssembler<AssemblerType>* masm)
301 : m_label(masm->m_assembler.label())
302 {
303 }
304
14957cd0 305 bool isSet() const { return m_label.isSet(); }
ba379fdc 306 private:
14957cd0 307 AssemblerLabel m_label;
ba379fdc
A
308 };
309
310 // DataLabelPtr:
311 //
312 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
313 // patched after the code has been generated.
314 class DataLabelPtr {
315 template<class TemplateAssemblerType>
316 friend class AbstractMacroAssembler;
317 friend class LinkBuffer;
318 public:
319 DataLabelPtr()
320 {
321 }
322
323 DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
324 : m_label(masm->m_assembler.label())
325 {
326 }
327
14957cd0
A
328 bool isSet() const { return m_label.isSet(); }
329
ba379fdc 330 private:
14957cd0 331 AssemblerLabel m_label;
ba379fdc
A
332 };
333
334 // DataLabel32:
335 //
336 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
337 // patched after the code has been generated.
338 class DataLabel32 {
339 template<class TemplateAssemblerType>
340 friend class AbstractMacroAssembler;
341 friend class LinkBuffer;
342 public:
343 DataLabel32()
344 {
345 }
346
347 DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
348 : m_label(masm->m_assembler.label())
349 {
350 }
351
14957cd0
A
352 AssemblerLabel label() const { return m_label; }
353
354 private:
355 AssemblerLabel m_label;
356 };
357
358 // DataLabelCompact:
359 //
360 // A DataLabelCompact is used to refer to a location in the code containing a
361 // compact immediate to be patched after the code has been generated.
362 class DataLabelCompact {
363 template<class TemplateAssemblerType>
364 friend class AbstractMacroAssembler;
365 friend class LinkBuffer;
366 public:
367 DataLabelCompact()
368 {
369 }
370
371 DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
372 : m_label(masm->m_assembler.label())
373 {
374 }
375
376 DataLabelCompact(AssemblerLabel label)
377 : m_label(label)
378 {
379 }
380
ba379fdc 381 private:
14957cd0 382 AssemblerLabel m_label;
ba379fdc
A
383 };
384
385 // Call:
386 //
387 // A Call object is a reference to a call instruction that has been planted
388 // into the code buffer - it is typically used to link the call, setting the
389 // relative offset such that when executed it will call to the desired
390 // destination.
391 class Call {
392 template<class TemplateAssemblerType>
393 friend class AbstractMacroAssembler;
394
395 public:
396 enum Flags {
397 None = 0x0,
398 Linkable = 0x1,
399 Near = 0x2,
400 LinkableNear = 0x3,
401 };
402
403 Call()
404 : m_flags(None)
405 {
406 }
407
14957cd0 408 Call(AssemblerLabel jmp, Flags flags)
6fe7ccc8 409 : m_label(jmp)
ba379fdc
A
410 , m_flags(flags)
411 {
412 }
413
414 bool isFlagSet(Flags flag)
415 {
416 return m_flags & flag;
417 }
418
419 static Call fromTailJump(Jump jump)
420 {
6fe7ccc8 421 return Call(jump.m_label, Linkable);
ba379fdc
A
422 }
423
6fe7ccc8 424 AssemblerLabel m_label;
ba379fdc
A
425 private:
426 Flags m_flags;
427 };
428
429 // Jump:
430 //
431 // A jump object is a reference to a jump instruction that has been planted
432 // into the code buffer - it is typically used to link the jump, setting the
433 // relative offset such that when executed it will jump to the desired
434 // destination.
435 class Jump {
436 template<class TemplateAssemblerType>
437 friend class AbstractMacroAssembler;
438 friend class Call;
6fe7ccc8 439 friend class DFG::CorrectableJumpPoint;
ba379fdc
A
440 friend class LinkBuffer;
441 public:
442 Jump()
443 {
444 }
445
14957cd0
A
446#if CPU(ARM_THUMB2)
447 // Fixme: this information should be stored in the instruction stream, not in the Jump object.
448 Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
6fe7ccc8 449 : m_label(jmp)
14957cd0
A
450 , m_type(type)
451 , m_condition(condition)
ba379fdc
A
452 {
453 }
6fe7ccc8
A
454#elif CPU(SH4)
455 Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
456 : m_label(jmp)
457 , m_type(type)
458 {
459 }
14957cd0
A
460#else
461 Jump(AssemblerLabel jmp)
6fe7ccc8 462 : m_label(jmp)
14957cd0
A
463 {
464 }
465#endif
466
467 void link(AbstractMacroAssembler<AssemblerType>* masm) const
ba379fdc 468 {
14957cd0 469#if CPU(ARM_THUMB2)
6fe7ccc8
A
470 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
471#elif CPU(SH4)
472 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
14957cd0 473#else
6fe7ccc8 474 masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
14957cd0 475#endif
ba379fdc
A
476 }
477
14957cd0 478 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
ba379fdc 479 {
14957cd0 480#if CPU(ARM_THUMB2)
6fe7ccc8 481 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
14957cd0 482#else
6fe7ccc8 483 masm->m_assembler.linkJump(m_label, label.m_label);
14957cd0 484#endif
ba379fdc
A
485 }
486
6fe7ccc8 487 bool isSet() const { return m_label.isSet(); }
14957cd0 488
ba379fdc 489 private:
6fe7ccc8 490 AssemblerLabel m_label;
14957cd0
A
491#if CPU(ARM_THUMB2)
492 ARMv7Assembler::JumpType m_type;
493 ARMv7Assembler::Condition m_condition;
494#endif
6fe7ccc8
A
495#if CPU(SH4)
496 SH4Assembler::JumpType m_type;
497#endif
498 };
499
500 struct PatchableJump {
501 PatchableJump()
502 {
503 }
504
505 explicit PatchableJump(Jump jump)
506 : m_jump(jump)
507 {
508 }
509
510 operator Jump&() { return m_jump; }
511
512 Jump m_jump;
ba379fdc
A
513 };
514
515 // JumpList:
516 //
517 // A JumpList is a set of Jump objects.
518 // All jumps in the set will be linked to the same destination.
519 class JumpList {
520 friend class LinkBuffer;
521
522 public:
523 typedef Vector<Jump, 16> JumpVector;
524
525 void link(AbstractMacroAssembler<AssemblerType>* masm)
526 {
527 size_t size = m_jumps.size();
528 for (size_t i = 0; i < size; ++i)
529 m_jumps[i].link(masm);
530 m_jumps.clear();
531 }
532
533 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
534 {
535 size_t size = m_jumps.size();
536 for (size_t i = 0; i < size; ++i)
537 m_jumps[i].linkTo(label, masm);
538 m_jumps.clear();
539 }
540
541 void append(Jump jump)
542 {
543 m_jumps.append(jump);
544 }
545
546 void append(JumpList& other)
547 {
548 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
549 }
550
551 bool empty()
552 {
553 return !m_jumps.size();
554 }
555
14957cd0
A
556 void clear()
557 {
558 m_jumps.clear();
559 }
560
ba379fdc
A
561 const JumpVector& jumps() { return m_jumps; }
562
563 private:
564 JumpVector m_jumps;
565 };
566
567
568 // Section 3: Misc admin methods
ba379fdc
A
569 Label label()
570 {
571 return Label(this);
572 }
573
574 Label align()
575 {
576 m_assembler.align(16);
577 return Label(this);
578 }
579
6fe7ccc8
A
580 template<typename T, typename U>
581 static ptrdiff_t differenceBetween(T from, U to)
ba379fdc
A
582 {
583 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
584 }
585
6fe7ccc8 586 static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
ba379fdc 587 {
6fe7ccc8 588 return reinterpret_cast<ptrdiff_t>(b.executableAddress()) - reinterpret_cast<ptrdiff_t>(a.executableAddress());
ba379fdc
A
589 }
590
6fe7ccc8 591 unsigned debugOffset() { return m_assembler.debugOffset(); }
ba379fdc 592
6fe7ccc8 593 ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
ba379fdc 594 {
6fe7ccc8 595 AssemblerType::cacheFlush(code, size);
ba379fdc 596 }
6fe7ccc8
A
597protected:
598 AbstractMacroAssembler()
599 : m_randomSource(cryptographicallyRandomNumber())
ba379fdc 600 {
ba379fdc
A
601 }
602
6fe7ccc8
A
603 AssemblerType m_assembler;
604
605 uint32_t random()
ba379fdc 606 {
6fe7ccc8 607 return m_randomSource.getUint32();
ba379fdc 608 }
14957cd0 609
6fe7ccc8 610 WeakRandom m_randomSource;
ba379fdc 611
6fe7ccc8
A
612#if ENABLE(JIT_CONSTANT_BLINDING)
613 static bool scratchRegisterForBlinding() { return false; }
614 static bool shouldBlindForSpecificArch(uint32_t) { return true; }
615 static bool shouldBlindForSpecificArch(uint64_t) { return true; }
14957cd0
A
616#endif
617
ba379fdc
A
618 friend class LinkBuffer;
619 friend class RepatchBuffer;
620
621 static void linkJump(void* code, Jump jump, CodeLocationLabel target)
622 {
6fe7ccc8 623 AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
ba379fdc
A
624 }
625
14957cd0 626 static void linkPointer(void* code, AssemblerLabel label, void* value)
ba379fdc
A
627 {
628 AssemblerType::linkPointer(code, label, value);
629 }
630
14957cd0 631 static void* getLinkerAddress(void* code, AssemblerLabel label)
ba379fdc
A
632 {
633 return AssemblerType::getRelocatedAddress(code, label);
634 }
635
636 static unsigned getLinkerCallReturnOffset(Call call)
637 {
6fe7ccc8 638 return AssemblerType::getCallReturnOffset(call.m_label);
ba379fdc
A
639 }
640
641 static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
642 {
643 AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
644 }
645
646 static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
647 {
648 AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
649 }
650
14957cd0
A
651 static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
652 {
653 AssemblerType::repatchCompact(dataLabelCompact.dataLocation(), value);
654 }
655
ba379fdc
A
656 static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
657 {
658 AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
659 }
660
661 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
662 {
663 AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
664 }
14957cd0
A
665
666 static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
ba379fdc 667 {
14957cd0 668 return AssemblerType::readPointer(dataLabelPtr.dataLocation());
ba379fdc 669 }
6fe7ccc8
A
670
671 static void unreachableForPlatform()
672 {
673#if COMPILER(CLANG)
674#pragma clang diagnostic push
675#pragma clang diagnostic ignored "-Wmissing-noreturn"
676 ASSERT_NOT_REACHED();
677#pragma clang diagnostic pop
678#else
679 ASSERT_NOT_REACHED();
680#endif
681 }
ba379fdc
A
682};
683
684} // namespace JSC
685
686#endif // ENABLE(ASSEMBLER)
687
688#endif // AbstractMacroAssembler_h