| 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 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/runtime_entry.h" | 9 #include "vm/runtime_entry.h" |
| 10 #include "vm/simulator.h" | 10 #include "vm/simulator.h" |
| 11 #include "vm/stack_frame.h" | 11 #include "vm/stack_frame.h" |
| 12 #include "vm/stub_code.h" | 12 #include "vm/stub_code.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 #if defined(USING_SIMULATOR) | 16 #if defined(USING_SIMULATOR) |
| 17 DECLARE_FLAG(bool, trace_sim); | 17 DECLARE_FLAG(bool, trace_sim); |
| 18 #endif | 18 #endif |
| 19 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | 19 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 20 DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches on MIPS"); |
| 20 DECLARE_FLAG(bool, inline_alloc); | 21 DECLARE_FLAG(bool, inline_alloc); |
| 21 | 22 |
| 22 void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) { | 23 void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) { |
| 23 ASSERT(Utils::IsAligned(data, 4)); | 24 ASSERT(Utils::IsAligned(data, 4)); |
| 24 ASSERT(Utils::IsAligned(length, 4)); | 25 ASSERT(Utils::IsAligned(length, 4)); |
| 25 const uword end = data + length; | 26 const uword end = data + length; |
| 26 while (data < end) { | 27 while (data < end) { |
| 27 *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction; | 28 *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction; |
| 28 data += 4; | 29 data += 4; |
| 29 } | 30 } |
| 30 } | 31 } |
| 31 | 32 |
| 32 | 33 |
| 33 void Assembler::Bind(Label* label) { | 34 void Assembler::GetNextPC(Register dest, Register temp) { |
| 34 ASSERT(!label->IsBound()); | 35 if (temp != kNoRegister) { |
| 35 int bound_pc = buffer_.Size(); | 36 mov(temp, RA); |
| 36 while (label->IsLinked()) { | |
| 37 const int32_t position = label->Position(); | |
| 38 const int32_t next = buffer_.Load<int32_t>(position); | |
| 39 // Relative destination from an instruction after the branch. | |
| 40 const int32_t dest = bound_pc - (position + Instr::kInstrSize); | |
| 41 const int32_t encoded = Assembler::EncodeBranchOffset(dest, next); | |
| 42 buffer_.Store<int32_t>(position, encoded); | |
| 43 label->position_ = Assembler::DecodeBranchOffset(next); | |
| 44 } | 37 } |
| 45 label->BindTo(bound_pc); | 38 EmitRegImmType(REGIMM, R0, BGEZAL, 1); |
| 46 delay_slot_available_ = false; | 39 mov(dest, RA); |
| 40 if (temp != kNoRegister) { |
| 41 mov(RA, temp); |
| 42 } |
| 47 } | 43 } |
| 48 | 44 |
| 49 | 45 |
| 50 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) { | 46 static bool CanEncodeBranchOffset(int32_t offset) { |
| 47 ASSERT(Utils::IsAligned(offset, 4)); |
| 48 return Utils::IsInt(18, offset); |
| 49 } |
| 50 |
| 51 |
| 52 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr) { |
| 51 ASSERT(Utils::IsAligned(offset, 4)); | 53 ASSERT(Utils::IsAligned(offset, 4)); |
| 52 ASSERT(Utils::IsInt(18, offset)); | 54 ASSERT(Utils::IsInt(18, offset)); |
| 53 | 55 |
| 54 // Properly preserve only the bits supported in the instruction. | 56 // Properly preserve only the bits supported in the instruction. |
| 55 offset >>= 2; | 57 offset >>= 2; |
| 56 offset &= kBranchOffsetMask; | 58 offset &= kBranchOffsetMask; |
| 57 return (instr & ~kBranchOffsetMask) | offset; | 59 return (instr & ~kBranchOffsetMask) | offset; |
| 58 } | 60 } |
| 59 | 61 |
| 60 | 62 |
| 61 int Assembler::DecodeBranchOffset(int32_t instr) { | 63 static int DecodeBranchOffset(int32_t instr) { |
| 62 // Sign-extend, left-shift by 2. | 64 // Sign-extend, left-shift by 2. |
| 63 return (((instr & kBranchOffsetMask) << 16) >> 14); | 65 return (((instr & kBranchOffsetMask) << 16) >> 14); |
| 64 } | 66 } |
| 65 | 67 |
| 66 | 68 |
| 69 static int32_t DecodeLoadImmediate(int32_t ori_instr, int32_t lui_instr) { |
| 70 return (((lui_instr & kBranchOffsetMask) << 16) | |
| 71 (ori_instr & kBranchOffsetMask)); |
| 72 } |
| 73 |
| 74 |
| 75 static int32_t EncodeLoadImmediate(int32_t dest, int32_t instr) { |
| 76 return ((instr & ~kBranchOffsetMask) | (dest & kBranchOffsetMask)); |
| 77 } |
| 78 |
| 79 |
| 80 class PatchFarJump : public AssemblerFixup { |
| 81 public: |
| 82 PatchFarJump() {} |
| 83 |
| 84 void Process(const MemoryRegion& region, int position) { |
| 85 const int32_t high = region.Load<int32_t>(position); |
| 86 const int32_t low = region.Load<int32_t>(position + Instr::kInstrSize); |
| 87 const int32_t offset = DecodeLoadImmediate(low, high); |
| 88 const int32_t dest = region.start() + offset; |
| 89 |
| 90 if ((Instr::At(reinterpret_cast<uword>(&high))->OpcodeField() == LUI) && |
| 91 (Instr::At(reinterpret_cast<uword>(&low))->OpcodeField() == ORI)) { |
| 92 // Change the offset to the absolute value. |
| 93 const int32_t encoded_low = |
| 94 EncodeLoadImmediate(dest & kBranchOffsetMask, low); |
| 95 const int32_t encoded_high = |
| 96 EncodeLoadImmediate(dest >> 16, high); |
| 97 |
| 98 region.Store<int32_t>(position, encoded_high); |
| 99 region.Store<int32_t>(position + Instr::kInstrSize, encoded_low); |
| 100 return; |
| 101 } |
| 102 // If the offset loading instructions aren't there, we must have replaced |
| 103 // the far branch with a near one, and so these instructions should be NOPs. |
| 104 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); |
| 105 } |
| 106 }; |
| 107 |
| 108 |
| 109 void Assembler::EmitFarJump(int32_t offset, bool link) { |
| 110 const uint16_t low = Utils::Low16Bits(offset); |
| 111 const uint16_t high = Utils::High16Bits(offset); |
| 112 buffer_.EmitFixup(new PatchFarJump()); |
| 113 lui(TMP, Immediate(high)); |
| 114 ori(TMP, TMP, Immediate(low)); |
| 115 if (link) { |
| 116 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); |
| 117 } else { |
| 118 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); |
| 119 } |
| 120 } |
| 121 |
| 122 |
| 123 static Opcode OppositeBranchOpcode(Opcode b) { |
| 124 switch (b) { |
| 125 case BEQ: return BNE; |
| 126 case BNE: return BEQ; |
| 127 case BGTZ: return BLEZ; |
| 128 case BLEZ: return BGTZ; |
| 129 case BEQL: return BNEL; |
| 130 case BNEL: return BEQL; |
| 131 case BGTZL: return BLEZL; |
| 132 case BLEZL: return BGTZL; |
| 133 default: |
| 134 UNREACHABLE(); |
| 135 break; |
| 136 } |
| 137 return BNE; |
| 138 } |
| 139 |
| 140 |
| 141 void Assembler::EmitFarBranch(Opcode b, Register rs, Register rt, |
| 142 int32_t offset) { |
| 143 EmitIType(b, rs, rt, 4); |
| 144 nop(); |
| 145 EmitFarJump(offset, false); |
| 146 } |
| 147 |
| 148 |
| 149 static RtRegImm OppositeBranchNoLink(RtRegImm b) { |
| 150 switch (b) { |
| 151 case BLTZ: return BGEZ; |
| 152 case BGEZ: return BLTZ; |
| 153 case BLTZAL: return BGEZ; |
| 154 case BGEZAL: return BLTZ; |
| 155 default: |
| 156 UNREACHABLE(); |
| 157 break; |
| 158 } |
| 159 return BLTZ; |
| 160 } |
| 161 |
| 162 |
| 163 void Assembler::EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset) { |
| 164 EmitRegImmType(REGIMM, rs, b, 4); |
| 165 nop(); |
| 166 EmitFarJump(offset, (b == BLTZAL) || (b == BGEZAL)); |
| 167 } |
| 168 |
| 169 |
| 170 void Assembler::EmitFarFpuBranch(bool kind, int32_t offset) { |
| 171 const uint32_t b16 = kind ? (1 << 16) : 0; |
| 172 Emit(COP1 << kOpcodeShift | COP1_BC << kCop1SubShift | b16 | 4); |
| 173 nop(); |
| 174 EmitFarJump(offset, false); |
| 175 } |
| 176 |
| 177 |
| 178 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
| 179 if (label->IsBound()) { |
| 180 // Relative destination from an instruction after the branch. |
| 181 const int32_t dest = |
| 182 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 183 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { |
| 184 EmitFarBranch(b, rs, rt, label->Position()); |
| 185 } else { |
| 186 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 187 EmitIType(b, rs, rt, dest_off); |
| 188 } |
| 189 } else { |
| 190 const int position = buffer_.Size(); |
| 191 if (FLAG_use_far_branches) { |
| 192 const uint32_t dest_off = label->position_; |
| 193 EmitFarBranch(b, rs, rt, dest_off); |
| 194 } else { |
| 195 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 196 EmitIType(b, rs, rt, dest_off); |
| 197 } |
| 198 label->LinkTo(position); |
| 199 } |
| 200 } |
| 201 |
| 202 |
| 203 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
| 204 if (label->IsBound()) { |
| 205 // Relative destination from an instruction after the branch. |
| 206 const int32_t dest = |
| 207 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 208 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { |
| 209 EmitFarRegImmBranch(b, rs, label->Position()); |
| 210 } else { |
| 211 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 212 EmitRegImmType(REGIMM, rs, b, dest_off); |
| 213 } |
| 214 } else { |
| 215 const int position = buffer_.Size(); |
| 216 if (FLAG_use_far_branches) { |
| 217 const uint32_t dest_off = label->position_; |
| 218 EmitFarRegImmBranch(b, rs, dest_off); |
| 219 } else { |
| 220 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 221 EmitRegImmType(REGIMM, rs, b, dest_off); |
| 222 } |
| 223 label->LinkTo(position); |
| 224 } |
| 225 } |
| 226 |
| 227 |
| 228 void Assembler::EmitFpuBranch(bool kind, Label *label) { |
| 229 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. |
| 230 if (label->IsBound()) { |
| 231 // Relative destination from an instruction after the branch. |
| 232 const int32_t dest = |
| 233 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 234 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { |
| 235 EmitFarFpuBranch(kind, label->Position()); |
| 236 } else { |
| 237 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 238 Emit(COP1 << kOpcodeShift | |
| 239 COP1_BC << kCop1SubShift | |
| 240 b16 | |
| 241 dest_off); |
| 242 } |
| 243 } else { |
| 244 const int position = buffer_.Size(); |
| 245 if (FLAG_use_far_branches) { |
| 246 const uint32_t dest_off = label->position_; |
| 247 EmitFarFpuBranch(kind, dest_off); |
| 248 } else { |
| 249 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 250 Emit(COP1 << kOpcodeShift | |
| 251 COP1_BC << kCop1SubShift | |
| 252 b16 | |
| 253 dest_off); |
| 254 } |
| 255 label->LinkTo(position); |
| 256 } |
| 257 } |
| 258 |
| 259 |
| 260 static int32_t FlipBranchInstruction(int32_t instr) { |
| 261 Instr* i = Instr::At(reinterpret_cast<uword>(&instr)); |
| 262 if (i->OpcodeField() == REGIMM) { |
| 263 RtRegImm b = OppositeBranchNoLink(i->RegImmFnField()); |
| 264 i->SetRegImmFnField(b); |
| 265 return i->InstructionBits(); |
| 266 } else if (i->OpcodeField() == COP1) { |
| 267 return instr ^ (1 << 16); |
| 268 } |
| 269 Opcode b = OppositeBranchOpcode(i->OpcodeField()); |
| 270 i->SetOpcodeField(b); |
| 271 return i->InstructionBits(); |
| 272 } |
| 273 |
| 274 |
| 275 void Assembler::Bind(Label* label) { |
| 276 ASSERT(!label->IsBound()); |
| 277 int bound_pc = buffer_.Size(); |
| 278 |
| 279 while (label->IsLinked()) { |
| 280 int32_t position = label->Position(); |
| 281 int32_t dest = bound_pc - (position + Instr::kInstrSize); |
| 282 |
| 283 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { |
| 284 // Far branches are enabled and we can't encode the branch offset. |
| 285 |
| 286 // Grab the branch instruction. We'll need to flip it later. |
| 287 const int32_t branch = buffer_.Load<int32_t>(position); |
| 288 |
| 289 // Grab instructions that load the offset. |
| 290 const int32_t high = |
| 291 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
| 292 const int32_t low = |
| 293 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); |
| 294 |
| 295 // Change from relative to the branch to relative to the assembler buffer. |
| 296 dest = buffer_.Size(); |
| 297 const int32_t encoded_low = |
| 298 EncodeLoadImmediate(dest & kBranchOffsetMask, low); |
| 299 const int32_t encoded_high = |
| 300 EncodeLoadImmediate(dest >> 16, high); |
| 301 |
| 302 // Skip the unconditional far jump if the test fails by flipping the |
| 303 // sense of the branch instruction. |
| 304 buffer_.Store<int32_t>(position, FlipBranchInstruction(branch)); |
| 305 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, encoded_high); |
| 306 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, encoded_low); |
| 307 label->position_ = DecodeLoadImmediate(low, high); |
| 308 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) { |
| 309 // We assembled a far branch, but we don't need it. Replace with a near |
| 310 // branch. |
| 311 |
| 312 // Grab the link to the next branch. |
| 313 const int32_t high = |
| 314 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
| 315 const int32_t low = |
| 316 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); |
| 317 |
| 318 // Grab the original branch instruction. |
| 319 int32_t branch = buffer_.Load<int32_t>(position); |
| 320 |
| 321 // Clear out the old (far) branch. |
| 322 for (int i = 0; i < 5; i++) { |
| 323 buffer_.Store<int32_t>(position + i * Instr::kInstrSize, |
| 324 Instr::kNopInstruction); |
| 325 } |
| 326 |
| 327 // Calculate the new offset. |
| 328 dest = dest - 4 * Instr::kInstrSize; |
| 329 const int32_t encoded = EncodeBranchOffset(dest, branch); |
| 330 buffer_.Store<int32_t>(position + 4 * Instr::kInstrSize, encoded); |
| 331 label->position_ = DecodeLoadImmediate(low, high); |
| 332 } else { |
| 333 const int32_t next = buffer_.Load<int32_t>(position); |
| 334 const int32_t encoded = EncodeBranchOffset(dest, next); |
| 335 buffer_.Store<int32_t>(position, encoded); |
| 336 label->position_ = DecodeBranchOffset(next); |
| 337 } |
| 338 } |
| 339 label->BindTo(bound_pc); |
| 340 delay_slot_available_ = false; |
| 341 } |
| 342 |
| 343 |
| 67 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { | 344 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { |
| 68 ASSERT(rd != PP); | 345 ASSERT(rd != PP); |
| 69 if (Address::CanHoldOffset(offset)) { | 346 if (Address::CanHoldOffset(offset)) { |
| 70 lw(rd, Address(PP, offset)); | 347 lw(rd, Address(PP, offset)); |
| 71 } else { | 348 } else { |
| 72 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. | 349 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. |
| 73 offset -= offset_low; | 350 offset -= offset_low; |
| 74 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. | 351 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. |
| 75 if (offset_high != 0) { | 352 if (offset_high != 0) { |
| 76 lui(rd, Immediate(offset_high)); | 353 lui(rd, Immediate(offset_high)); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 Label* no_update) { | 501 Label* no_update) { |
| 225 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 502 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 226 (kOldObjectAlignmentOffset == 0), young_alignment); | 503 (kOldObjectAlignmentOffset == 0), young_alignment); |
| 227 | 504 |
| 228 // Write-barrier triggers if the value is in the new space (has bit set) and | 505 // Write-barrier triggers if the value is in the new space (has bit set) and |
| 229 // the object is in the old space (has bit cleared). | 506 // the object is in the old space (has bit cleared). |
| 230 // To check that, we compute value & ~object and skip the write barrier | 507 // To check that, we compute value & ~object and skip the write barrier |
| 231 // if the bit is not set. We can't destroy the object. | 508 // if the bit is not set. We can't destroy the object. |
| 232 nor(TMP1, ZR, object); | 509 nor(TMP1, ZR, object); |
| 233 and_(TMP1, value, TMP1); | 510 and_(TMP1, value, TMP1); |
| 234 andi(TMP1, TMP1, Immediate(kNewObjectAlignmentOffset)); | 511 andi(CMPRES1, TMP1, Immediate(kNewObjectAlignmentOffset)); |
| 235 beq(TMP1, ZR, no_update); | 512 beq(CMPRES1, ZR, no_update); |
| 236 } | 513 } |
| 237 | 514 |
| 238 | 515 |
| 239 // Preserves object and value registers. | 516 // Preserves object and value registers. |
| 240 void Assembler::StoreIntoObjectFilter(Register object, | 517 void Assembler::StoreIntoObjectFilter(Register object, |
| 241 Register value, | 518 Register value, |
| 242 Label* no_update) { | 519 Label* no_update) { |
| 243 // For the value we are only interested in the new/old bit and the tag bit. | 520 // For the value we are only interested in the new/old bit and the tag bit. |
| 244 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. | 521 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. |
| 245 sll(TMP1, value, kObjectAlignmentLog2 - 1); | 522 sll(TMP1, value, kObjectAlignmentLog2 - 1); |
| 246 and_(TMP1, value, TMP1); | 523 and_(TMP1, value, TMP1); |
| 247 // And the result with the negated space bit of the object. | 524 // And the result with the negated space bit of the object. |
| 248 nor(CMPRES, ZR, object); | 525 nor(CMPRES1, ZR, object); |
| 249 and_(TMP1, TMP1, CMPRES); | 526 and_(TMP1, TMP1, CMPRES1); |
| 250 andi(TMP1, TMP1, Immediate(kNewObjectAlignmentOffset)); | 527 andi(CMPRES1, TMP1, Immediate(kNewObjectAlignmentOffset)); |
| 251 beq(TMP1, ZR, no_update); | 528 beq(CMPRES1, ZR, no_update); |
| 252 } | 529 } |
| 253 | 530 |
| 254 | 531 |
| 255 void Assembler::StoreIntoObject(Register object, | 532 void Assembler::StoreIntoObject(Register object, |
| 256 const Address& dest, | 533 const Address& dest, |
| 257 Register value, | 534 Register value, |
| 258 bool can_value_be_smi) { | 535 bool can_value_be_smi) { |
| 259 ASSERT(object != value); | 536 ASSERT(object != value); |
| 260 sw(value, dest); | 537 sw(value, dest); |
| 261 Label done; | 538 Label done; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 void Assembler::EnterStubFrame(bool uses_pp) { | 629 void Assembler::EnterStubFrame(bool uses_pp) { |
| 353 SetPrologueOffset(); | 630 SetPrologueOffset(); |
| 354 if (uses_pp) { | 631 if (uses_pp) { |
| 355 addiu(SP, SP, Immediate(-4 * kWordSize)); | 632 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 356 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. | 633 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. |
| 357 sw(RA, Address(SP, 2 * kWordSize)); | 634 sw(RA, Address(SP, 2 * kWordSize)); |
| 358 sw(FP, Address(SP, 1 * kWordSize)); | 635 sw(FP, Address(SP, 1 * kWordSize)); |
| 359 sw(PP, Address(SP, 0 * kWordSize)); | 636 sw(PP, Address(SP, 0 * kWordSize)); |
| 360 addiu(FP, SP, Immediate(1 * kWordSize)); | 637 addiu(FP, SP, Immediate(1 * kWordSize)); |
| 361 // Setup pool pointer for this stub. | 638 // Setup pool pointer for this stub. |
| 362 Label next; | 639 |
| 363 bal(&next); | 640 GetNextPC(TMP1); // TMP1 gets the address of the next instruction. |
| 364 delay_slot()->mov(TMP1, RA); | |
| 365 | 641 |
| 366 const intptr_t object_pool_pc_dist = | 642 const intptr_t object_pool_pc_dist = |
| 367 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 643 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 368 CodeSize(); | 644 CodeSize(); |
| 369 | 645 |
| 370 Bind(&next); | |
| 371 lw(PP, Address(TMP1, -object_pool_pc_dist)); | 646 lw(PP, Address(TMP1, -object_pool_pc_dist)); |
| 372 } else { | 647 } else { |
| 373 addiu(SP, SP, Immediate(-3 * kWordSize)); | 648 addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 374 sw(ZR, Address(SP, 2 * kWordSize)); // PC marker is 0 in stubs. | 649 sw(ZR, Address(SP, 2 * kWordSize)); // PC marker is 0 in stubs. |
| 375 sw(RA, Address(SP, 1 * kWordSize)); | 650 sw(RA, Address(SP, 1 * kWordSize)); |
| 376 sw(FP, Address(SP, 0 * kWordSize)); | 651 sw(FP, Address(SP, 0 * kWordSize)); |
| 377 mov(FP, SP); | 652 mov(FP, SP); |
| 378 } | 653 } |
| 379 } | 654 } |
| 380 | 655 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 void Assembler::EnterDartFrame(intptr_t frame_size) { | 733 void Assembler::EnterDartFrame(intptr_t frame_size) { |
| 459 const intptr_t offset = CodeSize(); | 734 const intptr_t offset = CodeSize(); |
| 460 | 735 |
| 461 SetPrologueOffset(); | 736 SetPrologueOffset(); |
| 462 | 737 |
| 463 addiu(SP, SP, Immediate(-4 * kWordSize)); | 738 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 464 sw(RA, Address(SP, 2 * kWordSize)); | 739 sw(RA, Address(SP, 2 * kWordSize)); |
| 465 sw(FP, Address(SP, 1 * kWordSize)); | 740 sw(FP, Address(SP, 1 * kWordSize)); |
| 466 sw(PP, Address(SP, 0 * kWordSize)); | 741 sw(PP, Address(SP, 0 * kWordSize)); |
| 467 | 742 |
| 468 Label next; | 743 GetNextPC(TMP1); // TMP1 gets the address of the next instruction. |
| 469 // Branch and link to the instruction after the delay slot to get the PC. | |
| 470 bal(&next); | |
| 471 // RA is the address of the sw instruction below. Save it in T0. | |
| 472 delay_slot()->mov(TMP1, RA); | |
| 473 | 744 |
| 474 // Calculate the offset of the pool pointer from the PC. | 745 // Calculate the offset of the pool pointer from the PC. |
| 475 const intptr_t object_pool_pc_dist = | 746 const intptr_t object_pool_pc_dist = |
| 476 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 747 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 477 CodeSize(); | 748 CodeSize(); |
| 478 | 749 |
| 479 // TMP1 has the address of the next instruction. | |
| 480 Bind(&next); | |
| 481 | |
| 482 // Save PC in frame for fast identification of corresponding code. | 750 // Save PC in frame for fast identification of corresponding code. |
| 483 AddImmediate(TMP1, -offset); | 751 AddImmediate(TMP1, -offset); |
| 484 sw(TMP1, Address(SP, 3 * kWordSize)); | 752 sw(TMP1, Address(SP, 3 * kWordSize)); |
| 485 | 753 |
| 486 // Set FP to the saved previous FP. | 754 // Set FP to the saved previous FP. |
| 487 addiu(FP, SP, Immediate(kWordSize)); | 755 addiu(FP, SP, Immediate(kWordSize)); |
| 488 | 756 |
| 489 // Load the pool pointer. offset has already been subtracted from TMP1. | 757 // Load the pool pointer. offset has already been subtracted from TMP1. |
| 490 lw(PP, Address(TMP1, -object_pool_pc_dist + offset)); | 758 lw(PP, Address(TMP1, -object_pool_pc_dist + offset)); |
| 491 | 759 |
| 492 // Reserve space for locals. | 760 // Reserve space for locals. |
| 493 AddImmediate(SP, -frame_size); | 761 AddImmediate(SP, -frame_size); |
| 494 } | 762 } |
| 495 | 763 |
| 496 | 764 |
| 497 // On entry to a function compiled for OSR, the caller's frame pointer, the | 765 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 498 // stack locals, and any copied parameters are already in place. The frame | 766 // stack locals, and any copied parameters are already in place. The frame |
| 499 // pointer is already set up. The PC marker is not correct for the | 767 // pointer is already set up. The PC marker is not correct for the |
| 500 // optimized function and there may be extra space for spill slots to | 768 // optimized function and there may be extra space for spill slots to |
| 501 // allocate. We must also set up the pool pointer for the function. | 769 // allocate. We must also set up the pool pointer for the function. |
| 502 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 770 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
| 503 Comment("EnterOsrFrame"); | 771 Comment("EnterOsrFrame"); |
| 504 Label next; | 772 |
| 505 // Branch and link to the instruction after the delay slot to get the PC. | 773 GetNextPC(TMP); // TMP gets the address of the next instruction. |
| 506 bal(&next); | |
| 507 // RA is the address of the sw instruction below. Save it in T0. | |
| 508 delay_slot()->mov(TMP, RA); | |
| 509 | 774 |
| 510 // The runtime system assumes that the code marker address is | 775 // The runtime system assumes that the code marker address is |
| 511 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no | 776 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no |
| 512 // code to set up the frame pointer, etc., the address needs to be adjusted. | 777 // code to set up the frame pointer, etc., the address needs to be adjusted. |
| 513 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | 778 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); |
| 514 // Calculate the offset of the pool pointer from the PC. | 779 // Calculate the offset of the pool pointer from the PC. |
| 515 const intptr_t object_pool_pc_dist = | 780 const intptr_t object_pool_pc_dist = |
| 516 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 781 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 517 CodeSize(); | 782 CodeSize(); |
| 518 | 783 |
| 519 // temp has the address of the next instruction. | |
| 520 Bind(&next); | |
| 521 | |
| 522 // Adjust PC by the offset, and store it in the stack frame. | 784 // Adjust PC by the offset, and store it in the stack frame. |
| 523 AddImmediate(TMP, TMP, offset); | 785 AddImmediate(TMP, TMP, offset); |
| 524 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); | 786 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
| 525 | 787 |
| 526 // Restore return address. | 788 // Restore return address. |
| 527 lw(RA, Address(FP, 1 * kWordSize)); | 789 lw(RA, Address(FP, 1 * kWordSize)); |
| 528 | 790 |
| 529 // Load the pool pointer. offset has already been subtracted from temp. | 791 // Load the pool pointer. offset has already been subtracted from temp. |
| 530 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); | 792 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); |
| 531 | 793 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 Bind(&msg); | 973 Bind(&msg); |
| 712 break_(Instr::kMsgMessageCode); | 974 break_(Instr::kMsgMessageCode); |
| 713 } | 975 } |
| 714 #endif | 976 #endif |
| 715 } | 977 } |
| 716 | 978 |
| 717 } // namespace dart | 979 } // namespace dart |
| 718 | 980 |
| 719 #endif // defined TARGET_ARCH_MIPS | 981 #endif // defined TARGET_ARCH_MIPS |
| 720 | 982 |
| OLD | NEW |