| OLD | NEW |
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
| 2 // All Rights Reserved. | 2 // All Rights Reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
| 6 // are met: | 6 // are met: |
| 7 // | 7 // |
| 8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
| 9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
| 10 // | 10 // |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| 31 // OF THE POSSIBILITY OF SUCH DAMAGE. | 31 // OF THE POSSIBILITY OF SUCH DAMAGE. |
| 32 | 32 |
| 33 // The original source code covered by the above license above has been modified | 33 // The original source code covered by the above license above has been modified |
| 34 // significantly by Google Inc. | 34 // significantly by Google Inc. |
| 35 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 35 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 36 | 36 |
| 37 #include "v8.h" | 37 #include "v8.h" |
| 38 | 38 |
| 39 #if defined(V8_TARGET_ARCH_IA32) |
| 40 |
| 39 #include "disassembler.h" | 41 #include "disassembler.h" |
| 40 #include "macro-assembler.h" | 42 #include "macro-assembler.h" |
| 41 #include "serialize.h" | 43 #include "serialize.h" |
| 42 | 44 |
| 43 namespace v8 { | 45 namespace v8 { |
| 44 namespace internal { | 46 namespace internal { |
| 45 | 47 |
| 46 // ----------------------------------------------------------------------------- | 48 // ----------------------------------------------------------------------------- |
| 47 // Implementation of CpuFeatures | 49 // Implementation of CpuFeatures |
| 48 | 50 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 | 155 |
| 154 // ----------------------------------------------------------------------------- | 156 // ----------------------------------------------------------------------------- |
| 155 // Implementation of RelocInfo | 157 // Implementation of RelocInfo |
| 156 | 158 |
| 157 | 159 |
| 158 const int RelocInfo::kApplyMask = | 160 const int RelocInfo::kApplyMask = |
| 159 RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | | 161 RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | |
| 160 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE; | 162 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE; |
| 161 | 163 |
| 162 | 164 |
| 165 bool RelocInfo::IsCodedSpecially() { |
| 166 // The deserializer needs to know whether a pointer is specially coded. Being |
| 167 // specially coded on IA32 means that it is a relative address, as used by |
| 168 // branch instructions. These are also the ones that need changing when a |
| 169 // code object moves. |
| 170 return (1 << rmode_) & kApplyMask; |
| 171 } |
| 172 |
| 173 |
| 163 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { | 174 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { |
| 164 // Patch the code at the current address with the supplied instructions. | 175 // Patch the code at the current address with the supplied instructions. |
| 165 for (int i = 0; i < instruction_count; i++) { | 176 for (int i = 0; i < instruction_count; i++) { |
| 166 *(pc_ + i) = *(instructions + i); | 177 *(pc_ + i) = *(instructions + i); |
| 167 } | 178 } |
| 168 | 179 |
| 169 // Indicate that code has changed. | 180 // Indicate that code has changed. |
| 170 CPU::FlushICache(pc_, instruction_count); | 181 CPU::FlushICache(pc_, instruction_count); |
| 171 } | 182 } |
| 172 | 183 |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 void Assembler::push(const Operand& src) { | 437 void Assembler::push(const Operand& src) { |
| 427 EnsureSpace ensure_space(this); | 438 EnsureSpace ensure_space(this); |
| 428 last_pc_ = pc_; | 439 last_pc_ = pc_; |
| 429 EMIT(0xFF); | 440 EMIT(0xFF); |
| 430 emit_operand(esi, src); | 441 emit_operand(esi, src); |
| 431 } | 442 } |
| 432 | 443 |
| 433 | 444 |
| 434 void Assembler::pop(Register dst) { | 445 void Assembler::pop(Register dst) { |
| 435 ASSERT(reloc_info_writer.last_pc() != NULL); | 446 ASSERT(reloc_info_writer.last_pc() != NULL); |
| 436 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { | 447 if (FLAG_peephole_optimization && (reloc_info_writer.last_pc() <= last_pc_)) { |
| 437 // (last_pc_ != NULL) is rolled into the above check. | 448 // (last_pc_ != NULL) is rolled into the above check. |
| 438 // If a last_pc_ is set, we need to make sure that there has not been any | 449 // If a last_pc_ is set, we need to make sure that there has not been any |
| 439 // relocation information generated between the last instruction and this | 450 // relocation information generated between the last instruction and this |
| 440 // pop instruction. | 451 // pop instruction. |
| 441 byte instr = last_pc_[0]; | 452 byte instr = last_pc_[0]; |
| 442 if ((instr & ~0x7) == 0x50) { | 453 if ((instr & ~0x7) == 0x50) { |
| 443 int push_reg_code = instr & 0x7; | 454 int push_reg_code = instr & 0x7; |
| 444 if (push_reg_code == dst.code()) { | 455 if (push_reg_code == dst.code()) { |
| 445 pc_ = last_pc_; | 456 pc_ = last_pc_; |
| 446 if (FLAG_print_push_pop_elimination) { | 457 if (FLAG_print_peephole_optimization) { |
| 447 PrintF("%d push/pop (same reg) eliminated\n", pc_offset()); | 458 PrintF("%d push/pop (same reg) eliminated\n", pc_offset()); |
| 448 } | 459 } |
| 449 } else { | 460 } else { |
| 450 // Convert 'push src; pop dst' to 'mov dst, src'. | 461 // Convert 'push src; pop dst' to 'mov dst, src'. |
| 451 last_pc_[0] = 0x8b; | 462 last_pc_[0] = 0x8b; |
| 452 Register src = { push_reg_code }; | 463 Register src = { push_reg_code }; |
| 453 EnsureSpace ensure_space(this); | 464 EnsureSpace ensure_space(this); |
| 454 emit_operand(dst, Operand(src)); | 465 emit_operand(dst, Operand(src)); |
| 455 if (FLAG_print_push_pop_elimination) { | 466 if (FLAG_print_peephole_optimization) { |
| 456 PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset()); | 467 PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset()); |
| 457 } | 468 } |
| 458 } | 469 } |
| 459 last_pc_ = NULL; | 470 last_pc_ = NULL; |
| 460 return; | 471 return; |
| 461 } else if (instr == 0xff) { // push of an operand, convert to a move | 472 } else if (instr == 0xff) { // push of an operand, convert to a move |
| 462 byte op1 = last_pc_[1]; | 473 byte op1 = last_pc_[1]; |
| 463 // Check if the operation is really a push. | 474 // Check if the operation is really a push. |
| 464 if ((op1 & 0x38) == (6 << 3)) { | 475 if ((op1 & 0x38) == (6 << 3)) { |
| 465 op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3); | 476 op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3); |
| 466 last_pc_[0] = 0x8b; | 477 last_pc_[0] = 0x8b; |
| 467 last_pc_[1] = op1; | 478 last_pc_[1] = op1; |
| 468 last_pc_ = NULL; | 479 last_pc_ = NULL; |
| 469 if (FLAG_print_push_pop_elimination) { | 480 if (FLAG_print_peephole_optimization) { |
| 470 PrintF("%d push/pop (op->reg) eliminated\n", pc_offset()); | 481 PrintF("%d push/pop (op->reg) eliminated\n", pc_offset()); |
| 471 } | 482 } |
| 472 return; | 483 return; |
| 473 } | 484 } |
| 474 } else if ((instr == 0x89) && | 485 } else if ((instr == 0x89) && |
| 475 (last_pc_[1] == 0x04) && | 486 (last_pc_[1] == 0x04) && |
| 476 (last_pc_[2] == 0x24)) { | 487 (last_pc_[2] == 0x24)) { |
| 477 // 0x71283c 396 890424 mov [esp],eax | 488 // 0x71283c 396 890424 mov [esp],eax |
| 478 // 0x71283f 399 58 pop eax | 489 // 0x71283f 399 58 pop eax |
| 479 if (dst.is(eax)) { | 490 if (dst.is(eax)) { |
| 480 // change to | 491 // change to |
| 481 // 0x710fac 216 83c404 add esp,0x4 | 492 // 0x710fac 216 83c404 add esp,0x4 |
| 482 last_pc_[0] = 0x83; | 493 last_pc_[0] = 0x83; |
| 483 last_pc_[1] = 0xc4; | 494 last_pc_[1] = 0xc4; |
| 484 last_pc_[2] = 0x04; | 495 last_pc_[2] = 0x04; |
| 485 last_pc_ = NULL; | 496 last_pc_ = NULL; |
| 486 if (FLAG_print_push_pop_elimination) { | 497 if (FLAG_print_peephole_optimization) { |
| 487 PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset()); | 498 PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset()); |
| 488 } | 499 } |
| 489 return; | 500 return; |
| 490 } | 501 } |
| 491 } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit | 502 } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit |
| 492 byte imm8 = last_pc_[1]; | 503 byte imm8 = last_pc_[1]; |
| 493 if (imm8 == 0) { | 504 if (imm8 == 0) { |
| 494 // 6a00 push 0x0 | 505 // 6a00 push 0x0 |
| 495 // 58 pop eax | 506 // 58 pop eax |
| 496 last_pc_[0] = 0x31; | 507 last_pc_[0] = 0x31; |
| 497 last_pc_[1] = 0xc0; | 508 last_pc_[1] = 0xc0; |
| 498 // change to | 509 // change to |
| 499 // 31c0 xor eax,eax | 510 // 31c0 xor eax,eax |
| 500 last_pc_ = NULL; | 511 last_pc_ = NULL; |
| 501 if (FLAG_print_push_pop_elimination) { | 512 if (FLAG_print_peephole_optimization) { |
| 502 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | 513 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 503 } | 514 } |
| 504 return; | 515 return; |
| 505 } else { | 516 } else { |
| 506 // 6a00 push 0xXX | 517 // 6a00 push 0xXX |
| 507 // 58 pop eax | 518 // 58 pop eax |
| 508 last_pc_[0] = 0xb8; | 519 last_pc_[0] = 0xb8; |
| 509 EnsureSpace ensure_space(this); | 520 EnsureSpace ensure_space(this); |
| 510 if ((imm8 & 0x80) != 0) { | 521 if ((imm8 & 0x80) != 0) { |
| 511 EMIT(0xff); | 522 EMIT(0xff); |
| 512 EMIT(0xff); | 523 EMIT(0xff); |
| 513 EMIT(0xff); | 524 EMIT(0xff); |
| 514 // change to | 525 // change to |
| 515 // b8XXffffff mov eax,0xffffffXX | 526 // b8XXffffff mov eax,0xffffffXX |
| 516 } else { | 527 } else { |
| 517 EMIT(0x00); | 528 EMIT(0x00); |
| 518 EMIT(0x00); | 529 EMIT(0x00); |
| 519 EMIT(0x00); | 530 EMIT(0x00); |
| 520 // change to | 531 // change to |
| 521 // b8XX000000 mov eax,0x000000XX | 532 // b8XX000000 mov eax,0x000000XX |
| 522 } | 533 } |
| 523 last_pc_ = NULL; | 534 last_pc_ = NULL; |
| 524 if (FLAG_print_push_pop_elimination) { | 535 if (FLAG_print_peephole_optimization) { |
| 525 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | 536 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 526 } | 537 } |
| 527 return; | 538 return; |
| 528 } | 539 } |
| 529 } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit | 540 } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit |
| 530 // 68XXXXXXXX push 0xXXXXXXXX | 541 // 68XXXXXXXX push 0xXXXXXXXX |
| 531 // 58 pop eax | 542 // 58 pop eax |
| 532 last_pc_[0] = 0xb8; | 543 last_pc_[0] = 0xb8; |
| 533 last_pc_ = NULL; | 544 last_pc_ = NULL; |
| 534 // change to | 545 // change to |
| 535 // b8XXXXXXXX mov eax,0xXXXXXXXX | 546 // b8XXXXXXXX mov eax,0xXXXXXXXX |
| 536 if (FLAG_print_push_pop_elimination) { | 547 if (FLAG_print_peephole_optimization) { |
| 537 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | 548 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); |
| 538 } | 549 } |
| 539 return; | 550 return; |
| 540 } | 551 } |
| 541 | 552 |
| 542 // Other potential patterns for peephole: | 553 // Other potential patterns for peephole: |
| 543 // 0x712716 102 890424 mov [esp], eax | 554 // 0x712716 102 890424 mov [esp], eax |
| 544 // 0x712719 105 8b1424 mov edx, [esp] | 555 // 0x712719 105 8b1424 mov edx, [esp] |
| 545 } | 556 } |
| 546 EnsureSpace ensure_space(this); | 557 EnsureSpace ensure_space(this); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 | 780 |
| 770 | 781 |
| 771 void Assembler::rep_stos() { | 782 void Assembler::rep_stos() { |
| 772 EnsureSpace ensure_space(this); | 783 EnsureSpace ensure_space(this); |
| 773 last_pc_ = pc_; | 784 last_pc_ = pc_; |
| 774 EMIT(0xF3); | 785 EMIT(0xF3); |
| 775 EMIT(0xAB); | 786 EMIT(0xAB); |
| 776 } | 787 } |
| 777 | 788 |
| 778 | 789 |
| 790 void Assembler::stos() { |
| 791 EnsureSpace ensure_space(this); |
| 792 last_pc_ = pc_; |
| 793 EMIT(0xAB); |
| 794 } |
| 795 |
| 796 |
| 779 void Assembler::xchg(Register dst, Register src) { | 797 void Assembler::xchg(Register dst, Register src) { |
| 780 EnsureSpace ensure_space(this); | 798 EnsureSpace ensure_space(this); |
| 781 last_pc_ = pc_; | 799 last_pc_ = pc_; |
| 782 if (src.is(eax) || dst.is(eax)) { // Single-byte encoding. | 800 if (src.is(eax) || dst.is(eax)) { // Single-byte encoding. |
| 783 EMIT(0x90 | (src.is(eax) ? dst.code() : src.code())); | 801 EMIT(0x90 | (src.is(eax) ? dst.code() : src.code())); |
| 784 } else { | 802 } else { |
| 785 EMIT(0x87); | 803 EMIT(0x87); |
| 786 EMIT(0xC0 | src.code() << 3 | dst.code()); | 804 EMIT(0xC0 | src.code() << 3 | dst.code()); |
| 787 } | 805 } |
| 788 } | 806 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 806 void Assembler::add(Register dst, const Operand& src) { | 824 void Assembler::add(Register dst, const Operand& src) { |
| 807 EnsureSpace ensure_space(this); | 825 EnsureSpace ensure_space(this); |
| 808 last_pc_ = pc_; | 826 last_pc_ = pc_; |
| 809 EMIT(0x03); | 827 EMIT(0x03); |
| 810 emit_operand(dst, src); | 828 emit_operand(dst, src); |
| 811 } | 829 } |
| 812 | 830 |
| 813 | 831 |
| 814 void Assembler::add(const Operand& dst, const Immediate& x) { | 832 void Assembler::add(const Operand& dst, const Immediate& x) { |
| 815 ASSERT(reloc_info_writer.last_pc() != NULL); | 833 ASSERT(reloc_info_writer.last_pc() != NULL); |
| 816 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { | 834 if (FLAG_peephole_optimization && (reloc_info_writer.last_pc() <= last_pc_)) { |
| 817 byte instr = last_pc_[0]; | 835 byte instr = last_pc_[0]; |
| 818 if ((instr & 0xf8) == 0x50) { | 836 if ((instr & 0xf8) == 0x50) { |
| 819 // Last instruction was a push. Check whether this is a pop without a | 837 // Last instruction was a push. Check whether this is a pop without a |
| 820 // result. | 838 // result. |
| 821 if ((dst.is_reg(esp)) && | 839 if ((dst.is_reg(esp)) && |
| 822 (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) { | 840 (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) { |
| 823 pc_ = last_pc_; | 841 pc_ = last_pc_; |
| 824 last_pc_ = NULL; | 842 last_pc_ = NULL; |
| 825 if (FLAG_print_push_pop_elimination) { | 843 if (FLAG_print_peephole_optimization) { |
| 826 PrintF("%d push/pop(noreg) eliminated\n", pc_offset()); | 844 PrintF("%d push/pop(noreg) eliminated\n", pc_offset()); |
| 827 } | 845 } |
| 828 return; | 846 return; |
| 829 } | 847 } |
| 830 } | 848 } |
| 831 } | 849 } |
| 832 EnsureSpace ensure_space(this); | 850 EnsureSpace ensure_space(this); |
| 833 last_pc_ = pc_; | 851 last_pc_ = pc_; |
| 834 emit_arith(0, dst, x); | 852 emit_arith(0, dst, x); |
| 835 } | 853 } |
| (...skipping 1685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2521 push_insn[1] = 13; // Skip over coverage insns. | 2539 push_insn[1] = 13; // Skip over coverage insns. |
| 2522 if (coverage_log != NULL) { | 2540 if (coverage_log != NULL) { |
| 2523 fprintf(coverage_log, "%s\n", file_line); | 2541 fprintf(coverage_log, "%s\n", file_line); |
| 2524 fflush(coverage_log); | 2542 fflush(coverage_log); |
| 2525 } | 2543 } |
| 2526 } | 2544 } |
| 2527 | 2545 |
| 2528 #endif | 2546 #endif |
| 2529 | 2547 |
| 2530 } } // namespace v8::internal | 2548 } } // namespace v8::internal |
| 2549 |
| 2550 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |