Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_ASSEMBLER_MIPS_H_ | 5 #ifndef VM_ASSEMBLER_MIPS_H_ |
| 6 #define VM_ASSEMBLER_MIPS_H_ | 6 #define VM_ASSEMBLER_MIPS_H_ |
| 7 | 7 |
| 8 #ifndef VM_ASSEMBLER_H_ | 8 #ifndef VM_ASSEMBLER_H_ |
| 9 #error Do not include assembler_mips.h directly; use assembler.h instead. | 9 #error Do not include assembler_mips.h directly; use assembler.h instead. |
| 10 #endif | 10 #endif |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 offset_ = other.offset_; | 51 offset_ = other.offset_; |
| 52 return *this; | 52 return *this; |
| 53 } | 53 } |
| 54 | 54 |
| 55 uint32_t encoding() const { | 55 uint32_t encoding() const { |
| 56 ASSERT(Utils::IsInt(16, offset_)); | 56 ASSERT(Utils::IsInt(16, offset_)); |
| 57 uint16_t imm_value = static_cast<uint16_t>(offset_); | 57 uint16_t imm_value = static_cast<uint16_t>(offset_); |
| 58 return (base_ << kRsShift) | imm_value; | 58 return (base_ << kRsShift) | imm_value; |
| 59 } | 59 } |
| 60 | 60 |
| 61 static bool CanHoldOffset(int32_t offset) { | |
| 62 return Utils::IsInt(16, offset); | |
| 63 } | |
| 64 | |
| 61 private: | 65 private: |
| 62 Register base_; | 66 Register base_; |
| 63 int32_t offset_; | 67 int32_t offset_; |
| 64 }; | 68 }; |
| 65 | 69 |
| 66 | 70 |
| 67 class FieldAddress : public Address { | 71 class FieldAddress : public Address { |
| 68 public: | 72 public: |
| 69 FieldAddress(Register base, int32_t disp) | 73 FieldAddress(Register base, int32_t disp) |
| 70 : Address(base, disp - kHeapObjectTag) { } | 74 : Address(base, disp - kHeapObjectTag) { } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 public: | 140 public: |
| 137 Assembler() | 141 Assembler() |
| 138 : buffer_(), | 142 : buffer_(), |
| 139 object_pool_(GrowableObjectArray::Handle()), | 143 object_pool_(GrowableObjectArray::Handle()), |
| 140 prologue_offset_(-1), | 144 prologue_offset_(-1), |
| 141 delay_slot_available_(false), | 145 delay_slot_available_(false), |
| 142 in_delay_slot_(false), | 146 in_delay_slot_(false), |
| 143 comments_() { } | 147 comments_() { } |
| 144 ~Assembler() { } | 148 ~Assembler() { } |
| 145 | 149 |
| 146 void PopRegister(Register r) { | 150 void PopRegister(Register r) { Pop(r); } |
| 147 UNIMPLEMENTED(); | |
| 148 } | |
| 149 | 151 |
| 150 void Bind(Label* label); | 152 void Bind(Label* label); |
| 151 | 153 |
| 152 // Misc. functionality | 154 // Misc. functionality |
| 153 int CodeSize() const { return buffer_.Size(); } | 155 int CodeSize() const { return buffer_.Size(); } |
| 154 int prologue_offset() const { return -1; } | 156 int prologue_offset() const { return -1; } |
| 155 const ZoneGrowableArray<int>& GetPointerOffsets() const { | 157 const ZoneGrowableArray<int>& GetPointerOffsets() const { |
| 156 return buffer_.pointer_offsets(); | 158 return buffer_.pointer_offsets(); |
| 157 } | 159 } |
| 158 const GrowableObjectArray& object_pool() const { return object_pool_; } | 160 const GrowableObjectArray& object_pool() const { return object_pool_; } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 183 // Allocated instance is returned in 'instance_reg'. | 185 // Allocated instance is returned in 'instance_reg'. |
| 184 // Only the tags field of the object is initialized. | 186 // Only the tags field of the object is initialized. |
| 185 void TryAllocate(const Class& cls, | 187 void TryAllocate(const Class& cls, |
| 186 Label* failure, | 188 Label* failure, |
| 187 bool near_jump, | 189 bool near_jump, |
| 188 Register instance_reg) { | 190 Register instance_reg) { |
| 189 UNIMPLEMENTED(); | 191 UNIMPLEMENTED(); |
| 190 } | 192 } |
| 191 | 193 |
| 192 // Debugging and bringup support. | 194 // Debugging and bringup support. |
| 193 void Stop(const char* message) { UNIMPLEMENTED(); } | 195 void Stop(const char* message); |
| 194 void Unimplemented(const char* message); | 196 void Unimplemented(const char* message); |
| 195 void Untested(const char* message); | 197 void Untested(const char* message); |
| 196 void Unreachable(const char* message); | 198 void Unreachable(const char* message); |
| 197 | 199 |
| 198 static void InitializeMemoryWithBreakpoints(uword data, int length); | 200 static void InitializeMemoryWithBreakpoints(uword data, int length); |
| 199 | 201 |
| 200 void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); | 202 void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
| 201 | 203 |
| 202 const Code::Comments& GetCodeComments() const; | 204 const Code::Comments& GetCodeComments() const; |
| 203 | 205 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 218 Instr::kNopInstruction); | 220 Instr::kNopInstruction); |
| 219 buffer_.Remit<int32_t>(); | 221 buffer_.Remit<int32_t>(); |
| 220 delay_slot_available_ = false; | 222 delay_slot_available_ = false; |
| 221 in_delay_slot_ = true; | 223 in_delay_slot_ = true; |
| 222 return this; | 224 return this; |
| 223 } | 225 } |
| 224 | 226 |
| 225 // CPU instructions in alphabetical order. | 227 // CPU instructions in alphabetical order. |
| 226 void addiu(Register rt, Register rs, const Immediate& imm) { | 228 void addiu(Register rt, Register rs, const Immediate& imm) { |
| 227 ASSERT(Utils::IsInt(16, imm.value())); | 229 ASSERT(Utils::IsInt(16, imm.value())); |
| 228 uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 230 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
| 229 EmitIType(ADDIU, rs, rt, imm_value); | 231 EmitIType(ADDIU, rs, rt, imm_value); |
| 230 } | 232 } |
| 231 | 233 |
| 232 void addu(Register rd, Register rs, Register rt) { | 234 void addu(Register rd, Register rs, Register rt) { |
| 233 EmitRType(SPECIAL, rs, rt, rd, 0, ADDU); | 235 EmitRType(SPECIAL, rs, rt, rd, 0, ADDU); |
| 234 } | 236 } |
| 235 | 237 |
| 236 void and_(Register rd, Register rs, Register rt) { | 238 void and_(Register rd, Register rs, Register rt) { |
| 237 EmitRType(SPECIAL, rs, rt, rd, 0, AND); | 239 EmitRType(SPECIAL, rs, rt, rd, 0, AND); |
| 238 } | 240 } |
| 239 | 241 |
| 240 void andi(Register rt, Register rs, const Immediate& imm) { | 242 void andi(Register rt, Register rs, const Immediate& imm) { |
| 241 ASSERT(Utils::IsUint(16, imm.value())); | 243 ASSERT(Utils::IsUint(16, imm.value())); |
| 242 uint16_t imm_value = static_cast<uint16_t>(imm.value()); | 244 const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
| 243 EmitIType(ANDI, rs, rt, imm_value); | 245 EmitIType(ANDI, rs, rt, imm_value); |
| 244 } | 246 } |
| 245 | 247 |
| 246 // Unconditional branch. | 248 // Unconditional branch. |
| 247 void b(Label* l) { | 249 void b(Label* l) { |
| 248 beq(R0, R0, l); | 250 beq(R0, R0, l); |
| 249 } | 251 } |
| 250 | 252 |
| 251 // Branch if equal. | 253 // Branch if equal. |
| 252 void beq(Register rs, Register rt, Label* l) { | 254 void beq(Register rs, Register rt, Label* l) { |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 | 498 |
| 497 void sw(Register rt, const Address& addr) { | 499 void sw(Register rt, const Address& addr) { |
| 498 EmitLoadStore(SW, rt, addr); | 500 EmitLoadStore(SW, rt, addr); |
| 499 } | 501 } |
| 500 | 502 |
| 501 void xor_(Register rd, Register rs, Register rt) { | 503 void xor_(Register rd, Register rs, Register rt) { |
| 502 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); | 504 EmitRType(SPECIAL, rs, rt, rd, 0, XOR); |
| 503 } | 505 } |
| 504 | 506 |
| 505 // Macros in alphabetical order. | 507 // Macros in alphabetical order. |
| 508 | |
| 509 void Branch(const ExternalLabel* label) { | |
| 510 // Doesn't need to be patchable, so use the delay slot. | |
| 511 if (Utils::IsInt(16, label->address())) { | |
| 512 jr(TMP); | |
| 513 delay_slot()->addiu(TMP, ZR, Immediate(label->address())); | |
| 514 } else { | |
| 515 const uint16_t low = Utils::Low16Bits(label->address()); | |
| 516 const uint16_t high = Utils::High16Bits(label->address()); | |
| 517 lui(TMP, Immediate(high)); | |
| 518 jr(TMP); | |
| 519 delay_slot()->ori(TMP, TMP, Immediate(low)); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 void BranchLink(const ExternalLabel* label) { | |
| 524 // Doesn't need to be patchable, so use the delay slot. | |
| 525 if (Utils::IsInt(16, label->address())) { | |
| 526 jalr(TMP); | |
| 527 delay_slot()->addiu(TMP, ZR, Immediate(label->address())); | |
| 528 } else { | |
| 529 const uint16_t low = Utils::Low16Bits(label->address()); | |
| 530 const uint16_t high = Utils::High16Bits(label->address()); | |
| 531 lui(TMP, Immediate(high)); | |
| 532 jalr(TMP); | |
| 533 delay_slot()->ori(TMP, TMP, Immediate(low)); | |
| 534 } | |
| 535 } | |
| 536 | |
| 537 void BranchLinkPatchable(const ExternalLabel* label) { | |
| 538 const int32_t offset = | |
| 539 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; | |
| 540 LoadWordFromPoolOffset(TMP, offset); | |
| 541 jalr(TMP); | |
| 542 } | |
| 543 | |
| 544 void BranchPatchable(const ExternalLabel* label) { | |
| 545 LoadImmediate(TMP, label->address()); | |
| 546 jr(TMP); | |
| 547 } | |
| 548 | |
| 549 void Drop(intptr_t stack_elements) { | |
| 550 ASSERT(stack_elements >= 0); | |
| 551 if (stack_elements > 0) { | |
| 552 addiu(SP, SP, Immediate(stack_elements * kWordSize)); | |
| 553 } | |
| 554 } | |
| 555 | |
| 506 void LoadImmediate(Register rd, int32_t value) { | 556 void LoadImmediate(Register rd, int32_t value) { |
| 507 if (Utils::IsInt(16, value)) { | 557 if (Utils::IsInt(16, value)) { |
| 508 addiu(rd, ZR, Immediate(value)); | 558 addiu(rd, ZR, Immediate(value)); |
| 509 } else { | 559 } else { |
| 510 lui(rd, Immediate((value >> 16) & 0xffff)); | 560 const uint16_t low = Utils::Low16Bits(value); |
| 511 ori(rd, rd, Immediate(value & 0xffff)); | 561 const uint16_t high = Utils::High16Bits(value); |
| 562 lui(rd, Immediate(high)); | |
| 563 ori(rd, rd, Immediate(low)); | |
| 512 } | 564 } |
| 513 } | 565 } |
| 514 | 566 |
| 567 void Push(Register rt) { | |
| 568 addiu(SP, SP, Immediate(-kWordSize)); | |
| 569 sw(rt, Address(SP)); | |
| 570 } | |
| 571 | |
| 572 void Pop(Register rt) { | |
| 573 lw(rt, Address(SP)); | |
| 574 addiu(SP, SP, Immediate(kWordSize)); | |
| 575 } | |
| 576 | |
| 577 void Ret() { | |
| 578 jr(RA); | |
| 579 } | |
| 580 | |
| 581 void LoadWordFromPoolOffset(Register rd, int32_t offset); | |
| 582 void LoadObject(Register rd, const Object& object); | |
| 583 void PushObject(const Object& object); | |
| 584 | |
| 585 // Sets register rd to zero if the object is equal to register rn, | |
| 586 // set to non-zero otherwise. | |
| 587 void CompareObject(Register rd, Register rn, const Object& object); | |
| 588 | |
| 515 private: | 589 private: |
| 516 AssemblerBuffer buffer_; | 590 AssemblerBuffer buffer_; |
| 517 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. | 591 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. |
| 518 int prologue_offset_; | 592 int prologue_offset_; |
| 519 | 593 |
| 520 bool delay_slot_available_; | 594 bool delay_slot_available_; |
| 521 bool in_delay_slot_; | 595 bool in_delay_slot_; |
| 522 | 596 |
| 597 int32_t AddObject(const Object& obj); | |
| 598 int32_t AddExternalLabel(const ExternalLabel* label); | |
| 599 | |
| 523 class CodeComment : public ZoneAllocated { | 600 class CodeComment : public ZoneAllocated { |
| 524 public: | 601 public: |
| 525 CodeComment(intptr_t pc_offset, const String& comment) | 602 CodeComment(intptr_t pc_offset, const String& comment) |
| 526 : pc_offset_(pc_offset), comment_(comment) { } | 603 : pc_offset_(pc_offset), comment_(comment) { } |
| 527 | 604 |
| 528 intptr_t pc_offset() const { return pc_offset_; } | 605 intptr_t pc_offset() const { return pc_offset_; } |
| 529 const String& comment() const { return comment_; } | 606 const String& comment() const { return comment_; } |
| 530 | 607 |
| 531 private: | 608 private: |
| 532 intptr_t pc_offset_; | 609 intptr_t pc_offset_; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 Emit(opcode << kOpcodeShift | | 665 Emit(opcode << kOpcodeShift | |
| 589 rs << kRsShift | | 666 rs << kRsShift | |
| 590 rt << kRtShift | | 667 rt << kRtShift | |
| 591 rd << kRdShift | | 668 rd << kRdShift | |
| 592 sa << kSaShift | | 669 sa << kSaShift | |
| 593 func << kFunctionShift); | 670 func << kFunctionShift); |
| 594 } | 671 } |
| 595 | 672 |
| 596 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | 673 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
| 597 if (label->IsBound()) { | 674 if (label->IsBound()) { |
| 598 // Reletive destination from an instruction after the branch. | 675 // Reletive destination from an instruction after the branch. |
|
regis
2013/03/26 17:52:35
ditto
regis
2013/03/26 17:52:35
ditto
| |
| 599 int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); | 676 const int32_t dest = |
| 600 uint16_t dest_off = EncodeBranchOffset(dest, 0); | 677 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 678 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 601 EmitIType(b, rs, rt, dest_off); | 679 EmitIType(b, rs, rt, dest_off); |
| 602 } else { | 680 } else { |
| 603 int position = buffer_.Size(); | 681 const int position = buffer_.Size(); |
| 604 EmitIType(b, rs, rt, label->position_); | 682 EmitIType(b, rs, rt, label->position_); |
| 605 label->LinkTo(position); | 683 label->LinkTo(position); |
| 606 } | 684 } |
| 607 } | 685 } |
| 608 | 686 |
| 609 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 687 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
| 610 if (label->IsBound()) { | 688 if (label->IsBound()) { |
| 611 // Reletive destination from an instruction after the branch. | 689 // Reletive destination from an instruction after the branch. |
|
regis
2013/03/26 17:52:35
ditto
| |
| 612 int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); | 690 const int32_t dest = |
| 613 uint16_t dest_off = EncodeBranchOffset(dest, 0); | 691 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 692 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 614 EmitRegImmType(REGIMM, rs, b, dest_off); | 693 EmitRegImmType(REGIMM, rs, b, dest_off); |
| 615 } else { | 694 } else { |
| 616 int position = buffer_.Size(); | 695 const int position = buffer_.Size(); |
| 617 EmitRegImmType(REGIMM, rs, b, label->position_); | 696 EmitRegImmType(REGIMM, rs, b, label->position_); |
| 618 label->LinkTo(position); | 697 label->LinkTo(position); |
| 619 } | 698 } |
| 620 } | 699 } |
| 621 | 700 |
| 622 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); | 701 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
| 623 static int DecodeBranchOffset(int32_t instr); | 702 static int DecodeBranchOffset(int32_t instr); |
| 624 | 703 |
| 625 void EmitBranchDelayNop() { | 704 void EmitBranchDelayNop() { |
| 626 Emit(Instr::kNopInstruction); // Branch delay NOP. | 705 Emit(Instr::kNopInstruction); // Branch delay NOP. |
| 627 delay_slot_available_ = true; | 706 delay_slot_available_ = true; |
| 628 } | 707 } |
| 629 | 708 |
| 630 DISALLOW_ALLOCATION(); | 709 DISALLOW_ALLOCATION(); |
| 631 DISALLOW_COPY_AND_ASSIGN(Assembler); | 710 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 632 }; | 711 }; |
| 633 | 712 |
| 634 } // namespace dart | 713 } // namespace dart |
| 635 | 714 |
| 636 #endif // VM_ASSEMBLER_MIPS_H_ | 715 #endif // VM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |