source: webkit/trunk/JavaScriptCore/assembler/MacroAssembler.h@ 38840

Last change on this file since 38840 was 38840, checked in by [email protected], 16 years ago

2008-11-29 Cameron Zwarich <[email protected]>

Not reviewed.

The C++ standard does not automatically grant the friendships of an
enclosing class to its nested subclasses, so we should do so explicitly.
This fixes the GCC 4.0 build, although both GCC 4.2 and Visual C++ 2005
accept the incorrect code as it is.

  • assembler/MacroAssembler.h:
File size: 15.4 KB
Line 
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 MacroAssembler_h
27#define MacroAssembler_h
28
29#include <wtf/Platform.h>
30
31#if ENABLE(ASSEMBLER)
32
33#include "X86Assembler.h"
34
35namespace JSC {
36
37class MacroAssembler {
38protected:
39 X86Assembler m_assembler;
40
41public:
42 typedef X86::RegisterID RegisterID;
43
44 // Note: do not rely on values in this enum, these will change (to 0..3).
45 enum Scale {
46 TimesOne = 1,
47 TimesTwo = 2,
48 TimesFour = 4,
49 TimesEight = 8
50 };
51
52 MacroAssembler(AssemblerBuffer* assemblerBuffer)
53 : m_assembler(assemblerBuffer)
54 {
55 }
56
57 void* copyCode()
58 {
59 return m_assembler.executableCopy();
60 }
61
62 // Address:
63 //
64 // Describes a simple base-offset address.
65 struct Address {
66 explicit Address(RegisterID base, int32_t offset = 0)
67 : base(base)
68 , offset(offset)
69 {
70 }
71
72 RegisterID base;
73 int32_t offset;
74 };
75
76 // ImplicitAddress:
77 //
78 // This class is used for explicit 'load' and 'store' operations
79 // (as opposed to situations in which a memory operand is provided
80 // to a generic operation, such as an integer arithmetic instruction).
81 //
82 // In the case of a load (or store) operation we want to permit
83 // addresses to be implicitly constructed, e.g. the two calls:
84 //
85 // load32(Address(addrReg), destReg);
86 // load32(addrReg, destReg);
87 //
88 // Are equivalent, and the explicit wrapping of the Address in the former
89 // is unnecessary.
90 struct ImplicitAddress {
91 ImplicitAddress(RegisterID base)
92 : base(base)
93 , offset(0)
94 {
95 }
96
97 ImplicitAddress(Address address)
98 : base(address.base)
99 , offset(address.offset)
100 {
101 }
102
103 RegisterID base;
104 int32_t offset;
105 };
106
107 // BaseIndex:
108 //
109 // Describes a complex addressing mode.
110 struct BaseIndex {
111 BaseIndex(RegisterID base, RegisterID index, int32_t offset = 0)
112 : base(base)
113 , index(index)
114 , scale(TimesOne)
115 , offset(offset)
116 {
117 }
118
119 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
120 : base(base)
121 , index(index)
122 , scale(scale)
123 , offset(offset)
124 {
125 }
126
127 RegisterID base;
128 RegisterID index;
129 Scale scale;
130 int32_t offset;
131 };
132
133 class Jump;
134
135 // Label:
136 //
137 // A Label records a point in the generated instruction stream, typically such that
138 // it may be used as a destination for a jump.
139 class Label {
140 friend class Jump;
141 friend class MacroAssembler;
142
143 public:
144 Label(MacroAssembler* masm)
145 : m_label(masm->m_assembler.label())
146 {
147 }
148
149 private:
150 X86Assembler::JmpDst m_label;
151 };
152
153 // Jump:
154 //
155 // A jump object is a reference to a jump instruction that has been planted
156 // into the code buffer - it is typically used to link the jump, setting the
157 // relative offset such that when executed it will jump to the desired
158 // destination.
159 //
160 // Jump objects retain a pointer to the assembler for syntactic purposes -
161 // to allow the jump object to be able to link itself, e.g.:
162 //
163 // Jump forwardsBranch = jne32(Imm32(0), reg1);
164 // // ...
165 // forwardsBranch.link();
166 //
167 // Jumps may also be linked to a Label.
168 class Jump {
169 public:
170 Jump()
171 : m_assembler(0)
172 {
173 }
174
175 Jump(X86Assembler& assembler, X86Assembler::JmpSrc jmp)
176 : m_assembler(&assembler)
177 , m_jmp(jmp)
178 {
179 }
180
181 void link()
182 {
183 ASSERT(m_assembler);
184 m_assembler->link(m_jmp, m_assembler->label());
185 }
186
187 void linkTo(Label label)
188 {
189 ASSERT(m_assembler);
190 m_assembler->link(m_jmp, label.m_label);
191 }
192
193 private:
194 X86Assembler* m_assembler;
195 X86Assembler::JmpSrc m_jmp;
196 };
197
198 // JumpList:
199 //
200 // A JumpList is a set of Jump objects.
201 // All jumps in the set will be linked to the same destination.
202 class JumpList {
203 public:
204 void link()
205 {
206 size_t size = jumps.size();
207 for (size_t i = 0; i < size; ++i)
208 jumps[i].link();
209 jumps.clear();
210 }
211
212 void linkTo(Label label)
213 {
214 size_t size = jumps.size();
215 for (size_t i = 0; i < size; ++i)
216 jumps[i].linkTo(label);
217 jumps.clear();
218 }
219
220 void append(Jump jump)
221 {
222 jumps.append(jump);
223 }
224
225 void append(JumpList& other)
226 {
227 jumps.append(other.jumps.begin(), other.jumps.size());
228 }
229
230 private:
231 Vector<Jump> jumps;
232 };
233
234 // Imm32:
235 //
236 // A 32bit immediate operand to an instruction - this is wrapped in a
237 // class requiring explicit construction in order to prevent RegisterIDs
238 // (which are implemented as an enum) from accidentally being passed as
239 // immediate values.
240 struct Imm32 {
241 explicit Imm32(int32_t value)
242 : m_value(value)
243 {
244 }
245
246 int32_t m_value;
247 };
248
249
250 // Integer arithmetic operations:
251 //
252 // Operations are typically two operand - operation(source, srcDst)
253 // For many operations the source may be an Imm32, the srcDst operand
254 // may often be a memory location (explictly described using an Address
255 // object).
256
257 void add32(Imm32 imm, RegisterID dest)
258 {
259 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
260 m_assembler.addl_i8r(imm.m_value, dest);
261 else
262 m_assembler.addl_i32r(imm.m_value, dest);
263 }
264
265 void add32(Address src, RegisterID dest)
266 {
267 m_assembler.addl_mr(src.offset, src.base, dest);
268 }
269
270 void or32(Imm32 imm, RegisterID dest)
271 {
272 m_assembler.orl_i32r(imm.m_value, dest);
273 }
274
275 void sub32(Imm32 imm, RegisterID dest)
276 {
277 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
278 m_assembler.subl_i8r(imm.m_value, dest);
279 else
280 m_assembler.subl_i32r(imm.m_value, dest);
281 }
282
283 void sub32(Address src, RegisterID dest)
284 {
285 m_assembler.subl_mr(src.offset, src.base, dest);
286 }
287
288
289 // Memory access operations:
290 //
291 // Loads are of the form load(address, destination) and stores of the form
292 // store(source, address). The source for a store may be an Imm32. Address
293 // operand objects to loads and store will be implicitly constructed if a
294 // register is passed.
295
296 void loadPtr(ImplicitAddress address, RegisterID dest)
297 {
298 if (address.offset)
299 m_assembler.movl_mr(address.offset, address.base, dest);
300 else
301 m_assembler.movl_mr(address.base, dest);
302 }
303
304 void load32(ImplicitAddress address, RegisterID dest)
305 {
306 if (address.offset)
307 m_assembler.movl_mr(address.offset, address.base, dest);
308 else
309 m_assembler.movl_mr(address.base, dest);
310 }
311
312 void load16(BaseIndex address, RegisterID dest)
313 {
314 if (address.offset)
315 m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
316 else
317 m_assembler.movzwl_mr(address.base, address.index, address.scale, dest);
318 }
319
320 void storePtr(RegisterID src, ImplicitAddress address)
321 {
322 if (address.offset)
323 m_assembler.movl_rm(src, address.offset, address.base);
324 else
325 m_assembler.movl_rm(src, address.base);
326 }
327
328 void store32(RegisterID src, ImplicitAddress address)
329 {
330 if (address.offset)
331 m_assembler.movl_rm(src, address.offset, address.base);
332 else
333 m_assembler.movl_rm(src, address.base);
334 }
335
336 void store32(Imm32 imm, ImplicitAddress address)
337 {
338 // FIXME: add a version that doesn't take an offset
339 m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
340 }
341
342
343 // Stack manipulation operations:
344 //
345 // The ABI is assumed to provide a stack abstraction to memory,
346 // containing machine word sized units of data. Push and pop
347 // operations add and remove a single register sized unit of data
348 // to or from the stack. Peek and poke operations read or write
349 // values on the stack, without moving the current stack position.
350
351 void pop(RegisterID dest)
352 {
353 m_assembler.popl_r(dest);
354 }
355
356 void push(RegisterID src)
357 {
358 m_assembler.pushl_r(src);
359 }
360
361 void pop()
362 {
363 m_assembler.addl_i8r(sizeof(void*), X86::esp);
364 }
365
366 void peek(RegisterID dest, int index = 0)
367 {
368 loadPtr(Address(X86::esp, (index * sizeof(void *))), dest);
369 }
370
371 void poke(RegisterID src, int index = 0)
372 {
373 storePtr(src, Address(X86::esp, (index * sizeof(void *))));
374 }
375
376
377 // Register move operations:
378 //
379 // Move values in registers.
380
381 void move(Imm32 imm, RegisterID dest)
382 {
383 if (!imm.m_value)
384 m_assembler.xorl_rr(dest, dest);
385 else
386 m_assembler.movl_i32r(imm.m_value, dest);
387 }
388
389
390 // Forwards / external control flow operations:
391 //
392 // This set of jump and conditional branch operations return a Jump
393 // object which may linked at a later point, allow forwards jump,
394 // or jumps that will require external linkage (after the code has been
395 // relocated).
396 //
397 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
398 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
399 // used (representing the names 'below' and 'above').
400 //
401 // Operands to the comparision are provided in the expected order, e.g.
402 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
403 // treated as a signed 32bit value, is less than or equal to 5.
404
405private:
406 void compareImm32ForBranch(RegisterID left, int32_t right)
407 {
408 if (CAN_SIGN_EXTEND_8_32(right))
409 m_assembler.cmpl_i8r(right, left);
410 else
411 m_assembler.cmpl_i32r(right, left);
412 }
413
414 void compareImm32ForBranchEquality(RegisterID reg, int32_t imm)
415 {
416 if (!imm)
417 m_assembler.testl_rr(reg, reg);
418 else if (CAN_SIGN_EXTEND_8_32(imm))
419 m_assembler.cmpl_i8r(imm, reg);
420 else
421 m_assembler.cmpl_i32r(imm, reg);
422 }
423
424public:
425 Jump jae32(RegisterID left, Imm32 right)
426 {
427 compareImm32ForBranch(left, right.m_value);
428 return Jump(m_assembler, m_assembler.jae());
429 }
430
431 Jump je32(RegisterID op1, RegisterID op2)
432 {
433 m_assembler.cmpl_rr(op1, op2);
434 return Jump(m_assembler, m_assembler.je());
435 }
436
437 Jump je32(RegisterID op1, Address op2)
438 {
439 m_assembler.cmpl_rm(op1, op2.offset, op2.base);
440 return Jump(m_assembler, m_assembler.je());
441 }
442
443 Jump je32(Imm32 imm, RegisterID reg)
444 {
445 compareImm32ForBranchEquality(reg, imm.m_value);
446 return Jump(m_assembler, m_assembler.je());
447 }
448
449 Jump je16(RegisterID op1, BaseIndex op2)
450 {
451 if (op2.offset)
452 m_assembler.cmpw_rm(op1, op2.base, op2.index, op2.scale);
453 else
454 m_assembler.cmpw_rm(op1, op2.offset, op2.base, op2.index, op2.scale);
455
456 return Jump(m_assembler, m_assembler.je());
457 }
458
459 Jump jg32(RegisterID left, RegisterID right)
460 {
461 m_assembler.cmpl_rr(right, left);
462 return Jump(m_assembler, m_assembler.jg());
463 }
464
465 Jump jge32(RegisterID left, Imm32 right)
466 {
467 compareImm32ForBranch(left, right.m_value);
468 return Jump(m_assembler, m_assembler.jge());
469 }
470
471 Jump jl32(RegisterID left, Imm32 right)
472 {
473 compareImm32ForBranch(left, right.m_value);
474 return Jump(m_assembler, m_assembler.jl());
475 }
476
477 Jump jle32(RegisterID left, RegisterID right)
478 {
479 m_assembler.cmpl_rr(right, left);
480 return Jump(m_assembler, m_assembler.jle());
481 }
482
483 Jump jle32(RegisterID left, Imm32 right)
484 {
485 compareImm32ForBranch(left, right.m_value);
486 return Jump(m_assembler, m_assembler.jle());
487 }
488
489 Jump jne32(RegisterID op1, RegisterID op2)
490 {
491 m_assembler.cmpl_rr(op1, op2);
492 return Jump(m_assembler, m_assembler.jne());
493 }
494
495 Jump jne32(Imm32 imm, RegisterID reg)
496 {
497 compareImm32ForBranchEquality(reg, imm.m_value);
498 return Jump(m_assembler, m_assembler.jne());
499 }
500
501 Jump jump()
502 {
503 return Jump(m_assembler, m_assembler.jmp());
504 }
505
506
507 // Backwards, local control flow operations:
508 //
509 // These operations provide a shorter notation for local
510 // backwards branches, which may be both more convenient
511 // for the user, and for the programmer, and for the
512 // assembler (allowing shorter values to be used in
513 // relative offsets).
514 //
515 // The code sequence:
516 //
517 // Label topOfLoop(this);
518 // // ...
519 // jne32(reg1, reg2, topOfLoop);
520 //
521 // Is equivalent to the longer, potentially less efficient form:
522 //
523 // Label topOfLoop(this);
524 // // ...
525 // jne32(reg1, reg2).linkTo(topOfLoop);
526
527 void je32(Imm32 imm, RegisterID op2, Label target)
528 {
529 je32(imm, op2).linkTo(target);
530 }
531
532 void je16(RegisterID op1, BaseIndex op2, Label target)
533 {
534 je16(op1, op2).linkTo(target);
535 }
536
537 void jl32(RegisterID left, Imm32 right, Label target)
538 {
539 jl32(left, right).linkTo(target);
540 }
541
542 void jle32(RegisterID left, RegisterID right, Label target)
543 {
544 jle32(left, right).linkTo(target);
545 }
546
547 void jne32(RegisterID op1, RegisterID op2, Label target)
548 {
549 jne32(op1, op2).linkTo(target);
550 }
551
552 void jne32(Imm32 imm, RegisterID op2, Label target)
553 {
554 jne32(imm, op2).linkTo(target);
555 }
556
557 void jump(Label target)
558 {
559 m_assembler.link(m_assembler.jmp(), target.m_label);
560 }
561
562
563 // Miscellaneous operations:
564
565 void breakpoint()
566 {
567 m_assembler.int3();
568 }
569
570 void ret()
571 {
572 m_assembler.ret();
573 }
574};
575
576} // namespace JSC
577
578#endif // ENABLE(ASSEMBLER)
579
580#endif // MacroAssembler_h
Note: See TracBrowser for help on using the repository browser.