blob: 2565acb5325567df488afff652fa1031b71e9818 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// 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//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
33// The original source code covered by the above license above has been modified
34// significantly by Google Inc.
35// Copyright 2006-2008 the V8 project authors. All rights reserved.
36
37#include "v8.h"
38
Leon Clarkef7060e22010-06-03 12:02:55 +010039#if defined(V8_TARGET_ARCH_IA32)
40
Steve Blocka7e24c12009-10-30 11:49:00 +000041#include "disassembler.h"
42#include "macro-assembler.h"
43#include "serialize.h"
44
45namespace v8 {
46namespace internal {
47
48// -----------------------------------------------------------------------------
49// Implementation of CpuFeatures
50
51// Safe default is no features.
52uint64_t CpuFeatures::supported_ = 0;
53uint64_t CpuFeatures::enabled_ = 0;
Steve Blockd0582a62009-12-15 09:54:21 +000054uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000055
56
57// The Probe method needs executable memory, so it uses Heap::CreateCode.
58// Allocation failure is silent and leads to safe default.
59void CpuFeatures::Probe() {
60 ASSERT(Heap::HasBeenSetup());
61 ASSERT(supported_ == 0);
Steve Blockd0582a62009-12-15 09:54:21 +000062 if (Serializer::enabled()) {
63 supported_ |= OS::CpuFeaturesImpliedByPlatform();
64 return; // No features if we might serialize.
65 }
Steve Blocka7e24c12009-10-30 11:49:00 +000066
67 Assembler assm(NULL, 0);
68 Label cpuid, done;
69#define __ assm.
70 // Save old esp, since we are going to modify the stack.
71 __ push(ebp);
72 __ pushfd();
73 __ push(ecx);
74 __ push(ebx);
75 __ mov(ebp, Operand(esp));
76
77 // If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
78 __ pushfd();
79 __ pop(eax);
80 __ mov(edx, Operand(eax));
81 __ xor_(eax, 0x200000); // Flip bit 21.
82 __ push(eax);
83 __ popfd();
84 __ pushfd();
85 __ pop(eax);
86 __ xor_(eax, Operand(edx)); // Different if CPUID is supported.
87 __ j(not_zero, &cpuid);
88
89 // CPUID not supported. Clear the supported features in edx:eax.
90 __ xor_(eax, Operand(eax));
91 __ xor_(edx, Operand(edx));
92 __ jmp(&done);
93
94 // Invoke CPUID with 1 in eax to get feature information in
95 // ecx:edx. Temporarily enable CPUID support because we know it's
96 // safe here.
97 __ bind(&cpuid);
98 __ mov(eax, 1);
99 supported_ = (1 << CPUID);
100 { Scope fscope(CPUID);
101 __ cpuid();
102 }
103 supported_ = 0;
104
105 // Move the result from ecx:edx to edx:eax and make sure to mark the
106 // CPUID feature as supported.
107 __ mov(eax, Operand(edx));
108 __ or_(eax, 1 << CPUID);
109 __ mov(edx, Operand(ecx));
110
111 // Done.
112 __ bind(&done);
113 __ mov(esp, Operand(ebp));
114 __ pop(ebx);
115 __ pop(ecx);
116 __ popfd();
117 __ pop(ebp);
118 __ ret(0);
119#undef __
120
121 CodeDesc desc;
122 assm.GetCode(&desc);
123 Object* code = Heap::CreateCode(desc,
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 Code::ComputeFlags(Code::STUB),
125 Handle<Code>::null());
126 if (!code->IsCode()) return;
Steve Block6ded16b2010-05-10 14:33:55 +0100127 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
128 Code::cast(code), "CpuFeatures::Probe"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 typedef uint64_t (*F0)();
130 F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
131 supported_ = probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000132 found_by_runtime_probing_ = supported_;
133 uint64_t os_guarantees = OS::CpuFeaturesImpliedByPlatform();
134 supported_ |= os_guarantees;
135 found_by_runtime_probing_ &= ~os_guarantees;
Steve Blocka7e24c12009-10-30 11:49:00 +0000136}
137
138
139// -----------------------------------------------------------------------------
140// Implementation of Displacement
141
142void Displacement::init(Label* L, Type type) {
143 ASSERT(!L->is_bound());
144 int next = 0;
145 if (L->is_linked()) {
146 next = L->pos();
147 ASSERT(next > 0); // Displacements must be at positions > 0
148 }
149 // Ensure that we _never_ overflow the next field.
150 ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize));
151 data_ = NextField::encode(next) | TypeField::encode(type);
152}
153
154
155// -----------------------------------------------------------------------------
156// Implementation of RelocInfo
157
158
159const int RelocInfo::kApplyMask =
160 RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY |
Ben Murdochbb769b22010-08-11 14:56:33 +0100161 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE |
162 1 << RelocInfo::DEBUG_BREAK_SLOT;
Steve Blocka7e24c12009-10-30 11:49:00 +0000163
164
Leon Clarkef7060e22010-06-03 12:02:55 +0100165bool RelocInfo::IsCodedSpecially() {
166 // The deserializer needs to know whether a pointer is specially coded. Being
167 // specially coded on IA32 means that it is a relative address, as used by
168 // branch instructions. These are also the ones that need changing when a
169 // code object moves.
170 return (1 << rmode_) & kApplyMask;
171}
172
173
Steve Blocka7e24c12009-10-30 11:49:00 +0000174void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
175 // Patch the code at the current address with the supplied instructions.
176 for (int i = 0; i < instruction_count; i++) {
177 *(pc_ + i) = *(instructions + i);
178 }
179
180 // Indicate that code has changed.
181 CPU::FlushICache(pc_, instruction_count);
182}
183
184
185// Patch the code at the current PC with a call to the target address.
186// Additional guard int3 instructions can be added if required.
187void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
188 // Call instruction takes up 5 bytes and int3 takes up one byte.
189 static const int kCallCodeSize = 5;
190 int code_size = kCallCodeSize + guard_bytes;
191
192 // Create a code patcher.
193 CodePatcher patcher(pc_, code_size);
194
195 // Add a label for checking the size of the code used for returning.
196#ifdef DEBUG
197 Label check_codesize;
198 patcher.masm()->bind(&check_codesize);
199#endif
200
201 // Patch the code.
202 patcher.masm()->call(target, RelocInfo::NONE);
203
204 // Check that the size of the code generated is as expected.
205 ASSERT_EQ(kCallCodeSize,
206 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
207
208 // Add the requested number of int3 instructions after the call.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100209 ASSERT_GE(guard_bytes, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 for (int i = 0; i < guard_bytes; i++) {
211 patcher.masm()->int3();
212 }
213}
214
215
216// -----------------------------------------------------------------------------
217// Implementation of Operand
218
219Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) {
220 // [base + disp/r]
221 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
222 // [base]
223 set_modrm(0, base);
224 if (base.is(esp)) set_sib(times_1, esp, base);
225 } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
226 // [base + disp8]
227 set_modrm(1, base);
228 if (base.is(esp)) set_sib(times_1, esp, base);
229 set_disp8(disp);
230 } else {
231 // [base + disp/r]
232 set_modrm(2, base);
233 if (base.is(esp)) set_sib(times_1, esp, base);
234 set_dispr(disp, rmode);
235 }
236}
237
238
239Operand::Operand(Register base,
240 Register index,
241 ScaleFactor scale,
242 int32_t disp,
243 RelocInfo::Mode rmode) {
244 ASSERT(!index.is(esp)); // illegal addressing mode
245 // [base + index*scale + disp/r]
246 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
247 // [base + index*scale]
248 set_modrm(0, esp);
249 set_sib(scale, index, base);
250 } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
251 // [base + index*scale + disp8]
252 set_modrm(1, esp);
253 set_sib(scale, index, base);
254 set_disp8(disp);
255 } else {
256 // [base + index*scale + disp/r]
257 set_modrm(2, esp);
258 set_sib(scale, index, base);
259 set_dispr(disp, rmode);
260 }
261}
262
263
264Operand::Operand(Register index,
265 ScaleFactor scale,
266 int32_t disp,
267 RelocInfo::Mode rmode) {
268 ASSERT(!index.is(esp)); // illegal addressing mode
269 // [index*scale + disp/r]
270 set_modrm(0, esp);
271 set_sib(scale, index, ebp);
272 set_dispr(disp, rmode);
273}
274
275
276bool Operand::is_reg(Register reg) const {
277 return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only.
278 && ((buf_[0] & 0x07) == reg.code()); // register codes match.
279}
280
281// -----------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000282// Implementation of Assembler.
Steve Blocka7e24c12009-10-30 11:49:00 +0000283
284// Emit a single byte. Must always be inlined.
285#define EMIT(x) \
286 *pc_++ = (x)
287
288
289#ifdef GENERATED_CODE_COVERAGE
290static void InitCoverageLog();
291#endif
292
Andrei Popescu31002712010-02-23 13:46:05 +0000293// Spare buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +0000294byte* Assembler::spare_buffer_ = NULL;
295
296Assembler::Assembler(void* buffer, int buffer_size) {
297 if (buffer == NULL) {
Andrei Popescu31002712010-02-23 13:46:05 +0000298 // Do our own buffer management.
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 if (buffer_size <= kMinimalBufferSize) {
300 buffer_size = kMinimalBufferSize;
301
302 if (spare_buffer_ != NULL) {
303 buffer = spare_buffer_;
304 spare_buffer_ = NULL;
305 }
306 }
307 if (buffer == NULL) {
308 buffer_ = NewArray<byte>(buffer_size);
309 } else {
310 buffer_ = static_cast<byte*>(buffer);
311 }
312 buffer_size_ = buffer_size;
313 own_buffer_ = true;
314 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000315 // Use externally provided buffer instead.
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 ASSERT(buffer_size > 0);
317 buffer_ = static_cast<byte*>(buffer);
318 buffer_size_ = buffer_size;
319 own_buffer_ = false;
320 }
321
322 // Clear the buffer in debug mode unless it was provided by the
323 // caller in which case we can't be sure it's okay to overwrite
324 // existing code in it; see CodePatcher::CodePatcher(...).
325#ifdef DEBUG
326 if (own_buffer_) {
327 memset(buffer_, 0xCC, buffer_size); // int3
328 }
329#endif
330
Andrei Popescu31002712010-02-23 13:46:05 +0000331 // Setup buffer pointers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 ASSERT(buffer_ != NULL);
333 pc_ = buffer_;
334 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
335
336 last_pc_ = NULL;
337 current_statement_position_ = RelocInfo::kNoPosition;
338 current_position_ = RelocInfo::kNoPosition;
339 written_statement_position_ = current_statement_position_;
340 written_position_ = current_position_;
341#ifdef GENERATED_CODE_COVERAGE
342 InitCoverageLog();
343#endif
344}
345
346
347Assembler::~Assembler() {
348 if (own_buffer_) {
349 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
350 spare_buffer_ = buffer_;
351 } else {
352 DeleteArray(buffer_);
353 }
354 }
355}
356
357
358void Assembler::GetCode(CodeDesc* desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000359 // Finalize code (at this point overflow() may be true, but the gap ensures
360 // that we are still not overlapping instructions and relocation info).
361 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
362 // Setup code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 desc->buffer = buffer_;
364 desc->buffer_size = buffer_size_;
365 desc->instr_size = pc_offset();
366 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
367 desc->origin = this;
368
369 Counters::reloc_info_size.Increment(desc->reloc_size);
370}
371
372
373void Assembler::Align(int m) {
374 ASSERT(IsPowerOf2(m));
375 while ((pc_offset() & (m - 1)) != 0) {
376 nop();
377 }
378}
379
380
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100381void Assembler::CodeTargetAlign() {
382 Align(16); // Preferred alignment of jump targets on ia32.
383}
384
385
Steve Blocka7e24c12009-10-30 11:49:00 +0000386void Assembler::cpuid() {
Steve Blockd0582a62009-12-15 09:54:21 +0000387 ASSERT(CpuFeatures::IsEnabled(CPUID));
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 EnsureSpace ensure_space(this);
389 last_pc_ = pc_;
390 EMIT(0x0F);
391 EMIT(0xA2);
392}
393
394
395void Assembler::pushad() {
396 EnsureSpace ensure_space(this);
397 last_pc_ = pc_;
398 EMIT(0x60);
399}
400
401
402void Assembler::popad() {
403 EnsureSpace ensure_space(this);
404 last_pc_ = pc_;
405 EMIT(0x61);
406}
407
408
409void Assembler::pushfd() {
410 EnsureSpace ensure_space(this);
411 last_pc_ = pc_;
412 EMIT(0x9C);
413}
414
415
416void Assembler::popfd() {
417 EnsureSpace ensure_space(this);
418 last_pc_ = pc_;
419 EMIT(0x9D);
420}
421
422
423void Assembler::push(const Immediate& x) {
424 EnsureSpace ensure_space(this);
425 last_pc_ = pc_;
426 if (x.is_int8()) {
427 EMIT(0x6a);
428 EMIT(x.x_);
429 } else {
430 EMIT(0x68);
431 emit(x);
432 }
433}
434
435
436void Assembler::push(Register src) {
437 EnsureSpace ensure_space(this);
438 last_pc_ = pc_;
439 EMIT(0x50 | src.code());
440}
441
442
443void Assembler::push(const Operand& src) {
444 EnsureSpace ensure_space(this);
445 last_pc_ = pc_;
446 EMIT(0xFF);
447 emit_operand(esi, src);
448}
449
450
451void Assembler::pop(Register dst) {
452 ASSERT(reloc_info_writer.last_pc() != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100453 if (FLAG_peephole_optimization && (reloc_info_writer.last_pc() <= last_pc_)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000454 // (last_pc_ != NULL) is rolled into the above check.
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 // If a last_pc_ is set, we need to make sure that there has not been any
456 // relocation information generated between the last instruction and this
457 // pop instruction.
458 byte instr = last_pc_[0];
459 if ((instr & ~0x7) == 0x50) {
460 int push_reg_code = instr & 0x7;
461 if (push_reg_code == dst.code()) {
462 pc_ = last_pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100463 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 PrintF("%d push/pop (same reg) eliminated\n", pc_offset());
465 }
466 } else {
467 // Convert 'push src; pop dst' to 'mov dst, src'.
468 last_pc_[0] = 0x8b;
469 Register src = { push_reg_code };
470 EnsureSpace ensure_space(this);
471 emit_operand(dst, Operand(src));
Leon Clarkef7060e22010-06-03 12:02:55 +0100472 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset());
474 }
475 }
476 last_pc_ = NULL;
477 return;
478 } else if (instr == 0xff) { // push of an operand, convert to a move
479 byte op1 = last_pc_[1];
Andrei Popescu31002712010-02-23 13:46:05 +0000480 // Check if the operation is really a push.
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 if ((op1 & 0x38) == (6 << 3)) {
482 op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3);
483 last_pc_[0] = 0x8b;
484 last_pc_[1] = op1;
485 last_pc_ = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +0100486 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 PrintF("%d push/pop (op->reg) eliminated\n", pc_offset());
488 }
489 return;
490 }
491 } else if ((instr == 0x89) &&
492 (last_pc_[1] == 0x04) &&
493 (last_pc_[2] == 0x24)) {
494 // 0x71283c 396 890424 mov [esp],eax
495 // 0x71283f 399 58 pop eax
496 if (dst.is(eax)) {
497 // change to
498 // 0x710fac 216 83c404 add esp,0x4
499 last_pc_[0] = 0x83;
500 last_pc_[1] = 0xc4;
501 last_pc_[2] = 0x04;
502 last_pc_ = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +0100503 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000504 PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset());
505 }
506 return;
507 }
508 } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit
509 byte imm8 = last_pc_[1];
510 if (imm8 == 0) {
511 // 6a00 push 0x0
512 // 58 pop eax
513 last_pc_[0] = 0x31;
514 last_pc_[1] = 0xc0;
515 // change to
516 // 31c0 xor eax,eax
517 last_pc_ = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +0100518 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
520 }
521 return;
522 } else {
523 // 6a00 push 0xXX
524 // 58 pop eax
525 last_pc_[0] = 0xb8;
526 EnsureSpace ensure_space(this);
527 if ((imm8 & 0x80) != 0) {
528 EMIT(0xff);
529 EMIT(0xff);
530 EMIT(0xff);
531 // change to
532 // b8XXffffff mov eax,0xffffffXX
533 } else {
534 EMIT(0x00);
535 EMIT(0x00);
536 EMIT(0x00);
537 // change to
538 // b8XX000000 mov eax,0x000000XX
539 }
540 last_pc_ = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +0100541 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000542 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
543 }
544 return;
545 }
546 } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit
547 // 68XXXXXXXX push 0xXXXXXXXX
548 // 58 pop eax
549 last_pc_[0] = 0xb8;
550 last_pc_ = NULL;
551 // change to
552 // b8XXXXXXXX mov eax,0xXXXXXXXX
Leon Clarkef7060e22010-06-03 12:02:55 +0100553 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
555 }
556 return;
557 }
558
559 // Other potential patterns for peephole:
560 // 0x712716 102 890424 mov [esp], eax
561 // 0x712719 105 8b1424 mov edx, [esp]
562 }
563 EnsureSpace ensure_space(this);
564 last_pc_ = pc_;
565 EMIT(0x58 | dst.code());
566}
567
568
569void Assembler::pop(const Operand& dst) {
570 EnsureSpace ensure_space(this);
571 last_pc_ = pc_;
572 EMIT(0x8F);
573 emit_operand(eax, dst);
574}
575
576
577void Assembler::enter(const Immediate& size) {
578 EnsureSpace ensure_space(this);
579 last_pc_ = pc_;
580 EMIT(0xC8);
581 emit_w(size);
582 EMIT(0);
583}
584
585
586void Assembler::leave() {
587 EnsureSpace ensure_space(this);
588 last_pc_ = pc_;
589 EMIT(0xC9);
590}
591
592
593void Assembler::mov_b(Register dst, const Operand& src) {
Leon Clarkee46be812010-01-19 14:06:41 +0000594 ASSERT(dst.code() < 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000595 EnsureSpace ensure_space(this);
596 last_pc_ = pc_;
597 EMIT(0x8A);
598 emit_operand(dst, src);
599}
600
601
602void Assembler::mov_b(const Operand& dst, int8_t imm8) {
603 EnsureSpace ensure_space(this);
604 last_pc_ = pc_;
605 EMIT(0xC6);
606 emit_operand(eax, dst);
607 EMIT(imm8);
608}
609
610
611void Assembler::mov_b(const Operand& dst, Register src) {
Leon Clarkee46be812010-01-19 14:06:41 +0000612 ASSERT(src.code() < 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 EnsureSpace ensure_space(this);
614 last_pc_ = pc_;
615 EMIT(0x88);
616 emit_operand(src, dst);
617}
618
619
620void Assembler::mov_w(Register dst, const Operand& src) {
621 EnsureSpace ensure_space(this);
622 last_pc_ = pc_;
623 EMIT(0x66);
624 EMIT(0x8B);
625 emit_operand(dst, src);
626}
627
628
629void Assembler::mov_w(const Operand& dst, Register src) {
630 EnsureSpace ensure_space(this);
631 last_pc_ = pc_;
632 EMIT(0x66);
633 EMIT(0x89);
634 emit_operand(src, dst);
635}
636
637
638void Assembler::mov(Register dst, int32_t imm32) {
639 EnsureSpace ensure_space(this);
640 last_pc_ = pc_;
641 EMIT(0xB8 | dst.code());
642 emit(imm32);
643}
644
645
646void Assembler::mov(Register dst, const Immediate& x) {
647 EnsureSpace ensure_space(this);
648 last_pc_ = pc_;
649 EMIT(0xB8 | dst.code());
650 emit(x);
651}
652
653
654void Assembler::mov(Register dst, Handle<Object> handle) {
655 EnsureSpace ensure_space(this);
656 last_pc_ = pc_;
657 EMIT(0xB8 | dst.code());
658 emit(handle);
659}
660
661
662void Assembler::mov(Register dst, const Operand& src) {
663 EnsureSpace ensure_space(this);
664 last_pc_ = pc_;
665 EMIT(0x8B);
666 emit_operand(dst, src);
667}
668
669
670void Assembler::mov(Register dst, Register src) {
671 EnsureSpace ensure_space(this);
672 last_pc_ = pc_;
673 EMIT(0x89);
674 EMIT(0xC0 | src.code() << 3 | dst.code());
675}
676
677
678void Assembler::mov(const Operand& dst, const Immediate& x) {
679 EnsureSpace ensure_space(this);
680 last_pc_ = pc_;
681 EMIT(0xC7);
682 emit_operand(eax, dst);
683 emit(x);
684}
685
686
687void Assembler::mov(const Operand& dst, Handle<Object> handle) {
688 EnsureSpace ensure_space(this);
689 last_pc_ = pc_;
690 EMIT(0xC7);
691 emit_operand(eax, dst);
692 emit(handle);
693}
694
695
696void Assembler::mov(const Operand& dst, Register src) {
697 EnsureSpace ensure_space(this);
698 last_pc_ = pc_;
699 EMIT(0x89);
700 emit_operand(src, dst);
701}
702
703
704void Assembler::movsx_b(Register dst, const Operand& src) {
705 EnsureSpace ensure_space(this);
706 last_pc_ = pc_;
707 EMIT(0x0F);
708 EMIT(0xBE);
709 emit_operand(dst, src);
710}
711
712
713void Assembler::movsx_w(Register dst, const Operand& src) {
714 EnsureSpace ensure_space(this);
715 last_pc_ = pc_;
716 EMIT(0x0F);
717 EMIT(0xBF);
718 emit_operand(dst, src);
719}
720
721
722void Assembler::movzx_b(Register dst, const Operand& src) {
723 EnsureSpace ensure_space(this);
724 last_pc_ = pc_;
725 EMIT(0x0F);
726 EMIT(0xB6);
727 emit_operand(dst, src);
728}
729
730
731void Assembler::movzx_w(Register dst, const Operand& src) {
732 EnsureSpace ensure_space(this);
733 last_pc_ = pc_;
734 EMIT(0x0F);
735 EMIT(0xB7);
736 emit_operand(dst, src);
737}
738
739
740void Assembler::cmov(Condition cc, Register dst, int32_t imm32) {
Steve Blockd0582a62009-12-15 09:54:21 +0000741 ASSERT(CpuFeatures::IsEnabled(CMOV));
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 EnsureSpace ensure_space(this);
743 last_pc_ = pc_;
744 UNIMPLEMENTED();
745 USE(cc);
746 USE(dst);
747 USE(imm32);
748}
749
750
751void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) {
Steve Blockd0582a62009-12-15 09:54:21 +0000752 ASSERT(CpuFeatures::IsEnabled(CMOV));
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 EnsureSpace ensure_space(this);
754 last_pc_ = pc_;
755 UNIMPLEMENTED();
756 USE(cc);
757 USE(dst);
758 USE(handle);
759}
760
761
762void Assembler::cmov(Condition cc, Register dst, const Operand& src) {
Steve Blockd0582a62009-12-15 09:54:21 +0000763 ASSERT(CpuFeatures::IsEnabled(CMOV));
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 EnsureSpace ensure_space(this);
765 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000766 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 EMIT(0x0F);
768 EMIT(0x40 + cc);
769 emit_operand(dst, src);
770}
771
772
Steve Block6ded16b2010-05-10 14:33:55 +0100773void Assembler::cld() {
774 EnsureSpace ensure_space(this);
775 last_pc_ = pc_;
776 EMIT(0xFC);
777}
778
779
Leon Clarkee46be812010-01-19 14:06:41 +0000780void Assembler::rep_movs() {
781 EnsureSpace ensure_space(this);
782 last_pc_ = pc_;
783 EMIT(0xF3);
784 EMIT(0xA5);
785}
786
787
Steve Block6ded16b2010-05-10 14:33:55 +0100788void Assembler::rep_stos() {
789 EnsureSpace ensure_space(this);
790 last_pc_ = pc_;
791 EMIT(0xF3);
792 EMIT(0xAB);
793}
794
795
Leon Clarkef7060e22010-06-03 12:02:55 +0100796void Assembler::stos() {
797 EnsureSpace ensure_space(this);
798 last_pc_ = pc_;
799 EMIT(0xAB);
800}
801
802
Steve Blocka7e24c12009-10-30 11:49:00 +0000803void Assembler::xchg(Register dst, Register src) {
804 EnsureSpace ensure_space(this);
805 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000806 if (src.is(eax) || dst.is(eax)) { // Single-byte encoding.
Steve Blocka7e24c12009-10-30 11:49:00 +0000807 EMIT(0x90 | (src.is(eax) ? dst.code() : src.code()));
808 } else {
809 EMIT(0x87);
810 EMIT(0xC0 | src.code() << 3 | dst.code());
811 }
812}
813
814
815void Assembler::adc(Register dst, int32_t imm32) {
816 EnsureSpace ensure_space(this);
817 last_pc_ = pc_;
818 emit_arith(2, Operand(dst), Immediate(imm32));
819}
820
821
822void Assembler::adc(Register dst, const Operand& src) {
823 EnsureSpace ensure_space(this);
824 last_pc_ = pc_;
825 EMIT(0x13);
826 emit_operand(dst, src);
827}
828
829
830void Assembler::add(Register dst, const Operand& src) {
831 EnsureSpace ensure_space(this);
832 last_pc_ = pc_;
833 EMIT(0x03);
834 emit_operand(dst, src);
835}
836
837
838void Assembler::add(const Operand& dst, const Immediate& x) {
839 ASSERT(reloc_info_writer.last_pc() != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100840 if (FLAG_peephole_optimization && (reloc_info_writer.last_pc() <= last_pc_)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000841 byte instr = last_pc_[0];
842 if ((instr & 0xf8) == 0x50) {
843 // Last instruction was a push. Check whether this is a pop without a
844 // result.
845 if ((dst.is_reg(esp)) &&
846 (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) {
847 pc_ = last_pc_;
848 last_pc_ = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +0100849 if (FLAG_print_peephole_optimization) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 PrintF("%d push/pop(noreg) eliminated\n", pc_offset());
851 }
852 return;
853 }
854 }
855 }
856 EnsureSpace ensure_space(this);
857 last_pc_ = pc_;
858 emit_arith(0, dst, x);
859}
860
861
862void Assembler::and_(Register dst, int32_t imm32) {
863 EnsureSpace ensure_space(this);
864 last_pc_ = pc_;
865 emit_arith(4, Operand(dst), Immediate(imm32));
866}
867
868
869void Assembler::and_(Register dst, const Operand& src) {
870 EnsureSpace ensure_space(this);
871 last_pc_ = pc_;
872 EMIT(0x23);
873 emit_operand(dst, src);
874}
875
876
877void Assembler::and_(const Operand& dst, const Immediate& x) {
878 EnsureSpace ensure_space(this);
879 last_pc_ = pc_;
880 emit_arith(4, dst, x);
881}
882
883
884void Assembler::and_(const Operand& dst, Register src) {
885 EnsureSpace ensure_space(this);
886 last_pc_ = pc_;
887 EMIT(0x21);
888 emit_operand(src, dst);
889}
890
891
892void Assembler::cmpb(const Operand& op, int8_t imm8) {
893 EnsureSpace ensure_space(this);
894 last_pc_ = pc_;
895 EMIT(0x80);
896 emit_operand(edi, op); // edi == 7
897 EMIT(imm8);
898}
899
900
Leon Clarked91b9f72010-01-27 17:25:45 +0000901void Assembler::cmpb(const Operand& dst, Register src) {
902 ASSERT(src.is_byte_register());
903 EnsureSpace ensure_space(this);
904 last_pc_ = pc_;
905 EMIT(0x38);
906 emit_operand(src, dst);
907}
908
909
910void Assembler::cmpb(Register dst, const Operand& src) {
911 ASSERT(dst.is_byte_register());
912 EnsureSpace ensure_space(this);
913 last_pc_ = pc_;
914 EMIT(0x3A);
915 emit_operand(dst, src);
916}
917
918
Steve Blocka7e24c12009-10-30 11:49:00 +0000919void Assembler::cmpw(const Operand& op, Immediate imm16) {
920 ASSERT(imm16.is_int16());
921 EnsureSpace ensure_space(this);
922 last_pc_ = pc_;
923 EMIT(0x66);
924 EMIT(0x81);
925 emit_operand(edi, op);
926 emit_w(imm16);
927}
928
929
930void Assembler::cmp(Register reg, int32_t imm32) {
931 EnsureSpace ensure_space(this);
932 last_pc_ = pc_;
933 emit_arith(7, Operand(reg), Immediate(imm32));
934}
935
936
937void Assembler::cmp(Register reg, Handle<Object> handle) {
938 EnsureSpace ensure_space(this);
939 last_pc_ = pc_;
940 emit_arith(7, Operand(reg), Immediate(handle));
941}
942
943
944void Assembler::cmp(Register reg, const Operand& op) {
945 EnsureSpace ensure_space(this);
946 last_pc_ = pc_;
947 EMIT(0x3B);
948 emit_operand(reg, op);
949}
950
951
952void Assembler::cmp(const Operand& op, const Immediate& imm) {
953 EnsureSpace ensure_space(this);
954 last_pc_ = pc_;
955 emit_arith(7, op, imm);
956}
957
958
959void Assembler::cmp(const Operand& op, Handle<Object> handle) {
960 EnsureSpace ensure_space(this);
961 last_pc_ = pc_;
962 emit_arith(7, op, Immediate(handle));
963}
964
965
966void Assembler::cmpb_al(const Operand& op) {
967 EnsureSpace ensure_space(this);
968 last_pc_ = pc_;
969 EMIT(0x38); // CMP r/m8, r8
970 emit_operand(eax, op); // eax has same code as register al.
971}
972
973
974void Assembler::cmpw_ax(const Operand& op) {
975 EnsureSpace ensure_space(this);
976 last_pc_ = pc_;
977 EMIT(0x66);
978 EMIT(0x39); // CMP r/m16, r16
979 emit_operand(eax, op); // eax has same code as register ax.
980}
981
982
983void Assembler::dec_b(Register dst) {
984 EnsureSpace ensure_space(this);
985 last_pc_ = pc_;
986 EMIT(0xFE);
987 EMIT(0xC8 | dst.code());
988}
989
990
991void Assembler::dec(Register dst) {
992 EnsureSpace ensure_space(this);
993 last_pc_ = pc_;
994 EMIT(0x48 | dst.code());
995}
996
997
998void Assembler::dec(const Operand& dst) {
999 EnsureSpace ensure_space(this);
1000 last_pc_ = pc_;
1001 EMIT(0xFF);
1002 emit_operand(ecx, dst);
1003}
1004
1005
1006void Assembler::cdq() {
1007 EnsureSpace ensure_space(this);
1008 last_pc_ = pc_;
1009 EMIT(0x99);
1010}
1011
1012
1013void Assembler::idiv(Register src) {
1014 EnsureSpace ensure_space(this);
1015 last_pc_ = pc_;
1016 EMIT(0xF7);
1017 EMIT(0xF8 | src.code());
1018}
1019
1020
1021void Assembler::imul(Register reg) {
1022 EnsureSpace ensure_space(this);
1023 last_pc_ = pc_;
1024 EMIT(0xF7);
1025 EMIT(0xE8 | reg.code());
1026}
1027
1028
1029void Assembler::imul(Register dst, const Operand& src) {
1030 EnsureSpace ensure_space(this);
1031 last_pc_ = pc_;
1032 EMIT(0x0F);
1033 EMIT(0xAF);
1034 emit_operand(dst, src);
1035}
1036
1037
1038void Assembler::imul(Register dst, Register src, int32_t imm32) {
1039 EnsureSpace ensure_space(this);
1040 last_pc_ = pc_;
1041 if (is_int8(imm32)) {
1042 EMIT(0x6B);
1043 EMIT(0xC0 | dst.code() << 3 | src.code());
1044 EMIT(imm32);
1045 } else {
1046 EMIT(0x69);
1047 EMIT(0xC0 | dst.code() << 3 | src.code());
1048 emit(imm32);
1049 }
1050}
1051
1052
1053void Assembler::inc(Register dst) {
1054 EnsureSpace ensure_space(this);
1055 last_pc_ = pc_;
1056 EMIT(0x40 | dst.code());
1057}
1058
1059
1060void Assembler::inc(const Operand& dst) {
1061 EnsureSpace ensure_space(this);
1062 last_pc_ = pc_;
1063 EMIT(0xFF);
1064 emit_operand(eax, dst);
1065}
1066
1067
1068void Assembler::lea(Register dst, const Operand& src) {
1069 EnsureSpace ensure_space(this);
1070 last_pc_ = pc_;
1071 EMIT(0x8D);
1072 emit_operand(dst, src);
1073}
1074
1075
1076void Assembler::mul(Register src) {
1077 EnsureSpace ensure_space(this);
1078 last_pc_ = pc_;
1079 EMIT(0xF7);
1080 EMIT(0xE0 | src.code());
1081}
1082
1083
1084void Assembler::neg(Register dst) {
1085 EnsureSpace ensure_space(this);
1086 last_pc_ = pc_;
1087 EMIT(0xF7);
1088 EMIT(0xD8 | dst.code());
1089}
1090
1091
1092void Assembler::not_(Register dst) {
1093 EnsureSpace ensure_space(this);
1094 last_pc_ = pc_;
1095 EMIT(0xF7);
1096 EMIT(0xD0 | dst.code());
1097}
1098
1099
1100void Assembler::or_(Register dst, int32_t imm32) {
1101 EnsureSpace ensure_space(this);
1102 last_pc_ = pc_;
1103 emit_arith(1, Operand(dst), Immediate(imm32));
1104}
1105
1106
1107void Assembler::or_(Register dst, const Operand& src) {
1108 EnsureSpace ensure_space(this);
1109 last_pc_ = pc_;
1110 EMIT(0x0B);
1111 emit_operand(dst, src);
1112}
1113
1114
1115void Assembler::or_(const Operand& dst, const Immediate& x) {
1116 EnsureSpace ensure_space(this);
1117 last_pc_ = pc_;
1118 emit_arith(1, dst, x);
1119}
1120
1121
1122void Assembler::or_(const Operand& dst, Register src) {
1123 EnsureSpace ensure_space(this);
1124 last_pc_ = pc_;
1125 EMIT(0x09);
1126 emit_operand(src, dst);
1127}
1128
1129
1130void Assembler::rcl(Register dst, uint8_t imm8) {
1131 EnsureSpace ensure_space(this);
1132 last_pc_ = pc_;
1133 ASSERT(is_uint5(imm8)); // illegal shift count
1134 if (imm8 == 1) {
1135 EMIT(0xD1);
1136 EMIT(0xD0 | dst.code());
1137 } else {
1138 EMIT(0xC1);
1139 EMIT(0xD0 | dst.code());
1140 EMIT(imm8);
1141 }
1142}
1143
1144
Iain Merrick75681382010-08-19 15:07:18 +01001145void Assembler::rcr(Register dst, uint8_t imm8) {
1146 EnsureSpace ensure_space(this);
1147 last_pc_ = pc_;
1148 ASSERT(is_uint5(imm8)); // illegal shift count
1149 if (imm8 == 1) {
1150 EMIT(0xD1);
1151 EMIT(0xD8 | dst.code());
1152 } else {
1153 EMIT(0xC1);
1154 EMIT(0xD8 | dst.code());
1155 EMIT(imm8);
1156 }
1157}
1158
1159
Steve Blocka7e24c12009-10-30 11:49:00 +00001160void Assembler::sar(Register dst, uint8_t imm8) {
1161 EnsureSpace ensure_space(this);
1162 last_pc_ = pc_;
1163 ASSERT(is_uint5(imm8)); // illegal shift count
1164 if (imm8 == 1) {
1165 EMIT(0xD1);
1166 EMIT(0xF8 | dst.code());
1167 } else {
1168 EMIT(0xC1);
1169 EMIT(0xF8 | dst.code());
1170 EMIT(imm8);
1171 }
1172}
1173
1174
Steve Blockd0582a62009-12-15 09:54:21 +00001175void Assembler::sar_cl(Register dst) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 EnsureSpace ensure_space(this);
1177 last_pc_ = pc_;
1178 EMIT(0xD3);
1179 EMIT(0xF8 | dst.code());
1180}
1181
1182
1183void Assembler::sbb(Register dst, const Operand& src) {
1184 EnsureSpace ensure_space(this);
1185 last_pc_ = pc_;
1186 EMIT(0x1B);
1187 emit_operand(dst, src);
1188}
1189
1190
1191void Assembler::shld(Register dst, const Operand& src) {
1192 EnsureSpace ensure_space(this);
1193 last_pc_ = pc_;
1194 EMIT(0x0F);
1195 EMIT(0xA5);
1196 emit_operand(dst, src);
1197}
1198
1199
1200void Assembler::shl(Register dst, uint8_t imm8) {
1201 EnsureSpace ensure_space(this);
1202 last_pc_ = pc_;
1203 ASSERT(is_uint5(imm8)); // illegal shift count
1204 if (imm8 == 1) {
1205 EMIT(0xD1);
1206 EMIT(0xE0 | dst.code());
1207 } else {
1208 EMIT(0xC1);
1209 EMIT(0xE0 | dst.code());
1210 EMIT(imm8);
1211 }
1212}
1213
1214
Steve Blockd0582a62009-12-15 09:54:21 +00001215void Assembler::shl_cl(Register dst) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001216 EnsureSpace ensure_space(this);
1217 last_pc_ = pc_;
1218 EMIT(0xD3);
1219 EMIT(0xE0 | dst.code());
1220}
1221
1222
1223void Assembler::shrd(Register dst, const Operand& src) {
1224 EnsureSpace ensure_space(this);
1225 last_pc_ = pc_;
1226 EMIT(0x0F);
1227 EMIT(0xAD);
1228 emit_operand(dst, src);
1229}
1230
1231
1232void Assembler::shr(Register dst, uint8_t imm8) {
1233 EnsureSpace ensure_space(this);
1234 last_pc_ = pc_;
1235 ASSERT(is_uint5(imm8)); // illegal shift count
Steve Blockd0582a62009-12-15 09:54:21 +00001236 if (imm8 == 1) {
1237 EMIT(0xD1);
1238 EMIT(0xE8 | dst.code());
1239 } else {
1240 EMIT(0xC1);
1241 EMIT(0xE8 | dst.code());
1242 EMIT(imm8);
1243 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001244}
1245
1246
1247void Assembler::shr_cl(Register dst) {
1248 EnsureSpace ensure_space(this);
1249 last_pc_ = pc_;
Steve Blockd0582a62009-12-15 09:54:21 +00001250 EMIT(0xD3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 EMIT(0xE8 | dst.code());
1252}
1253
1254
Steve Block3ce2e202009-11-05 08:53:23 +00001255void Assembler::subb(const Operand& op, int8_t imm8) {
1256 EnsureSpace ensure_space(this);
1257 last_pc_ = pc_;
1258 if (op.is_reg(eax)) {
1259 EMIT(0x2c);
1260 } else {
1261 EMIT(0x80);
1262 emit_operand(ebp, op); // ebp == 5
1263 }
1264 EMIT(imm8);
1265}
1266
1267
Steve Blocka7e24c12009-10-30 11:49:00 +00001268void Assembler::sub(const Operand& dst, const Immediate& x) {
1269 EnsureSpace ensure_space(this);
1270 last_pc_ = pc_;
1271 emit_arith(5, dst, x);
1272}
1273
1274
1275void Assembler::sub(Register dst, const Operand& src) {
1276 EnsureSpace ensure_space(this);
1277 last_pc_ = pc_;
1278 EMIT(0x2B);
1279 emit_operand(dst, src);
1280}
1281
1282
Leon Clarkee46be812010-01-19 14:06:41 +00001283void Assembler::subb(Register dst, const Operand& src) {
1284 ASSERT(dst.code() < 4);
1285 EnsureSpace ensure_space(this);
1286 last_pc_ = pc_;
1287 EMIT(0x2A);
1288 emit_operand(dst, src);
1289}
1290
1291
Steve Blocka7e24c12009-10-30 11:49:00 +00001292void Assembler::sub(const Operand& dst, Register src) {
1293 EnsureSpace ensure_space(this);
1294 last_pc_ = pc_;
1295 EMIT(0x29);
1296 emit_operand(src, dst);
1297}
1298
1299
1300void Assembler::test(Register reg, const Immediate& imm) {
1301 EnsureSpace ensure_space(this);
1302 last_pc_ = pc_;
1303 // Only use test against byte for registers that have a byte
1304 // variant: eax, ebx, ecx, and edx.
1305 if (imm.rmode_ == RelocInfo::NONE && is_uint8(imm.x_) && reg.code() < 4) {
1306 uint8_t imm8 = imm.x_;
1307 if (reg.is(eax)) {
1308 EMIT(0xA8);
1309 EMIT(imm8);
1310 } else {
1311 emit_arith_b(0xF6, 0xC0, reg, imm8);
1312 }
1313 } else {
1314 // This is not using emit_arith because test doesn't support
1315 // sign-extension of 8-bit operands.
1316 if (reg.is(eax)) {
1317 EMIT(0xA9);
1318 } else {
1319 EMIT(0xF7);
1320 EMIT(0xC0 | reg.code());
1321 }
1322 emit(imm);
1323 }
1324}
1325
1326
1327void Assembler::test(Register reg, const Operand& op) {
1328 EnsureSpace ensure_space(this);
1329 last_pc_ = pc_;
1330 EMIT(0x85);
1331 emit_operand(reg, op);
1332}
1333
1334
Leon Clarkee46be812010-01-19 14:06:41 +00001335void Assembler::test_b(Register reg, const Operand& op) {
1336 EnsureSpace ensure_space(this);
1337 last_pc_ = pc_;
1338 EMIT(0x84);
1339 emit_operand(reg, op);
1340}
1341
1342
Steve Blocka7e24c12009-10-30 11:49:00 +00001343void Assembler::test(const Operand& op, const Immediate& imm) {
1344 EnsureSpace ensure_space(this);
1345 last_pc_ = pc_;
1346 EMIT(0xF7);
1347 emit_operand(eax, op);
1348 emit(imm);
1349}
1350
1351
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001352void Assembler::test_b(const Operand& op, uint8_t imm8) {
1353 EnsureSpace ensure_space(this);
1354 last_pc_ = pc_;
1355 EMIT(0xF6);
1356 emit_operand(eax, op);
1357 EMIT(imm8);
1358}
1359
1360
Steve Blocka7e24c12009-10-30 11:49:00 +00001361void Assembler::xor_(Register dst, int32_t imm32) {
1362 EnsureSpace ensure_space(this);
1363 last_pc_ = pc_;
1364 emit_arith(6, Operand(dst), Immediate(imm32));
1365}
1366
1367
1368void Assembler::xor_(Register dst, const Operand& src) {
1369 EnsureSpace ensure_space(this);
1370 last_pc_ = pc_;
1371 EMIT(0x33);
1372 emit_operand(dst, src);
1373}
1374
1375
1376void Assembler::xor_(const Operand& src, Register dst) {
1377 EnsureSpace ensure_space(this);
1378 last_pc_ = pc_;
1379 EMIT(0x31);
1380 emit_operand(dst, src);
1381}
1382
1383
1384void Assembler::xor_(const Operand& dst, const Immediate& x) {
1385 EnsureSpace ensure_space(this);
1386 last_pc_ = pc_;
1387 emit_arith(6, dst, x);
1388}
1389
1390
1391void Assembler::bt(const Operand& dst, Register src) {
1392 EnsureSpace ensure_space(this);
1393 last_pc_ = pc_;
1394 EMIT(0x0F);
1395 EMIT(0xA3);
1396 emit_operand(src, dst);
1397}
1398
1399
1400void Assembler::bts(const Operand& dst, Register src) {
1401 EnsureSpace ensure_space(this);
1402 last_pc_ = pc_;
1403 EMIT(0x0F);
1404 EMIT(0xAB);
1405 emit_operand(src, dst);
1406}
1407
1408
1409void Assembler::hlt() {
1410 EnsureSpace ensure_space(this);
1411 last_pc_ = pc_;
1412 EMIT(0xF4);
1413}
1414
1415
1416void Assembler::int3() {
1417 EnsureSpace ensure_space(this);
1418 last_pc_ = pc_;
1419 EMIT(0xCC);
1420}
1421
1422
1423void Assembler::nop() {
1424 EnsureSpace ensure_space(this);
1425 last_pc_ = pc_;
1426 EMIT(0x90);
1427}
1428
1429
1430void Assembler::rdtsc() {
Steve Blockd0582a62009-12-15 09:54:21 +00001431 ASSERT(CpuFeatures::IsEnabled(RDTSC));
Steve Blocka7e24c12009-10-30 11:49:00 +00001432 EnsureSpace ensure_space(this);
1433 last_pc_ = pc_;
1434 EMIT(0x0F);
1435 EMIT(0x31);
1436}
1437
1438
1439void Assembler::ret(int imm16) {
1440 EnsureSpace ensure_space(this);
1441 last_pc_ = pc_;
1442 ASSERT(is_uint16(imm16));
1443 if (imm16 == 0) {
1444 EMIT(0xC3);
1445 } else {
1446 EMIT(0xC2);
1447 EMIT(imm16 & 0xFF);
1448 EMIT((imm16 >> 8) & 0xFF);
1449 }
1450}
1451
1452
1453// Labels refer to positions in the (to be) generated code.
1454// There are bound, linked, and unused labels.
1455//
1456// Bound labels refer to known positions in the already
1457// generated code. pos() is the position the label refers to.
1458//
1459// Linked labels refer to unknown positions in the code
1460// to be generated; pos() is the position of the 32bit
1461// Displacement of the last instruction using the label.
1462
1463
1464void Assembler::print(Label* L) {
1465 if (L->is_unused()) {
1466 PrintF("unused label\n");
1467 } else if (L->is_bound()) {
1468 PrintF("bound label to %d\n", L->pos());
1469 } else if (L->is_linked()) {
1470 Label l = *L;
1471 PrintF("unbound label");
1472 while (l.is_linked()) {
1473 Displacement disp = disp_at(&l);
1474 PrintF("@ %d ", l.pos());
1475 disp.print();
1476 PrintF("\n");
1477 disp.next(&l);
1478 }
1479 } else {
1480 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
1481 }
1482}
1483
1484
1485void Assembler::bind_to(Label* L, int pos) {
1486 EnsureSpace ensure_space(this);
1487 last_pc_ = NULL;
1488 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
1489 while (L->is_linked()) {
1490 Displacement disp = disp_at(L);
1491 int fixup_pos = L->pos();
1492 if (disp.type() == Displacement::CODE_RELATIVE) {
1493 // Relative to Code* heap object pointer.
1494 long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag);
1495 } else {
1496 if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
1497 ASSERT(byte_at(fixup_pos - 1) == 0xE9); // jmp expected
1498 }
Andrei Popescu31002712010-02-23 13:46:05 +00001499 // Relative address, relative to point after address.
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 int imm32 = pos - (fixup_pos + sizeof(int32_t));
1501 long_at_put(fixup_pos, imm32);
1502 }
1503 disp.next(L);
1504 }
1505 L->bind_to(pos);
1506}
1507
1508
1509void Assembler::link_to(Label* L, Label* appendix) {
1510 EnsureSpace ensure_space(this);
1511 last_pc_ = NULL;
1512 if (appendix->is_linked()) {
1513 if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001514 // Append appendix to L's list.
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 Label p;
1516 Label q = *L;
1517 do {
1518 p = q;
1519 Displacement disp = disp_at(&q);
1520 disp.next(&q);
1521 } while (q.is_linked());
1522 Displacement disp = disp_at(&p);
1523 disp.link_to(appendix);
1524 disp_at_put(&p, disp);
1525 p.Unuse(); // to avoid assertion failure in ~Label
1526 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001527 // L is empty, simply use appendix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001528 *L = *appendix;
1529 }
1530 }
1531 appendix->Unuse(); // appendix should not be used anymore
1532}
1533
1534
1535void Assembler::bind(Label* L) {
1536 EnsureSpace ensure_space(this);
1537 last_pc_ = NULL;
1538 ASSERT(!L->is_bound()); // label can only be bound once
1539 bind_to(L, pc_offset());
1540}
1541
1542
1543void Assembler::call(Label* L) {
1544 EnsureSpace ensure_space(this);
1545 last_pc_ = pc_;
1546 if (L->is_bound()) {
1547 const int long_size = 5;
1548 int offs = L->pos() - pc_offset();
1549 ASSERT(offs <= 0);
Andrei Popescu31002712010-02-23 13:46:05 +00001550 // 1110 1000 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 EMIT(0xE8);
1552 emit(offs - long_size);
1553 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001554 // 1110 1000 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 EMIT(0xE8);
1556 emit_disp(L, Displacement::OTHER);
1557 }
1558}
1559
1560
1561void Assembler::call(byte* entry, RelocInfo::Mode rmode) {
1562 EnsureSpace ensure_space(this);
1563 last_pc_ = pc_;
1564 ASSERT(!RelocInfo::IsCodeTarget(rmode));
1565 EMIT(0xE8);
1566 emit(entry - (pc_ + sizeof(int32_t)), rmode);
1567}
1568
1569
1570void Assembler::call(const Operand& adr) {
1571 EnsureSpace ensure_space(this);
1572 last_pc_ = pc_;
1573 EMIT(0xFF);
1574 emit_operand(edx, adr);
1575}
1576
1577
1578void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
1579 WriteRecordedPositions();
1580 EnsureSpace ensure_space(this);
1581 last_pc_ = pc_;
1582 ASSERT(RelocInfo::IsCodeTarget(rmode));
1583 EMIT(0xE8);
1584 emit(reinterpret_cast<intptr_t>(code.location()), rmode);
1585}
1586
1587
1588void Assembler::jmp(Label* L) {
1589 EnsureSpace ensure_space(this);
1590 last_pc_ = pc_;
1591 if (L->is_bound()) {
1592 const int short_size = 2;
1593 const int long_size = 5;
1594 int offs = L->pos() - pc_offset();
1595 ASSERT(offs <= 0);
1596 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001597 // 1110 1011 #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001598 EMIT(0xEB);
1599 EMIT((offs - short_size) & 0xFF);
1600 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001601 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 EMIT(0xE9);
1603 emit(offs - long_size);
1604 }
1605 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001606 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 EMIT(0xE9);
1608 emit_disp(L, Displacement::UNCONDITIONAL_JUMP);
1609 }
1610}
1611
1612
1613void Assembler::jmp(byte* entry, RelocInfo::Mode rmode) {
1614 EnsureSpace ensure_space(this);
1615 last_pc_ = pc_;
1616 ASSERT(!RelocInfo::IsCodeTarget(rmode));
1617 EMIT(0xE9);
1618 emit(entry - (pc_ + sizeof(int32_t)), rmode);
1619}
1620
1621
1622void Assembler::jmp(const Operand& adr) {
1623 EnsureSpace ensure_space(this);
1624 last_pc_ = pc_;
1625 EMIT(0xFF);
1626 emit_operand(esp, adr);
1627}
1628
1629
1630void Assembler::jmp(Handle<Code> code, RelocInfo::Mode rmode) {
1631 EnsureSpace ensure_space(this);
1632 last_pc_ = pc_;
1633 ASSERT(RelocInfo::IsCodeTarget(rmode));
1634 EMIT(0xE9);
1635 emit(reinterpret_cast<intptr_t>(code.location()), rmode);
1636}
1637
1638
1639
1640void Assembler::j(Condition cc, Label* L, Hint hint) {
1641 EnsureSpace ensure_space(this);
1642 last_pc_ = pc_;
1643 ASSERT(0 <= cc && cc < 16);
1644 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
1645 if (L->is_bound()) {
1646 const int short_size = 2;
1647 const int long_size = 6;
1648 int offs = L->pos() - pc_offset();
1649 ASSERT(offs <= 0);
1650 if (is_int8(offs - short_size)) {
1651 // 0111 tttn #8-bit disp
1652 EMIT(0x70 | cc);
1653 EMIT((offs - short_size) & 0xFF);
1654 } else {
1655 // 0000 1111 1000 tttn #32-bit disp
1656 EMIT(0x0F);
1657 EMIT(0x80 | cc);
1658 emit(offs - long_size);
1659 }
1660 } else {
1661 // 0000 1111 1000 tttn #32-bit disp
1662 // Note: could eliminate cond. jumps to this jump if condition
1663 // is the same however, seems to be rather unlikely case.
1664 EMIT(0x0F);
1665 EMIT(0x80 | cc);
1666 emit_disp(L, Displacement::OTHER);
1667 }
1668}
1669
1670
1671void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint) {
1672 EnsureSpace ensure_space(this);
1673 last_pc_ = pc_;
1674 ASSERT((0 <= cc) && (cc < 16));
1675 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
Andrei Popescu31002712010-02-23 13:46:05 +00001676 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001677 EMIT(0x0F);
1678 EMIT(0x80 | cc);
1679 emit(entry - (pc_ + sizeof(int32_t)), rmode);
1680}
1681
1682
1683void Assembler::j(Condition cc, Handle<Code> code, Hint hint) {
1684 EnsureSpace ensure_space(this);
1685 last_pc_ = pc_;
1686 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
1687 // 0000 1111 1000 tttn #32-bit disp
1688 EMIT(0x0F);
1689 EMIT(0x80 | cc);
1690 emit(reinterpret_cast<intptr_t>(code.location()), RelocInfo::CODE_TARGET);
1691}
1692
1693
Andrei Popescu31002712010-02-23 13:46:05 +00001694// FPU instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001695
Steve Blocka7e24c12009-10-30 11:49:00 +00001696void Assembler::fld(int i) {
1697 EnsureSpace ensure_space(this);
1698 last_pc_ = pc_;
1699 emit_farith(0xD9, 0xC0, i);
1700}
1701
1702
Andrei Popescu402d9372010-02-26 13:31:12 +00001703void Assembler::fstp(int i) {
1704 EnsureSpace ensure_space(this);
1705 last_pc_ = pc_;
1706 emit_farith(0xDD, 0xD8, i);
1707}
1708
1709
Steve Blocka7e24c12009-10-30 11:49:00 +00001710void Assembler::fld1() {
1711 EnsureSpace ensure_space(this);
1712 last_pc_ = pc_;
1713 EMIT(0xD9);
1714 EMIT(0xE8);
1715}
1716
1717
Andrei Popescu402d9372010-02-26 13:31:12 +00001718void Assembler::fldpi() {
1719 EnsureSpace ensure_space(this);
1720 last_pc_ = pc_;
1721 EMIT(0xD9);
1722 EMIT(0xEB);
1723}
1724
1725
Steve Blocka7e24c12009-10-30 11:49:00 +00001726void Assembler::fldz() {
1727 EnsureSpace ensure_space(this);
1728 last_pc_ = pc_;
1729 EMIT(0xD9);
1730 EMIT(0xEE);
1731}
1732
1733
1734void Assembler::fld_s(const Operand& adr) {
1735 EnsureSpace ensure_space(this);
1736 last_pc_ = pc_;
1737 EMIT(0xD9);
1738 emit_operand(eax, adr);
1739}
1740
1741
1742void Assembler::fld_d(const Operand& adr) {
1743 EnsureSpace ensure_space(this);
1744 last_pc_ = pc_;
1745 EMIT(0xDD);
1746 emit_operand(eax, adr);
1747}
1748
1749
1750void Assembler::fstp_s(const Operand& adr) {
1751 EnsureSpace ensure_space(this);
1752 last_pc_ = pc_;
1753 EMIT(0xD9);
1754 emit_operand(ebx, adr);
1755}
1756
1757
1758void Assembler::fstp_d(const Operand& adr) {
1759 EnsureSpace ensure_space(this);
1760 last_pc_ = pc_;
1761 EMIT(0xDD);
1762 emit_operand(ebx, adr);
1763}
1764
1765
Andrei Popescu402d9372010-02-26 13:31:12 +00001766void Assembler::fst_d(const Operand& adr) {
1767 EnsureSpace ensure_space(this);
1768 last_pc_ = pc_;
1769 EMIT(0xDD);
1770 emit_operand(edx, adr);
1771}
1772
1773
Steve Blocka7e24c12009-10-30 11:49:00 +00001774void Assembler::fild_s(const Operand& adr) {
1775 EnsureSpace ensure_space(this);
1776 last_pc_ = pc_;
1777 EMIT(0xDB);
1778 emit_operand(eax, adr);
1779}
1780
1781
1782void Assembler::fild_d(const Operand& adr) {
1783 EnsureSpace ensure_space(this);
1784 last_pc_ = pc_;
1785 EMIT(0xDF);
1786 emit_operand(ebp, adr);
1787}
1788
1789
1790void Assembler::fistp_s(const Operand& adr) {
1791 EnsureSpace ensure_space(this);
1792 last_pc_ = pc_;
1793 EMIT(0xDB);
1794 emit_operand(ebx, adr);
1795}
1796
1797
1798void Assembler::fisttp_s(const Operand& adr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001799 ASSERT(CpuFeatures::IsEnabled(SSE3));
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 EnsureSpace ensure_space(this);
1801 last_pc_ = pc_;
1802 EMIT(0xDB);
1803 emit_operand(ecx, adr);
1804}
1805
1806
Leon Clarkee46be812010-01-19 14:06:41 +00001807void Assembler::fisttp_d(const Operand& adr) {
1808 ASSERT(CpuFeatures::IsEnabled(SSE3));
1809 EnsureSpace ensure_space(this);
1810 last_pc_ = pc_;
1811 EMIT(0xDD);
1812 emit_operand(ecx, adr);
1813}
1814
1815
Steve Blocka7e24c12009-10-30 11:49:00 +00001816void Assembler::fist_s(const Operand& adr) {
1817 EnsureSpace ensure_space(this);
1818 last_pc_ = pc_;
1819 EMIT(0xDB);
1820 emit_operand(edx, adr);
1821}
1822
1823
1824void Assembler::fistp_d(const Operand& adr) {
1825 EnsureSpace ensure_space(this);
1826 last_pc_ = pc_;
1827 EMIT(0xDF);
1828 emit_operand(edi, adr);
1829}
1830
1831
1832void Assembler::fabs() {
1833 EnsureSpace ensure_space(this);
1834 last_pc_ = pc_;
1835 EMIT(0xD9);
1836 EMIT(0xE1);
1837}
1838
1839
1840void Assembler::fchs() {
1841 EnsureSpace ensure_space(this);
1842 last_pc_ = pc_;
1843 EMIT(0xD9);
1844 EMIT(0xE0);
1845}
1846
1847
1848void Assembler::fcos() {
1849 EnsureSpace ensure_space(this);
1850 last_pc_ = pc_;
1851 EMIT(0xD9);
1852 EMIT(0xFF);
1853}
1854
1855
1856void Assembler::fsin() {
1857 EnsureSpace ensure_space(this);
1858 last_pc_ = pc_;
1859 EMIT(0xD9);
1860 EMIT(0xFE);
1861}
1862
1863
1864void Assembler::fadd(int i) {
1865 EnsureSpace ensure_space(this);
1866 last_pc_ = pc_;
1867 emit_farith(0xDC, 0xC0, i);
1868}
1869
1870
1871void Assembler::fsub(int i) {
1872 EnsureSpace ensure_space(this);
1873 last_pc_ = pc_;
1874 emit_farith(0xDC, 0xE8, i);
1875}
1876
1877
1878void Assembler::fisub_s(const Operand& adr) {
1879 EnsureSpace ensure_space(this);
1880 last_pc_ = pc_;
1881 EMIT(0xDA);
1882 emit_operand(esp, adr);
1883}
1884
1885
1886void Assembler::fmul(int i) {
1887 EnsureSpace ensure_space(this);
1888 last_pc_ = pc_;
1889 emit_farith(0xDC, 0xC8, i);
1890}
1891
1892
1893void Assembler::fdiv(int i) {
1894 EnsureSpace ensure_space(this);
1895 last_pc_ = pc_;
1896 emit_farith(0xDC, 0xF8, i);
1897}
1898
1899
1900void Assembler::faddp(int i) {
1901 EnsureSpace ensure_space(this);
1902 last_pc_ = pc_;
1903 emit_farith(0xDE, 0xC0, i);
1904}
1905
1906
1907void Assembler::fsubp(int i) {
1908 EnsureSpace ensure_space(this);
1909 last_pc_ = pc_;
1910 emit_farith(0xDE, 0xE8, i);
1911}
1912
1913
1914void Assembler::fsubrp(int i) {
1915 EnsureSpace ensure_space(this);
1916 last_pc_ = pc_;
1917 emit_farith(0xDE, 0xE0, i);
1918}
1919
1920
1921void Assembler::fmulp(int i) {
1922 EnsureSpace ensure_space(this);
1923 last_pc_ = pc_;
1924 emit_farith(0xDE, 0xC8, i);
1925}
1926
1927
1928void Assembler::fdivp(int i) {
1929 EnsureSpace ensure_space(this);
1930 last_pc_ = pc_;
1931 emit_farith(0xDE, 0xF8, i);
1932}
1933
1934
1935void Assembler::fprem() {
1936 EnsureSpace ensure_space(this);
1937 last_pc_ = pc_;
1938 EMIT(0xD9);
1939 EMIT(0xF8);
1940}
1941
1942
1943void Assembler::fprem1() {
1944 EnsureSpace ensure_space(this);
1945 last_pc_ = pc_;
1946 EMIT(0xD9);
1947 EMIT(0xF5);
1948}
1949
1950
1951void Assembler::fxch(int i) {
1952 EnsureSpace ensure_space(this);
1953 last_pc_ = pc_;
1954 emit_farith(0xD9, 0xC8, i);
1955}
1956
1957
1958void Assembler::fincstp() {
1959 EnsureSpace ensure_space(this);
1960 last_pc_ = pc_;
1961 EMIT(0xD9);
1962 EMIT(0xF7);
1963}
1964
1965
1966void Assembler::ffree(int i) {
1967 EnsureSpace ensure_space(this);
1968 last_pc_ = pc_;
1969 emit_farith(0xDD, 0xC0, i);
1970}
1971
1972
1973void Assembler::ftst() {
1974 EnsureSpace ensure_space(this);
1975 last_pc_ = pc_;
1976 EMIT(0xD9);
1977 EMIT(0xE4);
1978}
1979
1980
1981void Assembler::fucomp(int i) {
1982 EnsureSpace ensure_space(this);
1983 last_pc_ = pc_;
1984 emit_farith(0xDD, 0xE8, i);
1985}
1986
1987
1988void Assembler::fucompp() {
1989 EnsureSpace ensure_space(this);
1990 last_pc_ = pc_;
1991 EMIT(0xDA);
1992 EMIT(0xE9);
1993}
1994
1995
Steve Block3ce2e202009-11-05 08:53:23 +00001996void Assembler::fucomi(int i) {
1997 EnsureSpace ensure_space(this);
1998 last_pc_ = pc_;
1999 EMIT(0xDB);
2000 EMIT(0xE8 + i);
2001}
2002
2003
2004void Assembler::fucomip() {
2005 EnsureSpace ensure_space(this);
2006 last_pc_ = pc_;
2007 EMIT(0xDF);
2008 EMIT(0xE9);
2009}
2010
2011
Steve Blocka7e24c12009-10-30 11:49:00 +00002012void Assembler::fcompp() {
2013 EnsureSpace ensure_space(this);
2014 last_pc_ = pc_;
2015 EMIT(0xDE);
2016 EMIT(0xD9);
2017}
2018
2019
2020void Assembler::fnstsw_ax() {
2021 EnsureSpace ensure_space(this);
2022 last_pc_ = pc_;
2023 EMIT(0xDF);
2024 EMIT(0xE0);
2025}
2026
2027
2028void Assembler::fwait() {
2029 EnsureSpace ensure_space(this);
2030 last_pc_ = pc_;
2031 EMIT(0x9B);
2032}
2033
2034
2035void Assembler::frndint() {
2036 EnsureSpace ensure_space(this);
2037 last_pc_ = pc_;
2038 EMIT(0xD9);
2039 EMIT(0xFC);
2040}
2041
2042
2043void Assembler::fnclex() {
2044 EnsureSpace ensure_space(this);
2045 last_pc_ = pc_;
2046 EMIT(0xDB);
2047 EMIT(0xE2);
2048}
2049
2050
2051void Assembler::sahf() {
2052 EnsureSpace ensure_space(this);
2053 last_pc_ = pc_;
2054 EMIT(0x9E);
2055}
2056
2057
2058void Assembler::setcc(Condition cc, Register reg) {
2059 ASSERT(reg.is_byte_register());
2060 EnsureSpace ensure_space(this);
2061 last_pc_ = pc_;
2062 EMIT(0x0F);
2063 EMIT(0x90 | cc);
2064 EMIT(0xC0 | reg.code());
2065}
2066
2067
2068void Assembler::cvttss2si(Register dst, const Operand& src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002069 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002070 EnsureSpace ensure_space(this);
2071 last_pc_ = pc_;
2072 EMIT(0xF3);
2073 EMIT(0x0F);
2074 EMIT(0x2C);
2075 emit_operand(dst, src);
2076}
2077
2078
2079void Assembler::cvttsd2si(Register dst, const Operand& src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002080 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002081 EnsureSpace ensure_space(this);
2082 last_pc_ = pc_;
2083 EMIT(0xF2);
2084 EMIT(0x0F);
2085 EMIT(0x2C);
2086 emit_operand(dst, src);
2087}
2088
2089
2090void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002091 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002092 EnsureSpace ensure_space(this);
2093 last_pc_ = pc_;
2094 EMIT(0xF2);
2095 EMIT(0x0F);
2096 EMIT(0x2A);
2097 emit_sse_operand(dst, src);
2098}
2099
2100
Steve Block6ded16b2010-05-10 14:33:55 +01002101void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
2102 ASSERT(CpuFeatures::IsEnabled(SSE2));
2103 EnsureSpace ensure_space(this);
2104 last_pc_ = pc_;
2105 EMIT(0xF3);
2106 EMIT(0x0F);
2107 EMIT(0x5A);
2108 emit_sse_operand(dst, src);
2109}
2110
2111
Steve Blocka7e24c12009-10-30 11:49:00 +00002112void Assembler::addsd(XMMRegister dst, XMMRegister src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002113 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002114 EnsureSpace ensure_space(this);
2115 last_pc_ = pc_;
2116 EMIT(0xF2);
2117 EMIT(0x0F);
2118 EMIT(0x58);
2119 emit_sse_operand(dst, src);
2120}
2121
2122
2123void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002124 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002125 EnsureSpace ensure_space(this);
2126 last_pc_ = pc_;
2127 EMIT(0xF2);
2128 EMIT(0x0F);
2129 EMIT(0x59);
2130 emit_sse_operand(dst, src);
2131}
2132
2133
2134void Assembler::subsd(XMMRegister dst, XMMRegister src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002135 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002136 EnsureSpace ensure_space(this);
2137 last_pc_ = pc_;
2138 EMIT(0xF2);
2139 EMIT(0x0F);
2140 EMIT(0x5C);
2141 emit_sse_operand(dst, src);
2142}
2143
2144
2145void Assembler::divsd(XMMRegister dst, XMMRegister src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002146 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002147 EnsureSpace ensure_space(this);
2148 last_pc_ = pc_;
2149 EMIT(0xF2);
2150 EMIT(0x0F);
2151 EMIT(0x5E);
2152 emit_sse_operand(dst, src);
2153}
2154
2155
Leon Clarkee46be812010-01-19 14:06:41 +00002156void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
2157 ASSERT(CpuFeatures::IsEnabled(SSE2));
2158 EnsureSpace ensure_space(this);
2159 last_pc_ = pc_;
2160 EMIT(0x66);
2161 EMIT(0x0F);
2162 EMIT(0x57);
2163 emit_sse_operand(dst, src);
2164}
2165
2166
Steve Block6ded16b2010-05-10 14:33:55 +01002167void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
2168 EnsureSpace ensure_space(this);
2169 last_pc_ = pc_;
2170 EMIT(0xF2);
2171 EMIT(0x0F);
2172 EMIT(0x51);
2173 emit_sse_operand(dst, src);
2174}
2175
2176
Steve Block6ded16b2010-05-10 14:33:55 +01002177void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
2178 ASSERT(CpuFeatures::IsEnabled(SSE2));
2179 EnsureSpace ensure_space(this);
2180 last_pc_ = pc_;
2181 EMIT(0x66);
2182 EMIT(0x0F);
2183 EMIT(0x2E);
2184 emit_sse_operand(dst, src);
2185}
2186
2187
2188void Assembler::movmskpd(Register dst, XMMRegister src) {
2189 ASSERT(CpuFeatures::IsEnabled(SSE2));
2190 EnsureSpace ensure_space(this);
2191 last_pc_ = pc_;
2192 EMIT(0x66);
2193 EMIT(0x0F);
2194 EMIT(0x50);
2195 emit_sse_operand(dst, src);
2196}
2197
2198
Leon Clarkee46be812010-01-19 14:06:41 +00002199void Assembler::movdqa(const Operand& dst, XMMRegister src ) {
2200 ASSERT(CpuFeatures::IsEnabled(SSE2));
2201 EnsureSpace ensure_space(this);
2202 last_pc_ = pc_;
2203 EMIT(0x66);
2204 EMIT(0x0F);
2205 EMIT(0x7F);
2206 emit_sse_operand(src, dst);
2207}
2208
2209
2210void Assembler::movdqa(XMMRegister dst, const Operand& src) {
2211 ASSERT(CpuFeatures::IsEnabled(SSE2));
2212 EnsureSpace ensure_space(this);
2213 last_pc_ = pc_;
2214 EMIT(0x66);
2215 EMIT(0x0F);
2216 EMIT(0x6F);
2217 emit_sse_operand(dst, src);
2218}
2219
2220
2221void Assembler::movdqu(const Operand& dst, XMMRegister src ) {
2222 ASSERT(CpuFeatures::IsEnabled(SSE2));
2223 EnsureSpace ensure_space(this);
2224 last_pc_ = pc_;
2225 EMIT(0xF3);
2226 EMIT(0x0F);
2227 EMIT(0x7F);
2228 emit_sse_operand(src, dst);
2229}
2230
2231
2232void Assembler::movdqu(XMMRegister dst, const Operand& src) {
2233 ASSERT(CpuFeatures::IsEnabled(SSE2));
2234 EnsureSpace ensure_space(this);
2235 last_pc_ = pc_;
2236 EMIT(0xF3);
2237 EMIT(0x0F);
2238 EMIT(0x6F);
2239 emit_sse_operand(dst, src);
2240}
2241
2242
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002243void Assembler::movntdqa(XMMRegister dst, const Operand& src) {
2244 ASSERT(CpuFeatures::IsEnabled(SSE4_1));
2245 EnsureSpace ensure_space(this);
2246 last_pc_ = pc_;
2247 EMIT(0x66);
2248 EMIT(0x0F);
2249 EMIT(0x38);
2250 EMIT(0x2A);
2251 emit_sse_operand(dst, src);
2252}
2253
2254
2255void Assembler::movntdq(const Operand& dst, XMMRegister src) {
2256 ASSERT(CpuFeatures::IsEnabled(SSE2));
2257 EnsureSpace ensure_space(this);
2258 last_pc_ = pc_;
2259 EMIT(0x66);
2260 EMIT(0x0F);
2261 EMIT(0xE7);
2262 emit_sse_operand(src, dst);
2263}
2264
2265
2266void Assembler::prefetch(const Operand& src, int level) {
2267 ASSERT(is_uint2(level));
2268 EnsureSpace ensure_space(this);
2269 last_pc_ = pc_;
2270 EMIT(0x0F);
2271 EMIT(0x18);
2272 XMMRegister code = { level }; // Emit hint number in Reg position of RegR/M.
2273 emit_sse_operand(code, src);
2274}
2275
2276
Steve Blocka7e24c12009-10-30 11:49:00 +00002277void Assembler::movdbl(XMMRegister dst, const Operand& src) {
2278 EnsureSpace ensure_space(this);
2279 last_pc_ = pc_;
2280 movsd(dst, src);
2281}
2282
2283
2284void Assembler::movdbl(const Operand& dst, XMMRegister src) {
2285 EnsureSpace ensure_space(this);
2286 last_pc_ = pc_;
2287 movsd(dst, src);
2288}
2289
2290
2291void Assembler::movsd(const Operand& dst, XMMRegister src ) {
Steve Blockd0582a62009-12-15 09:54:21 +00002292 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 EnsureSpace ensure_space(this);
2294 last_pc_ = pc_;
2295 EMIT(0xF2); // double
2296 EMIT(0x0F);
2297 EMIT(0x11); // store
2298 emit_sse_operand(src, dst);
2299}
2300
2301
2302void Assembler::movsd(XMMRegister dst, const Operand& src) {
Steve Blockd0582a62009-12-15 09:54:21 +00002303 ASSERT(CpuFeatures::IsEnabled(SSE2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002304 EnsureSpace ensure_space(this);
2305 last_pc_ = pc_;
2306 EMIT(0xF2); // double
2307 EMIT(0x0F);
2308 EMIT(0x10); // load
2309 emit_sse_operand(dst, src);
2310}
2311
Steve Block6ded16b2010-05-10 14:33:55 +01002312void Assembler::movsd(XMMRegister dst, XMMRegister src) {
2313 ASSERT(CpuFeatures::IsEnabled(SSE2));
2314 EnsureSpace ensure_space(this);
2315 last_pc_ = pc_;
2316 EMIT(0xF2);
2317 EMIT(0x0F);
2318 EMIT(0x10);
2319 emit_sse_operand(dst, src);
2320}
2321
2322
2323void Assembler::movd(XMMRegister dst, const Operand& src) {
2324 ASSERT(CpuFeatures::IsEnabled(SSE2));
2325 EnsureSpace ensure_space(this);
2326 last_pc_ = pc_;
2327 EMIT(0x66);
2328 EMIT(0x0F);
2329 EMIT(0x6E);
2330 emit_sse_operand(dst, src);
2331}
2332
2333
2334void Assembler::pxor(XMMRegister dst, XMMRegister src) {
2335 ASSERT(CpuFeatures::IsEnabled(SSE2));
2336 EnsureSpace ensure_space(this);
2337 last_pc_ = pc_;
2338 EMIT(0x66);
2339 EMIT(0x0F);
2340 EMIT(0xEF);
2341 emit_sse_operand(dst, src);
2342}
2343
2344
2345void Assembler::ptest(XMMRegister dst, XMMRegister src) {
2346 ASSERT(CpuFeatures::IsEnabled(SSE2));
2347 EnsureSpace ensure_space(this);
2348 last_pc_ = pc_;
2349 EMIT(0x66);
2350 EMIT(0x0F);
2351 EMIT(0x38);
2352 EMIT(0x17);
2353 emit_sse_operand(dst, src);
2354}
2355
Steve Blocka7e24c12009-10-30 11:49:00 +00002356void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
2357 Register ireg = { reg.code() };
2358 emit_operand(ireg, adr);
2359}
2360
2361
2362void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) {
2363 EMIT(0xC0 | dst.code() << 3 | src.code());
2364}
2365
2366
Steve Block6ded16b2010-05-10 14:33:55 +01002367void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
2368 EMIT(0xC0 | dst.code() << 3 | src.code());
2369}
2370
2371
Steve Blocka7e24c12009-10-30 11:49:00 +00002372void Assembler::Print() {
2373 Disassembler::Decode(stdout, buffer_, pc_);
2374}
2375
2376
2377void Assembler::RecordJSReturn() {
2378 WriteRecordedPositions();
2379 EnsureSpace ensure_space(this);
2380 RecordRelocInfo(RelocInfo::JS_RETURN);
2381}
2382
2383
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002384void Assembler::RecordDebugBreakSlot() {
2385 WriteRecordedPositions();
2386 EnsureSpace ensure_space(this);
2387 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2388}
2389
2390
Steve Blocka7e24c12009-10-30 11:49:00 +00002391void Assembler::RecordComment(const char* msg) {
2392 if (FLAG_debug_code) {
2393 EnsureSpace ensure_space(this);
2394 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2395 }
2396}
2397
2398
2399void Assembler::RecordPosition(int pos) {
2400 ASSERT(pos != RelocInfo::kNoPosition);
2401 ASSERT(pos >= 0);
2402 current_position_ = pos;
2403}
2404
2405
2406void Assembler::RecordStatementPosition(int pos) {
2407 ASSERT(pos != RelocInfo::kNoPosition);
2408 ASSERT(pos >= 0);
2409 current_statement_position_ = pos;
2410}
2411
2412
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002413bool Assembler::WriteRecordedPositions() {
2414 bool written = false;
2415
Steve Blocka7e24c12009-10-30 11:49:00 +00002416 // Write the statement position if it is different from what was written last
2417 // time.
2418 if (current_statement_position_ != written_statement_position_) {
2419 EnsureSpace ensure_space(this);
2420 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
2421 written_statement_position_ = current_statement_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002422 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002423 }
2424
2425 // Write the position if it is different from what was written last time and
2426 // also different from the written statement position.
2427 if (current_position_ != written_position_ &&
2428 current_position_ != written_statement_position_) {
2429 EnsureSpace ensure_space(this);
2430 RecordRelocInfo(RelocInfo::POSITION, current_position_);
2431 written_position_ = current_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002432 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002433 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002434
2435 // Return whether something was written.
2436 return written;
Steve Blocka7e24c12009-10-30 11:49:00 +00002437}
2438
2439
2440void Assembler::GrowBuffer() {
Andrei Popescu31002712010-02-23 13:46:05 +00002441 ASSERT(overflow());
Steve Blocka7e24c12009-10-30 11:49:00 +00002442 if (!own_buffer_) FATAL("external code buffer is too small");
2443
Andrei Popescu31002712010-02-23 13:46:05 +00002444 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +00002445 CodeDesc desc; // the new buffer
2446 if (buffer_size_ < 4*KB) {
2447 desc.buffer_size = 4*KB;
2448 } else {
2449 desc.buffer_size = 2*buffer_size_;
2450 }
2451 // Some internal data structures overflow for very large buffers,
2452 // they must ensure that kMaximalBufferSize is not too large.
2453 if ((desc.buffer_size > kMaximalBufferSize) ||
Steve Block3ce2e202009-11-05 08:53:23 +00002454 (desc.buffer_size > Heap::MaxOldGenerationSize())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002455 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
2456 }
2457
Andrei Popescu31002712010-02-23 13:46:05 +00002458 // Setup new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +00002459 desc.buffer = NewArray<byte>(desc.buffer_size);
2460 desc.instr_size = pc_offset();
2461 desc.reloc_size = (buffer_ + buffer_size_) - (reloc_info_writer.pos());
2462
2463 // Clear the buffer in debug mode. Use 'int3' instructions to make
2464 // sure to get into problems if we ever run uninitialized code.
2465#ifdef DEBUG
2466 memset(desc.buffer, 0xCC, desc.buffer_size);
2467#endif
2468
Andrei Popescu31002712010-02-23 13:46:05 +00002469 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +00002470 int pc_delta = desc.buffer - buffer_;
2471 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
2472 memmove(desc.buffer, buffer_, desc.instr_size);
2473 memmove(rc_delta + reloc_info_writer.pos(),
2474 reloc_info_writer.pos(), desc.reloc_size);
2475
Andrei Popescu31002712010-02-23 13:46:05 +00002476 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +00002477 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
2478 spare_buffer_ = buffer_;
2479 } else {
2480 DeleteArray(buffer_);
2481 }
2482 buffer_ = desc.buffer;
2483 buffer_size_ = desc.buffer_size;
2484 pc_ += pc_delta;
2485 if (last_pc_ != NULL) {
2486 last_pc_ += pc_delta;
2487 }
2488 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2489 reloc_info_writer.last_pc() + pc_delta);
2490
Andrei Popescu31002712010-02-23 13:46:05 +00002491 // Relocate runtime entries.
Steve Blocka7e24c12009-10-30 11:49:00 +00002492 for (RelocIterator it(desc); !it.done(); it.next()) {
2493 RelocInfo::Mode rmode = it.rinfo()->rmode();
2494 if (rmode == RelocInfo::RUNTIME_ENTRY) {
2495 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
2496 *p -= pc_delta; // relocate entry
2497 } else if (rmode == RelocInfo::INTERNAL_REFERENCE) {
2498 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
2499 if (*p != 0) { // 0 means uninitialized.
2500 *p += pc_delta;
2501 }
2502 }
2503 }
2504
2505 ASSERT(!overflow());
2506}
2507
2508
2509void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) {
2510 ASSERT(is_uint8(op1) && is_uint8(op2)); // wrong opcode
2511 ASSERT(is_uint8(imm8));
2512 ASSERT((op1 & 0x01) == 0); // should be 8bit operation
2513 EMIT(op1);
2514 EMIT(op2 | dst.code());
2515 EMIT(imm8);
2516}
2517
2518
2519void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) {
2520 ASSERT((0 <= sel) && (sel <= 7));
2521 Register ireg = { sel };
2522 if (x.is_int8()) {
2523 EMIT(0x83); // using a sign-extended 8-bit immediate.
2524 emit_operand(ireg, dst);
2525 EMIT(x.x_ & 0xFF);
2526 } else if (dst.is_reg(eax)) {
2527 EMIT((sel << 3) | 0x05); // short form if the destination is eax.
2528 emit(x);
2529 } else {
2530 EMIT(0x81); // using a literal 32-bit immediate.
2531 emit_operand(ireg, dst);
2532 emit(x);
2533 }
2534}
2535
2536
2537void Assembler::emit_operand(Register reg, const Operand& adr) {
2538 const unsigned length = adr.len_;
2539 ASSERT(length > 0);
2540
2541 // Emit updated ModRM byte containing the given register.
2542 pc_[0] = (adr.buf_[0] & ~0x38) | (reg.code() << 3);
2543
2544 // Emit the rest of the encoded operand.
2545 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
2546 pc_ += length;
2547
2548 // Emit relocation information if necessary.
2549 if (length >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
2550 pc_ -= sizeof(int32_t); // pc_ must be *at* disp32
2551 RecordRelocInfo(adr.rmode_);
2552 pc_ += sizeof(int32_t);
2553 }
2554}
2555
2556
2557void Assembler::emit_farith(int b1, int b2, int i) {
2558 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode
2559 ASSERT(0 <= i && i < 8); // illegal stack offset
2560 EMIT(b1);
2561 EMIT(b2 + i);
2562}
2563
2564
2565void Assembler::dd(uint32_t data, RelocInfo::Mode reloc_info) {
2566 EnsureSpace ensure_space(this);
2567 emit(data, reloc_info);
2568}
2569
2570
2571void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2572 ASSERT(rmode != RelocInfo::NONE);
2573 // Don't record external references unless the heap will be serialized.
Steve Blockd0582a62009-12-15 09:54:21 +00002574 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2575#ifdef DEBUG
2576 if (!Serializer::enabled()) {
2577 Serializer::TooLateToEnableNow();
2578 }
2579#endif
2580 if (!Serializer::enabled() && !FLAG_debug_code) {
2581 return;
2582 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002583 }
2584 RelocInfo rinfo(pc_, rmode, data);
2585 reloc_info_writer.Write(&rinfo);
2586}
2587
2588
2589#ifdef GENERATED_CODE_COVERAGE
2590static FILE* coverage_log = NULL;
2591
2592
2593static void InitCoverageLog() {
2594 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
2595 if (file_name != NULL) {
2596 coverage_log = fopen(file_name, "aw+");
2597 }
2598}
2599
2600
2601void LogGeneratedCodeCoverage(const char* file_line) {
2602 const char* return_address = (&file_line)[-1];
2603 char* push_insn = const_cast<char*>(return_address - 12);
2604 push_insn[0] = 0xeb; // Relative branch insn.
2605 push_insn[1] = 13; // Skip over coverage insns.
2606 if (coverage_log != NULL) {
2607 fprintf(coverage_log, "%s\n", file_line);
2608 fflush(coverage_log);
2609 }
2610}
2611
2612#endif
2613
2614} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002615
2616#endif // V8_TARGET_ARCH_IA32