B3::reduceStrength's DCE should be more agro and less wrong
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerX86_64.h
1 /*
2  * Copyright (C) 2008, 2012, 2014, 2015 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 MacroAssemblerX86_64_h
27 #define MacroAssemblerX86_64_h
28
29 #if ENABLE(ASSEMBLER) && CPU(X86_64)
30
31 #include "MacroAssemblerX86Common.h"
32
33 #define REPATCH_OFFSET_CALL_R11 3
34
35 inline bool CAN_SIGN_EXTEND_32_64(int64_t value) { return value == (int64_t)(int32_t)value; }
36
37 namespace JSC {
38
39 class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
40 public:
41     static const Scale ScalePtr = TimesEight;
42
43     using MacroAssemblerX86Common::add32;
44     using MacroAssemblerX86Common::and32;
45     using MacroAssemblerX86Common::branchAdd32;
46     using MacroAssemblerX86Common::or32;
47     using MacroAssemblerX86Common::sub32;
48     using MacroAssemblerX86Common::load8;
49     using MacroAssemblerX86Common::load32;
50     using MacroAssemblerX86Common::store32;
51     using MacroAssemblerX86Common::store8;
52     using MacroAssemblerX86Common::call;
53     using MacroAssemblerX86Common::jump;
54     using MacroAssemblerX86Common::addDouble;
55     using MacroAssemblerX86Common::loadDouble;
56     using MacroAssemblerX86Common::convertInt32ToDouble;
57
58     void add32(TrustedImm32 imm, AbsoluteAddress address)
59     {
60         move(TrustedImmPtr(address.m_ptr), scratchRegister);
61         add32(imm, Address(scratchRegister));
62     }
63     
64     void and32(TrustedImm32 imm, AbsoluteAddress address)
65     {
66         move(TrustedImmPtr(address.m_ptr), scratchRegister);
67         and32(imm, Address(scratchRegister));
68     }
69     
70     void add32(AbsoluteAddress address, RegisterID dest)
71     {
72         move(TrustedImmPtr(address.m_ptr), scratchRegister);
73         add32(Address(scratchRegister), dest);
74     }
75     
76     void or32(TrustedImm32 imm, AbsoluteAddress address)
77     {
78         move(TrustedImmPtr(address.m_ptr), scratchRegister);
79         or32(imm, Address(scratchRegister));
80     }
81
82     void or32(RegisterID reg, AbsoluteAddress address)
83     {
84         move(TrustedImmPtr(address.m_ptr), scratchRegister);
85         or32(reg, Address(scratchRegister));
86     }
87
88     void sub32(TrustedImm32 imm, AbsoluteAddress address)
89     {
90         move(TrustedImmPtr(address.m_ptr), scratchRegister);
91         sub32(imm, Address(scratchRegister));
92     }
93     
94     void load8(const void* address, RegisterID dest)
95     {
96         move(TrustedImmPtr(address), dest);
97         load8(dest, dest);
98     }
99
100     void load32(const void* address, RegisterID dest)
101     {
102         if (dest == X86Registers::eax)
103             m_assembler.movl_mEAX(address);
104         else {
105             move(TrustedImmPtr(address), dest);
106             load32(dest, dest);
107         }
108     }
109
110     void addDouble(AbsoluteAddress address, FPRegisterID dest)
111     {
112         move(TrustedImmPtr(address.m_ptr), scratchRegister);
113         m_assembler.addsd_mr(0, scratchRegister, dest);
114     }
115
116     void convertInt32ToDouble(TrustedImm32 imm, FPRegisterID dest)
117     {
118         move(imm, scratchRegister);
119         m_assembler.cvtsi2sd_rr(scratchRegister, dest);
120     }
121
122     void store32(TrustedImm32 imm, void* address)
123     {
124         move(TrustedImmPtr(address), scratchRegister);
125         store32(imm, scratchRegister);
126     }
127
128     void store32(RegisterID source, void* address)
129     {
130         if (source == X86Registers::eax)
131             m_assembler.movl_EAXm(address);
132         else {
133             move(TrustedImmPtr(address), scratchRegister);
134             store32(source, scratchRegister);
135         }
136     }
137     
138     void store8(TrustedImm32 imm, void* address)
139     {
140         move(TrustedImmPtr(address), scratchRegister);
141         store8(imm, Address(scratchRegister));
142     }
143
144     void store8(RegisterID reg, void* address)
145     {
146         move(TrustedImmPtr(address), scratchRegister);
147         store8(reg, Address(scratchRegister));
148     }
149
150 #if OS(WINDOWS)
151     Call callWithSlowPathReturnType()
152     {
153         // On Win64, when the return type is larger than 8 bytes, we need to allocate space on the stack for the return value.
154         // On entry, rcx should contain a pointer to this stack space. The other parameters are shifted to the right,
155         // rdx should contain the first argument, r8 should contain the second argument, and r9 should contain the third argument.
156         // On return, rax contains a pointer to this stack value. See http://msdn.microsoft.com/en-us/library/7572ztz4.aspx.
157         // We then need to copy the 16 byte return value into rax and rdx, since JIT expects the return value to be split between the two.
158         // It is assumed that the parameters are already shifted to the right, when entering this method.
159         // Note: this implementation supports up to 3 parameters.
160
161         // JIT relies on the CallerFrame (frame pointer) being put on the stack,
162         // On Win64 we need to manually copy the frame pointer to the stack, since MSVC may not maintain a frame pointer on 64-bit.
163         // See http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx where it's stated that rbp MAY be used as a frame pointer.
164         store64(X86Registers::ebp, Address(X86Registers::esp, -16));
165
166         // We also need to allocate the shadow space on the stack for the 4 parameter registers.
167         // In addition, we need to allocate 16 bytes for the return value.
168         // Also, we should allocate 16 bytes for the frame pointer, and return address (not populated).
169         sub64(TrustedImm32(8 * sizeof(int64_t)), X86Registers::esp);
170
171         // The first parameter register should contain a pointer to the stack allocated space for the return value.
172         move(X86Registers::esp, X86Registers::ecx);
173         add64(TrustedImm32(4 * sizeof(int64_t)), X86Registers::ecx);
174
175         DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
176         Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
177
178         add64(TrustedImm32(8 * sizeof(int64_t)), X86Registers::esp);
179
180         // Copy the return value into rax and rdx.
181         load64(Address(X86Registers::eax, sizeof(int64_t)), X86Registers::edx);
182         load64(Address(X86Registers::eax), X86Registers::eax);
183
184         ASSERT_UNUSED(label, differenceBetween(label, result) == REPATCH_OFFSET_CALL_R11);
185         return result;
186     }
187 #endif
188
189     Call call()
190     {
191 #if OS(WINDOWS)
192         // JIT relies on the CallerFrame (frame pointer) being put on the stack,
193         // On Win64 we need to manually copy the frame pointer to the stack, since MSVC may not maintain a frame pointer on 64-bit.
194         // See http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx where it's stated that rbp MAY be used as a frame pointer.
195         store64(X86Registers::ebp, Address(X86Registers::esp, -16));
196
197         // On Windows we need to copy the arguments that don't fit in registers to the stack location where the callee expects to find them.
198         // We don't know the number of arguments at this point, so the arguments (5, 6, ...) should always be copied.
199
200         // Copy argument 5
201         load64(Address(X86Registers::esp, 4 * sizeof(int64_t)), scratchRegister);
202         store64(scratchRegister, Address(X86Registers::esp, -4 * static_cast<int32_t>(sizeof(int64_t))));
203
204         // Copy argument 6
205         load64(Address(X86Registers::esp, 5 * sizeof(int64_t)), scratchRegister);
206         store64(scratchRegister, Address(X86Registers::esp, -3 * static_cast<int32_t>(sizeof(int64_t))));
207
208         // We also need to allocate the shadow space on the stack for the 4 parameter registers.
209         // Also, we should allocate 16 bytes for the frame pointer, and return address (not populated).
210         // In addition, we need to allocate 16 bytes for two more parameters, since the call can have up to 6 parameters.
211         sub64(TrustedImm32(8 * sizeof(int64_t)), X86Registers::esp);
212 #endif
213         DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
214         Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
215 #if OS(WINDOWS)
216         add64(TrustedImm32(8 * sizeof(int64_t)), X86Registers::esp);
217 #endif
218         ASSERT_UNUSED(label, differenceBetween(label, result) == REPATCH_OFFSET_CALL_R11);
219         return result;
220     }
221
222     // Address is a memory location containing the address to jump to
223     void jump(AbsoluteAddress address)
224     {
225         move(TrustedImmPtr(address.m_ptr), scratchRegister);
226         jump(Address(scratchRegister));
227     }
228
229     Call tailRecursiveCall()
230     {
231         DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
232         Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
233         ASSERT_UNUSED(label, differenceBetween(label, newJump) == REPATCH_OFFSET_CALL_R11);
234         return Call::fromTailJump(newJump);
235     }
236
237     Call makeTailRecursiveCall(Jump oldJump)
238     {
239         oldJump.link(this);
240         DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
241         Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
242         ASSERT_UNUSED(label, differenceBetween(label, newJump) == REPATCH_OFFSET_CALL_R11);
243         return Call::fromTailJump(newJump);
244     }
245
246     Jump branchAdd32(ResultCondition cond, TrustedImm32 src, AbsoluteAddress dest)
247     {
248         move(TrustedImmPtr(dest.m_ptr), scratchRegister);
249         add32(src, Address(scratchRegister));
250         return Jump(m_assembler.jCC(x86Condition(cond)));
251     }
252
253     void add64(RegisterID src, RegisterID dest)
254     {
255         m_assembler.addq_rr(src, dest);
256     }
257     
258     void add64(Address src, RegisterID dest)
259     {
260         m_assembler.addq_mr(src.offset, src.base, dest);
261     }
262
263     void add64(AbsoluteAddress src, RegisterID dest)
264     {
265         move(TrustedImmPtr(src.m_ptr), scratchRegister);
266         add64(Address(scratchRegister), dest);
267     }
268
269     void add64(TrustedImm32 imm, RegisterID srcDest)
270     {
271         if (imm.m_value == 1)
272             m_assembler.incq_r(srcDest);
273         else
274             m_assembler.addq_ir(imm.m_value, srcDest);
275     }
276
277     void add64(TrustedImm64 imm, RegisterID dest)
278     {
279         if (imm.m_value == 1)
280             m_assembler.incq_r(dest);
281         else {
282             move(imm, scratchRegister);
283             add64(scratchRegister, dest);
284         }
285     }
286
287     void add64(TrustedImm32 imm, RegisterID src, RegisterID dest)
288     {
289         m_assembler.leaq_mr(imm.m_value, src, dest);
290     }
291
292     void add64(TrustedImm32 imm, Address address)
293     {
294         if (imm.m_value == 1)
295             m_assembler.incq_m(address.offset, address.base);
296         else
297             m_assembler.addq_im(imm.m_value, address.offset, address.base);
298     }
299
300     void add64(TrustedImm32 imm, AbsoluteAddress address)
301     {
302         move(TrustedImmPtr(address.m_ptr), scratchRegister);
303         add64(imm, Address(scratchRegister));
304     }
305
306     void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
307     {
308         m_assembler.leaq_mr(imm.m_value, srcDest, srcDest);
309     }
310
311     void and64(RegisterID src, RegisterID dest)
312     {
313         m_assembler.andq_rr(src, dest);
314     }
315
316     void and64(TrustedImm32 imm, RegisterID srcDest)
317     {
318         m_assembler.andq_ir(imm.m_value, srcDest);
319     }
320
321     void and64(TrustedImmPtr imm, RegisterID srcDest)
322     {
323         move(imm, scratchRegister);
324         and64(scratchRegister, srcDest);
325     }
326
327     void lshift64(TrustedImm32 imm, RegisterID dest)
328     {
329         m_assembler.shlq_i8r(imm.m_value, dest);
330     }
331     
332     void lshift64(RegisterID src, RegisterID dest)
333     {
334         ASSERT(src != dest);
335         
336         if (src == X86Registers::ecx)
337             m_assembler.shlq_CLr(dest);
338         else {
339             // Can only shift by ecx, so we do some swapping if we see anything else.
340             swap(src, X86Registers::ecx);
341             m_assembler.shlq_CLr(dest);
342             swap(src, X86Registers::ecx);
343         }
344     }
345     
346     void rshift64(TrustedImm32 imm, RegisterID dest)
347     {
348         m_assembler.sarq_i8r(imm.m_value, dest);
349     }
350     
351     void urshift64(TrustedImm32 imm, RegisterID dest)
352     {
353         m_assembler.shrq_i8r(imm.m_value, dest);
354     }
355     
356     void mul64(RegisterID src, RegisterID dest)
357     {
358         m_assembler.imulq_rr(src, dest);
359     }
360     
361     void neg64(RegisterID dest)
362     {
363         m_assembler.negq_r(dest);
364     }
365
366     void or64(RegisterID src, RegisterID dest)
367     {
368         m_assembler.orq_rr(src, dest);
369     }
370
371     void or64(TrustedImm64 imm, RegisterID dest)
372     {
373         move(imm, scratchRegister);
374         or64(scratchRegister, dest);
375     }
376
377     void or64(TrustedImm32 imm, RegisterID dest)
378     {
379         m_assembler.orq_ir(imm.m_value, dest);
380     }
381
382     void or64(RegisterID op1, RegisterID op2, RegisterID dest)
383     {
384         if (op1 == op2)
385             move(op1, dest);
386         else if (op1 == dest)
387             or64(op2, dest);
388         else {
389             move(op2, dest);
390             or64(op1, dest);
391         }
392     }
393
394     void or64(TrustedImm32 imm, RegisterID src, RegisterID dest)
395     {
396         move(src, dest);
397         or64(imm, dest);
398     }
399     
400     void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
401     {
402         m_assembler.rorq_i8r(imm.m_value, srcDst);
403     }
404
405     void sub64(RegisterID src, RegisterID dest)
406     {
407         m_assembler.subq_rr(src, dest);
408     }
409     
410     void sub64(TrustedImm32 imm, RegisterID dest)
411     {
412         if (imm.m_value == 1)
413             m_assembler.decq_r(dest);
414         else
415             m_assembler.subq_ir(imm.m_value, dest);
416     }
417     
418     void sub64(TrustedImm64 imm, RegisterID dest)
419     {
420         if (imm.m_value == 1)
421             m_assembler.decq_r(dest);
422         else {
423             move(imm, scratchRegister);
424             sub64(scratchRegister, dest);
425         }
426     }
427
428     void xor64(RegisterID src, RegisterID dest)
429     {
430         m_assembler.xorq_rr(src, dest);
431     }
432     
433     void xor64(RegisterID src, Address dest)
434     {
435         m_assembler.xorq_rm(src, dest.offset, dest.base);
436     }
437
438     void xor64(TrustedImm32 imm, RegisterID srcDest)
439     {
440         m_assembler.xorq_ir(imm.m_value, srcDest);
441     }
442
443     void load64(ImplicitAddress address, RegisterID dest)
444     {
445         m_assembler.movq_mr(address.offset, address.base, dest);
446     }
447
448     void load64(BaseIndex address, RegisterID dest)
449     {
450         m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
451     }
452
453     void load64(const void* address, RegisterID dest)
454     {
455         if (dest == X86Registers::eax)
456             m_assembler.movq_mEAX(address);
457         else {
458             move(TrustedImmPtr(address), dest);
459             load64(dest, dest);
460         }
461     }
462
463     DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID dest)
464     {
465         padBeforePatch();
466         m_assembler.movq_mr_disp32(address.offset, address.base, dest);
467         return DataLabel32(this);
468     }
469     
470     DataLabelCompact load64WithCompactAddressOffsetPatch(Address address, RegisterID dest)
471     {
472         padBeforePatch();
473         m_assembler.movq_mr_disp8(address.offset, address.base, dest);
474         return DataLabelCompact(this);
475     }
476
477     void store64(RegisterID src, ImplicitAddress address)
478     {
479         m_assembler.movq_rm(src, address.offset, address.base);
480     }
481
482     void store64(RegisterID src, BaseIndex address)
483     {
484         m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
485     }
486     
487     void store64(RegisterID src, void* address)
488     {
489         if (src == X86Registers::eax)
490             m_assembler.movq_EAXm(address);
491         else {
492             move(TrustedImmPtr(address), scratchRegister);
493             store64(src, scratchRegister);
494         }
495     }
496
497     void store64(TrustedImm32 imm, ImplicitAddress address)
498     {
499         m_assembler.movq_i32m(imm.m_value, address.offset, address.base);
500     }
501
502     void store64(TrustedImm64 imm, ImplicitAddress address)
503     {
504         if (CAN_SIGN_EXTEND_32_64(imm.m_value)) {
505             store64(TrustedImm32(static_cast<int32_t>(imm.m_value)), address);
506             return;
507         }
508
509         move(imm, scratchRegister);
510         store64(scratchRegister, address);
511     }
512
513     void store64(TrustedImm64 imm, BaseIndex address)
514     {
515         move(imm, scratchRegister);
516         m_assembler.movq_rm(scratchRegister, address.offset, address.base, address.index, address.scale);
517     }
518     
519     DataLabel32 store64WithAddressOffsetPatch(RegisterID src, Address address)
520     {
521         padBeforePatch();
522         m_assembler.movq_rm_disp32(src, address.offset, address.base);
523         return DataLabel32(this);
524     }
525
526     void move64ToDouble(RegisterID src, FPRegisterID dest)
527     {
528         m_assembler.movq_rr(src, dest);
529     }
530
531     void moveDoubleTo64(FPRegisterID src, RegisterID dest)
532     {
533         m_assembler.movq_rr(src, dest);
534     }
535
536     void compare64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
537     {
538         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
539             m_assembler.testq_rr(left, left);
540         else
541             m_assembler.cmpq_ir(right.m_value, left);
542         m_assembler.setCC_r(x86Condition(cond), dest);
543         m_assembler.movzbl_rr(dest, dest);
544     }
545     
546     void compare64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
547     {
548         m_assembler.cmpq_rr(right, left);
549         m_assembler.setCC_r(x86Condition(cond), dest);
550         m_assembler.movzbl_rr(dest, dest);
551     }
552     
553     Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right)
554     {
555         m_assembler.cmpq_rr(right, left);
556         return Jump(m_assembler.jCC(x86Condition(cond)));
557     }
558
559     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
560     {
561         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) {
562             m_assembler.testq_rr(left, left);
563             return Jump(m_assembler.jCC(x86Condition(cond)));
564         }
565         move(right, scratchRegister);
566         return branch64(cond, left, scratchRegister);
567     }
568
569     Jump branch64(RelationalCondition cond, RegisterID left, Address right)
570     {
571         m_assembler.cmpq_mr(right.offset, right.base, left);
572         return Jump(m_assembler.jCC(x86Condition(cond)));
573     }
574
575     Jump branch64(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
576     {
577         move(TrustedImmPtr(left.m_ptr), scratchRegister);
578         return branch64(cond, Address(scratchRegister), right);
579     }
580
581     Jump branch64(RelationalCondition cond, Address left, RegisterID right)
582     {
583         m_assembler.cmpq_rm(right, left.offset, left.base);
584         return Jump(m_assembler.jCC(x86Condition(cond)));
585     }
586
587     Jump branch64(RelationalCondition cond, Address left, TrustedImm64 right)
588     {
589         move(right, scratchRegister);
590         return branch64(cond, left, scratchRegister);
591     }
592
593     Jump branch64(RelationalCondition cond, BaseIndex address, RegisterID right)
594     {
595         m_assembler.cmpq_rm(right, address.offset, address.base, address.index, address.scale);
596         return Jump(m_assembler.jCC(x86Condition(cond)));
597     }
598
599     Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
600     {
601         return branch64(cond, left, right);
602     }
603
604     Jump branchPtr(RelationalCondition cond, BaseIndex left, TrustedImmPtr right)
605     {
606         move(right, scratchRegister);
607         return branchPtr(cond, left, scratchRegister);
608     }
609
610     Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask)
611     {
612         m_assembler.testq_rr(reg, mask);
613         return Jump(m_assembler.jCC(x86Condition(cond)));
614     }
615     
616     Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
617     {
618         // if we are only interested in the low seven bits, this can be tested with a testb
619         if (mask.m_value == -1)
620             m_assembler.testq_rr(reg, reg);
621         else if ((mask.m_value & ~0x7f) == 0)
622             m_assembler.testb_i8r(mask.m_value, reg);
623         else
624             m_assembler.testq_i32r(mask.m_value, reg);
625         return Jump(m_assembler.jCC(x86Condition(cond)));
626     }
627
628     Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm64 mask)
629     {
630         move(mask, scratchRegister);
631         return branchTest64(cond, reg, scratchRegister);
632     }
633
634     void test64(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
635     {
636         if (mask.m_value == -1)
637             m_assembler.testq_rr(reg, reg);
638         else if ((mask.m_value & ~0x7f) == 0)
639             m_assembler.testb_i8r(mask.m_value, reg);
640         else
641             m_assembler.testq_i32r(mask.m_value, reg);
642         set32(x86Condition(cond), dest);
643     }
644
645     void test64(ResultCondition cond, RegisterID reg, RegisterID mask, RegisterID dest)
646     {
647         m_assembler.testq_rr(reg, mask);
648         set32(x86Condition(cond), dest);
649     }
650
651     Jump branchTest64(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
652     {
653         load64(address.m_ptr, scratchRegister);
654         return branchTest64(cond, scratchRegister, mask);
655     }
656
657     Jump branchTest64(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
658     {
659         if (mask.m_value == -1)
660             m_assembler.cmpq_im(0, address.offset, address.base);
661         else
662             m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
663         return Jump(m_assembler.jCC(x86Condition(cond)));
664     }
665
666     Jump branchTest64(ResultCondition cond, Address address, RegisterID reg)
667     {
668         m_assembler.testq_rm(reg, address.offset, address.base);
669         return Jump(m_assembler.jCC(x86Condition(cond)));
670     }
671
672     Jump branchTest64(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
673     {
674         if (mask.m_value == -1)
675             m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
676         else
677             m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
678         return Jump(m_assembler.jCC(x86Condition(cond)));
679     }
680
681
682     Jump branchAdd64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
683     {
684         add64(imm, dest);
685         return Jump(m_assembler.jCC(x86Condition(cond)));
686     }
687
688     Jump branchAdd64(ResultCondition cond, RegisterID src, RegisterID dest)
689     {
690         add64(src, dest);
691         return Jump(m_assembler.jCC(x86Condition(cond)));
692     }
693
694     Jump branchMul64(ResultCondition cond, RegisterID src, RegisterID dest)
695     {
696         mul64(src, dest);
697         if (cond != Overflow)
698             m_assembler.testq_rr(dest, dest);
699         return Jump(m_assembler.jCC(x86Condition(cond)));
700     }
701
702     Jump branchSub64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
703     {
704         sub64(imm, dest);
705         return Jump(m_assembler.jCC(x86Condition(cond)));
706     }
707
708     Jump branchSub64(ResultCondition cond, RegisterID src, RegisterID dest)
709     {
710         sub64(src, dest);
711         return Jump(m_assembler.jCC(x86Condition(cond)));
712     }
713
714     Jump branchSub64(ResultCondition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
715     {
716         move(src1, dest);
717         return branchSub64(cond, src2, dest);
718     }
719
720     Jump branchNeg64(ResultCondition cond, RegisterID srcDest)
721     {
722         neg64(srcDest);
723         return Jump(m_assembler.jCC(x86Condition(cond)));
724     }
725
726     void abortWithReason(AbortReason reason)
727     {
728         move(TrustedImm32(reason), X86Registers::r11);
729         breakpoint();
730     }
731
732     void abortWithReason(AbortReason reason, intptr_t misc)
733     {
734         move(TrustedImm64(misc), X86Registers::r10);
735         abortWithReason(reason);
736     }
737
738     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
739     {
740         ConvertibleLoadLabel result = ConvertibleLoadLabel(this);
741         m_assembler.movq_mr(address.offset, address.base, dest);
742         return result;
743     }
744
745     DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
746     {
747         padBeforePatch();
748         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
749         return DataLabelPtr(this);
750     }
751
752     DataLabelPtr moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
753     {
754         padBeforePatch();
755         m_assembler.movq_i64r(initialValue.m_value, dest);
756         return DataLabelPtr(this);
757     }
758
759     Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
760     {
761         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
762         return branch64(cond, left, scratchRegister);
763     }
764
765     Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
766     {
767         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
768         return branch64(cond, left, scratchRegister);
769     }
770
771     Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
772     {
773         padBeforePatch();
774         m_assembler.movl_i32r(initialRightValue.m_value, scratchRegister);
775         dataLabel = DataLabel32(this);
776         return branch32(cond, left, scratchRegister);
777     }
778
779     DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
780     {
781         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
782         store64(scratchRegister, address);
783         return label;
784     }
785
786     PatchableJump patchableBranch64(RelationalCondition cond, RegisterID reg, TrustedImm64 imm)
787     {
788         return PatchableJump(branch64(cond, reg, imm));
789     }
790
791     PatchableJump patchableBranch64(RelationalCondition cond, RegisterID left, RegisterID right)
792     {
793         return PatchableJump(branch64(cond, left, right));
794     }
795     
796     using MacroAssemblerX86Common::branch8;
797     Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
798     {
799         MacroAssemblerX86Common::move(TrustedImmPtr(left.m_ptr), scratchRegister);
800         return MacroAssemblerX86Common::branch8(cond, Address(scratchRegister), right);
801     }
802     
803     using MacroAssemblerX86Common::branchTest8;
804     Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
805     {
806         TrustedImmPtr addr(reinterpret_cast<void*>(address.offset));
807         MacroAssemblerX86Common::move(addr, scratchRegister);
808         return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
809     }
810     
811     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
812     {
813         MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister);
814         return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister), mask);
815     }
816
817     void convertInt64ToDouble(RegisterID src, FPRegisterID dest)
818     {
819         m_assembler.cvtsi2sdq_rr(src, dest);
820     }
821
822     static bool supportsFloatingPoint() { return true; }
823     static bool supportsFloatingPointTruncate() { return true; }
824     static bool supportsFloatingPointSqrt() { return true; }
825     static bool supportsFloatingPointAbs() { return true; }
826     
827     static FunctionPtr readCallTarget(CodeLocationCall call)
828     {
829         return FunctionPtr(X86Assembler::readPointer(call.dataLabelPtrAtOffset(-REPATCH_OFFSET_CALL_R11).dataLocation()));
830     }
831
832     static bool haveScratchRegisterForBlinding() { return true; }
833     static RegisterID scratchRegisterForBlinding() { return scratchRegister; }
834
835     static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
836     static bool canJumpReplacePatchableBranch32WithPatch() { return true; }
837     
838     static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
839     {
840         const int rexBytes = 1;
841         const int opcodeBytes = 1;
842         const int immediateBytes = 8;
843         const int totalBytes = rexBytes + opcodeBytes + immediateBytes;
844         ASSERT(totalBytes >= maxJumpReplacementSize());
845         return label.labelAtOffset(-totalBytes);
846     }
847     
848     static CodeLocationLabel startOfBranch32WithPatchOnRegister(CodeLocationDataLabel32 label)
849     {
850         const int rexBytes = 1;
851         const int opcodeBytes = 1;
852         const int immediateBytes = 4;
853         const int totalBytes = rexBytes + opcodeBytes + immediateBytes;
854         ASSERT(totalBytes >= maxJumpReplacementSize());
855         return label.labelAtOffset(-totalBytes);
856     }
857     
858     static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label)
859     {
860         return startOfBranchPtrWithPatchOnRegister(label);
861     }
862
863     static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32 label)
864     {
865         return startOfBranch32WithPatchOnRegister(label);
866     }
867     
868     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
869     {
870         X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
871     }
872
873     static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel instructionStart, Address, int32_t initialValue)
874     {
875         X86Assembler::revertJumpTo_movl_i32r(instructionStart.executableAddress(), initialValue, scratchRegister);
876     }
877
878     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
879     {
880         X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
881     }
882
883     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
884     {
885         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPATCH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
886     }
887
888     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
889     {
890         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPATCH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
891     }
892
893 private:
894     friend class LinkBuffer;
895
896     static void linkCall(void* code, Call call, FunctionPtr function)
897     {
898         if (!call.isFlagSet(Call::Near))
899             X86Assembler::linkPointer(code, call.m_label.labelAtOffset(-REPATCH_OFFSET_CALL_R11), function.value());
900         else if (call.isFlagSet(Call::Tail))
901             X86Assembler::linkJump(code, call.m_label, function.value());
902         else
903             X86Assembler::linkCall(code, call.m_label, function.value());
904     }
905 };
906
907 } // namespace JSC
908
909 #endif // ENABLE(ASSEMBLER)
910
911 #endif // MacroAssemblerX86_64_h