blob: 8db54f07527eab86f204986a688fe6f1d28b7089 [file] [log] [blame]
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY 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.
27
28#ifndef V8_X64_ASSEMBLER_X64_INL_H_
29#define V8_X64_ASSEMBLER_X64_INL_H_
30
31#include "cpu.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010032#include "debug.h"
Steve Block44f0eee2011-05-26 01:26:41 +010033#include "v8memory.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034
35namespace v8 {
36namespace internal {
37
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39// -----------------------------------------------------------------------------
40// Implementation of Assembler
41
42
Steve Blocka7e24c12009-10-30 11:49:00 +000043void Assembler::emitl(uint32_t x) {
44 Memory::uint32_at(pc_) = x;
45 pc_ += sizeof(uint32_t);
46}
47
48
49void Assembler::emitq(uint64_t x, RelocInfo::Mode rmode) {
50 Memory::uint64_at(pc_) = x;
51 if (rmode != RelocInfo::NONE) {
52 RecordRelocInfo(rmode, x);
53 }
54 pc_ += sizeof(uint64_t);
55}
56
57
58void Assembler::emitw(uint16_t x) {
59 Memory::uint16_at(pc_) = x;
60 pc_ += sizeof(uint16_t);
61}
62
63
Ben Murdoch257744e2011-11-30 15:57:28 +000064void Assembler::emit_code_target(Handle<Code> target,
65 RelocInfo::Mode rmode,
66 unsigned ast_id) {
Steve Block3ce2e202009-11-05 08:53:23 +000067 ASSERT(RelocInfo::IsCodeTarget(rmode));
Ben Murdoch257744e2011-11-30 15:57:28 +000068 if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
69 RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, ast_id);
70 } else {
71 RecordRelocInfo(rmode);
72 }
Steve Block3ce2e202009-11-05 08:53:23 +000073 int current = code_targets_.length();
74 if (current > 0 && code_targets_.last().is_identical_to(target)) {
75 // Optimization if we keep jumping to the same code target.
76 emitl(current - 1);
77 } else {
78 code_targets_.Add(target);
79 emitl(current);
80 }
81}
82
83
Steve Blocka7e24c12009-10-30 11:49:00 +000084void Assembler::emit_rex_64(Register reg, Register rm_reg) {
85 emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
86}
87
88
89void Assembler::emit_rex_64(XMMRegister reg, Register rm_reg) {
90 emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
91}
92
93
Steve Block6ded16b2010-05-10 14:33:55 +010094void Assembler::emit_rex_64(Register reg, XMMRegister rm_reg) {
95 emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
96}
97
98
Steve Blocka7e24c12009-10-30 11:49:00 +000099void Assembler::emit_rex_64(Register reg, const Operand& op) {
100 emit(0x48 | reg.high_bit() << 2 | op.rex_);
101}
102
103
104void Assembler::emit_rex_64(XMMRegister reg, const Operand& op) {
105 emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_);
106}
107
108
109void Assembler::emit_rex_64(Register rm_reg) {
110 ASSERT_EQ(rm_reg.code() & 0xf, rm_reg.code());
111 emit(0x48 | rm_reg.high_bit());
112}
113
114
115void Assembler::emit_rex_64(const Operand& op) {
116 emit(0x48 | op.rex_);
117}
118
119
120void Assembler::emit_rex_32(Register reg, Register rm_reg) {
121 emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit());
122}
123
124
125void Assembler::emit_rex_32(Register reg, const Operand& op) {
126 emit(0x40 | reg.high_bit() << 2 | op.rex_);
127}
128
129
130void Assembler::emit_rex_32(Register rm_reg) {
131 emit(0x40 | rm_reg.high_bit());
132}
133
134
135void Assembler::emit_rex_32(const Operand& op) {
136 emit(0x40 | op.rex_);
137}
138
139
140void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) {
141 byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit();
142 if (rex_bits != 0) emit(0x40 | rex_bits);
143}
144
145
146void Assembler::emit_optional_rex_32(Register reg, const Operand& op) {
147 byte rex_bits = reg.high_bit() << 2 | op.rex_;
148 if (rex_bits != 0) emit(0x40 | rex_bits);
149}
150
151
152void Assembler::emit_optional_rex_32(XMMRegister reg, const Operand& op) {
153 byte rex_bits = (reg.code() & 0x8) >> 1 | op.rex_;
154 if (rex_bits != 0) emit(0x40 | rex_bits);
155}
156
157
158void Assembler::emit_optional_rex_32(XMMRegister reg, XMMRegister base) {
159 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
160 if (rex_bits != 0) emit(0x40 | rex_bits);
161}
162
163
164void Assembler::emit_optional_rex_32(XMMRegister reg, Register base) {
165 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
166 if (rex_bits != 0) emit(0x40 | rex_bits);
167}
168
169
Steve Block6ded16b2010-05-10 14:33:55 +0100170void Assembler::emit_optional_rex_32(Register reg, XMMRegister base) {
171 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
172 if (rex_bits != 0) emit(0x40 | rex_bits);
173}
174
175
Steve Blocka7e24c12009-10-30 11:49:00 +0000176void Assembler::emit_optional_rex_32(Register rm_reg) {
177 if (rm_reg.high_bit()) emit(0x41);
178}
179
180
181void Assembler::emit_optional_rex_32(const Operand& op) {
182 if (op.rex_ != 0) emit(0x40 | op.rex_);
183}
184
185
186Address Assembler::target_address_at(Address pc) {
Steve Block3ce2e202009-11-05 08:53:23 +0000187 return Memory::int32_at(pc) + pc + 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000188}
189
190
191void Assembler::set_target_address_at(Address pc, Address target) {
Steve Blockd0582a62009-12-15 09:54:21 +0000192 Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4);
Steve Block3ce2e202009-11-05 08:53:23 +0000193 CPU::FlushICache(pc, sizeof(int32_t));
Steve Blocka7e24c12009-10-30 11:49:00 +0000194}
195
Steve Block3ce2e202009-11-05 08:53:23 +0000196Handle<Object> Assembler::code_target_object_handle_at(Address pc) {
197 return code_targets_[Memory::int32_at(pc)];
198}
Steve Blocka7e24c12009-10-30 11:49:00 +0000199
200// -----------------------------------------------------------------------------
201// Implementation of RelocInfo
202
203// The modes possibly affected by apply must be in kApplyMask.
204void RelocInfo::apply(intptr_t delta) {
205 if (IsInternalReference(rmode_)) {
206 // absolute code pointer inside code object moves with the code object.
Steve Blockd0582a62009-12-15 09:54:21 +0000207 Memory::Address_at(pc_) += static_cast<int32_t>(delta);
Steve Block1e0659c2011-05-24 12:43:12 +0100208 CPU::FlushICache(pc_, sizeof(Address));
Steve Block3ce2e202009-11-05 08:53:23 +0000209 } else if (IsCodeTarget(rmode_)) {
Steve Blockd0582a62009-12-15 09:54:21 +0000210 Memory::int32_at(pc_) -= static_cast<int32_t>(delta);
Steve Block1e0659c2011-05-24 12:43:12 +0100211 CPU::FlushICache(pc_, sizeof(int32_t));
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 }
213}
214
215
216Address RelocInfo::target_address() {
217 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
Steve Block3ce2e202009-11-05 08:53:23 +0000218 if (IsCodeTarget(rmode_)) {
219 return Assembler::target_address_at(pc_);
220 } else {
221 return Memory::Address_at(pc_);
222 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000223}
224
225
226Address RelocInfo::target_address_address() {
227 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
228 return reinterpret_cast<Address>(pc_);
229}
230
231
Leon Clarkef7060e22010-06-03 12:02:55 +0100232int RelocInfo::target_address_size() {
233 if (IsCodedSpecially()) {
234 return Assembler::kCallTargetSize;
235 } else {
236 return Assembler::kExternalTargetSize;
237 }
238}
239
240
Steve Blocka7e24c12009-10-30 11:49:00 +0000241void RelocInfo::set_target_address(Address target) {
242 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
Steve Block3ce2e202009-11-05 08:53:23 +0000243 if (IsCodeTarget(rmode_)) {
244 Assembler::set_target_address_at(pc_, target);
245 } else {
246 Memory::Address_at(pc_) = target;
Steve Block1e0659c2011-05-24 12:43:12 +0100247 CPU::FlushICache(pc_, sizeof(Address));
Steve Block3ce2e202009-11-05 08:53:23 +0000248 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000249}
250
251
252Object* RelocInfo::target_object() {
253 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Steve Block3ce2e202009-11-05 08:53:23 +0000254 return Memory::Object_at(pc_);
255}
256
257
258Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
259 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
260 if (rmode_ == EMBEDDED_OBJECT) {
261 return Memory::Object_Handle_at(pc_);
262 } else {
263 return origin->code_target_object_handle_at(pc_);
264 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000265}
266
267
268Object** RelocInfo::target_object_address() {
269 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
270 return reinterpret_cast<Object**>(pc_);
271}
272
273
274Address* RelocInfo::target_reference_address() {
275 ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
276 return reinterpret_cast<Address*>(pc_);
277}
278
279
280void RelocInfo::set_target_object(Object* target) {
281 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
282 *reinterpret_cast<Object**>(pc_) = target;
Steve Block1e0659c2011-05-24 12:43:12 +0100283 CPU::FlushICache(pc_, sizeof(Address));
Steve Blocka7e24c12009-10-30 11:49:00 +0000284}
285
286
Ben Murdochb0fe1622011-05-05 13:52:32 +0100287Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
288 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
289 Address address = Memory::Address_at(pc_);
290 return Handle<JSGlobalPropertyCell>(
291 reinterpret_cast<JSGlobalPropertyCell**>(address));
292}
293
294
295JSGlobalPropertyCell* RelocInfo::target_cell() {
296 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
297 Address address = Memory::Address_at(pc_);
298 Object* object = HeapObject::FromAddress(
299 address - JSGlobalPropertyCell::kValueOffset);
300 return reinterpret_cast<JSGlobalPropertyCell*>(object);
301}
302
303
304void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
305 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
306 Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
307 Memory::Address_at(pc_) = address;
Steve Block1e0659c2011-05-24 12:43:12 +0100308 CPU::FlushICache(pc_, sizeof(Address));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309}
310
311
Steve Block3ce2e202009-11-05 08:53:23 +0000312bool RelocInfo::IsPatchedReturnSequence() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 // The recognized call sequence is:
314 // movq(kScratchRegister, immediate64); call(kScratchRegister);
315 // It only needs to be distinguished from a return sequence
316 // movq(rsp, rbp); pop(rbp); ret(n); int3 *6
317 // The 11th byte is int3 (0xCC) in the return sequence and
318 // REX.WB (0x48+register bit) for the call sequence.
Steve Block3ce2e202009-11-05 08:53:23 +0000319#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 return pc_[10] != 0xCC;
Steve Block3ce2e202009-11-05 08:53:23 +0000321#else
322 return false;
323#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000324}
325
326
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100327bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
328 return !Assembler::IsNop(pc());
329}
330
331
Steve Blocka7e24c12009-10-30 11:49:00 +0000332Address RelocInfo::call_address() {
Ben Murdochbb769b22010-08-11 14:56:33 +0100333 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
334 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Block3ce2e202009-11-05 08:53:23 +0000335 return Memory::Address_at(
336 pc_ + Assembler::kRealPatchReturnSequenceAddressOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +0000337}
338
339
340void RelocInfo::set_call_address(Address target) {
Ben Murdochbb769b22010-08-11 14:56:33 +0100341 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
342 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Block3ce2e202009-11-05 08:53:23 +0000343 Memory::Address_at(pc_ + Assembler::kRealPatchReturnSequenceAddressOffset) =
344 target;
Steve Block1e0659c2011-05-24 12:43:12 +0100345 CPU::FlushICache(pc_ + Assembler::kRealPatchReturnSequenceAddressOffset,
346 sizeof(Address));
Steve Blocka7e24c12009-10-30 11:49:00 +0000347}
348
349
350Object* RelocInfo::call_object() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000351 return *call_object_address();
352}
353
354
355void RelocInfo::set_call_object(Object* target) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 *call_object_address() = target;
357}
358
359
360Object** RelocInfo::call_object_address() {
Ben Murdochbb769b22010-08-11 14:56:33 +0100361 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
362 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 return reinterpret_cast<Object**>(
364 pc_ + Assembler::kPatchReturnSequenceAddressOffset);
365}
366
Leon Clarkef7060e22010-06-03 12:02:55 +0100367
368void RelocInfo::Visit(ObjectVisitor* visitor) {
369 RelocInfo::Mode mode = rmode();
370 if (mode == RelocInfo::EMBEDDED_OBJECT) {
371 visitor->VisitPointer(target_object_address());
Steve Block1e0659c2011-05-24 12:43:12 +0100372 CPU::FlushICache(pc_, sizeof(Address));
Leon Clarkef7060e22010-06-03 12:02:55 +0100373 } else if (RelocInfo::IsCodeTarget(mode)) {
374 visitor->VisitCodeTarget(this);
Steve Block1e0659c2011-05-24 12:43:12 +0100375 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
376 visitor->VisitGlobalPropertyCell(this);
Leon Clarkef7060e22010-06-03 12:02:55 +0100377 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
378 visitor->VisitExternalReference(target_reference_address());
Steve Block1e0659c2011-05-24 12:43:12 +0100379 CPU::FlushICache(pc_, sizeof(Address));
Leon Clarkef7060e22010-06-03 12:02:55 +0100380#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100381 // TODO(isolates): Get a cached isolate below.
382 } else if (((RelocInfo::IsJSReturn(mode) &&
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100383 IsPatchedReturnSequence()) ||
384 (RelocInfo::IsDebugBreakSlot(mode) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100385 IsPatchedDebugBreakSlotSequence())) &&
386 Isolate::Current()->debug()->has_break_points()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100387 visitor->VisitDebugTarget(this);
388#endif
389 } else if (mode == RelocInfo::RUNTIME_ENTRY) {
390 visitor->VisitRuntimeEntry(this);
391 }
392}
393
394
Iain Merrick75681382010-08-19 15:07:18 +0100395template<typename StaticVisitor>
Steve Block44f0eee2011-05-26 01:26:41 +0100396void RelocInfo::Visit(Heap* heap) {
Iain Merrick75681382010-08-19 15:07:18 +0100397 RelocInfo::Mode mode = rmode();
398 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block44f0eee2011-05-26 01:26:41 +0100399 StaticVisitor::VisitPointer(heap, target_object_address());
Steve Block1e0659c2011-05-24 12:43:12 +0100400 CPU::FlushICache(pc_, sizeof(Address));
Iain Merrick75681382010-08-19 15:07:18 +0100401 } else if (RelocInfo::IsCodeTarget(mode)) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100402 StaticVisitor::VisitCodeTarget(heap, this);
Steve Block1e0659c2011-05-24 12:43:12 +0100403 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100404 StaticVisitor::VisitGlobalPropertyCell(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100405 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
406 StaticVisitor::VisitExternalReference(target_reference_address());
Steve Block1e0659c2011-05-24 12:43:12 +0100407 CPU::FlushICache(pc_, sizeof(Address));
Iain Merrick75681382010-08-19 15:07:18 +0100408#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100409 } else if (heap->isolate()->debug()->has_break_points() &&
Iain Merrick75681382010-08-19 15:07:18 +0100410 ((RelocInfo::IsJSReturn(mode) &&
411 IsPatchedReturnSequence()) ||
412 (RelocInfo::IsDebugBreakSlot(mode) &&
413 IsPatchedDebugBreakSlotSequence()))) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100414 StaticVisitor::VisitDebugTarget(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100415#endif
416 } else if (mode == RelocInfo::RUNTIME_ENTRY) {
417 StaticVisitor::VisitRuntimeEntry(this);
418 }
419}
420
421
Steve Blocka7e24c12009-10-30 11:49:00 +0000422// -----------------------------------------------------------------------------
423// Implementation of Operand
424
425void Operand::set_modrm(int mod, Register rm_reg) {
426 ASSERT(is_uint2(mod));
427 buf_[0] = mod << 6 | rm_reg.low_bits();
428 // Set REX.B to the high bit of rm.code().
429 rex_ |= rm_reg.high_bit();
430}
431
432
433void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
434 ASSERT(len_ == 1);
435 ASSERT(is_uint2(scale));
436 // Use SIB with no index register only for base rsp or r12. Otherwise we
437 // would skip the SIB byte entirely.
438 ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
Steve Block1e0659c2011-05-24 12:43:12 +0100439 buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 rex_ |= index.high_bit() << 1 | base.high_bit();
441 len_ = 2;
442}
443
444void Operand::set_disp8(int disp) {
445 ASSERT(is_int8(disp));
446 ASSERT(len_ == 1 || len_ == 2);
447 int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]);
448 *p = disp;
449 len_ += sizeof(int8_t);
450}
451
452void Operand::set_disp32(int disp) {
453 ASSERT(len_ == 1 || len_ == 2);
454 int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
455 *p = disp;
456 len_ += sizeof(int32_t);
457}
458
459
460} } // namespace v8::internal
461
462#endif // V8_X64_ASSEMBLER_X64_INL_H_