]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/MacroAssembler.h
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / assembler / MacroAssembler.h
CommitLineData
9dae56ea
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 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
41#if PLATFORM(X86_64)
42 static const X86::RegisterID scratchRegister = X86::r11;
43#endif
44
45public:
46 typedef X86::RegisterID RegisterID;
47
48 // Note: do not rely on values in this enum, these will change (to 0..3).
49 enum Scale {
50 TimesOne = 1,
51 TimesTwo = 2,
52 TimesFour = 4,
53 TimesEight = 8,
54#if PLATFORM(X86)
55 ScalePtr = TimesFour
56#endif
57#if PLATFORM(X86_64)
58 ScalePtr = TimesEight
59#endif
60 };
61
62 MacroAssembler()
63 {
64 }
65
66 size_t size() { return m_assembler.size(); }
67 void* copyCode(ExecutablePool* allocator)
68 {
69 return m_assembler.executableCopy(allocator);
70 }
71
72
73 // Address:
74 //
75 // Describes a simple base-offset address.
76 struct Address {
77 explicit Address(RegisterID base, int32_t offset = 0)
78 : base(base)
79 , offset(offset)
80 {
81 }
82
83 RegisterID base;
84 int32_t offset;
85 };
86
87 // ImplicitAddress:
88 //
89 // This class is used for explicit 'load' and 'store' operations
90 // (as opposed to situations in which a memory operand is provided
91 // to a generic operation, such as an integer arithmetic instruction).
92 //
93 // In the case of a load (or store) operation we want to permit
94 // addresses to be implicitly constructed, e.g. the two calls:
95 //
96 // load32(Address(addrReg), destReg);
97 // load32(addrReg, destReg);
98 //
99 // Are equivalent, and the explicit wrapping of the Address in the former
100 // is unnecessary.
101 struct ImplicitAddress {
102 ImplicitAddress(RegisterID base)
103 : base(base)
104 , offset(0)
105 {
106 }
107
108 ImplicitAddress(Address address)
109 : base(address.base)
110 , offset(address.offset)
111 {
112 }
113
114 RegisterID base;
115 int32_t offset;
116 };
117
118 // BaseIndex:
119 //
120 // Describes a complex addressing mode.
121 struct BaseIndex {
122 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
123 : base(base)
124 , index(index)
125 , scale(scale)
126 , offset(offset)
127 {
128 }
129
130 RegisterID base;
131 RegisterID index;
132 Scale scale;
133 int32_t offset;
134 };
135
136 // AbsoluteAddress:
137 //
138 // Describes an memory operand given by a pointer. For regular load & store
139 // operations an unwrapped void* will be used, rather than using this.
140 struct AbsoluteAddress {
141 explicit AbsoluteAddress(void* ptr)
142 : m_ptr(ptr)
143 {
144 }
145
146 void* m_ptr;
147 };
148
149
150 class Jump;
151 class PatchBuffer;
152
153 // DataLabelPtr:
154 //
155 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
156 // patched after the code has been generated.
157 class DataLabelPtr {
158 friend class MacroAssembler;
159 friend class PatchBuffer;
160
161 public:
162 DataLabelPtr()
163 {
164 }
165
166 DataLabelPtr(MacroAssembler* masm)
167 : m_label(masm->m_assembler.label())
168 {
169 }
170
171 static void patch(void* address, void* value)
172 {
173 X86Assembler::patchPointer(reinterpret_cast<intptr_t>(address), reinterpret_cast<intptr_t>(value));
174 }
175
176 private:
177 X86Assembler::JmpDst m_label;
178 };
179
180 // DataLabel32:
181 //
182 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
183 // patched after the code has been generated.
184 class DataLabel32 {
185 friend class MacroAssembler;
186 friend class PatchBuffer;
187
188 public:
189 DataLabel32()
190 {
191 }
192
193 DataLabel32(MacroAssembler* masm)
194 : m_label(masm->m_assembler.label())
195 {
196 }
197
198 static void patch(void* address, int32_t value)
199 {
200 X86Assembler::patchImmediate(reinterpret_cast<intptr_t>(address), value);
201 }
202
203 private:
204 X86Assembler::JmpDst m_label;
205 };
206
207 // Label:
208 //
209 // A Label records a point in the generated instruction stream, typically such that
210 // it may be used as a destination for a jump.
211 class Label {
212 friend class Jump;
213 friend class MacroAssembler;
214 friend class PatchBuffer;
215
216 public:
217 Label()
218 {
219 }
220
221 Label(MacroAssembler* masm)
222 : m_label(masm->m_assembler.label())
223 {
224 }
225
226 // FIXME: transitionary method, while we replace JmpSrces with Jumps.
227 operator X86Assembler::JmpDst()
228 {
229 return m_label;
230 }
231
232 private:
233 X86Assembler::JmpDst m_label;
234 };
235
236
237 // Jump:
238 //
239 // A jump object is a reference to a jump instruction that has been planted
240 // into the code buffer - it is typically used to link the jump, setting the
241 // relative offset such that when executed it will jump to the desired
242 // destination.
243 //
244 // Jump objects retain a pointer to the assembler for syntactic purposes -
245 // to allow the jump object to be able to link itself, e.g.:
246 //
247 // Jump forwardsBranch = jne32(Imm32(0), reg1);
248 // // ...
249 // forwardsBranch.link();
250 //
251 // Jumps may also be linked to a Label.
252 class Jump {
253 friend class PatchBuffer;
254 friend class MacroAssembler;
255
256 public:
257 Jump()
258 {
259 }
260
261 // FIXME: transitionary method, while we replace JmpSrces with Jumps.
262 Jump(X86Assembler::JmpSrc jmp)
263 : m_jmp(jmp)
264 {
265 }
266
267 void link(MacroAssembler* masm)
268 {
269 masm->m_assembler.link(m_jmp, masm->m_assembler.label());
270 }
271
272 void linkTo(Label label, MacroAssembler* masm)
273 {
274 masm->m_assembler.link(m_jmp, label.m_label);
275 }
276
277 // FIXME: transitionary method, while we replace JmpSrces with Jumps.
278 operator X86Assembler::JmpSrc()
279 {
280 return m_jmp;
281 }
282
283 static void patch(void* address, void* destination)
284 {
285 X86Assembler::patchBranchOffset(reinterpret_cast<intptr_t>(address), destination);
286 }
287
288 private:
289 X86Assembler::JmpSrc m_jmp;
290 };
291
292 // JumpList:
293 //
294 // A JumpList is a set of Jump objects.
295 // All jumps in the set will be linked to the same destination.
296 class JumpList {
297 friend class PatchBuffer;
298
299 public:
300 void link(MacroAssembler* masm)
301 {
302 size_t size = m_jumps.size();
303 for (size_t i = 0; i < size; ++i)
304 m_jumps[i].link(masm);
305 m_jumps.clear();
306 }
307
308 void linkTo(Label label, MacroAssembler* masm)
309 {
310 size_t size = m_jumps.size();
311 for (size_t i = 0; i < size; ++i)
312 m_jumps[i].linkTo(label, masm);
313 m_jumps.clear();
314 }
315
316 void append(Jump jump)
317 {
318 m_jumps.append(jump);
319 }
320
321 void append(JumpList& other)
322 {
323 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
324 }
325
326 bool empty()
327 {
328 return !m_jumps.size();
329 }
330
331 private:
332 Vector<Jump, 16> m_jumps;
333 };
334
335
336 // PatchBuffer:
337 //
338 // This class assists in linking code generated by the macro assembler, once code generation
339 // has been completed, and the code has been copied to is final location in memory. At this
340 // time pointers to labels within the code may be resolved, and relative offsets to external
341 // addresses may be fixed.
342 //
343 // Specifically:
344 // * Jump objects may be linked to external targets,
345 // * The address of Jump objects may taken, such that it can later be relinked.
346 // * The return address of a Jump object representing a call may be acquired.
347 // * The address of a Label pointing into the code may be resolved.
348 // * The value referenced by a DataLabel may be fixed.
349 //
350 // FIXME: distinguish between Calls & Jumps (make a specific call to obtain the return
351 // address of calls, as opposed to a point that can be used to later relink a Jump -
352 // possibly wrap the later up in an object that can do just that).
353 class PatchBuffer {
354 public:
355 PatchBuffer(void* code)
356 : m_code(code)
357 {
358 }
359
360 void link(Jump jump, void* target)
361 {
362 X86Assembler::link(m_code, jump.m_jmp, target);
363 }
364
365 void link(JumpList list, void* target)
366 {
367 for (unsigned i = 0; i < list.m_jumps.size(); ++i)
368 X86Assembler::link(m_code, list.m_jumps[i], target);
369 }
370
371 void* addressOf(Jump jump)
372 {
373 return X86Assembler::getRelocatedAddress(m_code, jump.m_jmp);
374 }
375
376 void* addressOf(Label label)
377 {
378 return X86Assembler::getRelocatedAddress(m_code, label.m_label);
379 }
380
381 void* addressOf(DataLabelPtr label)
382 {
383 return X86Assembler::getRelocatedAddress(m_code, label.m_label);
384 }
385
386 void* addressOf(DataLabel32 label)
387 {
388 return X86Assembler::getRelocatedAddress(m_code, label.m_label);
389 }
390
391 void setPtr(DataLabelPtr label, void* value)
392 {
393 X86Assembler::patchAddress(m_code, label.m_label, value);
394 }
395
396 private:
397 void* m_code;
398 };
399
400
401 // ImmPtr:
402 //
403 // A pointer sized immediate operand to an instruction - this is wrapped
404 // in a class requiring explicit construction in order to differentiate
405 // from pointers used as absolute addresses to memory operations
406 struct ImmPtr {
407 explicit ImmPtr(void* value)
408 : m_value(value)
409 {
410 }
411
412 intptr_t asIntptr()
413 {
414 return reinterpret_cast<intptr_t>(m_value);
415 }
416
417 void* m_value;
418 };
419
420
421 // Imm32:
422 //
423 // A 32bit immediate operand to an instruction - this is wrapped in a
424 // class requiring explicit construction in order to prevent RegisterIDs
425 // (which are implemented as an enum) from accidentally being passed as
426 // immediate values.
427 struct Imm32 {
428 explicit Imm32(int32_t value)
429 : m_value(value)
430 {
431 }
432
433#if PLATFORM(X86)
434 explicit Imm32(ImmPtr ptr)
435 : m_value(ptr.asIntptr())
436 {
437 }
438#endif
439
440 int32_t m_value;
441 };
442
443 // Integer arithmetic operations:
444 //
445 // Operations are typically two operand - operation(source, srcDst)
446 // For many operations the source may be an Imm32, the srcDst operand
447 // may often be a memory location (explictly described using an Address
448 // object).
449
450 void addPtr(RegisterID src, RegisterID dest)
451 {
452#if PLATFORM(X86_64)
453 m_assembler.addq_rr(src, dest);
454#else
455 add32(src, dest);
456#endif
457 }
458
459 void addPtr(Imm32 imm, RegisterID srcDest)
460 {
461#if PLATFORM(X86_64)
462 m_assembler.addq_ir(imm.m_value, srcDest);
463#else
464 add32(imm, srcDest);
465#endif
466 }
467
468 void addPtr(ImmPtr imm, RegisterID dest)
469 {
470#if PLATFORM(X86_64)
471 move(imm, scratchRegister);
472 m_assembler.addq_rr(scratchRegister, dest);
473#else
474 add32(Imm32(imm), dest);
475#endif
476 }
477
478 void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
479 {
480 m_assembler.leal_mr(imm.m_value, src, dest);
481 }
482
483 void add32(RegisterID src, RegisterID dest)
484 {
485 m_assembler.addl_rr(src, dest);
486 }
487
488 void add32(Imm32 imm, Address address)
489 {
490 m_assembler.addl_im(imm.m_value, address.offset, address.base);
491 }
492
493 void add32(Imm32 imm, RegisterID dest)
494 {
495 m_assembler.addl_ir(imm.m_value, dest);
496 }
497
498 void add32(Imm32 imm, AbsoluteAddress address)
499 {
500#if PLATFORM(X86_64)
501 move(ImmPtr(address.m_ptr), scratchRegister);
502 add32(imm, Address(scratchRegister));
503#else
504 m_assembler.addl_im(imm.m_value, address.m_ptr);
505#endif
506 }
507
508 void add32(Address src, RegisterID dest)
509 {
510 m_assembler.addl_mr(src.offset, src.base, dest);
511 }
512
513 void andPtr(RegisterID src, RegisterID dest)
514 {
515#if PLATFORM(X86_64)
516 m_assembler.andq_rr(src, dest);
517#else
518 and32(src, dest);
519#endif
520 }
521
522 void andPtr(Imm32 imm, RegisterID srcDest)
523 {
524#if PLATFORM(X86_64)
525 m_assembler.andq_ir(imm.m_value, srcDest);
526#else
527 and32(imm, srcDest);
528#endif
529 }
530
531 void and32(RegisterID src, RegisterID dest)
532 {
533 m_assembler.andl_rr(src, dest);
534 }
535
536 void and32(Imm32 imm, RegisterID dest)
537 {
538 m_assembler.andl_ir(imm.m_value, dest);
539 }
540
541 void lshift32(Imm32 imm, RegisterID dest)
542 {
543 m_assembler.shll_i8r(imm.m_value, dest);
544 }
545
546 void lshift32(RegisterID shift_amount, RegisterID dest)
547 {
548 // On x86 we can only shift by ecx; if asked to shift by another register we'll
549 // need rejig the shift amount into ecx first, and restore the registers afterwards.
550 if (shift_amount != X86::ecx) {
551 swap(shift_amount, X86::ecx);
552
553 // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
554 if (dest == shift_amount)
555 m_assembler.shll_CLr(X86::ecx);
556 // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
557 else if (dest == X86::ecx)
558 m_assembler.shll_CLr(shift_amount);
559 // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
560 else
561 m_assembler.shll_CLr(dest);
562
563 swap(shift_amount, X86::ecx);
564 } else
565 m_assembler.shll_CLr(dest);
566 }
567
568 // Take the value from dividend, divide it by divisor, and put the remainder in remainder.
569 // For now, this operation has specific register requirements, and the three register must
570 // be unique. It is unfortunate to expose this in the MacroAssembler interface, however
571 // given the complexity to fix, the fact that it is not uncommmon for processors to have
572 // specific register requirements on this operation (e.g. Mips result in 'hi'), or to not
573 // support a hardware divide at all, it may not be
574 void mod32(RegisterID divisor, RegisterID dividend, RegisterID remainder)
575 {
576#ifdef NDEBUG
577#pragma unused(dividend,remainder)
578#else
579 ASSERT((dividend == X86::eax) && (remainder == X86::edx));
580 ASSERT((dividend != divisor) && (remainder != divisor));
581#endif
582
583 m_assembler.cdq();
584 m_assembler.idivl_r(divisor);
585 }
586
587 void mul32(RegisterID src, RegisterID dest)
588 {
589 m_assembler.imull_rr(src, dest);
590 }
591
592 void mul32(Imm32 imm, RegisterID src, RegisterID dest)
593 {
594 m_assembler.imull_i32r(src, imm.m_value, dest);
595 }
596
597 void not32(RegisterID srcDest)
598 {
599 m_assembler.notl_r(srcDest);
600 }
601
602 void orPtr(RegisterID src, RegisterID dest)
603 {
604#if PLATFORM(X86_64)
605 m_assembler.orq_rr(src, dest);
606#else
607 or32(src, dest);
608#endif
609 }
610
611 void orPtr(ImmPtr imm, RegisterID dest)
612 {
613#if PLATFORM(X86_64)
614 move(imm, scratchRegister);
615 m_assembler.orq_rr(scratchRegister, dest);
616#else
617 or32(Imm32(imm), dest);
618#endif
619 }
620
621 void orPtr(Imm32 imm, RegisterID dest)
622 {
623#if PLATFORM(X86_64)
624 m_assembler.orq_ir(imm.m_value, dest);
625#else
626 or32(imm, dest);
627#endif
628 }
629
630 void or32(RegisterID src, RegisterID dest)
631 {
632 m_assembler.orl_rr(src, dest);
633 }
634
635 void or32(Imm32 imm, RegisterID dest)
636 {
637 m_assembler.orl_ir(imm.m_value, dest);
638 }
639
640 void rshiftPtr(RegisterID shift_amount, RegisterID dest)
641 {
642#if PLATFORM(X86_64)
643 // On x86 we can only shift by ecx; if asked to shift by another register we'll
644 // need rejig the shift amount into ecx first, and restore the registers afterwards.
645 if (shift_amount != X86::ecx) {
646 swap(shift_amount, X86::ecx);
647
648 // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
649 if (dest == shift_amount)
650 m_assembler.sarq_CLr(X86::ecx);
651 // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
652 else if (dest == X86::ecx)
653 m_assembler.sarq_CLr(shift_amount);
654 // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
655 else
656 m_assembler.sarq_CLr(dest);
657
658 swap(shift_amount, X86::ecx);
659 } else
660 m_assembler.sarq_CLr(dest);
661#else
662 rshift32(shift_amount, dest);
663#endif
664 }
665
666 void rshiftPtr(Imm32 imm, RegisterID dest)
667 {
668#if PLATFORM(X86_64)
669 m_assembler.sarq_i8r(imm.m_value, dest);
670#else
671 rshift32(imm, dest);
672#endif
673 }
674
675 void rshift32(RegisterID shift_amount, RegisterID dest)
676 {
677 // On x86 we can only shift by ecx; if asked to shift by another register we'll
678 // need rejig the shift amount into ecx first, and restore the registers afterwards.
679 if (shift_amount != X86::ecx) {
680 swap(shift_amount, X86::ecx);
681
682 // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
683 if (dest == shift_amount)
684 m_assembler.sarl_CLr(X86::ecx);
685 // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
686 else if (dest == X86::ecx)
687 m_assembler.sarl_CLr(shift_amount);
688 // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
689 else
690 m_assembler.sarl_CLr(dest);
691
692 swap(shift_amount, X86::ecx);
693 } else
694 m_assembler.sarl_CLr(dest);
695 }
696
697 void rshift32(Imm32 imm, RegisterID dest)
698 {
699 m_assembler.sarl_i8r(imm.m_value, dest);
700 }
701
702 void subPtr(RegisterID src, RegisterID dest)
703 {
704#if PLATFORM(X86_64)
705 m_assembler.subq_rr(src, dest);
706#else
707 sub32(src, dest);
708#endif
709 }
710
711 void subPtr(Imm32 imm, RegisterID dest)
712 {
713#if PLATFORM(X86_64)
714 m_assembler.subq_ir(imm.m_value, dest);
715#else
716 sub32(imm, dest);
717#endif
718 }
719
720 void subPtr(ImmPtr imm, RegisterID dest)
721 {
722#if PLATFORM(X86_64)
723 move(imm, scratchRegister);
724 m_assembler.subq_rr(scratchRegister, dest);
725#else
726 sub32(Imm32(imm), dest);
727#endif
728 }
729
730 void sub32(RegisterID src, RegisterID dest)
731 {
732 m_assembler.subl_rr(src, dest);
733 }
734
735 void sub32(Imm32 imm, RegisterID dest)
736 {
737 m_assembler.subl_ir(imm.m_value, dest);
738 }
739
740 void sub32(Imm32 imm, Address address)
741 {
742 m_assembler.subl_im(imm.m_value, address.offset, address.base);
743 }
744
745 void sub32(Imm32 imm, AbsoluteAddress address)
746 {
747#if PLATFORM(X86_64)
748 move(ImmPtr(address.m_ptr), scratchRegister);
749 sub32(imm, Address(scratchRegister));
750#else
751 m_assembler.subl_im(imm.m_value, address.m_ptr);
752#endif
753 }
754
755 void sub32(Address src, RegisterID dest)
756 {
757 m_assembler.subl_mr(src.offset, src.base, dest);
758 }
759
760 void xorPtr(RegisterID src, RegisterID dest)
761 {
762#if PLATFORM(X86_64)
763 m_assembler.xorq_rr(src, dest);
764#else
765 xor32(src, dest);
766#endif
767 }
768
769 void xorPtr(Imm32 imm, RegisterID srcDest)
770 {
771#if PLATFORM(X86_64)
772 m_assembler.xorq_ir(imm.m_value, srcDest);
773#else
774 xor32(imm, srcDest);
775#endif
776 }
777
778 void xor32(RegisterID src, RegisterID dest)
779 {
780 m_assembler.xorl_rr(src, dest);
781 }
782
783 void xor32(Imm32 imm, RegisterID srcDest)
784 {
785 m_assembler.xorl_ir(imm.m_value, srcDest);
786 }
787
788
789 // Memory access operations:
790 //
791 // Loads are of the form load(address, destination) and stores of the form
792 // store(source, address). The source for a store may be an Imm32. Address
793 // operand objects to loads and store will be implicitly constructed if a
794 // register is passed.
795
796 void loadPtr(ImplicitAddress address, RegisterID dest)
797 {
798#if PLATFORM(X86_64)
799 m_assembler.movq_mr(address.offset, address.base, dest);
800#else
801 load32(address, dest);
802#endif
803 }
804
805 DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
806 {
807#if PLATFORM(X86_64)
808 m_assembler.movq_mr_disp32(address.offset, address.base, dest);
809 return DataLabel32(this);
810#else
811 m_assembler.movl_mr_disp32(address.offset, address.base, dest);
812 return DataLabel32(this);
813#endif
814 }
815
816 void loadPtr(BaseIndex address, RegisterID dest)
817 {
818#if PLATFORM(X86_64)
819 m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
820#else
821 load32(address, dest);
822#endif
823 }
824
825 void loadPtr(void* address, RegisterID dest)
826 {
827#if PLATFORM(X86_64)
828 if (dest == X86::eax)
829 m_assembler.movq_mEAX(address);
830 else {
831 move(X86::eax, dest);
832 m_assembler.movq_mEAX(address);
833 swap(X86::eax, dest);
834 }
835#else
836 load32(address, dest);
837#endif
838 }
839
840 void load32(ImplicitAddress address, RegisterID dest)
841 {
842 m_assembler.movl_mr(address.offset, address.base, dest);
843 }
844
845 void load32(BaseIndex address, RegisterID dest)
846 {
847 m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest);
848 }
849
850 void load32(void* address, RegisterID dest)
851 {
852#if PLATFORM(X86_64)
853 if (dest == X86::eax)
854 m_assembler.movl_mEAX(address);
855 else {
856 move(X86::eax, dest);
857 m_assembler.movl_mEAX(address);
858 swap(X86::eax, dest);
859 }
860#else
861 m_assembler.movl_mr(address, dest);
862#endif
863 }
864
865 void load16(BaseIndex address, RegisterID dest)
866 {
867 m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
868 }
869
870 void storePtr(RegisterID src, ImplicitAddress address)
871 {
872#if PLATFORM(X86_64)
873 m_assembler.movq_rm(src, address.offset, address.base);
874#else
875 store32(src, address);
876#endif
877 }
878
879 DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
880 {
881#if PLATFORM(X86_64)
882 m_assembler.movq_rm_disp32(src, address.offset, address.base);
883 return DataLabel32(this);
884#else
885 m_assembler.movl_rm_disp32(src, address.offset, address.base);
886 return DataLabel32(this);
887#endif
888 }
889
890 void storePtr(RegisterID src, BaseIndex address)
891 {
892#if PLATFORM(X86_64)
893 m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
894#else
895 store32(src, address);
896#endif
897 }
898
899 void storePtr(ImmPtr imm, ImplicitAddress address)
900 {
901#if PLATFORM(X86_64)
902 move(imm, scratchRegister);
903 storePtr(scratchRegister, address);
904#else
905 m_assembler.movl_i32m(imm.asIntptr(), address.offset, address.base);
906#endif
907 }
908
909#if !PLATFORM(X86_64)
910 void storePtr(ImmPtr imm, void* address)
911 {
912 store32(Imm32(imm), address);
913 }
914#endif
915
916 DataLabelPtr storePtrWithPatch(Address address)
917 {
918#if PLATFORM(X86_64)
919 m_assembler.movq_i64r(0, scratchRegister);
920 DataLabelPtr label(this);
921 storePtr(scratchRegister, address);
922 return label;
923#else
924 m_assembler.movl_i32m(0, address.offset, address.base);
925 return DataLabelPtr(this);
926#endif
927 }
928
929 void store32(RegisterID src, ImplicitAddress address)
930 {
931 m_assembler.movl_rm(src, address.offset, address.base);
932 }
933
934 void store32(RegisterID src, BaseIndex address)
935 {
936 m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
937 }
938
939 void store32(Imm32 imm, ImplicitAddress address)
940 {
941 m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
942 }
943
944 void store32(Imm32 imm, void* address)
945 {
946#if PLATFORM(X86_64)
947 move(X86::eax, scratchRegister);
948 move(imm, X86::eax);
949 m_assembler.movl_EAXm(address);
950 move(scratchRegister, X86::eax);
951#else
952 m_assembler.movl_i32m(imm.m_value, address);
953#endif
954 }
955
956
957 // Stack manipulation operations:
958 //
959 // The ABI is assumed to provide a stack abstraction to memory,
960 // containing machine word sized units of data. Push and pop
961 // operations add and remove a single register sized unit of data
962 // to or from the stack. Peek and poke operations read or write
963 // values on the stack, without moving the current stack position.
964
965 void pop(RegisterID dest)
966 {
967 m_assembler.pop_r(dest);
968 }
969
970 void push(RegisterID src)
971 {
972 m_assembler.push_r(src);
973 }
974
975 void push(Address address)
976 {
977 m_assembler.push_m(address.offset, address.base);
978 }
979
980 void push(Imm32 imm)
981 {
982 m_assembler.push_i32(imm.m_value);
983 }
984
985 void pop()
986 {
987 addPtr(Imm32(sizeof(void*)), X86::esp);
988 }
989
990 void peek(RegisterID dest, int index = 0)
991 {
992 loadPtr(Address(X86::esp, (index * sizeof(void *))), dest);
993 }
994
995 void poke(RegisterID src, int index = 0)
996 {
997 storePtr(src, Address(X86::esp, (index * sizeof(void *))));
998 }
999
1000 void poke(Imm32 value, int index = 0)
1001 {
1002 store32(value, Address(X86::esp, (index * sizeof(void *))));
1003 }
1004
1005 void poke(ImmPtr imm, int index = 0)
1006 {
1007 storePtr(imm, Address(X86::esp, (index * sizeof(void *))));
1008 }
1009
1010 // Register move operations:
1011 //
1012 // Move values in registers.
1013
1014 void move(Imm32 imm, RegisterID dest)
1015 {
1016 // Note: on 64-bit the Imm32 value is zero extended into the register, it
1017 // may be useful to have a separate version that sign extends the value?
1018 if (!imm.m_value)
1019 m_assembler.xorl_rr(dest, dest);
1020 else
1021 m_assembler.movl_i32r(imm.m_value, dest);
1022 }
1023
1024 void move(RegisterID src, RegisterID dest)
1025 {
1026 // Note: on 64-bit this is is a full register move; perhaps it would be
1027 // useful to have separate move32 & movePtr, with move32 zero extending?
1028#if PLATFORM(X86_64)
1029 m_assembler.movq_rr(src, dest);
1030#else
1031 m_assembler.movl_rr(src, dest);
1032#endif
1033 }
1034
1035 void move(ImmPtr imm, RegisterID dest)
1036 {
1037#if PLATFORM(X86_64)
1038 if (CAN_SIGN_EXTEND_U32_64(imm.asIntptr()))
1039 m_assembler.movl_i32r(static_cast<int32_t>(imm.asIntptr()), dest);
1040 else
1041 m_assembler.movq_i64r(imm.asIntptr(), dest);
1042#else
1043 m_assembler.movl_i32r(imm.asIntptr(), dest);
1044#endif
1045 }
1046
1047 void swap(RegisterID reg1, RegisterID reg2)
1048 {
1049#if PLATFORM(X86_64)
1050 m_assembler.xchgq_rr(reg1, reg2);
1051#else
1052 m_assembler.xchgl_rr(reg1, reg2);
1053#endif
1054 }
1055
1056 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1057 {
1058#if PLATFORM(X86_64)
1059 m_assembler.movsxd_rr(src, dest);
1060#else
1061 if (src != dest)
1062 move(src, dest);
1063#endif
1064 }
1065
1066 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1067 {
1068#if PLATFORM(X86_64)
1069 m_assembler.movl_rr(src, dest);
1070#else
1071 if (src != dest)
1072 move(src, dest);
1073#endif
1074 }
1075
1076
1077 // Forwards / external control flow operations:
1078 //
1079 // This set of jump and conditional branch operations return a Jump
1080 // object which may linked at a later point, allow forwards jump,
1081 // or jumps that will require external linkage (after the code has been
1082 // relocated).
1083 //
1084 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1085 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1086 // used (representing the names 'below' and 'above').
1087 //
1088 // Operands to the comparision are provided in the expected order, e.g.
1089 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
1090 // treated as a signed 32bit value, is less than or equal to 5.
1091 //
1092 // jz and jnz test whether the first operand is equal to zero, and take
1093 // an optional second operand of a mask under which to perform the test.
1094
1095private:
1096 void compareImm32ForBranch(RegisterID left, int32_t right)
1097 {
1098 m_assembler.cmpl_ir(right, left);
1099 }
1100
1101 void compareImm32ForBranchEquality(RegisterID reg, int32_t imm)
1102 {
1103 if (!imm)
1104 m_assembler.testl_rr(reg, reg);
1105 else
1106 m_assembler.cmpl_ir(imm, reg);
1107 }
1108
1109 void compareImm32ForBranchEquality(Address address, int32_t imm)
1110 {
1111 m_assembler.cmpl_im(imm, address.offset, address.base);
1112 }
1113
1114 void testImm32(RegisterID reg, Imm32 mask)
1115 {
1116 // if we are only interested in the low seven bits, this can be tested with a testb
1117 if (mask.m_value == -1)
1118 m_assembler.testl_rr(reg, reg);
1119 else if ((mask.m_value & ~0x7f) == 0)
1120 m_assembler.testb_i8r(mask.m_value, reg);
1121 else
1122 m_assembler.testl_i32r(mask.m_value, reg);
1123 }
1124
1125 void testImm32(Address address, Imm32 mask)
1126 {
1127 if (mask.m_value == -1)
1128 m_assembler.cmpl_im(0, address.offset, address.base);
1129 else
1130 m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
1131 }
1132
1133 void testImm32(BaseIndex address, Imm32 mask)
1134 {
1135 if (mask.m_value == -1)
1136 m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale);
1137 else
1138 m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
1139 }
1140
1141#if PLATFORM(X86_64)
1142 void compareImm64ForBranch(RegisterID left, int32_t right)
1143 {
1144 m_assembler.cmpq_ir(right, left);
1145 }
1146
1147 void compareImm64ForBranchEquality(RegisterID reg, int32_t imm)
1148 {
1149 if (!imm)
1150 m_assembler.testq_rr(reg, reg);
1151 else
1152 m_assembler.cmpq_ir(imm, reg);
1153 }
1154
1155 void testImm64(RegisterID reg, Imm32 mask)
1156 {
1157 // if we are only interested in the low seven bits, this can be tested with a testb
1158 if (mask.m_value == -1)
1159 m_assembler.testq_rr(reg, reg);
1160 else if ((mask.m_value & ~0x7f) == 0)
1161 m_assembler.testb_i8r(mask.m_value, reg);
1162 else
1163 m_assembler.testq_i32r(mask.m_value, reg);
1164 }
1165
1166 void testImm64(Address address, Imm32 mask)
1167 {
1168 if (mask.m_value == -1)
1169 m_assembler.cmpq_im(0, address.offset, address.base);
1170 else
1171 m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
1172 }
1173
1174 void testImm64(BaseIndex address, Imm32 mask)
1175 {
1176 if (mask.m_value == -1)
1177 m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
1178 else
1179 m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
1180 }
1181#endif
1182
1183public:
1184 Jump ja32(RegisterID left, Imm32 right)
1185 {
1186 compareImm32ForBranch(left, right.m_value);
1187 return Jump(m_assembler.ja());
1188 }
1189
1190 Jump jaePtr(RegisterID left, RegisterID right)
1191 {
1192#if PLATFORM(X86_64)
1193 m_assembler.cmpq_rr(right, left);
1194 return Jump(m_assembler.jae());
1195#else
1196 return jae32(left, right);
1197#endif
1198 }
1199
1200 Jump jaePtr(RegisterID reg, ImmPtr ptr)
1201 {
1202#if PLATFORM(X86_64)
1203 intptr_t imm = ptr.asIntptr();
1204 if (CAN_SIGN_EXTEND_32_64(imm)) {
1205 compareImm64ForBranch(reg, imm);
1206 return Jump(m_assembler.jae());
1207 } else {
1208 move(ptr, scratchRegister);
1209 return jaePtr(reg, scratchRegister);
1210 }
1211#else
1212 return jae32(reg, Imm32(ptr));
1213#endif
1214 }
1215
1216 Jump jae32(RegisterID left, RegisterID right)
1217 {
1218 m_assembler.cmpl_rr(right, left);
1219 return Jump(m_assembler.jae());
1220 }
1221
1222 Jump jae32(RegisterID left, Imm32 right)
1223 {
1224 compareImm32ForBranch(left, right.m_value);
1225 return Jump(m_assembler.jae());
1226 }
1227
1228 Jump jae32(RegisterID left, Address right)
1229 {
1230 m_assembler.cmpl_mr(right.offset, right.base, left);
1231 return Jump(m_assembler.jae());
1232 }
1233
1234 Jump jae32(Address left, RegisterID right)
1235 {
1236 m_assembler.cmpl_rm(right, left.offset, left.base);
1237 return Jump(m_assembler.jae());
1238 }
1239
1240 Jump jbPtr(RegisterID left, RegisterID right)
1241 {
1242#if PLATFORM(X86_64)
1243 m_assembler.cmpq_rr(right, left);
1244 return Jump(m_assembler.jb());
1245#else
1246 return jb32(left, right);
1247#endif
1248 }
1249
1250 Jump jbPtr(RegisterID reg, ImmPtr ptr)
1251 {
1252#if PLATFORM(X86_64)
1253 intptr_t imm = ptr.asIntptr();
1254 if (CAN_SIGN_EXTEND_32_64(imm)) {
1255 compareImm64ForBranch(reg, imm);
1256 return Jump(m_assembler.jb());
1257 } else {
1258 move(ptr, scratchRegister);
1259 return jbPtr(reg, scratchRegister);
1260 }
1261#else
1262 return jb32(reg, Imm32(ptr));
1263#endif
1264 }
1265
1266 Jump jb32(RegisterID left, RegisterID right)
1267 {
1268 m_assembler.cmpl_rr(right, left);
1269 return Jump(m_assembler.jb());
1270 }
1271
1272 Jump jb32(RegisterID left, Imm32 right)
1273 {
1274 compareImm32ForBranch(left, right.m_value);
1275 return Jump(m_assembler.jb());
1276 }
1277
1278 Jump jb32(RegisterID left, Address right)
1279 {
1280 m_assembler.cmpl_mr(right.offset, right.base, left);
1281 return Jump(m_assembler.jb());
1282 }
1283
1284 Jump jePtr(RegisterID op1, RegisterID op2)
1285 {
1286#if PLATFORM(X86_64)
1287 m_assembler.cmpq_rr(op1, op2);
1288 return Jump(m_assembler.je());
1289#else
1290 return je32(op1, op2);
1291#endif
1292 }
1293
1294 Jump jePtr(RegisterID reg, Address address)
1295 {
1296#if PLATFORM(X86_64)
1297 m_assembler.cmpq_rm(reg, address.offset, address.base);
1298#else
1299 m_assembler.cmpl_rm(reg, address.offset, address.base);
1300#endif
1301 return Jump(m_assembler.je());
1302 }
1303
1304 Jump jePtr(RegisterID reg, ImmPtr ptr)
1305 {
1306#if PLATFORM(X86_64)
1307 intptr_t imm = ptr.asIntptr();
1308 if (CAN_SIGN_EXTEND_32_64(imm)) {
1309 compareImm64ForBranchEquality(reg, imm);
1310 return Jump(m_assembler.je());
1311 } else {
1312 move(ptr, scratchRegister);
1313 return jePtr(scratchRegister, reg);
1314 }
1315#else
1316 return je32(reg, Imm32(ptr));
1317#endif
1318 }
1319
1320 Jump jePtr(Address address, ImmPtr imm)
1321 {
1322#if PLATFORM(X86_64)
1323 move(imm, scratchRegister);
1324 return jePtr(scratchRegister, address);
1325#else
1326 return je32(address, Imm32(imm));
1327#endif
1328 }
1329
1330 Jump je32(RegisterID op1, RegisterID op2)
1331 {
1332 m_assembler.cmpl_rr(op1, op2);
1333 return Jump(m_assembler.je());
1334 }
1335
1336 Jump je32(Address op1, RegisterID op2)
1337 {
1338 m_assembler.cmpl_mr(op1.offset, op1.base, op2);
1339 return Jump(m_assembler.je());
1340 }
1341
1342 Jump je32(RegisterID reg, Imm32 imm)
1343 {
1344 compareImm32ForBranchEquality(reg, imm.m_value);
1345 return Jump(m_assembler.je());
1346 }
1347
1348 Jump je32(Address address, Imm32 imm)
1349 {
1350 compareImm32ForBranchEquality(address, imm.m_value);
1351 return Jump(m_assembler.je());
1352 }
1353
1354 Jump je16(RegisterID op1, BaseIndex op2)
1355 {
1356 m_assembler.cmpw_rm(op1, op2.offset, op2.base, op2.index, op2.scale);
1357 return Jump(m_assembler.je());
1358 }
1359
1360 Jump jg32(RegisterID left, RegisterID right)
1361 {
1362 m_assembler.cmpl_rr(right, left);
1363 return Jump(m_assembler.jg());
1364 }
1365
1366 Jump jg32(RegisterID reg, Address address)
1367 {
1368 m_assembler.cmpl_mr(address.offset, address.base, reg);
1369 return Jump(m_assembler.jg());
1370 }
1371
1372 Jump jgePtr(RegisterID left, RegisterID right)
1373 {
1374#if PLATFORM(X86_64)
1375 m_assembler.cmpq_rr(right, left);
1376 return Jump(m_assembler.jge());
1377#else
1378 return jge32(left, right);
1379#endif
1380 }
1381
1382 Jump jgePtr(RegisterID reg, ImmPtr ptr)
1383 {
1384#if PLATFORM(X86_64)
1385 intptr_t imm = ptr.asIntptr();
1386 if (CAN_SIGN_EXTEND_32_64(imm)) {
1387 compareImm64ForBranch(reg, imm);
1388 return Jump(m_assembler.jge());
1389 } else {
1390 move(ptr, scratchRegister);
1391 return jgePtr(reg, scratchRegister);
1392 }
1393#else
1394 return jge32(reg, Imm32(ptr));
1395#endif
1396 }
1397
1398 Jump jge32(RegisterID left, RegisterID right)
1399 {
1400 m_assembler.cmpl_rr(right, left);
1401 return Jump(m_assembler.jge());
1402 }
1403
1404 Jump jge32(RegisterID left, Imm32 right)
1405 {
1406 compareImm32ForBranch(left, right.m_value);
1407 return Jump(m_assembler.jge());
1408 }
1409
1410 Jump jlPtr(RegisterID left, RegisterID right)
1411 {
1412#if PLATFORM(X86_64)
1413 m_assembler.cmpq_rr(right, left);
1414 return Jump(m_assembler.jl());
1415#else
1416 return jl32(left, right);
1417#endif
1418 }
1419
1420 Jump jlPtr(RegisterID reg, ImmPtr ptr)
1421 {
1422#if PLATFORM(X86_64)
1423 intptr_t imm = ptr.asIntptr();
1424 if (CAN_SIGN_EXTEND_32_64(imm)) {
1425 compareImm64ForBranch(reg, imm);
1426 return Jump(m_assembler.jl());
1427 } else {
1428 move(ptr, scratchRegister);
1429 return jlPtr(reg, scratchRegister);
1430 }
1431#else
1432 return jl32(reg, Imm32(ptr));
1433#endif
1434 }
1435
1436 Jump jl32(RegisterID left, RegisterID right)
1437 {
1438 m_assembler.cmpl_rr(right, left);
1439 return Jump(m_assembler.jl());
1440 }
1441
1442 Jump jl32(RegisterID left, Imm32 right)
1443 {
1444 compareImm32ForBranch(left, right.m_value);
1445 return Jump(m_assembler.jl());
1446 }
1447
1448 Jump jlePtr(RegisterID left, RegisterID right)
1449 {
1450#if PLATFORM(X86_64)
1451 m_assembler.cmpq_rr(right, left);
1452 return Jump(m_assembler.jle());
1453#else
1454 return jle32(left, right);
1455#endif
1456 }
1457
1458 Jump jlePtr(RegisterID reg, ImmPtr ptr)
1459 {
1460#if PLATFORM(X86_64)
1461 intptr_t imm = ptr.asIntptr();
1462 if (CAN_SIGN_EXTEND_32_64(imm)) {
1463 compareImm64ForBranch(reg, imm);
1464 return Jump(m_assembler.jle());
1465 } else {
1466 move(ptr, scratchRegister);
1467 return jlePtr(reg, scratchRegister);
1468 }
1469#else
1470 return jle32(reg, Imm32(ptr));
1471#endif
1472 }
1473
1474 Jump jle32(RegisterID left, RegisterID right)
1475 {
1476 m_assembler.cmpl_rr(right, left);
1477 return Jump(m_assembler.jle());
1478 }
1479
1480 Jump jle32(RegisterID left, Imm32 right)
1481 {
1482 compareImm32ForBranch(left, right.m_value);
1483 return Jump(m_assembler.jle());
1484 }
1485
1486 Jump jnePtr(RegisterID op1, RegisterID op2)
1487 {
1488#if PLATFORM(X86_64)
1489 m_assembler.cmpq_rr(op1, op2);
1490 return Jump(m_assembler.jne());
1491#else
1492 return jne32(op1, op2);
1493#endif
1494 }
1495
1496 Jump jnePtr(RegisterID reg, Address address)
1497 {
1498#if PLATFORM(X86_64)
1499 m_assembler.cmpq_rm(reg, address.offset, address.base);
1500#else
1501 m_assembler.cmpl_rm(reg, address.offset, address.base);
1502#endif
1503 return Jump(m_assembler.jne());
1504 }
1505
1506 Jump jnePtr(RegisterID reg, AbsoluteAddress address)
1507 {
1508#if PLATFORM(X86_64)
1509 move(ImmPtr(address.m_ptr), scratchRegister);
1510 return jnePtr(reg, Address(scratchRegister));
1511#else
1512 m_assembler.cmpl_rm(reg, address.m_ptr);
1513 return Jump(m_assembler.jne());
1514#endif
1515 }
1516
1517 Jump jnePtr(RegisterID reg, ImmPtr ptr)
1518 {
1519#if PLATFORM(X86_64)
1520 intptr_t imm = ptr.asIntptr();
1521 if (CAN_SIGN_EXTEND_32_64(imm)) {
1522 compareImm64ForBranchEquality(reg, imm);
1523 return Jump(m_assembler.jne());
1524 } else {
1525 move(ptr, scratchRegister);
1526 return jnePtr(scratchRegister, reg);
1527 }
1528#else
1529 return jne32(reg, Imm32(ptr));
1530#endif
1531 }
1532
1533 Jump jnePtr(Address address, ImmPtr imm)
1534 {
1535#if PLATFORM(X86_64)
1536 move(imm, scratchRegister);
1537 return jnePtr(scratchRegister, address);
1538#else
1539 return jne32(address, Imm32(imm));
1540#endif
1541 }
1542
1543#if !PLATFORM(X86_64)
1544 Jump jnePtr(AbsoluteAddress address, ImmPtr imm)
1545 {
1546 m_assembler.cmpl_im(imm.asIntptr(), address.m_ptr);
1547 return Jump(m_assembler.jne());
1548 }
1549#endif
1550
1551 Jump jnePtrWithPatch(RegisterID reg, DataLabelPtr& dataLabel, ImmPtr initialValue = ImmPtr(0))
1552 {
1553#if PLATFORM(X86_64)
1554 m_assembler.movq_i64r(initialValue.asIntptr(), scratchRegister);
1555 dataLabel = DataLabelPtr(this);
1556 return jnePtr(scratchRegister, reg);
1557#else
1558 m_assembler.cmpl_ir_force32(initialValue.asIntptr(), reg);
1559 dataLabel = DataLabelPtr(this);
1560 return Jump(m_assembler.jne());
1561#endif
1562 }
1563
1564 Jump jnePtrWithPatch(Address address, DataLabelPtr& dataLabel, ImmPtr initialValue = ImmPtr(0))
1565 {
1566#if PLATFORM(X86_64)
1567 m_assembler.movq_i64r(initialValue.asIntptr(), scratchRegister);
1568 dataLabel = DataLabelPtr(this);
1569 return jnePtr(scratchRegister, address);
1570#else
1571 m_assembler.cmpl_im_force32(initialValue.asIntptr(), address.offset, address.base);
1572 dataLabel = DataLabelPtr(this);
1573 return Jump(m_assembler.jne());
1574#endif
1575 }
1576
1577 Jump jne32(RegisterID op1, RegisterID op2)
1578 {
1579 m_assembler.cmpl_rr(op1, op2);
1580 return Jump(m_assembler.jne());
1581 }
1582
1583 Jump jne32(RegisterID reg, Imm32 imm)
1584 {
1585 compareImm32ForBranchEquality(reg, imm.m_value);
1586 return Jump(m_assembler.jne());
1587 }
1588
1589 Jump jne32(Address address, Imm32 imm)
1590 {
1591 compareImm32ForBranchEquality(address, imm.m_value);
1592 return Jump(m_assembler.jne());
1593 }
1594
1595 Jump jne32(Address address, RegisterID reg)
1596 {
1597 m_assembler.cmpl_rm(reg, address.offset, address.base);
1598 return Jump(m_assembler.jne());
1599 }
1600
1601 Jump jnzPtr(RegisterID reg, RegisterID mask)
1602 {
1603#if PLATFORM(X86_64)
1604 m_assembler.testq_rr(reg, mask);
1605 return Jump(m_assembler.jne());
1606#else
1607 return jnz32(reg, mask);
1608#endif
1609 }
1610
1611 Jump jnzPtr(RegisterID reg, Imm32 mask = Imm32(-1))
1612 {
1613#if PLATFORM(X86_64)
1614 testImm64(reg, mask);
1615 return Jump(m_assembler.jne());
1616#else
1617 return jnz32(reg, mask);
1618#endif
1619 }
1620
1621 Jump jnzPtr(RegisterID reg, ImmPtr mask)
1622 {
1623#if PLATFORM(X86_64)
1624 move(mask, scratchRegister);
1625 m_assembler.testq_rr(scratchRegister, reg);
1626 return Jump(m_assembler.jne());
1627#else
1628 return jnz32(reg, Imm32(mask));
1629#endif
1630 }
1631
1632 Jump jnzPtr(Address address, Imm32 mask = Imm32(-1))
1633 {
1634#if PLATFORM(X86_64)
1635 testImm64(address, mask);
1636 return Jump(m_assembler.jne());
1637#else
1638 return jnz32(address, mask);
1639#endif
1640 }
1641
1642 Jump jnz32(RegisterID reg, RegisterID mask)
1643 {
1644 m_assembler.testl_rr(reg, mask);
1645 return Jump(m_assembler.jne());
1646 }
1647
1648 Jump jnz32(RegisterID reg, Imm32 mask = Imm32(-1))
1649 {
1650 testImm32(reg, mask);
1651 return Jump(m_assembler.jne());
1652 }
1653
1654 Jump jnz32(Address address, Imm32 mask = Imm32(-1))
1655 {
1656 testImm32(address, mask);
1657 return Jump(m_assembler.jne());
1658 }
1659
1660 Jump jzPtr(RegisterID reg, RegisterID mask)
1661 {
1662#if PLATFORM(X86_64)
1663 m_assembler.testq_rr(reg, mask);
1664 return Jump(m_assembler.je());
1665#else
1666 return jz32(reg, mask);
1667#endif
1668 }
1669
1670 Jump jzPtr(RegisterID reg, Imm32 mask = Imm32(-1))
1671 {
1672#if PLATFORM(X86_64)
1673 testImm64(reg, mask);
1674 return Jump(m_assembler.je());
1675#else
1676 return jz32(reg, mask);
1677#endif
1678 }
1679
1680 Jump jzPtr(RegisterID reg, ImmPtr mask)
1681 {
1682#if PLATFORM(X86_64)
1683 move(mask, scratchRegister);
1684 m_assembler.testq_rr(scratchRegister, reg);
1685 return Jump(m_assembler.je());
1686#else
1687 return jz32(reg, Imm32(mask));
1688#endif
1689 }
1690
1691 Jump jzPtr(Address address, Imm32 mask = Imm32(-1))
1692 {
1693#if PLATFORM(X86_64)
1694 testImm64(address, mask);
1695 return Jump(m_assembler.je());
1696#else
1697 return jz32(address, mask);
1698#endif
1699 }
1700
1701 Jump jzPtr(BaseIndex address, Imm32 mask = Imm32(-1))
1702 {
1703#if PLATFORM(X86_64)
1704 testImm64(address, mask);
1705 return Jump(m_assembler.je());
1706#else
1707 return jz32(address, mask);
1708#endif
1709 }
1710
1711 Jump jz32(RegisterID reg, RegisterID mask)
1712 {
1713 m_assembler.testl_rr(reg, mask);
1714 return Jump(m_assembler.je());
1715 }
1716
1717 Jump jz32(RegisterID reg, Imm32 mask = Imm32(-1))
1718 {
1719 testImm32(reg, mask);
1720 return Jump(m_assembler.je());
1721 }
1722
1723 Jump jz32(Address address, Imm32 mask = Imm32(-1))
1724 {
1725 testImm32(address, mask);
1726 return Jump(m_assembler.je());
1727 }
1728
1729 Jump jz32(BaseIndex address, Imm32 mask = Imm32(-1))
1730 {
1731 testImm32(address, mask);
1732 return Jump(m_assembler.je());
1733 }
1734
1735 Jump jump()
1736 {
1737 return Jump(m_assembler.jmp());
1738 }
1739
1740
1741 // Backwards, local control flow operations:
1742 //
1743 // These operations provide a shorter notation for local
1744 // backwards branches, which may be both more convenient
1745 // for the user, and for the programmer, and for the
1746 // assembler (allowing shorter values to be used in
1747 // relative offsets).
1748 //
1749 // The code sequence:
1750 //
1751 // Label topOfLoop(this);
1752 // // ...
1753 // jne32(reg1, reg2, topOfLoop);
1754 //
1755 // Is equivalent to the longer, potentially less efficient form:
1756 //
1757 // Label topOfLoop(this);
1758 // // ...
1759 // jne32(reg1, reg2).linkTo(topOfLoop);
1760
1761 void jae32(RegisterID left, Address right, Label target)
1762 {
1763 jae32(left, right).linkTo(target, this);
1764 }
1765
1766 void je32(RegisterID op1, Imm32 imm, Label target)
1767 {
1768 je32(op1, imm).linkTo(target, this);
1769 }
1770
1771 void je16(RegisterID op1, BaseIndex op2, Label target)
1772 {
1773 je16(op1, op2).linkTo(target, this);
1774 }
1775
1776 void jl32(RegisterID left, Imm32 right, Label target)
1777 {
1778 jl32(left, right).linkTo(target, this);
1779 }
1780
1781 void jle32(RegisterID left, RegisterID right, Label target)
1782 {
1783 jle32(left, right).linkTo(target, this);
1784 }
1785
1786 void jnePtr(RegisterID op1, ImmPtr imm, Label target)
1787 {
1788 jnePtr(op1, imm).linkTo(target, this);
1789 }
1790
1791 void jne32(RegisterID op1, RegisterID op2, Label target)
1792 {
1793 jne32(op1, op2).linkTo(target, this);
1794 }
1795
1796 void jne32(RegisterID op1, Imm32 imm, Label target)
1797 {
1798 jne32(op1, imm).linkTo(target, this);
1799 }
1800
1801 void jzPtr(RegisterID reg, Label target)
1802 {
1803 jzPtr(reg).linkTo(target, this);
1804 }
1805
1806 void jump(Label target)
1807 {
1808 m_assembler.link(m_assembler.jmp(), target.m_label);
1809 }
1810
1811 void jump(RegisterID target)
1812 {
1813 m_assembler.jmp_r(target);
1814 }
1815
1816 // Address is a memory location containing the address to jump to
1817 void jump(Address address)
1818 {
1819 m_assembler.jmp_m(address.offset, address.base);
1820 }
1821
1822
1823 // Arithmetic control flow operations:
1824 //
1825 // This set of conditional branch operations branch based
1826 // on the result of an arithmetic operation. The operation
1827 // is performed as normal, storing the result.
1828 //
1829 // * jz operations branch if the result is zero.
1830 // * jo operations branch if the (signed) arithmetic
1831 // operation caused an overflow to occur.
1832
1833 Jump jnzSubPtr(Imm32 imm, RegisterID dest)
1834 {
1835 subPtr(imm, dest);
1836 return Jump(m_assembler.jne());
1837 }
1838
1839 Jump jnzSub32(Imm32 imm, RegisterID dest)
1840 {
1841 sub32(imm, dest);
1842 return Jump(m_assembler.jne());
1843 }
1844
1845 Jump joAddPtr(RegisterID src, RegisterID dest)
1846 {
1847 addPtr(src, dest);
1848 return Jump(m_assembler.jo());
1849 }
1850
1851 Jump joAdd32(RegisterID src, RegisterID dest)
1852 {
1853 add32(src, dest);
1854 return Jump(m_assembler.jo());
1855 }
1856
1857 Jump joAdd32(Imm32 imm, RegisterID dest)
1858 {
1859 add32(imm, dest);
1860 return Jump(m_assembler.jo());
1861 }
1862
1863 Jump joMul32(RegisterID src, RegisterID dest)
1864 {
1865 mul32(src, dest);
1866 return Jump(m_assembler.jo());
1867 }
1868
1869 Jump joMul32(Imm32 imm, RegisterID src, RegisterID dest)
1870 {
1871 mul32(imm, src, dest);
1872 return Jump(m_assembler.jo());
1873 }
1874
1875 Jump joSub32(RegisterID src, RegisterID dest)
1876 {
1877 sub32(src, dest);
1878 return Jump(m_assembler.jo());
1879 }
1880
1881 Jump joSub32(Imm32 imm, RegisterID dest)
1882 {
1883 sub32(imm, dest);
1884 return Jump(m_assembler.jo());
1885 }
1886
1887 Jump jzSubPtr(Imm32 imm, RegisterID dest)
1888 {
1889 subPtr(imm, dest);
1890 return Jump(m_assembler.je());
1891 }
1892
1893 Jump jzSub32(Imm32 imm, RegisterID dest)
1894 {
1895 sub32(imm, dest);
1896 return Jump(m_assembler.je());
1897 }
1898
1899
1900 // Miscellaneous operations:
1901
1902 void breakpoint()
1903 {
1904 m_assembler.int3();
1905 }
1906
1907 Jump call()
1908 {
1909 return Jump(m_assembler.call());
1910 }
1911
1912 // FIXME: why does this return a Jump object? - it can't be linked.
1913 // This may be to get a reference to the return address of the call.
1914 //
1915 // This should probably be handled by a separate label type to a regular
1916 // jump. Todo: add a CallLabel type, for the regular call - can be linked
1917 // like a jump (possibly a subclass of jump?, or possibly casts to a Jump).
1918 // Also add a CallReturnLabel type for this to return (just a more JmpDsty
1919 // form of label, can get the void* after the code has been linked, but can't
1920 // try to link it like a Jump object), and let the CallLabel be cast into a
1921 // CallReturnLabel.
1922 Jump call(RegisterID target)
1923 {
1924 return Jump(m_assembler.call(target));
1925 }
1926
1927 Label label()
1928 {
1929 return Label(this);
1930 }
1931
1932 Label align()
1933 {
1934 m_assembler.align(16);
1935 return Label(this);
1936 }
1937
1938 ptrdiff_t differenceBetween(Label from, Jump to)
1939 {
1940 return X86Assembler::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
1941 }
1942
1943 ptrdiff_t differenceBetween(Label from, Label to)
1944 {
1945 return X86Assembler::getDifferenceBetweenLabels(from.m_label, to.m_label);
1946 }
1947
1948 ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
1949 {
1950 return X86Assembler::getDifferenceBetweenLabels(from.m_label, to.m_label);
1951 }
1952
1953 ptrdiff_t differenceBetween(Label from, DataLabel32 to)
1954 {
1955 return X86Assembler::getDifferenceBetweenLabels(from.m_label, to.m_label);
1956 }
1957
1958 ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
1959 {
1960 return X86Assembler::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
1961 }
1962
1963 void ret()
1964 {
1965 m_assembler.ret();
1966 }
1967
1968 void sete32(RegisterID src, RegisterID srcDest)
1969 {
1970 m_assembler.cmpl_rr(srcDest, src);
1971 m_assembler.sete_r(srcDest);
1972 m_assembler.movzbl_rr(srcDest, srcDest);
1973 }
1974
1975 void sete32(Imm32 imm, RegisterID srcDest)
1976 {
1977 compareImm32ForBranchEquality(srcDest, imm.m_value);
1978 m_assembler.sete_r(srcDest);
1979 m_assembler.movzbl_rr(srcDest, srcDest);
1980 }
1981
1982 void setne32(RegisterID src, RegisterID srcDest)
1983 {
1984 m_assembler.cmpl_rr(srcDest, src);
1985 m_assembler.setne_r(srcDest);
1986 m_assembler.movzbl_rr(srcDest, srcDest);
1987 }
1988
1989 void setne32(Imm32 imm, RegisterID srcDest)
1990 {
1991 compareImm32ForBranchEquality(srcDest, imm.m_value);
1992 m_assembler.setne_r(srcDest);
1993 m_assembler.movzbl_rr(srcDest, srcDest);
1994 }
1995
1996 // FIXME:
1997 // The mask should be optional... paerhaps the argument order should be
1998 // dest-src, operations always have a dest? ... possibly not true, considering
1999 // asm ops like test, or pseudo ops like pop().
2000 void setnz32(Address address, Imm32 mask, RegisterID dest)
2001 {
2002 testImm32(address, mask);
2003 m_assembler.setnz_r(dest);
2004 m_assembler.movzbl_rr(dest, dest);
2005 }
2006
2007 void setz32(Address address, Imm32 mask, RegisterID dest)
2008 {
2009 testImm32(address, mask);
2010 m_assembler.setz_r(dest);
2011 m_assembler.movzbl_rr(dest, dest);
2012 }
2013};
2014
2015} // namespace JSC
2016
2017#endif // ENABLE(ASSEMBLER)
2018
2019#endif // MacroAssembler_h