DFG should inline Array.push and Array.pop
[WebKit-https.git] / 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(const 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     void storePtr(TrustedImmPtr imm, BaseIndex address)
302     {
303         move(imm, scratchRegister);
304         m_assembler.movq_rm(scratchRegister, address.offset, address.base, address.index, address.scale);
305     }
306     
307     DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
308     {
309         m_assembler.movq_rm_disp32(src, address.offset, address.base);
310         return DataLabel32(this);
311     }
312
313     void movePtrToDouble(RegisterID src, FPRegisterID dest)
314     {
315         m_assembler.movq_rr(src, dest);
316     }
317
318     void moveDoubleToPtr(FPRegisterID src, RegisterID dest)
319     {
320         m_assembler.movq_rr(src, dest);
321     }
322
323     void comparePtr(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
324     {
325         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
326             m_assembler.testq_rr(left, left);
327         else
328             m_assembler.cmpq_ir(right.m_value, left);
329         m_assembler.setCC_r(x86Condition(cond), dest);
330         m_assembler.movzbl_rr(dest, dest);
331     }
332     
333     Jump branchAdd32(ResultCondition cond, TrustedImm32 src, AbsoluteAddress dest)
334     {
335         move(TrustedImmPtr(dest.m_ptr), scratchRegister);
336         add32(src, Address(scratchRegister));
337         return Jump(m_assembler.jCC(x86Condition(cond)));
338     }
339
340     Jump branchPtr(RelationalCondition cond, RegisterID left, RegisterID right)
341     {
342         m_assembler.cmpq_rr(right, left);
343         return Jump(m_assembler.jCC(x86Condition(cond)));
344     }
345
346     Jump branchPtr(RelationalCondition cond, RegisterID left, TrustedImmPtr right)
347     {
348         move(right, scratchRegister);
349         return branchPtr(cond, left, scratchRegister);
350     }
351
352     Jump branchPtr(RelationalCondition cond, RegisterID left, Address right)
353     {
354         m_assembler.cmpq_mr(right.offset, right.base, left);
355         return Jump(m_assembler.jCC(x86Condition(cond)));
356     }
357
358     Jump branchPtr(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
359     {
360         move(TrustedImmPtr(left.m_ptr), scratchRegister);
361         return branchPtr(cond, Address(scratchRegister), right);
362     }
363
364     Jump branchPtr(RelationalCondition cond, Address left, RegisterID right)
365     {
366         m_assembler.cmpq_rm(right, left.offset, left.base);
367         return Jump(m_assembler.jCC(x86Condition(cond)));
368     }
369
370     Jump branchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
371     {
372         move(right, scratchRegister);
373         return branchPtr(cond, left, scratchRegister);
374     }
375
376     Jump branchTestPtr(ResultCondition cond, RegisterID reg, RegisterID mask)
377     {
378         m_assembler.testq_rr(reg, mask);
379         return Jump(m_assembler.jCC(x86Condition(cond)));
380     }
381
382     Jump branchTestPtr(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
383     {
384         // if we are only interested in the low seven bits, this can be tested with a testb
385         if (mask.m_value == -1)
386             m_assembler.testq_rr(reg, reg);
387         else if ((mask.m_value & ~0x7f) == 0)
388             m_assembler.testb_i8r(mask.m_value, reg);
389         else
390             m_assembler.testq_i32r(mask.m_value, reg);
391         return Jump(m_assembler.jCC(x86Condition(cond)));
392     }
393
394     Jump branchTestPtr(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
395     {
396         loadPtr(address.m_ptr, scratchRegister);
397         return branchTestPtr(cond, scratchRegister, mask);
398     }
399
400     Jump branchTestPtr(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
401     {
402         if (mask.m_value == -1)
403             m_assembler.cmpq_im(0, address.offset, address.base);
404         else
405             m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
406         return Jump(m_assembler.jCC(x86Condition(cond)));
407     }
408
409     Jump branchTestPtr(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
410     {
411         if (mask.m_value == -1)
412             m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
413         else
414             m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
415         return Jump(m_assembler.jCC(x86Condition(cond)));
416     }
417
418
419     Jump branchAddPtr(ResultCondition cond, RegisterID src, RegisterID dest)
420     {
421         addPtr(src, dest);
422         return Jump(m_assembler.jCC(x86Condition(cond)));
423     }
424
425     Jump branchSubPtr(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
426     {
427         subPtr(imm, dest);
428         return Jump(m_assembler.jCC(x86Condition(cond)));
429     }
430
431     DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
432     {
433         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
434         return DataLabelPtr(this);
435     }
436
437     Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
438     {
439         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
440         return branchPtr(cond, left, scratchRegister);
441     }
442
443     Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
444     {
445         dataLabel = moveWithPatch(initialRightValue, scratchRegister);
446         return branchPtr(cond, left, scratchRegister);
447     }
448
449     DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
450     {
451         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
452         storePtr(scratchRegister, address);
453         return label;
454     }
455
456     using MacroAssemblerX86Common::branchTest8;
457     Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
458     {
459         TrustedImmPtr addr(reinterpret_cast<void*>(address.offset));
460         MacroAssemblerX86Common::move(addr, scratchRegister);
461         return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
462     }
463
464     bool supportsFloatingPoint() const { return true; }
465     // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
466     bool supportsFloatingPointTruncate() const { return true; }
467     bool supportsFloatingPointSqrt() const { return true; }
468     bool supportsDoubleBitops() const { return true; }
469
470 private:
471     friend class LinkBuffer;
472     friend class RepatchBuffer;
473
474     static void linkCall(void* code, Call call, FunctionPtr function)
475     {
476         if (!call.isFlagSet(Call::Near))
477             X86Assembler::linkPointer(code, call.m_label.labelAtOffset(-REPTACH_OFFSET_CALL_R11), function.value());
478         else
479             X86Assembler::linkCall(code, call.m_label, function.value());
480     }
481
482     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
483     {
484         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
485     }
486
487     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
488     {
489         X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
490     }
491
492 };
493
494 } // namespace JSC
495
496 #endif // ENABLE(ASSEMBLER)
497
498 #endif // MacroAssemblerX86_64_h