]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/AbstractMacroAssembler.h
JavaScriptCore-721.26.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 <MacroAssemblerCodeRef.h>
30 #include <CodeLocation.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(void* ptr)
149 : m_ptr(ptr)
150 {
151 }
152
153 void* m_ptr;
154 };
155
156 // ImmPtr:
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 ImmPtr {
162 explicit ImmPtr(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 // Imm32:
176 //
177 // A 32bit immediate operand to an instruction - this is wrapped in a
178 // class requiring explicit construction in order to prevent RegisterIDs
179 // (which are implemented as an enum) from accidentally being passed as
180 // immediate values.
181 struct Imm32 {
182 explicit Imm32(int32_t value)
183 : m_value(value)
184 #if CPU(ARM) || CPU(MIPS)
185 , m_isPointer(false)
186 #endif
187 {
188 }
189
190 #if !CPU(X86_64)
191 explicit Imm32(ImmPtr ptr)
192 : m_value(ptr.asIntptr())
193 #if CPU(ARM) || CPU(MIPS)
194 , m_isPointer(true)
195 #endif
196 {
197 }
198 #endif
199
200 int32_t m_value;
201 #if CPU(ARM) || CPU(MIPS)
202 // We rely on being able to regenerate code to recover exception handling
203 // information. Since ARMv7 supports 16-bit immediates there is a danger
204 // that if pointer values change the layout of the generated code will change.
205 // To avoid this problem, always generate pointers (and thus Imm32s constructed
206 // from ImmPtrs) with a code sequence that is able to represent any pointer
207 // value - don't use a more compact form in these cases.
208 // Same for MIPS.
209 bool m_isPointer;
210 #endif
211 };
212
213
214 // Section 2: MacroAssembler code buffer handles
215 //
216 // The following types are used to reference items in the code buffer
217 // during JIT code generation. For example, the type Jump is used to
218 // track the location of a jump instruction so that it may later be
219 // linked to a label marking its destination.
220
221
222 // Label:
223 //
224 // A Label records a point in the generated instruction stream, typically such that
225 // it may be used as a destination for a jump.
226 class Label {
227 template<class TemplateAssemblerType>
228 friend class AbstractMacroAssembler;
229 friend class Jump;
230 friend class MacroAssemblerCodeRef;
231 friend class LinkBuffer;
232
233 public:
234 Label()
235 {
236 }
237
238 Label(AbstractMacroAssembler<AssemblerType>* masm)
239 : m_label(masm->m_assembler.label())
240 {
241 }
242
243 bool isUsed() const { return m_label.isUsed(); }
244 void used() { m_label.used(); }
245 private:
246 JmpDst m_label;
247 };
248
249 // DataLabelPtr:
250 //
251 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
252 // patched after the code has been generated.
253 class DataLabelPtr {
254 template<class TemplateAssemblerType>
255 friend class AbstractMacroAssembler;
256 friend class LinkBuffer;
257 public:
258 DataLabelPtr()
259 {
260 }
261
262 DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
263 : m_label(masm->m_assembler.label())
264 {
265 }
266
267 private:
268 JmpDst m_label;
269 };
270
271 // DataLabel32:
272 //
273 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
274 // patched after the code has been generated.
275 class DataLabel32 {
276 template<class TemplateAssemblerType>
277 friend class AbstractMacroAssembler;
278 friend class LinkBuffer;
279 public:
280 DataLabel32()
281 {
282 }
283
284 DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
285 : m_label(masm->m_assembler.label())
286 {
287 }
288
289 private:
290 JmpDst m_label;
291 };
292
293 // Call:
294 //
295 // A Call object is a reference to a call instruction that has been planted
296 // into the code buffer - it is typically used to link the call, setting the
297 // relative offset such that when executed it will call to the desired
298 // destination.
299 class Call {
300 template<class TemplateAssemblerType>
301 friend class AbstractMacroAssembler;
302
303 public:
304 enum Flags {
305 None = 0x0,
306 Linkable = 0x1,
307 Near = 0x2,
308 LinkableNear = 0x3,
309 };
310
311 Call()
312 : m_flags(None)
313 {
314 }
315
316 Call(JmpSrc jmp, Flags flags)
317 : m_jmp(jmp)
318 , m_flags(flags)
319 {
320 }
321
322 bool isFlagSet(Flags flag)
323 {
324 return m_flags & flag;
325 }
326
327 static Call fromTailJump(Jump jump)
328 {
329 return Call(jump.m_jmp, Linkable);
330 }
331
332 JmpSrc m_jmp;
333 private:
334 Flags m_flags;
335 };
336
337 // Jump:
338 //
339 // A jump object is a reference to a jump instruction that has been planted
340 // into the code buffer - it is typically used to link the jump, setting the
341 // relative offset such that when executed it will jump to the desired
342 // destination.
343 class Jump {
344 template<class TemplateAssemblerType>
345 friend class AbstractMacroAssembler;
346 friend class Call;
347 friend class LinkBuffer;
348 public:
349 Jump()
350 {
351 }
352
353 Jump(JmpSrc jmp)
354 : m_jmp(jmp)
355 {
356 }
357
358 void link(AbstractMacroAssembler<AssemblerType>* masm)
359 {
360 masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
361 }
362
363 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
364 {
365 masm->m_assembler.linkJump(m_jmp, label.m_label);
366 }
367
368 private:
369 JmpSrc m_jmp;
370 };
371
372 // JumpList:
373 //
374 // A JumpList is a set of Jump objects.
375 // All jumps in the set will be linked to the same destination.
376 class JumpList {
377 friend class LinkBuffer;
378
379 public:
380 typedef Vector<Jump, 16> JumpVector;
381
382 void link(AbstractMacroAssembler<AssemblerType>* masm)
383 {
384 size_t size = m_jumps.size();
385 for (size_t i = 0; i < size; ++i)
386 m_jumps[i].link(masm);
387 m_jumps.clear();
388 }
389
390 void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
391 {
392 size_t size = m_jumps.size();
393 for (size_t i = 0; i < size; ++i)
394 m_jumps[i].linkTo(label, masm);
395 m_jumps.clear();
396 }
397
398 void append(Jump jump)
399 {
400 m_jumps.append(jump);
401 }
402
403 void append(JumpList& other)
404 {
405 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
406 }
407
408 bool empty()
409 {
410 return !m_jumps.size();
411 }
412
413 const JumpVector& jumps() { return m_jumps; }
414
415 private:
416 JumpVector m_jumps;
417 };
418
419
420 // Section 3: Misc admin methods
421 size_t size()
422 {
423 return m_assembler.size();
424 }
425
426 Label label()
427 {
428 return Label(this);
429 }
430
431 Label align()
432 {
433 m_assembler.align(16);
434 return Label(this);
435 }
436
437 ptrdiff_t differenceBetween(Label from, Jump to)
438 {
439 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
440 }
441
442 ptrdiff_t differenceBetween(Label from, Call to)
443 {
444 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
445 }
446
447 ptrdiff_t differenceBetween(Label from, Label to)
448 {
449 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
450 }
451
452 ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
453 {
454 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
455 }
456
457 ptrdiff_t differenceBetween(Label from, DataLabel32 to)
458 {
459 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
460 }
461
462 ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
463 {
464 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
465 }
466
467 ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
468 {
469 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
470 }
471
472 ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
473 {
474 return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
475 }
476
477 void beginUninterruptedSequence() { }
478 void endUninterruptedSequence() { }
479
480 protected:
481 AssemblerType m_assembler;
482
483 friend class LinkBuffer;
484 friend class RepatchBuffer;
485
486 static void linkJump(void* code, Jump jump, CodeLocationLabel target)
487 {
488 AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
489 }
490
491 static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
492 {
493 AssemblerType::linkPointer(code, label, value);
494 }
495
496 static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
497 {
498 return AssemblerType::getRelocatedAddress(code, label);
499 }
500
501 static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
502 {
503 return AssemblerType::getRelocatedAddress(code, label);
504 }
505
506 static unsigned getLinkerCallReturnOffset(Call call)
507 {
508 return AssemblerType::getCallReturnOffset(call.m_jmp);
509 }
510
511 static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
512 {
513 AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
514 }
515
516 static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
517 {
518 AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
519 }
520
521 static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
522 {
523 AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
524 }
525
526 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
527 {
528 AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
529 }
530
531 static void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
532 {
533 AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation());
534 }
535 };
536
537 } // namespace JSC
538
539 #endif // ENABLE(ASSEMBLER)
540
541 #endif // AbstractMacroAssembler_h