OLD | NEW |
(Empty) | |
| 1 // 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 |
| 39 #include "disassembler.h" |
| 40 #include "macro-assembler.h" |
| 41 #include "serialize.h" |
| 42 |
| 43 namespace v8 { namespace internal { |
| 44 |
| 45 // ----------------------------------------------------------------------------- |
| 46 // Implementation of Register |
| 47 |
| 48 Register eax = { 0 }; |
| 49 Register ecx = { 1 }; |
| 50 Register edx = { 2 }; |
| 51 Register ebx = { 3 }; |
| 52 Register esp = { 4 }; |
| 53 Register ebp = { 5 }; |
| 54 Register esi = { 6 }; |
| 55 Register edi = { 7 }; |
| 56 Register no_reg = { -1 }; |
| 57 |
| 58 XMMRegister xmm0 = { 0 }; |
| 59 XMMRegister xmm1 = { 1 }; |
| 60 XMMRegister xmm2 = { 2 }; |
| 61 XMMRegister xmm3 = { 3 }; |
| 62 XMMRegister xmm4 = { 4 }; |
| 63 XMMRegister xmm5 = { 5 }; |
| 64 XMMRegister xmm6 = { 6 }; |
| 65 XMMRegister xmm7 = { 7 }; |
| 66 |
| 67 |
| 68 // ----------------------------------------------------------------------------- |
| 69 // Implementation of CpuFeatures |
| 70 |
| 71 // Safe default is no features. |
| 72 uint64_t CpuFeatures::supported_ = 0; |
| 73 uint64_t CpuFeatures::enabled_ = 0; |
| 74 |
| 75 |
| 76 // The Probe method needs executable memory, so it uses Heap::CreateCode. |
| 77 // Allocation failure is silent and leads to safe default. |
| 78 void CpuFeatures::Probe() { |
| 79 ASSERT(Heap::HasBeenSetup()); |
| 80 ASSERT(supported_ == 0); |
| 81 if (Serializer::enabled()) return; // No features if we might serialize. |
| 82 |
| 83 Assembler assm(NULL, 0); |
| 84 Label cpuid, done; |
| 85 #define __ assm. |
| 86 // Save old esp, since we are going to modify the stack. |
| 87 __ push(ebp); |
| 88 __ pushfd(); |
| 89 __ push(ecx); |
| 90 __ push(ebx); |
| 91 __ mov(ebp, Operand(esp)); |
| 92 |
| 93 // If we can modify bit 21 of the EFLAGS register, then CPUID is supported. |
| 94 __ pushfd(); |
| 95 __ pop(eax); |
| 96 __ mov(edx, Operand(eax)); |
| 97 __ xor_(eax, 0x200000); // Flip bit 21. |
| 98 __ push(eax); |
| 99 __ popfd(); |
| 100 __ pushfd(); |
| 101 __ pop(eax); |
| 102 __ xor_(eax, Operand(edx)); // Different if CPUID is supported. |
| 103 __ j(not_zero, &cpuid); |
| 104 |
| 105 // CPUID not supported. Clear the supported features in edx:eax. |
| 106 __ xor_(eax, Operand(eax)); |
| 107 __ xor_(edx, Operand(edx)); |
| 108 __ jmp(&done); |
| 109 |
| 110 // Invoke CPUID with 1 in eax to get feature information in |
| 111 // ecx:edx. Temporarily enable CPUID support because we know it's |
| 112 // safe here. |
| 113 __ bind(&cpuid); |
| 114 __ mov(eax, 1); |
| 115 supported_ = (1 << CPUID); |
| 116 { Scope fscope(CPUID); |
| 117 __ cpuid(); |
| 118 } |
| 119 supported_ = 0; |
| 120 |
| 121 // Move the result from ecx:edx to edx:eax and make sure to mark the |
| 122 // CPUID feature as supported. |
| 123 __ mov(eax, Operand(edx)); |
| 124 __ or_(eax, 1 << CPUID); |
| 125 __ mov(edx, Operand(ecx)); |
| 126 |
| 127 // Done. |
| 128 __ bind(&done); |
| 129 __ mov(esp, Operand(ebp)); |
| 130 __ pop(ebx); |
| 131 __ pop(ecx); |
| 132 __ popfd(); |
| 133 __ pop(ebp); |
| 134 __ ret(0); |
| 135 #undef __ |
| 136 |
| 137 CodeDesc desc; |
| 138 assm.GetCode(&desc); |
| 139 Object* code = |
| 140 Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL); |
| 141 if (!code->IsCode()) return; |
| 142 LOG(CodeCreateEvent("Builtin", Code::cast(code), "CpuFeatures::Probe")); |
| 143 typedef uint64_t (*F0)(); |
| 144 F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry()); |
| 145 supported_ = probe(); |
| 146 } |
| 147 |
| 148 |
| 149 // ----------------------------------------------------------------------------- |
| 150 // Implementation of Displacement |
| 151 |
| 152 void Displacement::init(Label* L, Type type) { |
| 153 ASSERT(!L->is_bound()); |
| 154 int next = 0; |
| 155 if (L->is_linked()) { |
| 156 next = L->pos(); |
| 157 ASSERT(next > 0); // Displacements must be at positions > 0 |
| 158 } |
| 159 // Ensure that we _never_ overflow the next field. |
| 160 ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize)); |
| 161 data_ = NextField::encode(next) | TypeField::encode(type); |
| 162 } |
| 163 |
| 164 |
| 165 // ----------------------------------------------------------------------------- |
| 166 // Implementation of RelocInfo |
| 167 |
| 168 |
| 169 const int RelocInfo::kApplyMask = |
| 170 RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | |
| 171 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE; |
| 172 |
| 173 |
| 174 void 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 |
| 181 |
| 182 // Patch the code at the current PC with a call to the target address. |
| 183 // Additional guard int3 instructions can be added if required. |
| 184 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { |
| 185 // Call instruction takes up 5 bytes and int3 takes up one byte. |
| 186 int code_size = 5 + guard_bytes; |
| 187 |
| 188 // Patch the code. |
| 189 CodePatcher patcher(pc_, code_size); |
| 190 patcher.masm()->call(target, RelocInfo::NONE); |
| 191 |
| 192 // Add the requested number of int3 instructions after the call. |
| 193 for (int i = 0; i < guard_bytes; i++) { |
| 194 patcher.masm()->int3(); |
| 195 } |
| 196 } |
| 197 |
| 198 |
| 199 // ----------------------------------------------------------------------------- |
| 200 // Implementation of Operand |
| 201 |
| 202 Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) { |
| 203 // [base + disp/r] |
| 204 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { |
| 205 // [base] |
| 206 set_modrm(0, base); |
| 207 if (base.is(esp)) set_sib(times_1, esp, base); |
| 208 } else if (is_int8(disp) && rmode == RelocInfo::NONE) { |
| 209 // [base + disp8] |
| 210 set_modrm(1, base); |
| 211 if (base.is(esp)) set_sib(times_1, esp, base); |
| 212 set_disp8(disp); |
| 213 } else { |
| 214 // [base + disp/r] |
| 215 set_modrm(2, base); |
| 216 if (base.is(esp)) set_sib(times_1, esp, base); |
| 217 set_dispr(disp, rmode); |
| 218 } |
| 219 } |
| 220 |
| 221 |
| 222 Operand::Operand(Register base, |
| 223 Register index, |
| 224 ScaleFactor scale, |
| 225 int32_t disp, |
| 226 RelocInfo::Mode rmode) { |
| 227 ASSERT(!index.is(esp)); // illegal addressing mode |
| 228 // [base + index*scale + disp/r] |
| 229 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { |
| 230 // [base + index*scale] |
| 231 set_modrm(0, esp); |
| 232 set_sib(scale, index, base); |
| 233 } else if (is_int8(disp) && rmode == RelocInfo::NONE) { |
| 234 // [base + index*scale + disp8] |
| 235 set_modrm(1, esp); |
| 236 set_sib(scale, index, base); |
| 237 set_disp8(disp); |
| 238 } else { |
| 239 // [base + index*scale + disp/r] |
| 240 set_modrm(2, esp); |
| 241 set_sib(scale, index, base); |
| 242 set_dispr(disp, rmode); |
| 243 } |
| 244 } |
| 245 |
| 246 |
| 247 Operand::Operand(Register index, |
| 248 ScaleFactor scale, |
| 249 int32_t disp, |
| 250 RelocInfo::Mode rmode) { |
| 251 ASSERT(!index.is(esp)); // illegal addressing mode |
| 252 // [index*scale + disp/r] |
| 253 set_modrm(0, esp); |
| 254 set_sib(scale, index, ebp); |
| 255 set_dispr(disp, rmode); |
| 256 } |
| 257 |
| 258 |
| 259 void Operand::set_sib(ScaleFactor scale, Register index, Register base) { |
| 260 ASSERT(len_ == 1); |
| 261 ASSERT((scale & -4) == 0); |
| 262 buf_[1] = scale << 6 | index.code() << 3 | base.code(); |
| 263 len_ = 2; |
| 264 } |
| 265 |
| 266 |
| 267 void Operand::set_disp8(int8_t disp) { |
| 268 ASSERT(len_ == 1 || len_ == 2); |
| 269 *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp; |
| 270 } |
| 271 |
| 272 |
| 273 bool Operand::is_reg(Register reg) const { |
| 274 return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. |
| 275 && ((buf_[0] & 0x07) == reg.code()); // register codes match. |
| 276 } |
| 277 |
| 278 // ----------------------------------------------------------------------------- |
| 279 // Implementation of Assembler |
| 280 |
| 281 // Emit a single byte. Must always be inlined. |
| 282 #define EMIT(x) \ |
| 283 *pc_++ = (x) |
| 284 |
| 285 |
| 286 #ifdef GENERATED_CODE_COVERAGE |
| 287 static void InitCoverageLog(); |
| 288 #endif |
| 289 |
| 290 // spare_buffer_ |
| 291 static byte* spare_buffer_ = NULL; |
| 292 |
| 293 Assembler::Assembler(void* buffer, int buffer_size) { |
| 294 if (buffer == NULL) { |
| 295 // do our own buffer management |
| 296 if (buffer_size <= kMinimalBufferSize) { |
| 297 buffer_size = kMinimalBufferSize; |
| 298 |
| 299 if (spare_buffer_ != NULL) { |
| 300 buffer = spare_buffer_; |
| 301 spare_buffer_ = NULL; |
| 302 } |
| 303 } |
| 304 if (buffer == NULL) { |
| 305 buffer_ = NewArray<byte>(buffer_size); |
| 306 } else { |
| 307 buffer_ = static_cast<byte*>(buffer); |
| 308 } |
| 309 buffer_size_ = buffer_size; |
| 310 own_buffer_ = true; |
| 311 } else { |
| 312 // use externally provided buffer instead |
| 313 ASSERT(buffer_size > 0); |
| 314 buffer_ = static_cast<byte*>(buffer); |
| 315 buffer_size_ = buffer_size; |
| 316 own_buffer_ = false; |
| 317 } |
| 318 |
| 319 // Clear the buffer in debug mode unless it was provided by the |
| 320 // caller in which case we can't be sure it's okay to overwrite |
| 321 // existing code in it; see CodePatcher::CodePatcher(...). |
| 322 #ifdef DEBUG |
| 323 if (own_buffer_) { |
| 324 memset(buffer_, 0xCC, buffer_size); // int3 |
| 325 } |
| 326 #endif |
| 327 |
| 328 // setup buffer pointers |
| 329 ASSERT(buffer_ != NULL); |
| 330 pc_ = buffer_; |
| 331 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); |
| 332 |
| 333 last_pc_ = NULL; |
| 334 current_statement_position_ = RelocInfo::kNoPosition; |
| 335 current_position_ = RelocInfo::kNoPosition; |
| 336 written_statement_position_ = current_statement_position_; |
| 337 written_position_ = current_position_; |
| 338 #ifdef GENERATED_CODE_COVERAGE |
| 339 InitCoverageLog(); |
| 340 #endif |
| 341 } |
| 342 |
| 343 |
| 344 Assembler::~Assembler() { |
| 345 if (own_buffer_) { |
| 346 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { |
| 347 spare_buffer_ = buffer_; |
| 348 } else { |
| 349 DeleteArray(buffer_); |
| 350 } |
| 351 } |
| 352 } |
| 353 |
| 354 |
| 355 void Assembler::GetCode(CodeDesc* desc) { |
| 356 // finalize code |
| 357 // (at this point overflow() may be true, but the gap ensures that |
| 358 // we are still not overlapping instructions and relocation info) |
| 359 ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap |
| 360 // setup desc |
| 361 desc->buffer = buffer_; |
| 362 desc->buffer_size = buffer_size_; |
| 363 desc->instr_size = pc_offset(); |
| 364 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); |
| 365 desc->origin = this; |
| 366 |
| 367 Counters::reloc_info_size.Increment(desc->reloc_size); |
| 368 } |
| 369 |
| 370 |
| 371 void Assembler::Align(int m) { |
| 372 ASSERT(IsPowerOf2(m)); |
| 373 while ((pc_offset() & (m - 1)) != 0) { |
| 374 nop(); |
| 375 } |
| 376 } |
| 377 |
| 378 |
| 379 void Assembler::cpuid() { |
| 380 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID)); |
| 381 EnsureSpace ensure_space(this); |
| 382 last_pc_ = pc_; |
| 383 EMIT(0x0F); |
| 384 EMIT(0xA2); |
| 385 } |
| 386 |
| 387 |
| 388 void Assembler::pushad() { |
| 389 EnsureSpace ensure_space(this); |
| 390 last_pc_ = pc_; |
| 391 EMIT(0x60); |
| 392 } |
| 393 |
| 394 |
| 395 void Assembler::popad() { |
| 396 EnsureSpace ensure_space(this); |
| 397 last_pc_ = pc_; |
| 398 EMIT(0x61); |
| 399 } |
| 400 |
| 401 |
| 402 void Assembler::pushfd() { |
| 403 EnsureSpace ensure_space(this); |
| 404 last_pc_ = pc_; |
| 405 EMIT(0x9C); |
| 406 } |
| 407 |
| 408 |
| 409 void Assembler::popfd() { |
| 410 EnsureSpace ensure_space(this); |
| 411 last_pc_ = pc_; |
| 412 EMIT(0x9D); |
| 413 } |
| 414 |
| 415 |
| 416 void Assembler::push(const Immediate& x) { |
| 417 EnsureSpace ensure_space(this); |
| 418 last_pc_ = pc_; |
| 419 if (x.is_int8()) { |
| 420 EMIT(0x6a); |
| 421 EMIT(x.x_); |
| 422 } else { |
| 423 EMIT(0x68); |
| 424 emit(x); |
| 425 } |
| 426 } |
| 427 |
| 428 |
| 429 void Assembler::push(Register src) { |
| 430 EnsureSpace ensure_space(this); |
| 431 last_pc_ = pc_; |
| 432 EMIT(0x50 | src.code()); |
| 433 } |
| 434 |
| 435 |
| 436 void Assembler::push(const Operand& src) { |
| 437 EnsureSpace ensure_space(this); |
| 438 last_pc_ = pc_; |
| 439 EMIT(0xFF); |
| 440 emit_operand(esi, src); |
| 441 } |
| 442 |
| 443 |
| 444 void Assembler::pop(Register dst) { |
| 445 ASSERT(reloc_info_writer.last_pc() != NULL); |
| 446 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { |
| 447 // (last_pc_ != NULL) is rolled into the above check |
| 448 // If a last_pc_ is set, we need to make sure that there has not been any |
| 449 // relocation information generated between the last instruction and this |
| 450 // pop instruction. |
| 451 byte instr = last_pc_[0]; |
| 452 if ((instr & ~0x7) == 0x50) { |
| 453 int push_reg_code = instr & 0x7; |
| 454 if (push_reg_code == dst.code()) { |
| 455 pc_ = last_pc_; |
| 456 if (FLAG_print_push_pop_elimination) { |
| 457 PrintF("%d push/pop (same reg) eliminated\n", pc_offset()); |
| 458 } |
| 459 } else { |
| 460 // Convert 'push src; pop dst' to 'mov dst, src'. |
| 461 last_pc_[0] = 0x8b; |
| 462 Register src = { push_reg_code }; |
| 463 EnsureSpace ensure_space(this); |
| 464 emit_operand(dst, Operand(src)); |
| 465 if (FLAG_print_push_pop_elimination) { |
| 466 PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset()); |
| 467 } |
| 468 } |
| 469 last_pc_ = NULL; |
| 470 return; |
| 471 } else if (instr == 0xff) { // push of an operand, convert to a move |
| 472 byte op1 = last_pc_[1]; |
| 473 // Check if the operation is really a push |
| 474 if ((op1 & 0x38) == (6 << 3)) { |
| 475 op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3); |
| 476 last_pc_[0] = 0x8b; |
| 477 last_pc_[1] = op1; |
| 478 last_pc_ = NULL; |
| 479 if (FLAG_print_push_pop_elimination) { |
| 480 PrintF("%d push/pop (op->reg) eliminated\n", pc_offset()); |
| 481 } |
| 482 return; |
| 483 } |
| 484 } else if ((instr == 0x89) && |
| 485 (last_pc_[1] == 0x04) && |
| 486 (last_pc_[2] == 0x24)) { |
| 487 // 0x71283c 396 890424 mov [esp],eax |
| 488 // 0x71283f 399 58 pop eax |
| 489 if (dst.is(eax)) { |
| 490 // change to |
| 491 // 0x710fac 216 83c404 add esp,0x4 |
| 492 last_pc_[0] = 0x83; |
| 493 last_pc_[1] = 0xc4; |
| 494 last_pc_[2] = 0x04; |
| 495 last_pc_ = NULL; |
| 496 if (FLAG_print_push_pop_elimination) { |
| 497 PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset()); |
| 498 } |
| 499 return; |
| 500 } |
| 501 } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit |
| 502 byte imm8 = last_pc_[1]; |
| 503 if (imm8 == 0) { |
| 504 // 6a00 push 0x0 |
| 505 // 58 pop eax |
| 506 last_pc_[0] = 0x31; |
| 507 last_pc_[1] = 0xc0; |
| 508 // change to |
| 509 // 31c0 xor eax,eax |
| 510 last_pc_ = NULL; |
| 511 if (FLAG_print_push_pop_elimination) { |
| 512 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 513 } |
| 514 return; |
| 515 } else { |
| 516 // 6a00 push 0xXX |
| 517 // 58 pop eax |
| 518 last_pc_[0] = 0xb8; |
| 519 EnsureSpace ensure_space(this); |
| 520 if ((imm8 & 0x80) != 0) { |
| 521 EMIT(0xff); |
| 522 EMIT(0xff); |
| 523 EMIT(0xff); |
| 524 // change to |
| 525 // b8XXffffff mov eax,0xffffffXX |
| 526 } else { |
| 527 EMIT(0x00); |
| 528 EMIT(0x00); |
| 529 EMIT(0x00); |
| 530 // change to |
| 531 // b8XX000000 mov eax,0x000000XX |
| 532 } |
| 533 last_pc_ = NULL; |
| 534 if (FLAG_print_push_pop_elimination) { |
| 535 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 536 } |
| 537 return; |
| 538 } |
| 539 } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit |
| 540 // 68XXXXXXXX push 0xXXXXXXXX |
| 541 // 58 pop eax |
| 542 last_pc_[0] = 0xb8; |
| 543 last_pc_ = NULL; |
| 544 // change to |
| 545 // b8XXXXXXXX mov eax,0xXXXXXXXX |
| 546 if (FLAG_print_push_pop_elimination) { |
| 547 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 548 } |
| 549 return; |
| 550 } |
| 551 |
| 552 // Other potential patterns for peephole: |
| 553 // 0x712716 102 890424 mov [esp], eax |
| 554 // 0x712719 105 8b1424 mov edx, [esp] |
| 555 } |
| 556 EnsureSpace ensure_space(this); |
| 557 last_pc_ = pc_; |
| 558 EMIT(0x58 | dst.code()); |
| 559 } |
| 560 |
| 561 |
| 562 void Assembler::pop(const Operand& dst) { |
| 563 EnsureSpace ensure_space(this); |
| 564 last_pc_ = pc_; |
| 565 EMIT(0x8F); |
| 566 emit_operand(eax, dst); |
| 567 } |
| 568 |
| 569 |
| 570 void Assembler::enter(const Immediate& size) { |
| 571 EnsureSpace ensure_space(this); |
| 572 last_pc_ = pc_; |
| 573 EMIT(0xC8); |
| 574 emit_w(size); |
| 575 EMIT(0); |
| 576 } |
| 577 |
| 578 |
| 579 void Assembler::leave() { |
| 580 EnsureSpace ensure_space(this); |
| 581 last_pc_ = pc_; |
| 582 EMIT(0xC9); |
| 583 } |
| 584 |
| 585 |
| 586 void Assembler::mov_b(Register dst, const Operand& src) { |
| 587 EnsureSpace ensure_space(this); |
| 588 last_pc_ = pc_; |
| 589 EMIT(0x8A); |
| 590 emit_operand(dst, src); |
| 591 } |
| 592 |
| 593 |
| 594 void Assembler::mov_b(const Operand& dst, int8_t imm8) { |
| 595 EnsureSpace ensure_space(this); |
| 596 last_pc_ = pc_; |
| 597 EMIT(0xC6); |
| 598 emit_operand(eax, dst); |
| 599 EMIT(imm8); |
| 600 } |
| 601 |
| 602 |
| 603 void Assembler::mov_b(const Operand& dst, Register src) { |
| 604 EnsureSpace ensure_space(this); |
| 605 last_pc_ = pc_; |
| 606 EMIT(0x88); |
| 607 emit_operand(src, dst); |
| 608 } |
| 609 |
| 610 |
| 611 void Assembler::mov_w(Register dst, const Operand& src) { |
| 612 EnsureSpace ensure_space(this); |
| 613 last_pc_ = pc_; |
| 614 EMIT(0x66); |
| 615 EMIT(0x8B); |
| 616 emit_operand(dst, src); |
| 617 } |
| 618 |
| 619 |
| 620 void Assembler::mov_w(const Operand& dst, Register src) { |
| 621 EnsureSpace ensure_space(this); |
| 622 last_pc_ = pc_; |
| 623 EMIT(0x66); |
| 624 EMIT(0x89); |
| 625 emit_operand(src, dst); |
| 626 } |
| 627 |
| 628 |
| 629 void Assembler::mov(Register dst, int32_t imm32) { |
| 630 EnsureSpace ensure_space(this); |
| 631 last_pc_ = pc_; |
| 632 EMIT(0xB8 | dst.code()); |
| 633 emit(imm32); |
| 634 } |
| 635 |
| 636 |
| 637 void Assembler::mov(Register dst, const Immediate& x) { |
| 638 EnsureSpace ensure_space(this); |
| 639 last_pc_ = pc_; |
| 640 EMIT(0xB8 | dst.code()); |
| 641 emit(x); |
| 642 } |
| 643 |
| 644 |
| 645 void Assembler::mov(Register dst, Handle<Object> handle) { |
| 646 EnsureSpace ensure_space(this); |
| 647 last_pc_ = pc_; |
| 648 EMIT(0xB8 | dst.code()); |
| 649 emit(handle); |
| 650 } |
| 651 |
| 652 |
| 653 void Assembler::mov(Register dst, const Operand& src) { |
| 654 EnsureSpace ensure_space(this); |
| 655 last_pc_ = pc_; |
| 656 EMIT(0x8B); |
| 657 emit_operand(dst, src); |
| 658 } |
| 659 |
| 660 |
| 661 void Assembler::mov(Register dst, Register src) { |
| 662 EnsureSpace ensure_space(this); |
| 663 last_pc_ = pc_; |
| 664 EMIT(0x89); |
| 665 EMIT(0xC0 | src.code() << 3 | dst.code()); |
| 666 } |
| 667 |
| 668 |
| 669 void Assembler::mov(const Operand& dst, const Immediate& x) { |
| 670 EnsureSpace ensure_space(this); |
| 671 last_pc_ = pc_; |
| 672 EMIT(0xC7); |
| 673 emit_operand(eax, dst); |
| 674 emit(x); |
| 675 } |
| 676 |
| 677 |
| 678 void Assembler::mov(const Operand& dst, Handle<Object> handle) { |
| 679 EnsureSpace ensure_space(this); |
| 680 last_pc_ = pc_; |
| 681 EMIT(0xC7); |
| 682 emit_operand(eax, dst); |
| 683 emit(handle); |
| 684 } |
| 685 |
| 686 |
| 687 void Assembler::mov(const Operand& dst, Register src) { |
| 688 EnsureSpace ensure_space(this); |
| 689 last_pc_ = pc_; |
| 690 EMIT(0x89); |
| 691 emit_operand(src, dst); |
| 692 } |
| 693 |
| 694 |
| 695 void Assembler::movsx_b(Register dst, const Operand& src) { |
| 696 EnsureSpace ensure_space(this); |
| 697 last_pc_ = pc_; |
| 698 EMIT(0x0F); |
| 699 EMIT(0xBE); |
| 700 emit_operand(dst, src); |
| 701 } |
| 702 |
| 703 |
| 704 void Assembler::movsx_w(Register dst, const Operand& src) { |
| 705 EnsureSpace ensure_space(this); |
| 706 last_pc_ = pc_; |
| 707 EMIT(0x0F); |
| 708 EMIT(0xBF); |
| 709 emit_operand(dst, src); |
| 710 } |
| 711 |
| 712 |
| 713 void Assembler::movzx_b(Register dst, const Operand& src) { |
| 714 EnsureSpace ensure_space(this); |
| 715 last_pc_ = pc_; |
| 716 EMIT(0x0F); |
| 717 EMIT(0xB6); |
| 718 emit_operand(dst, src); |
| 719 } |
| 720 |
| 721 |
| 722 void Assembler::movzx_w(Register dst, const Operand& src) { |
| 723 EnsureSpace ensure_space(this); |
| 724 last_pc_ = pc_; |
| 725 EMIT(0x0F); |
| 726 EMIT(0xB7); |
| 727 emit_operand(dst, src); |
| 728 } |
| 729 |
| 730 |
| 731 void Assembler::cmov(Condition cc, Register dst, int32_t imm32) { |
| 732 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); |
| 733 EnsureSpace ensure_space(this); |
| 734 last_pc_ = pc_; |
| 735 UNIMPLEMENTED(); |
| 736 USE(cc); |
| 737 USE(dst); |
| 738 USE(imm32); |
| 739 } |
| 740 |
| 741 |
| 742 void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) { |
| 743 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); |
| 744 EnsureSpace ensure_space(this); |
| 745 last_pc_ = pc_; |
| 746 UNIMPLEMENTED(); |
| 747 USE(cc); |
| 748 USE(dst); |
| 749 USE(handle); |
| 750 } |
| 751 |
| 752 |
| 753 void Assembler::cmov(Condition cc, Register dst, const Operand& src) { |
| 754 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); |
| 755 EnsureSpace ensure_space(this); |
| 756 last_pc_ = pc_; |
| 757 UNIMPLEMENTED(); |
| 758 USE(cc); |
| 759 USE(dst); |
| 760 USE(src); |
| 761 } |
| 762 |
| 763 |
| 764 void Assembler::xchg(Register dst, Register src) { |
| 765 EnsureSpace ensure_space(this); |
| 766 last_pc_ = pc_; |
| 767 if (src.is(eax) || dst.is(eax)) { // Single-byte encoding |
| 768 EMIT(0x90 | (src.is(eax) ? dst.code() : src.code())); |
| 769 } else { |
| 770 EMIT(0x87); |
| 771 EMIT(0xC0 | src.code() << 3 | dst.code()); |
| 772 } |
| 773 } |
| 774 |
| 775 |
| 776 void Assembler::adc(Register dst, int32_t imm32) { |
| 777 EnsureSpace ensure_space(this); |
| 778 last_pc_ = pc_; |
| 779 emit_arith(2, Operand(dst), Immediate(imm32)); |
| 780 } |
| 781 |
| 782 |
| 783 void Assembler::adc(Register dst, const Operand& src) { |
| 784 EnsureSpace ensure_space(this); |
| 785 last_pc_ = pc_; |
| 786 EMIT(0x13); |
| 787 emit_operand(dst, src); |
| 788 } |
| 789 |
| 790 |
| 791 void Assembler::add(Register dst, const Operand& src) { |
| 792 EnsureSpace ensure_space(this); |
| 793 last_pc_ = pc_; |
| 794 EMIT(0x03); |
| 795 emit_operand(dst, src); |
| 796 } |
| 797 |
| 798 |
| 799 void Assembler::add(const Operand& dst, const Immediate& x) { |
| 800 ASSERT(reloc_info_writer.last_pc() != NULL); |
| 801 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { |
| 802 byte instr = last_pc_[0]; |
| 803 if ((instr & 0xf8) == 0x50) { |
| 804 // Last instruction was a push. Check whether this is a pop without a |
| 805 // result. |
| 806 if ((dst.is_reg(esp)) && |
| 807 (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) { |
| 808 pc_ = last_pc_; |
| 809 last_pc_ = NULL; |
| 810 if (FLAG_print_push_pop_elimination) { |
| 811 PrintF("%d push/pop(noreg) eliminated\n", pc_offset()); |
| 812 } |
| 813 return; |
| 814 } |
| 815 } |
| 816 } |
| 817 EnsureSpace ensure_space(this); |
| 818 last_pc_ = pc_; |
| 819 emit_arith(0, dst, x); |
| 820 } |
| 821 |
| 822 |
| 823 void Assembler::and_(Register dst, int32_t imm32) { |
| 824 EnsureSpace ensure_space(this); |
| 825 last_pc_ = pc_; |
| 826 emit_arith(4, Operand(dst), Immediate(imm32)); |
| 827 } |
| 828 |
| 829 |
| 830 void Assembler::and_(Register dst, const Operand& src) { |
| 831 EnsureSpace ensure_space(this); |
| 832 last_pc_ = pc_; |
| 833 EMIT(0x23); |
| 834 emit_operand(dst, src); |
| 835 } |
| 836 |
| 837 |
| 838 void Assembler::and_(const Operand& dst, const Immediate& x) { |
| 839 EnsureSpace ensure_space(this); |
| 840 last_pc_ = pc_; |
| 841 emit_arith(4, dst, x); |
| 842 } |
| 843 |
| 844 |
| 845 void Assembler::and_(const Operand& dst, Register src) { |
| 846 EnsureSpace ensure_space(this); |
| 847 last_pc_ = pc_; |
| 848 EMIT(0x21); |
| 849 emit_operand(src, dst); |
| 850 } |
| 851 |
| 852 |
| 853 void Assembler::cmpb(const Operand& op, int8_t imm8) { |
| 854 EnsureSpace ensure_space(this); |
| 855 last_pc_ = pc_; |
| 856 EMIT(0x80); |
| 857 emit_operand(edi, op); // edi == 7 |
| 858 EMIT(imm8); |
| 859 } |
| 860 |
| 861 |
| 862 void Assembler::cmpw(const Operand& op, Immediate imm16) { |
| 863 ASSERT(imm16.is_int16()); |
| 864 EnsureSpace ensure_space(this); |
| 865 last_pc_ = pc_; |
| 866 EMIT(0x66); |
| 867 EMIT(0x81); |
| 868 emit_operand(edi, op); |
| 869 emit_w(imm16); |
| 870 } |
| 871 |
| 872 |
| 873 void Assembler::cmp(Register reg, int32_t imm32) { |
| 874 EnsureSpace ensure_space(this); |
| 875 last_pc_ = pc_; |
| 876 emit_arith(7, Operand(reg), Immediate(imm32)); |
| 877 } |
| 878 |
| 879 |
| 880 void Assembler::cmp(Register reg, Handle<Object> handle) { |
| 881 EnsureSpace ensure_space(this); |
| 882 last_pc_ = pc_; |
| 883 emit_arith(7, Operand(reg), Immediate(handle)); |
| 884 } |
| 885 |
| 886 |
| 887 void Assembler::cmp(Register reg, const Operand& op) { |
| 888 EnsureSpace ensure_space(this); |
| 889 last_pc_ = pc_; |
| 890 EMIT(0x3B); |
| 891 emit_operand(reg, op); |
| 892 } |
| 893 |
| 894 |
| 895 void Assembler::cmp(const Operand& op, const Immediate& imm) { |
| 896 EnsureSpace ensure_space(this); |
| 897 last_pc_ = pc_; |
| 898 emit_arith(7, op, imm); |
| 899 } |
| 900 |
| 901 |
| 902 void Assembler::cmpb_al(const Operand& op) { |
| 903 EnsureSpace ensure_space(this); |
| 904 last_pc_ = pc_; |
| 905 EMIT(0x38); // CMP r/m8, r8 |
| 906 emit_operand(eax, op); // eax has same code as register al. |
| 907 } |
| 908 |
| 909 |
| 910 void Assembler::cmpw_ax(const Operand& op) { |
| 911 EnsureSpace ensure_space(this); |
| 912 last_pc_ = pc_; |
| 913 EMIT(0x66); |
| 914 EMIT(0x39); // CMP r/m16, r16 |
| 915 emit_operand(eax, op); // eax has same code as register ax. |
| 916 } |
| 917 |
| 918 |
| 919 void Assembler::dec_b(Register dst) { |
| 920 EnsureSpace ensure_space(this); |
| 921 last_pc_ = pc_; |
| 922 EMIT(0xFE); |
| 923 EMIT(0xC8 | dst.code()); |
| 924 } |
| 925 |
| 926 |
| 927 void Assembler::dec(Register dst) { |
| 928 EnsureSpace ensure_space(this); |
| 929 last_pc_ = pc_; |
| 930 EMIT(0x48 | dst.code()); |
| 931 } |
| 932 |
| 933 |
| 934 void Assembler::dec(const Operand& dst) { |
| 935 EnsureSpace ensure_space(this); |
| 936 last_pc_ = pc_; |
| 937 EMIT(0xFF); |
| 938 emit_operand(ecx, dst); |
| 939 } |
| 940 |
| 941 |
| 942 void Assembler::cdq() { |
| 943 EnsureSpace ensure_space(this); |
| 944 last_pc_ = pc_; |
| 945 EMIT(0x99); |
| 946 } |
| 947 |
| 948 |
| 949 void Assembler::idiv(Register src) { |
| 950 EnsureSpace ensure_space(this); |
| 951 last_pc_ = pc_; |
| 952 EMIT(0xF7); |
| 953 EMIT(0xF8 | src.code()); |
| 954 } |
| 955 |
| 956 |
| 957 void Assembler::imul(Register dst, const Operand& src) { |
| 958 EnsureSpace ensure_space(this); |
| 959 last_pc_ = pc_; |
| 960 EMIT(0x0F); |
| 961 EMIT(0xAF); |
| 962 emit_operand(dst, src); |
| 963 } |
| 964 |
| 965 |
| 966 void Assembler::imul(Register dst, Register src, int32_t imm32) { |
| 967 EnsureSpace ensure_space(this); |
| 968 last_pc_ = pc_; |
| 969 if (is_int8(imm32)) { |
| 970 EMIT(0x6B); |
| 971 EMIT(0xC0 | dst.code() << 3 | src.code()); |
| 972 EMIT(imm32); |
| 973 } else { |
| 974 EMIT(0x69); |
| 975 EMIT(0xC0 | dst.code() << 3 | src.code()); |
| 976 emit(imm32); |
| 977 } |
| 978 } |
| 979 |
| 980 |
| 981 void Assembler::inc(Register dst) { |
| 982 EnsureSpace ensure_space(this); |
| 983 last_pc_ = pc_; |
| 984 EMIT(0x40 | dst.code()); |
| 985 } |
| 986 |
| 987 |
| 988 void Assembler::inc(const Operand& dst) { |
| 989 EnsureSpace ensure_space(this); |
| 990 last_pc_ = pc_; |
| 991 EMIT(0xFF); |
| 992 emit_operand(eax, dst); |
| 993 } |
| 994 |
| 995 |
| 996 void Assembler::lea(Register dst, const Operand& src) { |
| 997 EnsureSpace ensure_space(this); |
| 998 last_pc_ = pc_; |
| 999 EMIT(0x8D); |
| 1000 emit_operand(dst, src); |
| 1001 } |
| 1002 |
| 1003 |
| 1004 void Assembler::mul(Register src) { |
| 1005 EnsureSpace ensure_space(this); |
| 1006 last_pc_ = pc_; |
| 1007 EMIT(0xF7); |
| 1008 EMIT(0xE0 | src.code()); |
| 1009 } |
| 1010 |
| 1011 |
| 1012 void Assembler::neg(Register dst) { |
| 1013 EnsureSpace ensure_space(this); |
| 1014 last_pc_ = pc_; |
| 1015 EMIT(0xF7); |
| 1016 EMIT(0xD8 | dst.code()); |
| 1017 } |
| 1018 |
| 1019 |
| 1020 void Assembler::not_(Register dst) { |
| 1021 EnsureSpace ensure_space(this); |
| 1022 last_pc_ = pc_; |
| 1023 EMIT(0xF7); |
| 1024 EMIT(0xD0 | dst.code()); |
| 1025 } |
| 1026 |
| 1027 |
| 1028 void Assembler::or_(Register dst, int32_t imm32) { |
| 1029 EnsureSpace ensure_space(this); |
| 1030 last_pc_ = pc_; |
| 1031 emit_arith(1, Operand(dst), Immediate(imm32)); |
| 1032 } |
| 1033 |
| 1034 |
| 1035 void Assembler::or_(Register dst, const Operand& src) { |
| 1036 EnsureSpace ensure_space(this); |
| 1037 last_pc_ = pc_; |
| 1038 EMIT(0x0B); |
| 1039 emit_operand(dst, src); |
| 1040 } |
| 1041 |
| 1042 |
| 1043 void Assembler::or_(const Operand& dst, const Immediate& x) { |
| 1044 EnsureSpace ensure_space(this); |
| 1045 last_pc_ = pc_; |
| 1046 emit_arith(1, dst, x); |
| 1047 } |
| 1048 |
| 1049 |
| 1050 void Assembler::or_(const Operand& dst, Register src) { |
| 1051 EnsureSpace ensure_space(this); |
| 1052 last_pc_ = pc_; |
| 1053 EMIT(0x09); |
| 1054 emit_operand(src, dst); |
| 1055 } |
| 1056 |
| 1057 |
| 1058 void Assembler::rcl(Register dst, uint8_t imm8) { |
| 1059 EnsureSpace ensure_space(this); |
| 1060 last_pc_ = pc_; |
| 1061 ASSERT(is_uint5(imm8)); // illegal shift count |
| 1062 if (imm8 == 1) { |
| 1063 EMIT(0xD1); |
| 1064 EMIT(0xD0 | dst.code()); |
| 1065 } else { |
| 1066 EMIT(0xC1); |
| 1067 EMIT(0xD0 | dst.code()); |
| 1068 EMIT(imm8); |
| 1069 } |
| 1070 } |
| 1071 |
| 1072 |
| 1073 void Assembler::sar(Register dst, uint8_t imm8) { |
| 1074 EnsureSpace ensure_space(this); |
| 1075 last_pc_ = pc_; |
| 1076 ASSERT(is_uint5(imm8)); // illegal shift count |
| 1077 if (imm8 == 1) { |
| 1078 EMIT(0xD1); |
| 1079 EMIT(0xF8 | dst.code()); |
| 1080 } else { |
| 1081 EMIT(0xC1); |
| 1082 EMIT(0xF8 | dst.code()); |
| 1083 EMIT(imm8); |
| 1084 } |
| 1085 } |
| 1086 |
| 1087 |
| 1088 void Assembler::sar(Register dst) { |
| 1089 EnsureSpace ensure_space(this); |
| 1090 last_pc_ = pc_; |
| 1091 EMIT(0xD3); |
| 1092 EMIT(0xF8 | dst.code()); |
| 1093 } |
| 1094 |
| 1095 |
| 1096 void Assembler::sbb(Register dst, const Operand& src) { |
| 1097 EnsureSpace ensure_space(this); |
| 1098 last_pc_ = pc_; |
| 1099 EMIT(0x1B); |
| 1100 emit_operand(dst, src); |
| 1101 } |
| 1102 |
| 1103 |
| 1104 void Assembler::shld(Register dst, const Operand& src) { |
| 1105 EnsureSpace ensure_space(this); |
| 1106 last_pc_ = pc_; |
| 1107 EMIT(0x0F); |
| 1108 EMIT(0xA5); |
| 1109 emit_operand(dst, src); |
| 1110 } |
| 1111 |
| 1112 |
| 1113 void Assembler::shl(Register dst, uint8_t imm8) { |
| 1114 EnsureSpace ensure_space(this); |
| 1115 last_pc_ = pc_; |
| 1116 ASSERT(is_uint5(imm8)); // illegal shift count |
| 1117 if (imm8 == 1) { |
| 1118 EMIT(0xD1); |
| 1119 EMIT(0xE0 | dst.code()); |
| 1120 } else { |
| 1121 EMIT(0xC1); |
| 1122 EMIT(0xE0 | dst.code()); |
| 1123 EMIT(imm8); |
| 1124 } |
| 1125 } |
| 1126 |
| 1127 |
| 1128 void Assembler::shl(Register dst) { |
| 1129 EnsureSpace ensure_space(this); |
| 1130 last_pc_ = pc_; |
| 1131 EMIT(0xD3); |
| 1132 EMIT(0xE0 | dst.code()); |
| 1133 } |
| 1134 |
| 1135 |
| 1136 void Assembler::shrd(Register dst, const Operand& src) { |
| 1137 EnsureSpace ensure_space(this); |
| 1138 last_pc_ = pc_; |
| 1139 EMIT(0x0F); |
| 1140 EMIT(0xAD); |
| 1141 emit_operand(dst, src); |
| 1142 } |
| 1143 |
| 1144 |
| 1145 void Assembler::shr(Register dst, uint8_t imm8) { |
| 1146 EnsureSpace ensure_space(this); |
| 1147 last_pc_ = pc_; |
| 1148 ASSERT(is_uint5(imm8)); // illegal shift count |
| 1149 EMIT(0xC1); |
| 1150 EMIT(0xE8 | dst.code()); |
| 1151 EMIT(imm8); |
| 1152 } |
| 1153 |
| 1154 |
| 1155 void Assembler::shr(Register dst) { |
| 1156 EnsureSpace ensure_space(this); |
| 1157 last_pc_ = pc_; |
| 1158 EMIT(0xD3); |
| 1159 EMIT(0xE8 | dst.code()); |
| 1160 } |
| 1161 |
| 1162 |
| 1163 void Assembler::shr_cl(Register dst) { |
| 1164 EnsureSpace ensure_space(this); |
| 1165 last_pc_ = pc_; |
| 1166 EMIT(0xD1); |
| 1167 EMIT(0xE8 | dst.code()); |
| 1168 } |
| 1169 |
| 1170 |
| 1171 void Assembler::sub(const Operand& dst, const Immediate& x) { |
| 1172 EnsureSpace ensure_space(this); |
| 1173 last_pc_ = pc_; |
| 1174 emit_arith(5, dst, x); |
| 1175 } |
| 1176 |
| 1177 |
| 1178 void Assembler::sub(Register dst, const Operand& src) { |
| 1179 EnsureSpace ensure_space(this); |
| 1180 last_pc_ = pc_; |
| 1181 EMIT(0x2B); |
| 1182 emit_operand(dst, src); |
| 1183 } |
| 1184 |
| 1185 |
| 1186 void Assembler::sub(const Operand& dst, Register src) { |
| 1187 EnsureSpace ensure_space(this); |
| 1188 last_pc_ = pc_; |
| 1189 EMIT(0x29); |
| 1190 emit_operand(src, dst); |
| 1191 } |
| 1192 |
| 1193 |
| 1194 void Assembler::test(Register reg, const Immediate& imm) { |
| 1195 EnsureSpace ensure_space(this); |
| 1196 last_pc_ = pc_; |
| 1197 // Only use test against byte for registers that have a byte |
| 1198 // variant: eax, ebx, ecx, and edx. |
| 1199 if (imm.rmode_ == RelocInfo::NONE && is_uint8(imm.x_) && reg.code() < 4) { |
| 1200 uint8_t imm8 = imm.x_; |
| 1201 if (reg.is(eax)) { |
| 1202 EMIT(0xA8); |
| 1203 EMIT(imm8); |
| 1204 } else { |
| 1205 emit_arith_b(0xF6, 0xC0, reg, imm8); |
| 1206 } |
| 1207 } else { |
| 1208 // This is not using emit_arith because test doesn't support |
| 1209 // sign-extension of 8-bit operands. |
| 1210 if (reg.is(eax)) { |
| 1211 EMIT(0xA9); |
| 1212 } else { |
| 1213 EMIT(0xF7); |
| 1214 EMIT(0xC0 | reg.code()); |
| 1215 } |
| 1216 emit(imm); |
| 1217 } |
| 1218 } |
| 1219 |
| 1220 |
| 1221 void Assembler::test(Register reg, const Operand& op) { |
| 1222 EnsureSpace ensure_space(this); |
| 1223 last_pc_ = pc_; |
| 1224 EMIT(0x85); |
| 1225 emit_operand(reg, op); |
| 1226 } |
| 1227 |
| 1228 |
| 1229 void Assembler::test(const Operand& op, const Immediate& imm) { |
| 1230 EnsureSpace ensure_space(this); |
| 1231 last_pc_ = pc_; |
| 1232 EMIT(0xF7); |
| 1233 emit_operand(eax, op); |
| 1234 emit(imm); |
| 1235 } |
| 1236 |
| 1237 |
| 1238 void Assembler::xor_(Register dst, int32_t imm32) { |
| 1239 EnsureSpace ensure_space(this); |
| 1240 last_pc_ = pc_; |
| 1241 emit_arith(6, Operand(dst), Immediate(imm32)); |
| 1242 } |
| 1243 |
| 1244 |
| 1245 void Assembler::xor_(Register dst, const Operand& src) { |
| 1246 EnsureSpace ensure_space(this); |
| 1247 last_pc_ = pc_; |
| 1248 EMIT(0x33); |
| 1249 emit_operand(dst, src); |
| 1250 } |
| 1251 |
| 1252 |
| 1253 void Assembler::xor_(const Operand& src, Register dst) { |
| 1254 EnsureSpace ensure_space(this); |
| 1255 last_pc_ = pc_; |
| 1256 EMIT(0x31); |
| 1257 emit_operand(dst, src); |
| 1258 } |
| 1259 |
| 1260 |
| 1261 void Assembler::xor_(const Operand& dst, const Immediate& x) { |
| 1262 EnsureSpace ensure_space(this); |
| 1263 last_pc_ = pc_; |
| 1264 emit_arith(6, dst, x); |
| 1265 } |
| 1266 |
| 1267 |
| 1268 void Assembler::bt(const Operand& dst, Register src) { |
| 1269 EnsureSpace ensure_space(this); |
| 1270 last_pc_ = pc_; |
| 1271 EMIT(0x0F); |
| 1272 EMIT(0xA3); |
| 1273 emit_operand(src, dst); |
| 1274 } |
| 1275 |
| 1276 |
| 1277 void Assembler::bts(const Operand& dst, Register src) { |
| 1278 EnsureSpace ensure_space(this); |
| 1279 last_pc_ = pc_; |
| 1280 EMIT(0x0F); |
| 1281 EMIT(0xAB); |
| 1282 emit_operand(src, dst); |
| 1283 } |
| 1284 |
| 1285 |
| 1286 void Assembler::hlt() { |
| 1287 EnsureSpace ensure_space(this); |
| 1288 last_pc_ = pc_; |
| 1289 EMIT(0xF4); |
| 1290 } |
| 1291 |
| 1292 |
| 1293 void Assembler::int3() { |
| 1294 EnsureSpace ensure_space(this); |
| 1295 last_pc_ = pc_; |
| 1296 EMIT(0xCC); |
| 1297 } |
| 1298 |
| 1299 |
| 1300 void Assembler::nop() { |
| 1301 EnsureSpace ensure_space(this); |
| 1302 last_pc_ = pc_; |
| 1303 EMIT(0x90); |
| 1304 } |
| 1305 |
| 1306 |
| 1307 void Assembler::rdtsc() { |
| 1308 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::RDTSC)); |
| 1309 EnsureSpace ensure_space(this); |
| 1310 last_pc_ = pc_; |
| 1311 EMIT(0x0F); |
| 1312 EMIT(0x31); |
| 1313 } |
| 1314 |
| 1315 |
| 1316 void Assembler::ret(int imm16) { |
| 1317 EnsureSpace ensure_space(this); |
| 1318 last_pc_ = pc_; |
| 1319 ASSERT(is_uint16(imm16)); |
| 1320 if (imm16 == 0) { |
| 1321 EMIT(0xC3); |
| 1322 } else { |
| 1323 EMIT(0xC2); |
| 1324 EMIT(imm16 & 0xFF); |
| 1325 EMIT((imm16 >> 8) & 0xFF); |
| 1326 } |
| 1327 } |
| 1328 |
| 1329 |
| 1330 // Labels refer to positions in the (to be) generated code. |
| 1331 // There are bound, linked, and unused labels. |
| 1332 // |
| 1333 // Bound labels refer to known positions in the already |
| 1334 // generated code. pos() is the position the label refers to. |
| 1335 // |
| 1336 // Linked labels refer to unknown positions in the code |
| 1337 // to be generated; pos() is the position of the 32bit |
| 1338 // Displacement of the last instruction using the label. |
| 1339 |
| 1340 |
| 1341 void Assembler::print(Label* L) { |
| 1342 if (L->is_unused()) { |
| 1343 PrintF("unused label\n"); |
| 1344 } else if (L->is_bound()) { |
| 1345 PrintF("bound label to %d\n", L->pos()); |
| 1346 } else if (L->is_linked()) { |
| 1347 Label l = *L; |
| 1348 PrintF("unbound label"); |
| 1349 while (l.is_linked()) { |
| 1350 Displacement disp = disp_at(&l); |
| 1351 PrintF("@ %d ", l.pos()); |
| 1352 disp.print(); |
| 1353 PrintF("\n"); |
| 1354 disp.next(&l); |
| 1355 } |
| 1356 } else { |
| 1357 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); |
| 1358 } |
| 1359 } |
| 1360 |
| 1361 |
| 1362 void Assembler::bind_to(Label* L, int pos) { |
| 1363 EnsureSpace ensure_space(this); |
| 1364 last_pc_ = NULL; |
| 1365 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position |
| 1366 while (L->is_linked()) { |
| 1367 Displacement disp = disp_at(L); |
| 1368 int fixup_pos = L->pos(); |
| 1369 if (disp.type() == Displacement::CODE_RELATIVE) { |
| 1370 // Relative to Code* heap object pointer. |
| 1371 long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag); |
| 1372 } else { |
| 1373 if (disp.type() == Displacement::UNCONDITIONAL_JUMP) { |
| 1374 ASSERT(byte_at(fixup_pos - 1) == 0xE9); // jmp expected |
| 1375 } |
| 1376 // relative address, relative to point after address |
| 1377 int imm32 = pos - (fixup_pos + sizeof(int32_t)); |
| 1378 long_at_put(fixup_pos, imm32); |
| 1379 } |
| 1380 disp.next(L); |
| 1381 } |
| 1382 L->bind_to(pos); |
| 1383 } |
| 1384 |
| 1385 |
| 1386 void Assembler::link_to(Label* L, Label* appendix) { |
| 1387 EnsureSpace ensure_space(this); |
| 1388 last_pc_ = NULL; |
| 1389 if (appendix->is_linked()) { |
| 1390 if (L->is_linked()) { |
| 1391 // append appendix to L's list |
| 1392 Label p; |
| 1393 Label q = *L; |
| 1394 do { |
| 1395 p = q; |
| 1396 Displacement disp = disp_at(&q); |
| 1397 disp.next(&q); |
| 1398 } while (q.is_linked()); |
| 1399 Displacement disp = disp_at(&p); |
| 1400 disp.link_to(appendix); |
| 1401 disp_at_put(&p, disp); |
| 1402 p.Unuse(); // to avoid assertion failure in ~Label |
| 1403 } else { |
| 1404 // L is empty, simply use appendix |
| 1405 *L = *appendix; |
| 1406 } |
| 1407 } |
| 1408 appendix->Unuse(); // appendix should not be used anymore |
| 1409 } |
| 1410 |
| 1411 |
| 1412 void Assembler::bind(Label* L) { |
| 1413 EnsureSpace ensure_space(this); |
| 1414 last_pc_ = NULL; |
| 1415 ASSERT(!L->is_bound()); // label can only be bound once |
| 1416 bind_to(L, pc_offset()); |
| 1417 } |
| 1418 |
| 1419 |
| 1420 void Assembler::call(Label* L) { |
| 1421 EnsureSpace ensure_space(this); |
| 1422 last_pc_ = pc_; |
| 1423 if (L->is_bound()) { |
| 1424 const int long_size = 5; |
| 1425 int offs = L->pos() - pc_offset(); |
| 1426 ASSERT(offs <= 0); |
| 1427 // 1110 1000 #32-bit disp |
| 1428 EMIT(0xE8); |
| 1429 emit(offs - long_size); |
| 1430 } else { |
| 1431 // 1110 1000 #32-bit disp |
| 1432 EMIT(0xE8); |
| 1433 emit_disp(L, Displacement::OTHER); |
| 1434 } |
| 1435 } |
| 1436 |
| 1437 |
| 1438 void Assembler::call(byte* entry, RelocInfo::Mode rmode) { |
| 1439 EnsureSpace ensure_space(this); |
| 1440 last_pc_ = pc_; |
| 1441 ASSERT(!RelocInfo::IsCodeTarget(rmode)); |
| 1442 EMIT(0xE8); |
| 1443 emit(entry - (pc_ + sizeof(int32_t)), rmode); |
| 1444 } |
| 1445 |
| 1446 |
| 1447 void Assembler::call(const Operand& adr) { |
| 1448 EnsureSpace ensure_space(this); |
| 1449 last_pc_ = pc_; |
| 1450 EMIT(0xFF); |
| 1451 emit_operand(edx, adr); |
| 1452 } |
| 1453 |
| 1454 |
| 1455 void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) { |
| 1456 WriteRecordedPositions(); |
| 1457 EnsureSpace ensure_space(this); |
| 1458 last_pc_ = pc_; |
| 1459 ASSERT(RelocInfo::IsCodeTarget(rmode)); |
| 1460 EMIT(0xE8); |
| 1461 emit(reinterpret_cast<intptr_t>(code.location()), rmode); |
| 1462 } |
| 1463 |
| 1464 |
| 1465 void Assembler::jmp(Label* L) { |
| 1466 EnsureSpace ensure_space(this); |
| 1467 last_pc_ = pc_; |
| 1468 if (L->is_bound()) { |
| 1469 const int short_size = 2; |
| 1470 const int long_size = 5; |
| 1471 int offs = L->pos() - pc_offset(); |
| 1472 ASSERT(offs <= 0); |
| 1473 if (is_int8(offs - short_size)) { |
| 1474 // 1110 1011 #8-bit disp |
| 1475 EMIT(0xEB); |
| 1476 EMIT((offs - short_size) & 0xFF); |
| 1477 } else { |
| 1478 // 1110 1001 #32-bit disp |
| 1479 EMIT(0xE9); |
| 1480 emit(offs - long_size); |
| 1481 } |
| 1482 } else { |
| 1483 // 1110 1001 #32-bit disp |
| 1484 EMIT(0xE9); |
| 1485 emit_disp(L, Displacement::UNCONDITIONAL_JUMP); |
| 1486 } |
| 1487 } |
| 1488 |
| 1489 |
| 1490 void Assembler::jmp(byte* entry, RelocInfo::Mode rmode) { |
| 1491 EnsureSpace ensure_space(this); |
| 1492 last_pc_ = pc_; |
| 1493 ASSERT(!RelocInfo::IsCodeTarget(rmode)); |
| 1494 EMIT(0xE9); |
| 1495 emit(entry - (pc_ + sizeof(int32_t)), rmode); |
| 1496 } |
| 1497 |
| 1498 |
| 1499 void Assembler::jmp(const Operand& adr) { |
| 1500 EnsureSpace ensure_space(this); |
| 1501 last_pc_ = pc_; |
| 1502 EMIT(0xFF); |
| 1503 emit_operand(esp, adr); |
| 1504 } |
| 1505 |
| 1506 |
| 1507 void Assembler::jmp(Handle<Code> code, RelocInfo::Mode rmode) { |
| 1508 EnsureSpace ensure_space(this); |
| 1509 last_pc_ = pc_; |
| 1510 ASSERT(RelocInfo::IsCodeTarget(rmode)); |
| 1511 EMIT(0xE9); |
| 1512 emit(reinterpret_cast<intptr_t>(code.location()), rmode); |
| 1513 } |
| 1514 |
| 1515 |
| 1516 |
| 1517 void Assembler::j(Condition cc, Label* L, Hint hint) { |
| 1518 EnsureSpace ensure_space(this); |
| 1519 last_pc_ = pc_; |
| 1520 ASSERT(0 <= cc && cc < 16); |
| 1521 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); |
| 1522 if (L->is_bound()) { |
| 1523 const int short_size = 2; |
| 1524 const int long_size = 6; |
| 1525 int offs = L->pos() - pc_offset(); |
| 1526 ASSERT(offs <= 0); |
| 1527 if (is_int8(offs - short_size)) { |
| 1528 // 0111 tttn #8-bit disp |
| 1529 EMIT(0x70 | cc); |
| 1530 EMIT((offs - short_size) & 0xFF); |
| 1531 } else { |
| 1532 // 0000 1111 1000 tttn #32-bit disp |
| 1533 EMIT(0x0F); |
| 1534 EMIT(0x80 | cc); |
| 1535 emit(offs - long_size); |
| 1536 } |
| 1537 } else { |
| 1538 // 0000 1111 1000 tttn #32-bit disp |
| 1539 // Note: could eliminate cond. jumps to this jump if condition |
| 1540 // is the same however, seems to be rather unlikely case. |
| 1541 EMIT(0x0F); |
| 1542 EMIT(0x80 | cc); |
| 1543 emit_disp(L, Displacement::OTHER); |
| 1544 } |
| 1545 } |
| 1546 |
| 1547 |
| 1548 void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint) { |
| 1549 EnsureSpace ensure_space(this); |
| 1550 last_pc_ = pc_; |
| 1551 ASSERT((0 <= cc) && (cc < 16)); |
| 1552 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); |
| 1553 // 0000 1111 1000 tttn #32-bit disp |
| 1554 EMIT(0x0F); |
| 1555 EMIT(0x80 | cc); |
| 1556 emit(entry - (pc_ + sizeof(int32_t)), rmode); |
| 1557 } |
| 1558 |
| 1559 |
| 1560 void Assembler::j(Condition cc, Handle<Code> code, Hint hint) { |
| 1561 EnsureSpace ensure_space(this); |
| 1562 last_pc_ = pc_; |
| 1563 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); |
| 1564 // 0000 1111 1000 tttn #32-bit disp |
| 1565 EMIT(0x0F); |
| 1566 EMIT(0x80 | cc); |
| 1567 emit(reinterpret_cast<intptr_t>(code.location()), RelocInfo::CODE_TARGET); |
| 1568 } |
| 1569 |
| 1570 |
| 1571 // FPU instructions |
| 1572 |
| 1573 |
| 1574 void Assembler::fld(int i) { |
| 1575 EnsureSpace ensure_space(this); |
| 1576 last_pc_ = pc_; |
| 1577 emit_farith(0xD9, 0xC0, i); |
| 1578 } |
| 1579 |
| 1580 |
| 1581 void Assembler::fld1() { |
| 1582 EnsureSpace ensure_space(this); |
| 1583 last_pc_ = pc_; |
| 1584 EMIT(0xD9); |
| 1585 EMIT(0xE8); |
| 1586 } |
| 1587 |
| 1588 |
| 1589 void Assembler::fldz() { |
| 1590 EnsureSpace ensure_space(this); |
| 1591 last_pc_ = pc_; |
| 1592 EMIT(0xD9); |
| 1593 EMIT(0xEE); |
| 1594 } |
| 1595 |
| 1596 |
| 1597 void Assembler::fld_s(const Operand& adr) { |
| 1598 EnsureSpace ensure_space(this); |
| 1599 last_pc_ = pc_; |
| 1600 EMIT(0xD9); |
| 1601 emit_operand(eax, adr); |
| 1602 } |
| 1603 |
| 1604 |
| 1605 void Assembler::fld_d(const Operand& adr) { |
| 1606 EnsureSpace ensure_space(this); |
| 1607 last_pc_ = pc_; |
| 1608 EMIT(0xDD); |
| 1609 emit_operand(eax, adr); |
| 1610 } |
| 1611 |
| 1612 |
| 1613 void Assembler::fstp_s(const Operand& adr) { |
| 1614 EnsureSpace ensure_space(this); |
| 1615 last_pc_ = pc_; |
| 1616 EMIT(0xD9); |
| 1617 emit_operand(ebx, adr); |
| 1618 } |
| 1619 |
| 1620 |
| 1621 void Assembler::fstp_d(const Operand& adr) { |
| 1622 EnsureSpace ensure_space(this); |
| 1623 last_pc_ = pc_; |
| 1624 EMIT(0xDD); |
| 1625 emit_operand(ebx, adr); |
| 1626 } |
| 1627 |
| 1628 |
| 1629 void Assembler::fild_s(const Operand& adr) { |
| 1630 EnsureSpace ensure_space(this); |
| 1631 last_pc_ = pc_; |
| 1632 EMIT(0xDB); |
| 1633 emit_operand(eax, adr); |
| 1634 } |
| 1635 |
| 1636 |
| 1637 void Assembler::fild_d(const Operand& adr) { |
| 1638 EnsureSpace ensure_space(this); |
| 1639 last_pc_ = pc_; |
| 1640 EMIT(0xDF); |
| 1641 emit_operand(ebp, adr); |
| 1642 } |
| 1643 |
| 1644 |
| 1645 void Assembler::fistp_s(const Operand& adr) { |
| 1646 EnsureSpace ensure_space(this); |
| 1647 last_pc_ = pc_; |
| 1648 EMIT(0xDB); |
| 1649 emit_operand(ebx, adr); |
| 1650 } |
| 1651 |
| 1652 |
| 1653 void Assembler::fisttp_s(const Operand& adr) { |
| 1654 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE3)); |
| 1655 EnsureSpace ensure_space(this); |
| 1656 last_pc_ = pc_; |
| 1657 EMIT(0xDB); |
| 1658 emit_operand(ecx, adr); |
| 1659 } |
| 1660 |
| 1661 |
| 1662 void Assembler::fist_s(const Operand& adr) { |
| 1663 EnsureSpace ensure_space(this); |
| 1664 last_pc_ = pc_; |
| 1665 EMIT(0xDB); |
| 1666 emit_operand(edx, adr); |
| 1667 } |
| 1668 |
| 1669 |
| 1670 void Assembler::fistp_d(const Operand& adr) { |
| 1671 EnsureSpace ensure_space(this); |
| 1672 last_pc_ = pc_; |
| 1673 EMIT(0xDF); |
| 1674 emit_operand(edi, adr); |
| 1675 } |
| 1676 |
| 1677 |
| 1678 void Assembler::fabs() { |
| 1679 EnsureSpace ensure_space(this); |
| 1680 last_pc_ = pc_; |
| 1681 EMIT(0xD9); |
| 1682 EMIT(0xE1); |
| 1683 } |
| 1684 |
| 1685 |
| 1686 void Assembler::fchs() { |
| 1687 EnsureSpace ensure_space(this); |
| 1688 last_pc_ = pc_; |
| 1689 EMIT(0xD9); |
| 1690 EMIT(0xE0); |
| 1691 } |
| 1692 |
| 1693 |
| 1694 void Assembler::fadd(int i) { |
| 1695 EnsureSpace ensure_space(this); |
| 1696 last_pc_ = pc_; |
| 1697 emit_farith(0xDC, 0xC0, i); |
| 1698 } |
| 1699 |
| 1700 |
| 1701 void Assembler::fsub(int i) { |
| 1702 EnsureSpace ensure_space(this); |
| 1703 last_pc_ = pc_; |
| 1704 emit_farith(0xDC, 0xE8, i); |
| 1705 } |
| 1706 |
| 1707 |
| 1708 void Assembler::fisub_s(const Operand& adr) { |
| 1709 EnsureSpace ensure_space(this); |
| 1710 last_pc_ = pc_; |
| 1711 EMIT(0xDA); |
| 1712 emit_operand(esp, adr); |
| 1713 } |
| 1714 |
| 1715 |
| 1716 void Assembler::fmul(int i) { |
| 1717 EnsureSpace ensure_space(this); |
| 1718 last_pc_ = pc_; |
| 1719 emit_farith(0xDC, 0xC8, i); |
| 1720 } |
| 1721 |
| 1722 |
| 1723 void Assembler::fdiv(int i) { |
| 1724 EnsureSpace ensure_space(this); |
| 1725 last_pc_ = pc_; |
| 1726 emit_farith(0xDC, 0xF8, i); |
| 1727 } |
| 1728 |
| 1729 |
| 1730 void Assembler::faddp(int i) { |
| 1731 EnsureSpace ensure_space(this); |
| 1732 last_pc_ = pc_; |
| 1733 emit_farith(0xDE, 0xC0, i); |
| 1734 } |
| 1735 |
| 1736 |
| 1737 void Assembler::fsubp(int i) { |
| 1738 EnsureSpace ensure_space(this); |
| 1739 last_pc_ = pc_; |
| 1740 emit_farith(0xDE, 0xE8, i); |
| 1741 } |
| 1742 |
| 1743 |
| 1744 void Assembler::fsubrp(int i) { |
| 1745 EnsureSpace ensure_space(this); |
| 1746 last_pc_ = pc_; |
| 1747 emit_farith(0xDE, 0xE0, i); |
| 1748 } |
| 1749 |
| 1750 |
| 1751 void Assembler::fmulp(int i) { |
| 1752 EnsureSpace ensure_space(this); |
| 1753 last_pc_ = pc_; |
| 1754 emit_farith(0xDE, 0xC8, i); |
| 1755 } |
| 1756 |
| 1757 |
| 1758 void Assembler::fdivp(int i) { |
| 1759 EnsureSpace ensure_space(this); |
| 1760 last_pc_ = pc_; |
| 1761 emit_farith(0xDE, 0xF8, i); |
| 1762 } |
| 1763 |
| 1764 |
| 1765 void Assembler::fprem() { |
| 1766 EnsureSpace ensure_space(this); |
| 1767 last_pc_ = pc_; |
| 1768 EMIT(0xD9); |
| 1769 EMIT(0xF8); |
| 1770 } |
| 1771 |
| 1772 |
| 1773 void Assembler::fprem1() { |
| 1774 EnsureSpace ensure_space(this); |
| 1775 last_pc_ = pc_; |
| 1776 EMIT(0xD9); |
| 1777 EMIT(0xF5); |
| 1778 } |
| 1779 |
| 1780 |
| 1781 void Assembler::fxch(int i) { |
| 1782 EnsureSpace ensure_space(this); |
| 1783 last_pc_ = pc_; |
| 1784 emit_farith(0xD9, 0xC8, i); |
| 1785 } |
| 1786 |
| 1787 |
| 1788 void Assembler::fincstp() { |
| 1789 EnsureSpace ensure_space(this); |
| 1790 last_pc_ = pc_; |
| 1791 EMIT(0xD9); |
| 1792 EMIT(0xF7); |
| 1793 } |
| 1794 |
| 1795 |
| 1796 void Assembler::ffree(int i) { |
| 1797 EnsureSpace ensure_space(this); |
| 1798 last_pc_ = pc_; |
| 1799 emit_farith(0xDD, 0xC0, i); |
| 1800 } |
| 1801 |
| 1802 |
| 1803 void Assembler::ftst() { |
| 1804 EnsureSpace ensure_space(this); |
| 1805 last_pc_ = pc_; |
| 1806 EMIT(0xD9); |
| 1807 EMIT(0xE4); |
| 1808 } |
| 1809 |
| 1810 |
| 1811 void Assembler::fucomp(int i) { |
| 1812 EnsureSpace ensure_space(this); |
| 1813 last_pc_ = pc_; |
| 1814 emit_farith(0xDD, 0xE8, i); |
| 1815 } |
| 1816 |
| 1817 |
| 1818 void Assembler::fucompp() { |
| 1819 EnsureSpace ensure_space(this); |
| 1820 last_pc_ = pc_; |
| 1821 EMIT(0xDA); |
| 1822 EMIT(0xE9); |
| 1823 } |
| 1824 |
| 1825 |
| 1826 void Assembler::fcompp() { |
| 1827 EnsureSpace ensure_space(this); |
| 1828 last_pc_ = pc_; |
| 1829 EMIT(0xDE); |
| 1830 EMIT(0xD9); |
| 1831 } |
| 1832 |
| 1833 |
| 1834 void Assembler::fnstsw_ax() { |
| 1835 EnsureSpace ensure_space(this); |
| 1836 last_pc_ = pc_; |
| 1837 EMIT(0xdF); |
| 1838 EMIT(0xE0); |
| 1839 } |
| 1840 |
| 1841 |
| 1842 void Assembler::fwait() { |
| 1843 EnsureSpace ensure_space(this); |
| 1844 last_pc_ = pc_; |
| 1845 EMIT(0x9B); |
| 1846 } |
| 1847 |
| 1848 |
| 1849 void Assembler::frndint() { |
| 1850 EnsureSpace ensure_space(this); |
| 1851 last_pc_ = pc_; |
| 1852 EMIT(0xD9); |
| 1853 EMIT(0xFC); |
| 1854 } |
| 1855 |
| 1856 |
| 1857 void Assembler::fnclex() { |
| 1858 EnsureSpace ensure_space(this); |
| 1859 last_pc_ = pc_; |
| 1860 EMIT(0xDB); |
| 1861 EMIT(0xE2); |
| 1862 } |
| 1863 |
| 1864 |
| 1865 void Assembler::sahf() { |
| 1866 EnsureSpace ensure_space(this); |
| 1867 last_pc_ = pc_; |
| 1868 EMIT(0x9E); |
| 1869 } |
| 1870 |
| 1871 |
| 1872 void Assembler::setcc(Condition cc, Register reg) { |
| 1873 ASSERT(reg.is_byte_register()); |
| 1874 EnsureSpace ensure_space(this); |
| 1875 last_pc_ = pc_; |
| 1876 EMIT(0x0F); |
| 1877 EMIT(0x90 | cc); |
| 1878 EMIT(0xC0 | reg.code()); |
| 1879 } |
| 1880 |
| 1881 |
| 1882 void Assembler::cvttss2si(Register dst, const Operand& src) { |
| 1883 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1884 EnsureSpace ensure_space(this); |
| 1885 last_pc_ = pc_; |
| 1886 EMIT(0xF3); |
| 1887 EMIT(0x0F); |
| 1888 EMIT(0x2C); |
| 1889 emit_operand(dst, src); |
| 1890 } |
| 1891 |
| 1892 |
| 1893 void Assembler::cvttsd2si(Register dst, const Operand& src) { |
| 1894 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1895 EnsureSpace ensure_space(this); |
| 1896 last_pc_ = pc_; |
| 1897 EMIT(0xF2); |
| 1898 EMIT(0x0F); |
| 1899 EMIT(0x2C); |
| 1900 emit_operand(dst, src); |
| 1901 } |
| 1902 |
| 1903 |
| 1904 void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) { |
| 1905 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1906 EnsureSpace ensure_space(this); |
| 1907 last_pc_ = pc_; |
| 1908 EMIT(0xF2); |
| 1909 EMIT(0x0F); |
| 1910 EMIT(0x2A); |
| 1911 emit_sse_operand(dst, src); |
| 1912 } |
| 1913 |
| 1914 |
| 1915 void Assembler::addsd(XMMRegister dst, XMMRegister src) { |
| 1916 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1917 EnsureSpace ensure_space(this); |
| 1918 last_pc_ = pc_; |
| 1919 EMIT(0xF2); |
| 1920 EMIT(0x0F); |
| 1921 EMIT(0x58); |
| 1922 emit_sse_operand(dst, src); |
| 1923 } |
| 1924 |
| 1925 |
| 1926 void Assembler::mulsd(XMMRegister dst, XMMRegister src) { |
| 1927 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1928 EnsureSpace ensure_space(this); |
| 1929 last_pc_ = pc_; |
| 1930 EMIT(0xF2); |
| 1931 EMIT(0x0F); |
| 1932 EMIT(0x59); |
| 1933 emit_sse_operand(dst, src); |
| 1934 } |
| 1935 |
| 1936 |
| 1937 void Assembler::subsd(XMMRegister dst, XMMRegister src) { |
| 1938 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1939 EnsureSpace ensure_space(this); |
| 1940 last_pc_ = pc_; |
| 1941 EMIT(0xF2); |
| 1942 EMIT(0x0F); |
| 1943 EMIT(0x5C); |
| 1944 emit_sse_operand(dst, src); |
| 1945 } |
| 1946 |
| 1947 |
| 1948 void Assembler::divsd(XMMRegister dst, XMMRegister src) { |
| 1949 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1950 EnsureSpace ensure_space(this); |
| 1951 last_pc_ = pc_; |
| 1952 EMIT(0xF2); |
| 1953 EMIT(0x0F); |
| 1954 EMIT(0x5E); |
| 1955 emit_sse_operand(dst, src); |
| 1956 } |
| 1957 |
| 1958 |
| 1959 void Assembler::movdbl(XMMRegister dst, const Operand& src) { |
| 1960 EnsureSpace ensure_space(this); |
| 1961 last_pc_ = pc_; |
| 1962 movsd(dst, src); |
| 1963 } |
| 1964 |
| 1965 |
| 1966 void Assembler::movdbl(const Operand& dst, XMMRegister src) { |
| 1967 EnsureSpace ensure_space(this); |
| 1968 last_pc_ = pc_; |
| 1969 movsd(dst, src); |
| 1970 } |
| 1971 |
| 1972 |
| 1973 void Assembler::movsd(const Operand& dst, XMMRegister src ) { |
| 1974 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1975 EnsureSpace ensure_space(this); |
| 1976 last_pc_ = pc_; |
| 1977 EMIT(0xF2); // double |
| 1978 EMIT(0x0F); |
| 1979 EMIT(0x11); // store |
| 1980 emit_sse_operand(src, dst); |
| 1981 } |
| 1982 |
| 1983 |
| 1984 void Assembler::movsd(XMMRegister dst, const Operand& src) { |
| 1985 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); |
| 1986 EnsureSpace ensure_space(this); |
| 1987 last_pc_ = pc_; |
| 1988 EMIT(0xF2); // double |
| 1989 EMIT(0x0F); |
| 1990 EMIT(0x10); // load |
| 1991 emit_sse_operand(dst, src); |
| 1992 } |
| 1993 |
| 1994 |
| 1995 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) { |
| 1996 Register ireg = { reg.code() }; |
| 1997 emit_operand(ireg, adr); |
| 1998 } |
| 1999 |
| 2000 |
| 2001 void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) { |
| 2002 EMIT(0xC0 | dst.code() << 3 | src.code()); |
| 2003 } |
| 2004 |
| 2005 |
| 2006 void Assembler::Print() { |
| 2007 Disassembler::Decode(stdout, buffer_, pc_); |
| 2008 } |
| 2009 |
| 2010 |
| 2011 void Assembler::RecordJSReturn() { |
| 2012 WriteRecordedPositions(); |
| 2013 EnsureSpace ensure_space(this); |
| 2014 RecordRelocInfo(RelocInfo::JS_RETURN); |
| 2015 } |
| 2016 |
| 2017 |
| 2018 void Assembler::RecordComment(const char* msg) { |
| 2019 if (FLAG_debug_code) { |
| 2020 EnsureSpace ensure_space(this); |
| 2021 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); |
| 2022 } |
| 2023 } |
| 2024 |
| 2025 |
| 2026 void Assembler::RecordPosition(int pos) { |
| 2027 ASSERT(pos != RelocInfo::kNoPosition); |
| 2028 ASSERT(pos >= 0); |
| 2029 current_position_ = pos; |
| 2030 } |
| 2031 |
| 2032 |
| 2033 void Assembler::RecordStatementPosition(int pos) { |
| 2034 ASSERT(pos != RelocInfo::kNoPosition); |
| 2035 ASSERT(pos >= 0); |
| 2036 current_statement_position_ = pos; |
| 2037 } |
| 2038 |
| 2039 |
| 2040 void Assembler::WriteRecordedPositions() { |
| 2041 // Write the statement position if it is different from what was written last |
| 2042 // time. |
| 2043 if (current_statement_position_ != written_statement_position_) { |
| 2044 EnsureSpace ensure_space(this); |
| 2045 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_); |
| 2046 written_statement_position_ = current_statement_position_; |
| 2047 } |
| 2048 |
| 2049 // Write the position if it is different from what was written last time and |
| 2050 // also different from the written statement position. |
| 2051 if (current_position_ != written_position_ && |
| 2052 current_position_ != written_statement_position_) { |
| 2053 EnsureSpace ensure_space(this); |
| 2054 RecordRelocInfo(RelocInfo::POSITION, current_position_); |
| 2055 written_position_ = current_position_; |
| 2056 } |
| 2057 } |
| 2058 |
| 2059 |
| 2060 void Assembler::GrowBuffer() { |
| 2061 ASSERT(overflow()); // should not call this otherwise |
| 2062 if (!own_buffer_) FATAL("external code buffer is too small"); |
| 2063 |
| 2064 // compute new buffer size |
| 2065 CodeDesc desc; // the new buffer |
| 2066 if (buffer_size_ < 4*KB) { |
| 2067 desc.buffer_size = 4*KB; |
| 2068 } else { |
| 2069 desc.buffer_size = 2*buffer_size_; |
| 2070 } |
| 2071 // Some internal data structures overflow for very large buffers, |
| 2072 // they must ensure that kMaximalBufferSize is not too large. |
| 2073 if ((desc.buffer_size > kMaximalBufferSize) || |
| 2074 (desc.buffer_size > Heap::OldGenerationSize())) { |
| 2075 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer"); |
| 2076 } |
| 2077 |
| 2078 // setup new buffer |
| 2079 desc.buffer = NewArray<byte>(desc.buffer_size); |
| 2080 desc.instr_size = pc_offset(); |
| 2081 desc.reloc_size = (buffer_ + buffer_size_) - (reloc_info_writer.pos()); |
| 2082 |
| 2083 // Clear the buffer in debug mode. Use 'int3' instructions to make |
| 2084 // sure to get into problems if we ever run uninitialized code. |
| 2085 #ifdef DEBUG |
| 2086 memset(desc.buffer, 0xCC, desc.buffer_size); |
| 2087 #endif |
| 2088 |
| 2089 // copy the data |
| 2090 int pc_delta = desc.buffer - buffer_; |
| 2091 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); |
| 2092 memmove(desc.buffer, buffer_, desc.instr_size); |
| 2093 memmove(rc_delta + reloc_info_writer.pos(), |
| 2094 reloc_info_writer.pos(), desc.reloc_size); |
| 2095 |
| 2096 // switch buffers |
| 2097 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { |
| 2098 spare_buffer_ = buffer_; |
| 2099 } else { |
| 2100 DeleteArray(buffer_); |
| 2101 } |
| 2102 buffer_ = desc.buffer; |
| 2103 buffer_size_ = desc.buffer_size; |
| 2104 pc_ += pc_delta; |
| 2105 if (last_pc_ != NULL) { |
| 2106 last_pc_ += pc_delta; |
| 2107 } |
| 2108 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, |
| 2109 reloc_info_writer.last_pc() + pc_delta); |
| 2110 |
| 2111 // relocate runtime entries |
| 2112 for (RelocIterator it(desc); !it.done(); it.next()) { |
| 2113 RelocInfo::Mode rmode = it.rinfo()->rmode(); |
| 2114 if (rmode == RelocInfo::RUNTIME_ENTRY) { |
| 2115 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc()); |
| 2116 *p -= pc_delta; // relocate entry |
| 2117 } else if (rmode == RelocInfo::INTERNAL_REFERENCE) { |
| 2118 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc()); |
| 2119 if (*p != 0) { // 0 means uninitialized. |
| 2120 *p += pc_delta; |
| 2121 } |
| 2122 } |
| 2123 } |
| 2124 |
| 2125 ASSERT(!overflow()); |
| 2126 } |
| 2127 |
| 2128 |
| 2129 void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { |
| 2130 ASSERT(is_uint8(op1) && is_uint8(op2)); // wrong opcode |
| 2131 ASSERT(is_uint8(imm8)); |
| 2132 ASSERT((op1 & 0x01) == 0); // should be 8bit operation |
| 2133 EMIT(op1); |
| 2134 EMIT(op2 | dst.code()); |
| 2135 EMIT(imm8); |
| 2136 } |
| 2137 |
| 2138 |
| 2139 void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) { |
| 2140 ASSERT((0 <= sel) && (sel <= 7)); |
| 2141 Register ireg = { sel }; |
| 2142 if (x.is_int8()) { |
| 2143 EMIT(0x83); // using a sign-extended 8-bit immediate. |
| 2144 emit_operand(ireg, dst); |
| 2145 EMIT(x.x_ & 0xFF); |
| 2146 } else if (dst.is_reg(eax)) { |
| 2147 EMIT((sel << 3) | 0x05); // short form if the destination is eax. |
| 2148 emit(x); |
| 2149 } else { |
| 2150 EMIT(0x81); // using a literal 32-bit immediate. |
| 2151 emit_operand(ireg, dst); |
| 2152 emit(x); |
| 2153 } |
| 2154 } |
| 2155 |
| 2156 |
| 2157 void Assembler::emit_operand(Register reg, const Operand& adr) { |
| 2158 const unsigned length = adr.len_; |
| 2159 ASSERT(length > 0); |
| 2160 |
| 2161 // Emit updated ModRM byte containing the given register. |
| 2162 pc_[0] = (adr.buf_[0] & ~0x38) | (reg.code() << 3); |
| 2163 |
| 2164 // Emit the rest of the encoded operand. |
| 2165 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i]; |
| 2166 pc_ += length; |
| 2167 |
| 2168 // Emit relocation information if necessary. |
| 2169 if (length >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) { |
| 2170 pc_ -= sizeof(int32_t); // pc_ must be *at* disp32 |
| 2171 RecordRelocInfo(adr.rmode_); |
| 2172 pc_ += sizeof(int32_t); |
| 2173 } |
| 2174 } |
| 2175 |
| 2176 |
| 2177 void Assembler::emit_farith(int b1, int b2, int i) { |
| 2178 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode |
| 2179 ASSERT(0 <= i && i < 8); // illegal stack offset |
| 2180 EMIT(b1); |
| 2181 EMIT(b2 + i); |
| 2182 } |
| 2183 |
| 2184 |
| 2185 void Assembler::dd(uint32_t data, RelocInfo::Mode reloc_info) { |
| 2186 EnsureSpace ensure_space(this); |
| 2187 emit(data, reloc_info); |
| 2188 } |
| 2189 |
| 2190 |
| 2191 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
| 2192 ASSERT(rmode != RelocInfo::NONE); |
| 2193 // Don't record external references unless the heap will be serialized. |
| 2194 if (rmode == RelocInfo::EXTERNAL_REFERENCE && |
| 2195 !Serializer::enabled() && |
| 2196 !FLAG_debug_code) { |
| 2197 return; |
| 2198 } |
| 2199 RelocInfo rinfo(pc_, rmode, data); |
| 2200 reloc_info_writer.Write(&rinfo); |
| 2201 } |
| 2202 |
| 2203 |
| 2204 void Assembler::WriteInternalReference(int position, const Label& bound_label) { |
| 2205 ASSERT(bound_label.is_bound()); |
| 2206 ASSERT(0 <= position); |
| 2207 ASSERT(position + static_cast<int>(sizeof(uint32_t)) <= pc_offset()); |
| 2208 ASSERT(long_at(position) == 0); // only initialize once! |
| 2209 |
| 2210 uint32_t label_loc = reinterpret_cast<uint32_t>(addr_at(bound_label.pos())); |
| 2211 long_at_put(position, label_loc); |
| 2212 } |
| 2213 |
| 2214 |
| 2215 #ifdef GENERATED_CODE_COVERAGE |
| 2216 static FILE* coverage_log = NULL; |
| 2217 |
| 2218 |
| 2219 static void InitCoverageLog() { |
| 2220 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); |
| 2221 if (file_name != NULL) { |
| 2222 coverage_log = fopen(file_name, "aw+"); |
| 2223 } |
| 2224 } |
| 2225 |
| 2226 |
| 2227 void LogGeneratedCodeCoverage(const char* file_line) { |
| 2228 const char* return_address = (&file_line)[-1]; |
| 2229 char* push_insn = const_cast<char*>(return_address - 12); |
| 2230 push_insn[0] = 0xeb; // Relative branch insn. |
| 2231 push_insn[1] = 13; // Skip over coverage insns. |
| 2232 if (coverage_log != NULL) { |
| 2233 fprintf(coverage_log, "%s\n", file_line); |
| 2234 fflush(coverage_log); |
| 2235 } |
| 2236 } |
| 2237 |
| 2238 #endif |
| 2239 |
| 2240 } } // namespace v8::internal |
OLD | NEW |