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