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 MacroAssemblerX86_64_h
27 #define MacroAssemblerX86_64_h
28 
29 #include <wtf/Platform.h>
30 
31 #if ENABLE(ASSEMBLER) && CPU(X86_64)
32 
33 #include "MacroAssemblerX86Common.h"
34 
35 #define REPTACH_OFFSET_CALL_R11 3
36 
37 namespace JSC {
38 
39 class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
40 protected:
41     static const X86Registers::RegisterID scratchRegister = X86Registers::r11;
42 
43 public:
44     static const Scale ScalePtr = TimesEight;
45 
46     using MacroAssemblerX86Common::add32;
47     using MacroAssemblerX86Common::and32;
48     using MacroAssemblerX86Common::or32;
49     using MacroAssemblerX86Common::sub32;
50     using MacroAssemblerX86Common::load32;
51     using MacroAssemblerX86Common::store32;
52     using MacroAssemblerX86Common::call;
53     using MacroAssemblerX86Common::loadDouble;
54     using MacroAssemblerX86Common::convertInt32ToDouble;
55 
add32(Imm32 imm,AbsoluteAddress address)56     void add32(Imm32 imm, AbsoluteAddress address)
57     {
58         move(ImmPtr(address.m_ptr), scratchRegister);
59         add32(imm, Address(scratchRegister));
60     }
61 
and32(Imm32 imm,AbsoluteAddress address)62     void and32(Imm32 imm, AbsoluteAddress address)
63     {
64         move(ImmPtr(address.m_ptr), scratchRegister);
65         and32(imm, Address(scratchRegister));
66     }
67 
or32(Imm32 imm,AbsoluteAddress address)68     void or32(Imm32 imm, AbsoluteAddress address)
69     {
70         move(ImmPtr(address.m_ptr), scratchRegister);
71         or32(imm, Address(scratchRegister));
72     }
73 
sub32(Imm32 imm,AbsoluteAddress address)74     void sub32(Imm32 imm, AbsoluteAddress address)
75     {
76         move(ImmPtr(address.m_ptr), scratchRegister);
77         sub32(imm, Address(scratchRegister));
78     }
79 
load32(void * address,RegisterID dest)80     void load32(void* address, RegisterID dest)
81     {
82         if (dest == X86Registers::eax)
83             m_assembler.movl_mEAX(address);
84         else {
85             move(X86Registers::eax, dest);
86             m_assembler.movl_mEAX(address);
87             swap(X86Registers::eax, dest);
88         }
89     }
90 
loadDouble(void * address,FPRegisterID dest)91     void loadDouble(void* address, FPRegisterID dest)
92     {
93         move(ImmPtr(address), scratchRegister);
94         loadDouble(scratchRegister, dest);
95     }
96 
convertInt32ToDouble(AbsoluteAddress src,FPRegisterID dest)97     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
98     {
99         move(Imm32(*static_cast<int32_t*>(src.m_ptr)), scratchRegister);
100         m_assembler.cvtsi2sd_rr(scratchRegister, dest);
101     }
102 
store32(Imm32 imm,void * address)103     void store32(Imm32 imm, void* address)
104     {
105         move(X86Registers::eax, scratchRegister);
106         move(imm, X86Registers::eax);
107         m_assembler.movl_EAXm(address);
108         move(scratchRegister, X86Registers::eax);
109     }
110 
call()111     Call call()
112     {
113         DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
114         Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
115         ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11);
116         return result;
117     }
118 
tailRecursiveCall()119     Call tailRecursiveCall()
120     {
121         DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
122         Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
123         ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
124         return Call::fromTailJump(newJump);
125     }
126 
makeTailRecursiveCall(Jump oldJump)127     Call makeTailRecursiveCall(Jump oldJump)
128     {
129         oldJump.link(this);
130         DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
131         Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
132         ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
133         return Call::fromTailJump(newJump);
134     }
135 
136 
addPtr(RegisterID src,RegisterID dest)137     void addPtr(RegisterID src, RegisterID dest)
138     {
139         m_assembler.addq_rr(src, dest);
140     }
141 
addPtr(Imm32 imm,RegisterID srcDest)142     void addPtr(Imm32 imm, RegisterID srcDest)
143     {
144         m_assembler.addq_ir(imm.m_value, srcDest);
145     }
146 
addPtr(ImmPtr imm,RegisterID dest)147     void addPtr(ImmPtr imm, RegisterID dest)
148     {
149         move(imm, scratchRegister);
150         m_assembler.addq_rr(scratchRegister, dest);
151     }
152 
addPtr(Imm32 imm,RegisterID src,RegisterID dest)153     void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
154     {
155         m_assembler.leaq_mr(imm.m_value, src, dest);
156     }
157 
addPtr(Imm32 imm,Address address)158     void addPtr(Imm32 imm, Address address)
159     {
160         m_assembler.addq_im(imm.m_value, address.offset, address.base);
161     }
162 
addPtr(Imm32 imm,AbsoluteAddress address)163     void addPtr(Imm32 imm, AbsoluteAddress address)
164     {
165         move(ImmPtr(address.m_ptr), scratchRegister);
166         addPtr(imm, Address(scratchRegister));
167     }
168 
andPtr(RegisterID src,RegisterID dest)169     void andPtr(RegisterID src, RegisterID dest)
170     {
171         m_assembler.andq_rr(src, dest);
172     }
173 
andPtr(Imm32 imm,RegisterID srcDest)174     void andPtr(Imm32 imm, RegisterID srcDest)
175     {
176         m_assembler.andq_ir(imm.m_value, srcDest);
177     }
178 
orPtr(RegisterID src,RegisterID dest)179     void orPtr(RegisterID src, RegisterID dest)
180     {
181         m_assembler.orq_rr(src, dest);
182     }
183 
orPtr(ImmPtr imm,RegisterID dest)184     void orPtr(ImmPtr imm, RegisterID dest)
185     {
186         move(imm, scratchRegister);
187         m_assembler.orq_rr(scratchRegister, dest);
188     }
189 
orPtr(Imm32 imm,RegisterID dest)190     void orPtr(Imm32 imm, RegisterID dest)
191     {
192         m_assembler.orq_ir(imm.m_value, dest);
193     }
194 
subPtr(RegisterID src,RegisterID dest)195     void subPtr(RegisterID src, RegisterID dest)
196     {
197         m_assembler.subq_rr(src, dest);
198     }
199 
subPtr(Imm32 imm,RegisterID dest)200     void subPtr(Imm32 imm, RegisterID dest)
201     {
202         m_assembler.subq_ir(imm.m_value, dest);
203     }
204 
subPtr(ImmPtr imm,RegisterID dest)205     void subPtr(ImmPtr imm, RegisterID dest)
206     {
207         move(imm, scratchRegister);
208         m_assembler.subq_rr(scratchRegister, dest);
209     }
210 
xorPtr(RegisterID src,RegisterID dest)211     void xorPtr(RegisterID src, RegisterID dest)
212     {
213         m_assembler.xorq_rr(src, dest);
214     }
215 
xorPtr(Imm32 imm,RegisterID srcDest)216     void xorPtr(Imm32 imm, RegisterID srcDest)
217     {
218         m_assembler.xorq_ir(imm.m_value, srcDest);
219     }
220 
221 
loadPtr(ImplicitAddress address,RegisterID dest)222     void loadPtr(ImplicitAddress address, RegisterID dest)
223     {
224         m_assembler.movq_mr(address.offset, address.base, dest);
225     }
226 
loadPtr(BaseIndex address,RegisterID dest)227     void loadPtr(BaseIndex address, RegisterID dest)
228     {
229         m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
230     }
231 
loadPtr(void * address,RegisterID dest)232     void loadPtr(void* address, RegisterID dest)
233     {
234         if (dest == X86Registers::eax)
235             m_assembler.movq_mEAX(address);
236         else {
237             move(X86Registers::eax, dest);
238             m_assembler.movq_mEAX(address);
239             swap(X86Registers::eax, dest);
240         }
241     }
242 
loadPtrWithAddressOffsetPatch(Address address,RegisterID dest)243     DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
244     {
245         m_assembler.movq_mr_disp32(address.offset, address.base, dest);
246         return DataLabel32(this);
247     }
248 
storePtr(RegisterID src,ImplicitAddress address)249     void storePtr(RegisterID src, ImplicitAddress address)
250     {
251         m_assembler.movq_rm(src, address.offset, address.base);
252     }
253 
storePtr(RegisterID src,BaseIndex address)254     void storePtr(RegisterID src, BaseIndex address)
255     {
256         m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
257     }
258 
storePtr(RegisterID src,void * address)259     void storePtr(RegisterID src, void* address)
260     {
261         if (src == X86Registers::eax)
262             m_assembler.movq_EAXm(address);
263         else {
264             swap(X86Registers::eax, src);
265             m_assembler.movq_EAXm(address);
266             swap(X86Registers::eax, src);
267         }
268     }
269 
storePtr(ImmPtr imm,ImplicitAddress address)270     void storePtr(ImmPtr imm, ImplicitAddress address)
271     {
272         move(imm, scratchRegister);
273         storePtr(scratchRegister, address);
274     }
275 
storePtrWithAddressOffsetPatch(RegisterID src,Address address)276     DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
277     {
278         m_assembler.movq_rm_disp32(src, address.offset, address.base);
279         return DataLabel32(this);
280     }
281 
movePtrToDouble(RegisterID src,FPRegisterID dest)282     void movePtrToDouble(RegisterID src, FPRegisterID dest)
283     {
284         m_assembler.movq_rr(src, dest);
285     }
286 
moveDoubleToPtr(FPRegisterID src,RegisterID dest)287     void moveDoubleToPtr(FPRegisterID src, RegisterID dest)
288     {
289         m_assembler.movq_rr(src, dest);
290     }
291 
setPtr(Condition cond,RegisterID left,Imm32 right,RegisterID dest)292     void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
293     {
294         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
295             m_assembler.testq_rr(left, left);
296         else
297             m_assembler.cmpq_ir(right.m_value, left);
298         m_assembler.setCC_r(x86Condition(cond), dest);
299         m_assembler.movzbl_rr(dest, dest);
300     }
301 
branchPtr(Condition cond,RegisterID left,RegisterID right)302     Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
303     {
304         m_assembler.cmpq_rr(right, left);
305         return Jump(m_assembler.jCC(x86Condition(cond)));
306     }
307 
branchPtr(Condition cond,RegisterID left,ImmPtr right)308     Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
309     {
310         move(right, scratchRegister);
311         return branchPtr(cond, left, scratchRegister);
312     }
313 
branchPtr(Condition cond,RegisterID left,Address right)314     Jump branchPtr(Condition cond, RegisterID left, Address right)
315     {
316         m_assembler.cmpq_mr(right.offset, right.base, left);
317         return Jump(m_assembler.jCC(x86Condition(cond)));
318     }
319 
branchPtr(Condition cond,AbsoluteAddress left,RegisterID right)320     Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
321     {
322         move(ImmPtr(left.m_ptr), scratchRegister);
323         return branchPtr(cond, Address(scratchRegister), right);
324     }
325 
branchPtr(Condition cond,Address left,RegisterID right)326     Jump branchPtr(Condition cond, Address left, RegisterID right)
327     {
328         m_assembler.cmpq_rm(right, left.offset, left.base);
329         return Jump(m_assembler.jCC(x86Condition(cond)));
330     }
331 
branchPtr(Condition cond,Address left,ImmPtr right)332     Jump branchPtr(Condition cond, Address left, ImmPtr right)
333     {
334         move(right, scratchRegister);
335         return branchPtr(cond, left, scratchRegister);
336     }
337 
branchTestPtr(Condition cond,RegisterID reg,RegisterID mask)338     Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
339     {
340         m_assembler.testq_rr(reg, mask);
341         return Jump(m_assembler.jCC(x86Condition(cond)));
342     }
343 
344     Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
345     {
346         // if we are only interested in the low seven bits, this can be tested with a testb
347         if (mask.m_value == -1)
348             m_assembler.testq_rr(reg, reg);
349         else if ((mask.m_value & ~0x7f) == 0)
350             m_assembler.testb_i8r(mask.m_value, reg);
351         else
352             m_assembler.testq_i32r(mask.m_value, reg);
353         return Jump(m_assembler.jCC(x86Condition(cond)));
354     }
355 
356     Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
357     {
358         if (mask.m_value == -1)
359             m_assembler.cmpq_im(0, address.offset, address.base);
360         else
361             m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
362         return Jump(m_assembler.jCC(x86Condition(cond)));
363     }
364 
365     Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
366     {
367         if (mask.m_value == -1)
368             m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
369         else
370             m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
371         return Jump(m_assembler.jCC(x86Condition(cond)));
372     }
373 
374 
branchAddPtr(Condition cond,RegisterID src,RegisterID dest)375     Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
376     {
377         ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
378         addPtr(src, dest);
379         return Jump(m_assembler.jCC(x86Condition(cond)));
380     }
381 
branchSubPtr(Condition cond,Imm32 imm,RegisterID dest)382     Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
383     {
384         ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
385         subPtr(imm, dest);
386         return Jump(m_assembler.jCC(x86Condition(cond)));
387     }
388 
moveWithPatch(ImmPtr initialValue,RegisterID dest)389     DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
390     {
391         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
392         return DataLabelPtr(this);
393     }
394 
395     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
396     {
397         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
398         return branchPtr(cond, left, scratchRegister);
399     }
400 
401     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
402     {
403         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
404         return branchPtr(cond, left, scratchRegister);
405     }
406 
storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)407     DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
408     {
409         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
410         storePtr(scratchRegister, address);
411         return label;
412     }
413 
loadPtrWithPatchToLEA(Address address,RegisterID dest)414     Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
415     {
416         Label label(this);
417         loadPtr(address, dest);
418         return label;
419     }
420 
supportsFloatingPoint()421     bool supportsFloatingPoint() const { return true; }
422     // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
supportsFloatingPointTruncate()423     bool supportsFloatingPointTruncate() const { return true; }
424 
425 private:
426     friend class LinkBuffer;
427     friend class RepatchBuffer;
428 
linkCall(void * code,Call call,FunctionPtr function)429     static void linkCall(void* code, Call call, FunctionPtr function)
430     {
431         if (!call.isFlagSet(Call::Near))
432             X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value());
433         else
434             X86Assembler::linkCall(code, call.m_jmp, function.value());
435     }
436 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)437     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
438     {
439         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
440     }
441 
repatchCall(CodeLocationCall call,FunctionPtr destination)442     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
443     {
444         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
445     }
446 
447 };
448 
449 } // namespace JSC
450 
451 #endif // ENABLE(ASSEMBLER)
452 
453 #endif // MacroAssemblerX86_64_h
454