1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
* vim: set ts=8 sw=4 et tw=79:
4
* ***** BEGIN LICENSE BLOCK *****
5
* Copyright (C) 2008 Apple Inc. All rights reserved.
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
16
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
20
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
* ***** END LICENSE BLOCK ***** */
30
#ifndef MacroAssemblerX86_64_h
31
#define MacroAssemblerX86_64_h
33
#include "assembler/wtf/Platform.h"
35
#if ENABLE_ASSEMBLER && WTF_CPU_X86_64
37
#include "MacroAssemblerX86Common.h"
39
#define REPTACH_OFFSET_CALL_R11 3
41
#include "mozilla/Util.h"
45
class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
47
static const intptr_t MinInt32 = 0xFFFFFFFF80000000;
48
static const intptr_t MaxInt32 = 0x000000007FFFFFFF;
51
static const Scale ScalePtr = TimesEight;
52
static const unsigned int TotalRegisters = 16;
54
using MacroAssemblerX86Common::add32;
55
using MacroAssemblerX86Common::and32;
56
using MacroAssemblerX86Common::or32;
57
using MacroAssemblerX86Common::sub32;
58
using MacroAssemblerX86Common::load32;
59
using MacroAssemblerX86Common::store32;
60
using MacroAssemblerX86Common::call;
61
using MacroAssemblerX86Common::loadDouble;
62
using MacroAssemblerX86Common::storeDouble;
63
using MacroAssemblerX86Common::convertInt32ToDouble;
65
void add32(TrustedImm32 imm, AbsoluteAddress address)
67
move(ImmPtr(address.m_ptr), scratchRegister);
68
add32(imm, Address(scratchRegister));
71
void and32(Imm32 imm, AbsoluteAddress address)
73
move(ImmPtr(address.m_ptr), scratchRegister);
74
and32(imm, Address(scratchRegister));
77
void or32(TrustedImm32 imm, AbsoluteAddress address)
79
move(ImmPtr(address.m_ptr), scratchRegister);
80
or32(imm, Address(scratchRegister));
83
void sub32(TrustedImm32 imm, AbsoluteAddress address)
85
move(ImmPtr(address.m_ptr), scratchRegister);
86
sub32(imm, Address(scratchRegister));
89
void load32(void* address, RegisterID dest)
91
if (dest == X86Registers::eax)
92
m_assembler.movl_mEAX(address);
94
move(ImmPtr(address), scratchRegister);
95
load32(ImplicitAddress(scratchRegister), dest);
99
DataLabelPtr loadDouble(const void* address, FPRegisterID dest)
101
DataLabelPtr label = moveWithPatch(ImmPtr(address), scratchRegister);
102
loadDouble(scratchRegister, dest);
106
void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
108
move(Imm32(*static_cast<int32_t*>(src.m_ptr)), scratchRegister);
109
m_assembler.cvtsi2sd_rr(scratchRegister, dest);
112
void convertUInt32ToDouble(RegisterID srcDest, FPRegisterID dest)
114
zeroExtend32ToPtr(srcDest, srcDest);
115
zeroDouble(dest); // break dependency chains
116
m_assembler.cvtsq2sd_rr(srcDest, dest);
119
void store32(TrustedImm32 imm, void* address)
121
move(X86Registers::eax, scratchRegister);
122
move(imm, X86Registers::eax);
123
m_assembler.movl_EAXm(address);
124
move(scratchRegister, X86Registers::eax);
129
js::DebugOnly<DataLabelPtr> label = moveWithPatch(ImmPtr(0), scratchRegister);
130
Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
131
ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11);
135
Call tailRecursiveCall()
137
js::DebugOnly<DataLabelPtr> label = moveWithPatch(ImmPtr(0), scratchRegister);
138
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
139
ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
140
return Call::fromTailJump(newJump);
143
Call makeTailRecursiveCall(Jump oldJump)
146
js::DebugOnly<DataLabelPtr> label = moveWithPatch(ImmPtr(0), scratchRegister);
147
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
148
ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
149
return Call::fromTailJump(newJump);
153
void addPtr(RegisterID src, RegisterID dest)
155
m_assembler.addq_rr(src, dest);
158
void lea(BaseIndex address, RegisterID dest)
160
m_assembler.leaq_mr(address.offset, address.base, address.index, address.scale, dest);
163
void lea(Address address, RegisterID dest)
165
m_assembler.leaq_mr(address.offset, address.base, dest);
168
void addPtr(Imm32 imm, RegisterID srcDest)
170
m_assembler.addq_ir(imm.m_value, srcDest);
173
void addPtr(ImmPtr imm, RegisterID dest)
175
move(imm, scratchRegister);
176
m_assembler.addq_rr(scratchRegister, dest);
179
void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
181
m_assembler.leaq_mr(imm.m_value, src, dest);
184
void addPtr(Imm32 imm, Address address)
186
m_assembler.addq_im(imm.m_value, address.offset, address.base);
189
void addPtr(Imm32 imm, AbsoluteAddress address)
191
move(ImmPtr(address.m_ptr), scratchRegister);
192
addPtr(imm, Address(scratchRegister));
195
void andPtr(RegisterID src, RegisterID dest)
197
m_assembler.andq_rr(src, dest);
200
void andPtr(Address src, RegisterID dest)
202
m_assembler.andq_mr(src.offset, src.base, dest);
205
void andPtr(Imm32 imm, RegisterID srcDest)
207
m_assembler.andq_ir(imm.m_value, srcDest);
210
void andPtr(ImmPtr imm, RegisterID srcDest)
212
intptr_t value = intptr_t(imm.m_value);
214
// 32-bit immediates in 64-bit ALU ops are sign-extended.
215
if (value >= MinInt32 && value <= MaxInt32) {
216
andPtr(Imm32(int(value)), srcDest);
218
move(imm, scratchRegister);
219
m_assembler.andq_rr(scratchRegister, srcDest);
223
void negPtr(RegisterID srcDest)
225
m_assembler.negq_r(srcDest);
228
void notPtr(RegisterID srcDest)
230
m_assembler.notq_r(srcDest);
233
void orPtr(Address src, RegisterID dest)
235
m_assembler.orq_mr(src.offset, src.base, dest);
238
void orPtr(RegisterID src, RegisterID dest)
240
m_assembler.orq_rr(src, dest);
243
void orPtr(ImmPtr imm, RegisterID dest)
245
move(imm, scratchRegister);
246
m_assembler.orq_rr(scratchRegister, dest);
249
void orPtr(Imm32 imm, RegisterID dest)
251
m_assembler.orq_ir(imm.m_value, dest);
254
void subPtr(RegisterID src, RegisterID dest)
256
m_assembler.subq_rr(src, dest);
259
void subPtr(Imm32 imm, RegisterID dest)
261
m_assembler.subq_ir(imm.m_value, dest);
264
void subPtr(ImmPtr imm, RegisterID dest)
266
move(imm, scratchRegister);
267
m_assembler.subq_rr(scratchRegister, dest);
270
void xorPtr(RegisterID src, RegisterID dest)
272
m_assembler.xorq_rr(src, dest);
275
void xorPtr(Imm32 imm, RegisterID srcDest)
277
m_assembler.xorq_ir(imm.m_value, srcDest);
280
void rshiftPtr(Imm32 imm, RegisterID srcDest)
282
m_assembler.sarq_i8r(imm.m_value, srcDest);
285
void lshiftPtr(Imm32 imm, RegisterID srcDest)
287
m_assembler.shlq_i8r(imm.m_value, srcDest);
290
void loadPtr(ImplicitAddress address, RegisterID dest)
292
m_assembler.movq_mr(address.offset, address.base, dest);
295
void loadPtr(BaseIndex address, RegisterID dest)
297
m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
300
void loadPtr(void* address, RegisterID dest)
302
if (dest == X86Registers::eax)
303
m_assembler.movq_mEAX(address);
305
move(ImmPtr(address), scratchRegister);
306
loadPtr(ImplicitAddress(scratchRegister), dest);
310
DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
312
m_assembler.movq_mr_disp32(address.offset, address.base, dest);
313
return DataLabel32(this);
316
void storePtr(RegisterID src, ImplicitAddress address)
318
m_assembler.movq_rm(src, address.offset, address.base);
321
void storePtr(TrustedImmPtr imm, BaseIndex address)
323
intptr_t value = intptr_t(imm.m_value);
325
// 32-bit immediates in 64-bit stores will be zero-extended, so check
326
// if the value can fit in such a store.
327
if (value >= 0 && value < intptr_t(0x7FFFFFFF)) {
328
m_assembler.movq_i32m(int32_t(value), address.offset, address.base, address.index,
331
move(imm, scratchRegister);
332
storePtr(scratchRegister, address);
336
void storePtr(RegisterID src, BaseIndex address)
338
m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
341
void storePtr(RegisterID src, void* address)
343
if (src == X86Registers::eax)
344
m_assembler.movq_EAXm(address);
346
move(ImmPtr(address), scratchRegister);
347
storePtr(src, ImplicitAddress(scratchRegister));
351
void storePtr(TrustedImmPtr imm, ImplicitAddress address)
353
intptr_t value = intptr_t(imm.m_value);
355
// 32-bit immediates in 64-bit stores will be zero-extended, so check
356
// if the value can fit in such a store.
357
if (value >= 0 && value < intptr_t(0x7FFFFFFF)) {
358
m_assembler.movq_i32m(int32_t(value), address.offset, address.base);
360
move(imm, scratchRegister);
361
storePtr(scratchRegister, address);
365
DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
367
m_assembler.movq_rm_disp32(src, address.offset, address.base);
368
return DataLabel32(this);
371
void movePtrToDouble(RegisterID src, FPRegisterID dest)
373
m_assembler.movq_rr(src, dest);
376
void moveDoubleToPtr(FPRegisterID src, RegisterID dest)
378
m_assembler.movq_rr(src, dest);
381
void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
383
if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
384
m_assembler.testq_rr(left, left);
386
m_assembler.cmpq_ir(right.m_value, left);
387
m_assembler.setCC_r(x86Condition(cond), dest);
388
m_assembler.movzbl_rr(dest, dest);
391
void setPtr(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
393
m_assembler.cmpq_rr(right, left);
394
m_assembler.setCC_r(x86Condition(cond), dest);
395
m_assembler.movzbl_rr(dest, dest);
398
void setPtr(Condition cond, RegisterID left, ImmPtr right, RegisterID dest)
400
move(right, scratchRegister);
401
setPtr(cond, left, scratchRegister, dest);
404
Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
406
m_assembler.cmpq_rr(right, left);
407
return Jump(m_assembler.jCC(x86Condition(cond)));
410
Jump branchPtr(Condition cond, RegisterID left, Imm32 right)
412
m_assembler.cmpq_ir(right.m_value, left);
413
return Jump(m_assembler.jCC(x86Condition(cond)));
416
Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
418
move(right, scratchRegister);
419
return branchPtr(cond, left, scratchRegister);
422
Jump branchPtr(Condition cond, RegisterID left, Address right)
424
m_assembler.cmpq_mr(right.offset, right.base, left);
425
return Jump(m_assembler.jCC(x86Condition(cond)));
428
Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
430
move(ImmPtr(left.m_ptr), scratchRegister);
431
return branchPtr(cond, Address(scratchRegister), right);
434
Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right, RegisterID scratch)
436
move(ImmPtr(left.m_ptr), scratch);
437
return branchPtr(cond, Address(scratch), right);
440
Jump branchPtr(Condition cond, Address left, RegisterID right)
442
m_assembler.cmpq_rm(right, left.offset, left.base);
443
return Jump(m_assembler.jCC(x86Condition(cond)));
446
Jump branchPtr(Condition cond, Address left, ImmPtr right)
448
move(right, scratchRegister);
449
return branchPtr(cond, left, scratchRegister);
452
Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
454
m_assembler.testq_rr(reg, mask);
455
return Jump(m_assembler.jCC(x86Condition(cond)));
458
Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
460
// if we are only interested in the low seven bits, this can be tested with a testb
461
if (mask.m_value == -1)
462
m_assembler.testq_rr(reg, reg);
463
else if ((mask.m_value & ~0x7f) == 0)
464
m_assembler.testb_i8r(mask.m_value, reg);
466
m_assembler.testq_i32r(mask.m_value, reg);
467
return Jump(m_assembler.jCC(x86Condition(cond)));
470
Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
472
if (mask.m_value == -1)
473
m_assembler.cmpq_im(0, address.offset, address.base);
475
m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
476
return Jump(m_assembler.jCC(x86Condition(cond)));
479
Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
481
if (mask.m_value == -1)
482
m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
484
m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
485
return Jump(m_assembler.jCC(x86Condition(cond)));
489
Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
491
ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
493
return Jump(m_assembler.jCC(x86Condition(cond)));
496
Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
498
ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
500
return Jump(m_assembler.jCC(x86Condition(cond)));
503
DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
505
m_assembler.movq_i64r(initialValue.asIntptr(), dest);
506
return DataLabelPtr(this);
509
Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
511
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
512
return branchPtr(cond, left, scratchRegister);
515
Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
517
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
518
return branchPtr(cond, left, scratchRegister);
521
DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
523
DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
524
storePtr(scratchRegister, address);
528
using MacroAssemblerX86Common::branchTest8;
529
Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1))
531
ImmPtr addr(reinterpret_cast<void*>(address.offset));
532
MacroAssemblerX86Common::move(addr, scratchRegister);
533
return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
536
Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
539
loadPtr(address, dest);
545
for (int i = X86Registers::eax; i <= X86Registers::r15; i++)
546
m_assembler.push_r((RegisterID)i);
551
for (int i = X86Registers::r15; i >= X86Registers::eax; i--)
552
m_assembler.pop_r((RegisterID)i);
555
void storeDouble(ImmDouble imm, Address address)
557
storePtr(ImmPtr(reinterpret_cast<void *>(imm.u.u64)), address);
560
void storeDouble(ImmDouble imm, BaseIndex address)
562
storePtr(ImmPtr(reinterpret_cast<void *>(imm.u.u64)), address);
565
bool supportsFloatingPoint() const { return true; }
566
// See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
567
bool supportsFloatingPointTruncate() const { return true; }
568
bool supportsFloatingPointSqrt() const { return true; }
571
friend class LinkBuffer;
572
friend class RepatchBuffer;
574
static void linkCall(void* code, Call call, FunctionPtr function)
576
if (!call.isFlagSet(Call::Near))
577
X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value());
579
X86Assembler::linkCall(code, call.m_jmp, function.value());
582
static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
584
X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
587
static void repatchCall(CodeLocationCall call, FunctionPtr destination)
589
X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
596
#endif // ENABLE(ASSEMBLER)
598
#endif // MacroAssemblerX86_64_h