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