• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) && PLATFORM(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 X86::RegisterID scratchRegister = X86::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 == X86::eax)
83             m_assembler.movl_mEAX(address);
84         else {
85             move(X86::eax, dest);
86             m_assembler.movl_mEAX(address);
87             swap(X86::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(X86::eax, scratchRegister);
106         move(imm, X86::eax);
107         m_assembler.movl_EAXm(address);
108         move(scratchRegister, X86::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 
rshiftPtr(RegisterID shift_amount,RegisterID dest)195     void rshiftPtr(RegisterID shift_amount, RegisterID dest)
196     {
197         // On x86 we can only shift by ecx; if asked to shift by another register we'll
198         // need rejig the shift amount into ecx first, and restore the registers afterwards.
199         if (shift_amount != X86::ecx) {
200             swap(shift_amount, X86::ecx);
201 
202             // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
203             if (dest == shift_amount)
204                 m_assembler.sarq_CLr(X86::ecx);
205             // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
206             else if (dest == X86::ecx)
207                 m_assembler.sarq_CLr(shift_amount);
208             // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
209             else
210                 m_assembler.sarq_CLr(dest);
211 
212             swap(shift_amount, X86::ecx);
213         } else
214             m_assembler.sarq_CLr(dest);
215     }
216 
rshiftPtr(Imm32 imm,RegisterID dest)217     void rshiftPtr(Imm32 imm, RegisterID dest)
218     {
219         m_assembler.sarq_i8r(imm.m_value, dest);
220     }
221 
subPtr(RegisterID src,RegisterID dest)222     void subPtr(RegisterID src, RegisterID dest)
223     {
224         m_assembler.subq_rr(src, dest);
225     }
226 
subPtr(Imm32 imm,RegisterID dest)227     void subPtr(Imm32 imm, RegisterID dest)
228     {
229         m_assembler.subq_ir(imm.m_value, dest);
230     }
231 
subPtr(ImmPtr imm,RegisterID dest)232     void subPtr(ImmPtr imm, RegisterID dest)
233     {
234         move(imm, scratchRegister);
235         m_assembler.subq_rr(scratchRegister, dest);
236     }
237 
xorPtr(RegisterID src,RegisterID dest)238     void xorPtr(RegisterID src, RegisterID dest)
239     {
240         m_assembler.xorq_rr(src, dest);
241     }
242 
xorPtr(Imm32 imm,RegisterID srcDest)243     void xorPtr(Imm32 imm, RegisterID srcDest)
244     {
245         m_assembler.xorq_ir(imm.m_value, srcDest);
246     }
247 
248 
loadPtr(ImplicitAddress address,RegisterID dest)249     void loadPtr(ImplicitAddress address, RegisterID dest)
250     {
251         m_assembler.movq_mr(address.offset, address.base, dest);
252     }
253 
loadPtr(BaseIndex address,RegisterID dest)254     void loadPtr(BaseIndex address, RegisterID dest)
255     {
256         m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
257     }
258 
loadPtr(void * address,RegisterID dest)259     void loadPtr(void* address, RegisterID dest)
260     {
261         if (dest == X86::eax)
262             m_assembler.movq_mEAX(address);
263         else {
264             move(X86::eax, dest);
265             m_assembler.movq_mEAX(address);
266             swap(X86::eax, dest);
267         }
268     }
269 
loadPtrWithAddressOffsetPatch(Address address,RegisterID dest)270     DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
271     {
272         m_assembler.movq_mr_disp32(address.offset, address.base, dest);
273         return DataLabel32(this);
274     }
275 
storePtr(RegisterID src,ImplicitAddress address)276     void storePtr(RegisterID src, ImplicitAddress address)
277     {
278         m_assembler.movq_rm(src, address.offset, address.base);
279     }
280 
storePtr(RegisterID src,BaseIndex address)281     void storePtr(RegisterID src, BaseIndex address)
282     {
283         m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
284     }
285 
storePtr(RegisterID src,void * address)286     void storePtr(RegisterID src, void* address)
287     {
288         if (src == X86::eax)
289             m_assembler.movq_EAXm(address);
290         else {
291             swap(X86::eax, src);
292             m_assembler.movq_EAXm(address);
293             swap(X86::eax, src);
294         }
295     }
296 
storePtr(ImmPtr imm,ImplicitAddress address)297     void storePtr(ImmPtr imm, ImplicitAddress address)
298     {
299         intptr_t ptr = imm.asIntptr();
300         if (CAN_SIGN_EXTEND_32_64(ptr))
301             m_assembler.movq_i32m(static_cast<int>(ptr), address.offset, address.base);
302         else {
303             move(imm, scratchRegister);
304             storePtr(scratchRegister, address);
305         }
306     }
307 
storePtrWithAddressOffsetPatch(RegisterID src,Address address)308     DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
309     {
310         m_assembler.movq_rm_disp32(src, address.offset, address.base);
311         return DataLabel32(this);
312     }
313 
movePtrToDouble(RegisterID src,FPRegisterID dest)314     void movePtrToDouble(RegisterID src, FPRegisterID dest)
315     {
316         m_assembler.movq_rr(src, dest);
317     }
318 
moveDoubleToPtr(FPRegisterID src,RegisterID dest)319     void moveDoubleToPtr(FPRegisterID src, RegisterID dest)
320     {
321         m_assembler.movq_rr(src, dest);
322     }
323 
setPtr(Condition cond,RegisterID left,Imm32 right,RegisterID dest)324     void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
325     {
326         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
327             m_assembler.testq_rr(left, left);
328         else
329             m_assembler.cmpq_ir(right.m_value, left);
330         m_assembler.setCC_r(x86Condition(cond), dest);
331         m_assembler.movzbl_rr(dest, dest);
332     }
333 
branchPtr(Condition cond,RegisterID left,RegisterID right)334     Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
335     {
336         m_assembler.cmpq_rr(right, left);
337         return Jump(m_assembler.jCC(x86Condition(cond)));
338     }
339 
branchPtr(Condition cond,RegisterID left,ImmPtr right)340     Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
341     {
342         intptr_t imm = right.asIntptr();
343         if (CAN_SIGN_EXTEND_32_64(imm)) {
344             if (!imm)
345                 m_assembler.testq_rr(left, left);
346             else
347                 m_assembler.cmpq_ir(imm, left);
348             return Jump(m_assembler.jCC(x86Condition(cond)));
349         } else {
350             move(right, scratchRegister);
351             return branchPtr(cond, left, scratchRegister);
352         }
353     }
354 
branchPtr(Condition cond,RegisterID left,Address right)355     Jump branchPtr(Condition cond, RegisterID left, Address right)
356     {
357         m_assembler.cmpq_mr(right.offset, right.base, left);
358         return Jump(m_assembler.jCC(x86Condition(cond)));
359     }
360 
branchPtr(Condition cond,AbsoluteAddress left,RegisterID right)361     Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
362     {
363         move(ImmPtr(left.m_ptr), scratchRegister);
364         return branchPtr(cond, Address(scratchRegister), right);
365     }
366 
branchPtr(Condition cond,Address left,RegisterID right)367     Jump branchPtr(Condition cond, Address left, RegisterID right)
368     {
369         m_assembler.cmpq_rm(right, left.offset, left.base);
370         return Jump(m_assembler.jCC(x86Condition(cond)));
371     }
372 
branchPtr(Condition cond,Address left,ImmPtr right)373     Jump branchPtr(Condition cond, Address left, ImmPtr right)
374     {
375         move(right, scratchRegister);
376         return branchPtr(cond, left, scratchRegister);
377     }
378 
branchTestPtr(Condition cond,RegisterID reg,RegisterID mask)379     Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
380     {
381         m_assembler.testq_rr(reg, mask);
382         return Jump(m_assembler.jCC(x86Condition(cond)));
383     }
384 
385     Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
386     {
387         // if we are only interested in the low seven bits, this can be tested with a testb
388         if (mask.m_value == -1)
389             m_assembler.testq_rr(reg, reg);
390         else if ((mask.m_value & ~0x7f) == 0)
391             m_assembler.testb_i8r(mask.m_value, reg);
392         else
393             m_assembler.testq_i32r(mask.m_value, reg);
394         return Jump(m_assembler.jCC(x86Condition(cond)));
395     }
396 
397     Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
398     {
399         if (mask.m_value == -1)
400             m_assembler.cmpq_im(0, address.offset, address.base);
401         else
402             m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
403         return Jump(m_assembler.jCC(x86Condition(cond)));
404     }
405 
406     Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
407     {
408         if (mask.m_value == -1)
409             m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
410         else
411             m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
412         return Jump(m_assembler.jCC(x86Condition(cond)));
413     }
414 
415 
branchAddPtr(Condition cond,RegisterID src,RegisterID dest)416     Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
417     {
418         ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
419         addPtr(src, dest);
420         return Jump(m_assembler.jCC(x86Condition(cond)));
421     }
422 
branchSubPtr(Condition cond,Imm32 imm,RegisterID dest)423     Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
424     {
425         ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
426         subPtr(imm, dest);
427         return Jump(m_assembler.jCC(x86Condition(cond)));
428     }
429 
moveWithPatch(ImmPtr initialValue,RegisterID dest)430     DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
431     {
432         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
433         return DataLabelPtr(this);
434     }
435 
436     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
437     {
438         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
439         return branchPtr(cond, left, scratchRegister);
440     }
441 
442     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
443     {
444         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
445         return branchPtr(cond, left, scratchRegister);
446     }
447 
storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)448     DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
449     {
450         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
451         storePtr(scratchRegister, address);
452         return label;
453     }
454 
loadPtrWithPatchToLEA(Address address,RegisterID dest)455     Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
456     {
457         Label label(this);
458         loadPtr(address, dest);
459         return label;
460     }
461 
supportsFloatingPoint()462     bool supportsFloatingPoint() const { return true; }
463     // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
supportsFloatingPointTruncate()464     bool supportsFloatingPointTruncate() const { return true; }
465 
466 private:
467     friend class LinkBuffer;
468     friend class RepatchBuffer;
469 
linkCall(void * code,Call call,FunctionPtr function)470     static void linkCall(void* code, Call call, FunctionPtr function)
471     {
472         if (!call.isFlagSet(Call::Near))
473             X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value());
474         else
475             X86Assembler::linkCall(code, call.m_jmp, function.value());
476     }
477 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)478     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
479     {
480         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
481     }
482 
repatchCall(CodeLocationCall call,FunctionPtr destination)483     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
484     {
485         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
486     }
487 
488 };
489 
490 } // namespace JSC
491 
492 #endif // ENABLE(ASSEMBLER)
493 
494 #endif // MacroAssemblerX86_64_h
495