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