| 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 |