]>
Commit | Line | Data |
---|---|---|
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 | ||
ba379fdc A |
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; | |
ba379fdc A |
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 | ||
4e4e5a6f A |
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 | ||
ba379fdc A |
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 { | |
4e4e5a6f | 162 | explicit ImmPtr(const void* value) |
ba379fdc A |
163 | : m_value(value) |
164 | { | |
165 | } | |
166 | ||
167 | intptr_t asIntptr() | |
168 | { | |
169 | return reinterpret_cast<intptr_t>(m_value); | |
170 | } | |
171 | ||
4e4e5a6f | 172 | const void* m_value; |
ba379fdc A |
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) | |
4e4e5a6f | 184 | #if CPU(ARM) || CPU(MIPS) |
ba379fdc A |
185 | , m_isPointer(false) |
186 | #endif | |
187 | { | |
188 | } | |
189 | ||
f9bf01c6 | 190 | #if !CPU(X86_64) |
ba379fdc A |
191 | explicit Imm32(ImmPtr ptr) |
192 | : m_value(ptr.asIntptr()) | |
4e4e5a6f | 193 | #if CPU(ARM) || CPU(MIPS) |
ba379fdc A |
194 | , m_isPointer(true) |
195 | #endif | |
196 | { | |
197 | } | |
198 | #endif | |
199 | ||
200 | int32_t m_value; | |
4e4e5a6f | 201 | #if CPU(ARM) || CPU(MIPS) |
ba379fdc A |
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. | |
4e4e5a6f | 208 | // Same for MIPS. |
ba379fdc A |
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; | |
ba379fdc A |
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 | ||
422 | static CodePtr trampolineAt(CodeRef ref, Label label) | |
423 | { | |
424 | return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); | |
425 | } | |
426 | ||
427 | size_t size() | |
428 | { | |
429 | return m_assembler.size(); | |
430 | } | |
431 | ||
432 | Label label() | |
433 | { | |
434 | return Label(this); | |
435 | } | |
436 | ||
437 | Label align() | |
438 | { | |
439 | m_assembler.align(16); | |
440 | return Label(this); | |
441 | } | |
442 | ||
443 | ptrdiff_t differenceBetween(Label from, Jump to) | |
444 | { | |
445 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); | |
446 | } | |
447 | ||
448 | ptrdiff_t differenceBetween(Label from, Call to) | |
449 | { | |
450 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); | |
451 | } | |
452 | ||
453 | ptrdiff_t differenceBetween(Label from, Label to) | |
454 | { | |
455 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); | |
456 | } | |
457 | ||
458 | ptrdiff_t differenceBetween(Label from, DataLabelPtr to) | |
459 | { | |
460 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); | |
461 | } | |
462 | ||
463 | ptrdiff_t differenceBetween(Label from, DataLabel32 to) | |
464 | { | |
465 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); | |
466 | } | |
467 | ||
468 | ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) | |
469 | { | |
470 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); | |
471 | } | |
472 | ||
473 | ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) | |
474 | { | |
475 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); | |
476 | } | |
477 | ||
478 | ptrdiff_t differenceBetween(DataLabelPtr from, Call to) | |
479 | { | |
480 | return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); | |
481 | } | |
482 | ||
483 | protected: | |
484 | AssemblerType m_assembler; | |
485 | ||
486 | friend class LinkBuffer; | |
487 | friend class RepatchBuffer; | |
488 | ||
489 | static void linkJump(void* code, Jump jump, CodeLocationLabel target) | |
490 | { | |
491 | AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); | |
492 | } | |
493 | ||
494 | static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) | |
495 | { | |
496 | AssemblerType::linkPointer(code, label, value); | |
497 | } | |
498 | ||
499 | static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) | |
500 | { | |
501 | return AssemblerType::getRelocatedAddress(code, label); | |
502 | } | |
503 | ||
504 | static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) | |
505 | { | |
506 | return AssemblerType::getRelocatedAddress(code, label); | |
507 | } | |
508 | ||
509 | static unsigned getLinkerCallReturnOffset(Call call) | |
510 | { | |
511 | return AssemblerType::getCallReturnOffset(call.m_jmp); | |
512 | } | |
513 | ||
514 | static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) | |
515 | { | |
516 | AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); | |
517 | } | |
518 | ||
519 | static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) | |
520 | { | |
521 | AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); | |
522 | } | |
523 | ||
524 | static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) | |
525 | { | |
526 | AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); | |
527 | } | |
528 | ||
529 | static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) | |
530 | { | |
531 | AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); | |
532 | } | |
533 | ||
534 | static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) | |
535 | { | |
536 | AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); | |
537 | } | |
538 | }; | |
539 | ||
540 | } // namespace JSC | |
541 | ||
542 | #endif // ENABLE(ASSEMBLER) | |
543 | ||
544 | #endif // AbstractMacroAssembler_h |