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