| 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/longjump.h" | 9 #include "vm/longjump.h" |
| 10 #include "vm/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // If the offset loading instructions aren't there, we must have replaced | 105 // If the offset loading instructions aren't there, we must have replaced |
| 106 // the far branch with a near one, and so these instructions should be NOPs. | 106 // the far branch with a near one, and so these instructions should be NOPs. |
| 107 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); | 107 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); |
| 108 } | 108 } |
| 109 | 109 |
| 110 virtual bool IsPointerOffset() const { return false; } | 110 virtual bool IsPointerOffset() const { return false; } |
| 111 }; | 111 }; |
| 112 | 112 |
| 113 | 113 |
| 114 void Assembler::EmitFarJump(int32_t offset, bool link) { | 114 void Assembler::EmitFarJump(int32_t offset, bool link) { |
| 115 ASSERT(!in_delay_slot_); |
| 115 ASSERT(use_far_branches()); | 116 ASSERT(use_far_branches()); |
| 116 const uint16_t low = Utils::Low16Bits(offset); | 117 const uint16_t low = Utils::Low16Bits(offset); |
| 117 const uint16_t high = Utils::High16Bits(offset); | 118 const uint16_t high = Utils::High16Bits(offset); |
| 118 buffer_.EmitFixup(new PatchFarJump()); | 119 buffer_.EmitFixup(new PatchFarJump()); |
| 119 lui(T9, Immediate(high)); | 120 lui(T9, Immediate(high)); |
| 120 ori(T9, T9, Immediate(low)); | 121 ori(T9, T9, Immediate(low)); |
| 121 if (link) { | 122 if (link) { |
| 122 EmitRType(SPECIAL, T9, R0, RA, 0, JALR); | 123 EmitRType(SPECIAL, T9, R0, RA, 0, JALR); |
| 123 } else { | 124 } else { |
| 124 EmitRType(SPECIAL, T9, R0, R0, 0, JR); | 125 EmitRType(SPECIAL, T9, R0, R0, 0, JR); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 139 default: | 140 default: |
| 140 UNREACHABLE(); | 141 UNREACHABLE(); |
| 141 break; | 142 break; |
| 142 } | 143 } |
| 143 return BNE; | 144 return BNE; |
| 144 } | 145 } |
| 145 | 146 |
| 146 | 147 |
| 147 void Assembler::EmitFarBranch(Opcode b, Register rs, Register rt, | 148 void Assembler::EmitFarBranch(Opcode b, Register rs, Register rt, |
| 148 int32_t offset) { | 149 int32_t offset) { |
| 150 ASSERT(!in_delay_slot_); |
| 149 EmitIType(b, rs, rt, 4); | 151 EmitIType(b, rs, rt, 4); |
| 150 nop(); | 152 nop(); |
| 151 EmitFarJump(offset, false); | 153 EmitFarJump(offset, false); |
| 152 } | 154 } |
| 153 | 155 |
| 154 | 156 |
| 155 static RtRegImm OppositeBranchNoLink(RtRegImm b) { | 157 static RtRegImm OppositeBranchNoLink(RtRegImm b) { |
| 156 switch (b) { | 158 switch (b) { |
| 157 case BLTZ: return BGEZ; | 159 case BLTZ: return BGEZ; |
| 158 case BGEZ: return BLTZ; | 160 case BGEZ: return BLTZ; |
| 159 case BLTZAL: return BGEZ; | 161 case BLTZAL: return BGEZ; |
| 160 case BGEZAL: return BLTZ; | 162 case BGEZAL: return BLTZ; |
| 161 default: | 163 default: |
| 162 UNREACHABLE(); | 164 UNREACHABLE(); |
| 163 break; | 165 break; |
| 164 } | 166 } |
| 165 return BLTZ; | 167 return BLTZ; |
| 166 } | 168 } |
| 167 | 169 |
| 168 | 170 |
| 169 void Assembler::EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset) { | 171 void Assembler::EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset) { |
| 172 ASSERT(!in_delay_slot_); |
| 170 EmitRegImmType(REGIMM, rs, b, 4); | 173 EmitRegImmType(REGIMM, rs, b, 4); |
| 171 nop(); | 174 nop(); |
| 172 EmitFarJump(offset, (b == BLTZAL) || (b == BGEZAL)); | 175 EmitFarJump(offset, (b == BLTZAL) || (b == BGEZAL)); |
| 173 } | 176 } |
| 174 | 177 |
| 175 | 178 |
| 176 void Assembler::EmitFarFpuBranch(bool kind, int32_t offset) { | 179 void Assembler::EmitFarFpuBranch(bool kind, int32_t offset) { |
| 180 ASSERT(!in_delay_slot_); |
| 177 const uint32_t b16 = kind ? (1 << 16) : 0; | 181 const uint32_t b16 = kind ? (1 << 16) : 0; |
| 178 Emit(COP1 << kOpcodeShift | COP1_BC << kCop1SubShift | b16 | 4); | 182 Emit(COP1 << kOpcodeShift | COP1_BC << kCop1SubShift | b16 | 4); |
| 179 nop(); | 183 nop(); |
| 180 EmitFarJump(offset, false); | 184 EmitFarJump(offset, false); |
| 181 } | 185 } |
| 182 | 186 |
| 183 | 187 |
| 184 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | 188 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
| 189 ASSERT(!in_delay_slot_); |
| 185 if (label->IsBound()) { | 190 if (label->IsBound()) { |
| 186 // Relative destination from an instruction after the branch. | 191 // Relative destination from an instruction after the branch. |
| 187 const int32_t dest = | 192 const int32_t dest = |
| 188 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 193 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 189 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { | 194 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
| 190 EmitFarBranch(OppositeBranchOpcode(b), rs, rt, label->Position()); | 195 EmitFarBranch(OppositeBranchOpcode(b), rs, rt, label->Position()); |
| 191 } else { | 196 } else { |
| 192 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 197 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 193 EmitIType(b, rs, rt, dest_off); | 198 EmitIType(b, rs, rt, dest_off); |
| 194 } | 199 } |
| 195 } else { | 200 } else { |
| 196 const intptr_t position = buffer_.Size(); | 201 const intptr_t position = buffer_.Size(); |
| 197 if (use_far_branches()) { | 202 if (use_far_branches()) { |
| 198 const uint32_t dest_off = label->position_; | 203 const uint32_t dest_off = label->position_; |
| 199 EmitFarBranch(b, rs, rt, dest_off); | 204 EmitFarBranch(b, rs, rt, dest_off); |
| 200 } else { | 205 } else { |
| 201 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 206 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 202 EmitIType(b, rs, rt, dest_off); | 207 EmitIType(b, rs, rt, dest_off); |
| 203 } | 208 } |
| 204 label->LinkTo(position); | 209 label->LinkTo(position); |
| 205 } | 210 } |
| 206 } | 211 } |
| 207 | 212 |
| 208 | 213 |
| 209 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 214 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
| 215 ASSERT(!in_delay_slot_); |
| 210 if (label->IsBound()) { | 216 if (label->IsBound()) { |
| 211 // Relative destination from an instruction after the branch. | 217 // Relative destination from an instruction after the branch. |
| 212 const int32_t dest = | 218 const int32_t dest = |
| 213 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 219 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 214 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { | 220 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
| 215 EmitFarRegImmBranch(OppositeBranchNoLink(b), rs, label->Position()); | 221 EmitFarRegImmBranch(OppositeBranchNoLink(b), rs, label->Position()); |
| 216 } else { | 222 } else { |
| 217 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 223 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 218 EmitRegImmType(REGIMM, rs, b, dest_off); | 224 EmitRegImmType(REGIMM, rs, b, dest_off); |
| 219 } | 225 } |
| 220 } else { | 226 } else { |
| 221 const intptr_t position = buffer_.Size(); | 227 const intptr_t position = buffer_.Size(); |
| 222 if (use_far_branches()) { | 228 if (use_far_branches()) { |
| 223 const uint32_t dest_off = label->position_; | 229 const uint32_t dest_off = label->position_; |
| 224 EmitFarRegImmBranch(b, rs, dest_off); | 230 EmitFarRegImmBranch(b, rs, dest_off); |
| 225 } else { | 231 } else { |
| 226 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 232 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 227 EmitRegImmType(REGIMM, rs, b, dest_off); | 233 EmitRegImmType(REGIMM, rs, b, dest_off); |
| 228 } | 234 } |
| 229 label->LinkTo(position); | 235 label->LinkTo(position); |
| 230 } | 236 } |
| 231 } | 237 } |
| 232 | 238 |
| 233 | 239 |
| 234 void Assembler::EmitFpuBranch(bool kind, Label *label) { | 240 void Assembler::EmitFpuBranch(bool kind, Label *label) { |
| 241 ASSERT(!in_delay_slot_); |
| 235 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. | 242 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. |
| 236 if (label->IsBound()) { | 243 if (label->IsBound()) { |
| 237 // Relative destination from an instruction after the branch. | 244 // Relative destination from an instruction after the branch. |
| 238 const int32_t dest = | 245 const int32_t dest = |
| 239 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 246 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 240 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { | 247 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
| 241 EmitFarFpuBranch(kind, label->Position()); | 248 EmitFarFpuBranch(kind, label->Position()); |
| 242 } else { | 249 } else { |
| 243 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 250 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| 244 Emit(COP1 << kOpcodeShift | | 251 Emit(COP1 << kOpcodeShift | |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 buffer_.Store<int32_t>(position, encoded); | 348 buffer_.Store<int32_t>(position, encoded); |
| 342 label->position_ = DecodeBranchOffset(next); | 349 label->position_ = DecodeBranchOffset(next); |
| 343 } | 350 } |
| 344 } | 351 } |
| 345 label->BindTo(bound_pc); | 352 label->BindTo(bound_pc); |
| 346 delay_slot_available_ = false; | 353 delay_slot_available_ = false; |
| 347 } | 354 } |
| 348 | 355 |
| 349 | 356 |
| 350 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { | 357 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { |
| 358 ASSERT(!in_delay_slot_); |
| 351 ASSERT(rd != PP); | 359 ASSERT(rd != PP); |
| 352 if (Address::CanHoldOffset(offset)) { | 360 if (Address::CanHoldOffset(offset)) { |
| 353 lw(rd, Address(PP, offset)); | 361 lw(rd, Address(PP, offset)); |
| 354 } else { | 362 } else { |
| 355 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. | 363 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. |
| 356 offset -= offset_low; | 364 offset -= offset_low; |
| 357 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. | 365 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. |
| 358 if (offset_high != 0) { | 366 if (offset_high != 0) { |
| 359 lui(rd, Immediate(offset_high)); | 367 lui(rd, Immediate(offset_high)); |
| 360 addu(rd, rd, PP); | 368 addu(rd, rd, PP); |
| 361 lw(rd, Address(rd, offset_low)); | 369 lw(rd, Address(rd, offset_low)); |
| 362 } else { | 370 } else { |
| 363 lw(rd, Address(PP, offset_low)); | 371 lw(rd, Address(PP, offset_low)); |
| 364 } | 372 } |
| 365 } | 373 } |
| 366 } | 374 } |
| 367 | 375 |
| 368 | 376 |
| 369 void Assembler::AdduDetectOverflow(Register rd, Register rs, Register rt, | 377 void Assembler::AdduDetectOverflow(Register rd, Register rs, Register rt, |
| 370 Register ro, Register scratch) { | 378 Register ro, Register scratch) { |
| 379 ASSERT(!in_delay_slot_); |
| 371 ASSERT(rd != ro); | 380 ASSERT(rd != ro); |
| 372 ASSERT(rd != TMP); | 381 ASSERT(rd != TMP); |
| 373 ASSERT(ro != TMP); | 382 ASSERT(ro != TMP); |
| 374 ASSERT(ro != rs); | 383 ASSERT(ro != rs); |
| 375 ASSERT(ro != rt); | 384 ASSERT(ro != rt); |
| 376 | 385 |
| 377 if ((rs == rt) && (rd == rs)) { | 386 if ((rs == rt) && (rd == rs)) { |
| 378 ASSERT(scratch != kNoRegister); | 387 ASSERT(scratch != kNoRegister); |
| 379 ASSERT(scratch != TMP); | 388 ASSERT(scratch != TMP); |
| 380 ASSERT(rd != scratch); | 389 ASSERT(rd != scratch); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 401 addu(rd, rs, rt); | 410 addu(rd, rs, rt); |
| 402 xor_(ro, rd, rs); | 411 xor_(ro, rd, rs); |
| 403 xor_(TMP, rd, rt); | 412 xor_(TMP, rd, rt); |
| 404 and_(ro, TMP, ro); | 413 and_(ro, TMP, ro); |
| 405 } | 414 } |
| 406 } | 415 } |
| 407 | 416 |
| 408 | 417 |
| 409 void Assembler::SubuDetectOverflow(Register rd, Register rs, Register rt, | 418 void Assembler::SubuDetectOverflow(Register rd, Register rs, Register rt, |
| 410 Register ro) { | 419 Register ro) { |
| 420 ASSERT(!in_delay_slot_); |
| 411 ASSERT(rd != ro); | 421 ASSERT(rd != ro); |
| 412 ASSERT(rd != TMP); | 422 ASSERT(rd != TMP); |
| 413 ASSERT(ro != TMP); | 423 ASSERT(ro != TMP); |
| 414 ASSERT(ro != rs); | 424 ASSERT(ro != rs); |
| 415 ASSERT(ro != rt); | 425 ASSERT(ro != rt); |
| 416 ASSERT(rs != TMP); | 426 ASSERT(rs != TMP); |
| 417 ASSERT(rt != TMP); | 427 ASSERT(rt != TMP); |
| 418 | 428 |
| 419 // This happens with some crankshaft code. Since Subu works fine if | 429 // This happens with some crankshaft code. Since Subu works fine if |
| 420 // left == right, let's not make that restriction here. | 430 // left == right, let's not make that restriction here. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 439 } else { | 449 } else { |
| 440 subu(rd, rs, rt); | 450 subu(rd, rs, rt); |
| 441 xor_(ro, rd, rs); | 451 xor_(ro, rd, rs); |
| 442 xor_(TMP, rs, rt); | 452 xor_(TMP, rs, rt); |
| 443 and_(ro, TMP, ro); | 453 and_(ro, TMP, ro); |
| 444 } | 454 } |
| 445 } | 455 } |
| 446 | 456 |
| 447 | 457 |
| 448 void Assembler::LoadObject(Register rd, const Object& object) { | 458 void Assembler::LoadObject(Register rd, const Object& object) { |
| 459 ASSERT(!in_delay_slot_); |
| 449 // Smis and VM heap objects are never relocated; do not use object pool. | 460 // Smis and VM heap objects are never relocated; do not use object pool. |
| 450 if (object.IsSmi()) { | 461 if (object.IsSmi()) { |
| 451 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); | 462 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); |
| 452 } else if (object.InVMHeap()) { | 463 } else if (object.InVMHeap()) { |
| 453 // Make sure that class CallPattern is able to decode this load immediate. | 464 // Make sure that class CallPattern is able to decode this load immediate. |
| 454 int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); | 465 int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); |
| 455 const uint16_t object_low = Utils::Low16Bits(object_raw); | 466 const uint16_t object_low = Utils::Low16Bits(object_raw); |
| 456 const uint16_t object_high = Utils::High16Bits(object_raw); | 467 const uint16_t object_high = Utils::High16Bits(object_raw); |
| 457 lui(rd, Immediate(object_high)); | 468 lui(rd, Immediate(object_high)); |
| 458 ori(rd, rd, Immediate(object_low)); | 469 ori(rd, rd, Immediate(object_low)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 478 if (object_pool_.At(i) == obj.raw()) { | 489 if (object_pool_.At(i) == obj.raw()) { |
| 479 return i; | 490 return i; |
| 480 } | 491 } |
| 481 } | 492 } |
| 482 object_pool_.Add(obj, Heap::kOld); | 493 object_pool_.Add(obj, Heap::kOld); |
| 483 return object_pool_.Length() - 1; | 494 return object_pool_.Length() - 1; |
| 484 } | 495 } |
| 485 | 496 |
| 486 | 497 |
| 487 void Assembler::PushObject(const Object& object) { | 498 void Assembler::PushObject(const Object& object) { |
| 499 ASSERT(!in_delay_slot_); |
| 488 LoadObject(TMP, object); | 500 LoadObject(TMP, object); |
| 489 Push(TMP); | 501 Push(TMP); |
| 490 } | 502 } |
| 491 | 503 |
| 492 | 504 |
| 493 void Assembler::CompareObject(Register rd1, Register rd2, | 505 void Assembler::CompareObject(Register rd1, Register rd2, |
| 494 Register rn, const Object& object) { | 506 Register rn, const Object& object) { |
| 507 ASSERT(!in_delay_slot_); |
| 495 ASSERT(rn != TMP); | 508 ASSERT(rn != TMP); |
| 496 ASSERT(rd1 != TMP); | 509 ASSERT(rd1 != TMP); |
| 497 ASSERT(rd1 != rd2); | 510 ASSERT(rd1 != rd2); |
| 498 LoadObject(TMP, object); | 511 LoadObject(TMP, object); |
| 499 slt(rd1, rn, TMP); | 512 slt(rd1, rn, TMP); |
| 500 slt(rd2, TMP, rn); | 513 slt(rd2, TMP, rn); |
| 501 } | 514 } |
| 502 | 515 |
| 503 | 516 |
| 504 // Preserves object and value registers. | 517 // Preserves object and value registers. |
| 505 void Assembler::StoreIntoObjectFilterNoSmi(Register object, | 518 void Assembler::StoreIntoObjectFilterNoSmi(Register object, |
| 506 Register value, | 519 Register value, |
| 507 Label* no_update) { | 520 Label* no_update) { |
| 521 ASSERT(!in_delay_slot_); |
| 508 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 522 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 509 (kOldObjectAlignmentOffset == 0), young_alignment); | 523 (kOldObjectAlignmentOffset == 0), young_alignment); |
| 510 | 524 |
| 511 // Write-barrier triggers if the value is in the new space (has bit set) and | 525 // Write-barrier triggers if the value is in the new space (has bit set) and |
| 512 // the object is in the old space (has bit cleared). | 526 // the object is in the old space (has bit cleared). |
| 513 // To check that, we compute value & ~object and skip the write barrier | 527 // To check that, we compute value & ~object and skip the write barrier |
| 514 // if the bit is not set. We can't destroy the object. | 528 // if the bit is not set. We can't destroy the object. |
| 515 nor(TMP, ZR, object); | 529 nor(TMP, ZR, object); |
| 516 and_(TMP, value, TMP); | 530 and_(TMP, value, TMP); |
| 517 andi(CMPRES1, TMP, Immediate(kNewObjectAlignmentOffset)); | 531 andi(CMPRES1, TMP, Immediate(kNewObjectAlignmentOffset)); |
| 518 beq(CMPRES1, ZR, no_update); | 532 beq(CMPRES1, ZR, no_update); |
| 519 } | 533 } |
| 520 | 534 |
| 521 | 535 |
| 522 // Preserves object and value registers. | 536 // Preserves object and value registers. |
| 523 void Assembler::StoreIntoObjectFilter(Register object, | 537 void Assembler::StoreIntoObjectFilter(Register object, |
| 524 Register value, | 538 Register value, |
| 525 Label* no_update) { | 539 Label* no_update) { |
| 540 ASSERT(!in_delay_slot_); |
| 526 // For the value we are only interested in the new/old bit and the tag bit. | 541 // For the value we are only interested in the new/old bit and the tag bit. |
| 527 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. | 542 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. |
| 528 sll(TMP, value, kObjectAlignmentLog2 - 1); | 543 sll(TMP, value, kObjectAlignmentLog2 - 1); |
| 529 and_(TMP, value, TMP); | 544 and_(TMP, value, TMP); |
| 530 // And the result with the negated space bit of the object. | 545 // And the result with the negated space bit of the object. |
| 531 nor(CMPRES1, ZR, object); | 546 nor(CMPRES1, ZR, object); |
| 532 and_(TMP, TMP, CMPRES1); | 547 and_(TMP, TMP, CMPRES1); |
| 533 andi(CMPRES1, TMP, Immediate(kNewObjectAlignmentOffset)); | 548 andi(CMPRES1, TMP, Immediate(kNewObjectAlignmentOffset)); |
| 534 beq(CMPRES1, ZR, no_update); | 549 beq(CMPRES1, ZR, no_update); |
| 535 } | 550 } |
| 536 | 551 |
| 537 | 552 |
| 538 void Assembler::StoreIntoObject(Register object, | 553 void Assembler::StoreIntoObject(Register object, |
| 539 const Address& dest, | 554 const Address& dest, |
| 540 Register value, | 555 Register value, |
| 541 bool can_value_be_smi) { | 556 bool can_value_be_smi) { |
| 557 ASSERT(!in_delay_slot_); |
| 542 ASSERT(object != value); | 558 ASSERT(object != value); |
| 543 sw(value, dest); | 559 sw(value, dest); |
| 544 Label done; | 560 Label done; |
| 545 if (can_value_be_smi) { | 561 if (can_value_be_smi) { |
| 546 StoreIntoObjectFilter(object, value, &done); | 562 StoreIntoObjectFilter(object, value, &done); |
| 547 } else { | 563 } else { |
| 548 StoreIntoObjectFilterNoSmi(object, value, &done); | 564 StoreIntoObjectFilterNoSmi(object, value, &done); |
| 549 } | 565 } |
| 550 // A store buffer update is required. | 566 // A store buffer update is required. |
| 551 if (value != T0) { | 567 if (value != T0) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 568 } else { | 584 } else { |
| 569 addiu(SP, SP, Immediate(1 * kWordSize)); | 585 addiu(SP, SP, Immediate(1 * kWordSize)); |
| 570 } | 586 } |
| 571 Bind(&done); | 587 Bind(&done); |
| 572 } | 588 } |
| 573 | 589 |
| 574 | 590 |
| 575 void Assembler::StoreIntoObjectNoBarrier(Register object, | 591 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 576 const Address& dest, | 592 const Address& dest, |
| 577 Register value) { | 593 Register value) { |
| 594 ASSERT(!in_delay_slot_); |
| 578 sw(value, dest); | 595 sw(value, dest); |
| 579 #if defined(DEBUG) | 596 #if defined(DEBUG) |
| 580 Label done; | 597 Label done; |
| 581 StoreIntoObjectFilter(object, value, &done); | 598 StoreIntoObjectFilter(object, value, &done); |
| 582 Stop("Store buffer update is required"); | 599 Stop("Store buffer update is required"); |
| 583 Bind(&done); | 600 Bind(&done); |
| 584 #endif // defined(DEBUG) | 601 #endif // defined(DEBUG) |
| 585 // No store buffer update. | 602 // No store buffer update. |
| 586 } | 603 } |
| 587 | 604 |
| 588 | 605 |
| 589 void Assembler::StoreIntoObjectNoBarrier(Register object, | 606 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 590 const Address& dest, | 607 const Address& dest, |
| 591 const Object& value) { | 608 const Object& value) { |
| 609 ASSERT(!in_delay_slot_); |
| 592 ASSERT(value.IsSmi() || value.InVMHeap() || | 610 ASSERT(value.IsSmi() || value.InVMHeap() || |
| 593 (value.IsOld() && value.IsNotTemporaryScopedHandle())); | 611 (value.IsOld() && value.IsNotTemporaryScopedHandle())); |
| 594 // No store buffer update. | 612 // No store buffer update. |
| 595 LoadObject(TMP, value); | 613 LoadObject(TMP, value); |
| 596 sw(TMP, dest); | 614 sw(TMP, dest); |
| 597 } | 615 } |
| 598 | 616 |
| 599 | 617 |
| 600 void Assembler::LoadClassId(Register result, Register object) { | 618 void Assembler::LoadClassId(Register result, Register object) { |
| 601 ASSERT(RawObject::kClassIdTagPos == 16); | 619 ASSERT(RawObject::kClassIdTagPos == 16); |
| 602 ASSERT(RawObject::kClassIdTagSize == 16); | 620 ASSERT(RawObject::kClassIdTagSize == 16); |
| 603 const intptr_t class_id_offset = Object::tags_offset() + | 621 const intptr_t class_id_offset = Object::tags_offset() + |
| 604 RawObject::kClassIdTagPos / kBitsPerByte; | 622 RawObject::kClassIdTagPos / kBitsPerByte; |
| 605 lhu(result, FieldAddress(object, class_id_offset)); | 623 lhu(result, FieldAddress(object, class_id_offset)); |
| 606 } | 624 } |
| 607 | 625 |
| 608 | 626 |
| 609 void Assembler::LoadClassById(Register result, Register class_id) { | 627 void Assembler::LoadClassById(Register result, Register class_id) { |
| 628 ASSERT(!in_delay_slot_); |
| 610 ASSERT(result != class_id); | 629 ASSERT(result != class_id); |
| 611 lw(result, FieldAddress(CTX, Context::isolate_offset())); | 630 lw(result, FieldAddress(CTX, Context::isolate_offset())); |
| 612 const intptr_t table_offset_in_isolate = | 631 const intptr_t table_offset_in_isolate = |
| 613 Isolate::class_table_offset() + ClassTable::table_offset(); | 632 Isolate::class_table_offset() + ClassTable::table_offset(); |
| 614 lw(result, Address(result, table_offset_in_isolate)); | 633 lw(result, Address(result, table_offset_in_isolate)); |
| 615 sll(TMP, class_id, 2); | 634 sll(TMP, class_id, 2); |
| 616 addu(result, result, TMP); | 635 addu(result, result, TMP); |
| 617 lw(result, Address(result)); | 636 lw(result, Address(result)); |
| 618 } | 637 } |
| 619 | 638 |
| 620 | 639 |
| 621 void Assembler::LoadClass(Register result, Register object) { | 640 void Assembler::LoadClass(Register result, Register object) { |
| 641 ASSERT(!in_delay_slot_); |
| 622 ASSERT(TMP != result); | 642 ASSERT(TMP != result); |
| 623 LoadClassId(TMP, object); | 643 LoadClassId(TMP, object); |
| 624 | 644 |
| 625 lw(result, FieldAddress(CTX, Context::isolate_offset())); | 645 lw(result, FieldAddress(CTX, Context::isolate_offset())); |
| 626 const intptr_t table_offset_in_isolate = | 646 const intptr_t table_offset_in_isolate = |
| 627 Isolate::class_table_offset() + ClassTable::table_offset(); | 647 Isolate::class_table_offset() + ClassTable::table_offset(); |
| 628 lw(result, Address(result, table_offset_in_isolate)); | 648 lw(result, Address(result, table_offset_in_isolate)); |
| 629 sll(TMP, TMP, 2); | 649 sll(TMP, TMP, 2); |
| 630 addu(result, result, TMP); | 650 addu(result, result, TMP); |
| 631 lw(result, Address(result)); | 651 lw(result, Address(result)); |
| 632 } | 652 } |
| 633 | 653 |
| 634 | 654 |
| 635 void Assembler::EnterFrame() { | 655 void Assembler::EnterFrame() { |
| 656 ASSERT(!in_delay_slot_); |
| 636 addiu(SP, SP, Immediate(-2 * kWordSize)); | 657 addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 637 sw(RA, Address(SP, 1 * kWordSize)); | 658 sw(RA, Address(SP, 1 * kWordSize)); |
| 638 sw(FP, Address(SP, 0 * kWordSize)); | 659 sw(FP, Address(SP, 0 * kWordSize)); |
| 639 mov(FP, SP); | 660 mov(FP, SP); |
| 640 } | 661 } |
| 641 | 662 |
| 642 | 663 |
| 643 void Assembler::LeaveFrameAndReturn() { | 664 void Assembler::LeaveFrameAndReturn() { |
| 665 ASSERT(!in_delay_slot_); |
| 644 mov(SP, FP); | 666 mov(SP, FP); |
| 645 lw(RA, Address(SP, 1 * kWordSize)); | 667 lw(RA, Address(SP, 1 * kWordSize)); |
| 646 lw(FP, Address(SP, 0 * kWordSize)); | 668 lw(FP, Address(SP, 0 * kWordSize)); |
| 647 Ret(); | 669 Ret(); |
| 648 delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); | 670 delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); |
| 649 } | 671 } |
| 650 | 672 |
| 651 | 673 |
| 652 void Assembler::EnterStubFrame(bool load_pp) { | 674 void Assembler::EnterStubFrame(bool load_pp) { |
| 675 ASSERT(!in_delay_slot_); |
| 653 SetPrologueOffset(); | 676 SetPrologueOffset(); |
| 654 addiu(SP, SP, Immediate(-4 * kWordSize)); | 677 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 655 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. | 678 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. |
| 656 sw(RA, Address(SP, 2 * kWordSize)); | 679 sw(RA, Address(SP, 2 * kWordSize)); |
| 657 sw(FP, Address(SP, 1 * kWordSize)); | 680 sw(FP, Address(SP, 1 * kWordSize)); |
| 658 sw(PP, Address(SP, 0 * kWordSize)); | 681 sw(PP, Address(SP, 0 * kWordSize)); |
| 659 addiu(FP, SP, Immediate(1 * kWordSize)); | 682 addiu(FP, SP, Immediate(1 * kWordSize)); |
| 660 if (load_pp) { | 683 if (load_pp) { |
| 661 // Setup pool pointer for this stub. | 684 // Setup pool pointer for this stub. |
| 662 LoadPoolPointer(); | 685 LoadPoolPointer(); |
| 663 } | 686 } |
| 664 } | 687 } |
| 665 | 688 |
| 666 | 689 |
| 667 void Assembler::LeaveStubFrame() { | 690 void Assembler::LeaveStubFrame() { |
| 691 ASSERT(!in_delay_slot_); |
| 668 addiu(SP, FP, Immediate(-1 * kWordSize)); | 692 addiu(SP, FP, Immediate(-1 * kWordSize)); |
| 669 lw(RA, Address(SP, 2 * kWordSize)); | 693 lw(RA, Address(SP, 2 * kWordSize)); |
| 670 lw(FP, Address(SP, 1 * kWordSize)); | 694 lw(FP, Address(SP, 1 * kWordSize)); |
| 671 lw(PP, Address(SP, 0 * kWordSize)); | 695 lw(PP, Address(SP, 0 * kWordSize)); |
| 672 addiu(SP, SP, Immediate(4 * kWordSize)); | 696 addiu(SP, SP, Immediate(4 * kWordSize)); |
| 673 } | 697 } |
| 674 | 698 |
| 675 | 699 |
| 676 void Assembler::LeaveStubFrameAndReturn(Register ra) { | 700 void Assembler::LeaveStubFrameAndReturn(Register ra) { |
| 701 ASSERT(!in_delay_slot_); |
| 677 addiu(SP, FP, Immediate(-1 * kWordSize)); | 702 addiu(SP, FP, Immediate(-1 * kWordSize)); |
| 678 lw(RA, Address(SP, 2 * kWordSize)); | 703 lw(RA, Address(SP, 2 * kWordSize)); |
| 679 lw(FP, Address(SP, 1 * kWordSize)); | 704 lw(FP, Address(SP, 1 * kWordSize)); |
| 680 lw(PP, Address(SP, 0 * kWordSize)); | 705 lw(PP, Address(SP, 0 * kWordSize)); |
| 681 jr(ra); | 706 jr(ra); |
| 682 delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize)); | 707 delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize)); |
| 683 } | 708 } |
| 684 | 709 |
| 685 | 710 |
| 686 void Assembler::UpdateAllocationStats(intptr_t cid, | 711 void Assembler::UpdateAllocationStats(intptr_t cid, |
| 687 Register temp_reg, | 712 Register temp_reg, |
| 688 Heap::Space space) { | 713 Heap::Space space) { |
| 714 ASSERT(!in_delay_slot_); |
| 689 ASSERT(temp_reg != kNoRegister); | 715 ASSERT(temp_reg != kNoRegister); |
| 690 ASSERT(temp_reg != TMP); | 716 ASSERT(temp_reg != TMP); |
| 691 ASSERT(cid > 0); | 717 ASSERT(cid > 0); |
| 692 Isolate* isolate = Isolate::Current(); | 718 Isolate* isolate = Isolate::Current(); |
| 693 ClassTable* class_table = isolate->class_table(); | 719 ClassTable* class_table = isolate->class_table(); |
| 694 if (cid < kNumPredefinedCids) { | 720 if (cid < kNumPredefinedCids) { |
| 695 const uword class_heap_stats_table_address = | 721 const uword class_heap_stats_table_address = |
| 696 class_table->PredefinedClassHeapStatsTableAddress(); | 722 class_table->PredefinedClassHeapStatsTableAddress(); |
| 697 const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT | 723 const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT |
| 698 const uword count_field_offset = (space == Heap::kNew) ? | 724 const uword count_field_offset = (space == Heap::kNew) ? |
| (...skipping 17 matching lines...) Expand all Loading... |
| 716 AddImmediate(TMP, 1); | 742 AddImmediate(TMP, 1); |
| 717 sw(TMP, Address(temp_reg, count_field_offset)); | 743 sw(TMP, Address(temp_reg, count_field_offset)); |
| 718 } | 744 } |
| 719 } | 745 } |
| 720 | 746 |
| 721 | 747 |
| 722 void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, | 748 void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, |
| 723 Register size_reg, | 749 Register size_reg, |
| 724 Register temp_reg, | 750 Register temp_reg, |
| 725 Heap::Space space) { | 751 Heap::Space space) { |
| 752 ASSERT(!in_delay_slot_); |
| 726 ASSERT(temp_reg != kNoRegister); | 753 ASSERT(temp_reg != kNoRegister); |
| 727 ASSERT(cid > 0); | 754 ASSERT(cid > 0); |
| 728 ASSERT(temp_reg != TMP); | 755 ASSERT(temp_reg != TMP); |
| 729 Isolate* isolate = Isolate::Current(); | 756 Isolate* isolate = Isolate::Current(); |
| 730 ClassTable* class_table = isolate->class_table(); | 757 ClassTable* class_table = isolate->class_table(); |
| 731 if (cid < kNumPredefinedCids) { | 758 if (cid < kNumPredefinedCids) { |
| 732 const uword class_heap_stats_table_address = | 759 const uword class_heap_stats_table_address = |
| 733 class_table->PredefinedClassHeapStatsTableAddress(); | 760 class_table->PredefinedClassHeapStatsTableAddress(); |
| 734 const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT | 761 const uword class_offset = cid * sizeof(ClassHeapStats); // NOLINT |
| 735 const uword count_field_offset = (space == Heap::kNew) ? | 762 const uword count_field_offset = (space == Heap::kNew) ? |
| (...skipping 30 matching lines...) Expand all Loading... |
| 766 addu(TMP, TMP, size_reg); | 793 addu(TMP, TMP, size_reg); |
| 767 sw(TMP, Address(temp_reg, size_field_offset)); | 794 sw(TMP, Address(temp_reg, size_field_offset)); |
| 768 } | 795 } |
| 769 } | 796 } |
| 770 | 797 |
| 771 | 798 |
| 772 void Assembler::TryAllocate(const Class& cls, | 799 void Assembler::TryAllocate(const Class& cls, |
| 773 Label* failure, | 800 Label* failure, |
| 774 Register instance_reg, | 801 Register instance_reg, |
| 775 Register temp_reg) { | 802 Register temp_reg) { |
| 803 ASSERT(!in_delay_slot_); |
| 776 ASSERT(failure != NULL); | 804 ASSERT(failure != NULL); |
| 777 if (FLAG_inline_alloc) { | 805 if (FLAG_inline_alloc) { |
| 778 Heap* heap = Isolate::Current()->heap(); | 806 Heap* heap = Isolate::Current()->heap(); |
| 779 const intptr_t instance_size = cls.instance_size(); | 807 const intptr_t instance_size = cls.instance_size(); |
| 780 LoadImmediate(instance_reg, heap->TopAddress()); | 808 LoadImmediate(instance_reg, heap->TopAddress()); |
| 781 lw(instance_reg, Address(instance_reg, 0)); | 809 lw(instance_reg, Address(instance_reg, 0)); |
| 782 AddImmediate(instance_reg, instance_size); | 810 AddImmediate(instance_reg, instance_size); |
| 783 | 811 |
| 784 // instance_reg: potential next object start. | 812 // instance_reg: potential next object start. |
| 785 LoadImmediate(TMP, heap->EndAddress()); | 813 LoadImmediate(TMP, heap->EndAddress()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 807 } | 835 } |
| 808 | 836 |
| 809 | 837 |
| 810 void Assembler::CallRuntime(const RuntimeEntry& entry, | 838 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 811 intptr_t argument_count) { | 839 intptr_t argument_count) { |
| 812 entry.Call(this, argument_count); | 840 entry.Call(this, argument_count); |
| 813 } | 841 } |
| 814 | 842 |
| 815 | 843 |
| 816 void Assembler::EnterDartFrame(intptr_t frame_size) { | 844 void Assembler::EnterDartFrame(intptr_t frame_size) { |
| 845 ASSERT(!in_delay_slot_); |
| 817 const intptr_t offset = CodeSize(); | 846 const intptr_t offset = CodeSize(); |
| 818 | 847 |
| 819 SetPrologueOffset(); | 848 SetPrologueOffset(); |
| 820 | 849 |
| 821 addiu(SP, SP, Immediate(-4 * kWordSize)); | 850 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 822 sw(RA, Address(SP, 2 * kWordSize)); | 851 sw(RA, Address(SP, 2 * kWordSize)); |
| 823 sw(FP, Address(SP, 1 * kWordSize)); | 852 sw(FP, Address(SP, 1 * kWordSize)); |
| 824 sw(PP, Address(SP, 0 * kWordSize)); | 853 sw(PP, Address(SP, 0 * kWordSize)); |
| 825 | 854 |
| 826 GetNextPC(TMP); // TMP gets the address of the next instruction. | 855 GetNextPC(TMP); // TMP gets the address of the next instruction. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 844 AddImmediate(SP, -frame_size); | 873 AddImmediate(SP, -frame_size); |
| 845 } | 874 } |
| 846 | 875 |
| 847 | 876 |
| 848 // On entry to a function compiled for OSR, the caller's frame pointer, the | 877 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 849 // stack locals, and any copied parameters are already in place. The frame | 878 // stack locals, and any copied parameters are already in place. The frame |
| 850 // pointer is already set up. The PC marker is not correct for the | 879 // pointer is already set up. The PC marker is not correct for the |
| 851 // optimized function and there may be extra space for spill slots to | 880 // optimized function and there may be extra space for spill slots to |
| 852 // allocate. We must also set up the pool pointer for the function. | 881 // allocate. We must also set up the pool pointer for the function. |
| 853 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 882 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
| 883 ASSERT(!in_delay_slot_); |
| 854 Comment("EnterOsrFrame"); | 884 Comment("EnterOsrFrame"); |
| 855 | 885 |
| 856 GetNextPC(TMP); // TMP gets the address of the next instruction. | 886 GetNextPC(TMP); // TMP gets the address of the next instruction. |
| 857 | 887 |
| 858 // The runtime system assumes that the code marker address is | 888 // The runtime system assumes that the code marker address is |
| 859 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no | 889 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no |
| 860 // code to set up the frame pointer, etc., the address needs to be adjusted. | 890 // code to set up the frame pointer, etc., the address needs to be adjusted. |
| 861 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | 891 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); |
| 862 // Calculate the offset of the pool pointer from the PC. | 892 // Calculate the offset of the pool pointer from the PC. |
| 863 const intptr_t object_pool_pc_dist = | 893 const intptr_t object_pool_pc_dist = |
| 864 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 894 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 865 CodeSize(); | 895 CodeSize(); |
| 866 | 896 |
| 867 // Adjust PC by the offset, and store it in the stack frame. | 897 // Adjust PC by the offset, and store it in the stack frame. |
| 868 AddImmediate(TMP, TMP, offset); | 898 AddImmediate(TMP, TMP, offset); |
| 869 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); | 899 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
| 870 | 900 |
| 871 // Restore return address. | 901 // Restore return address. |
| 872 lw(RA, Address(FP, 1 * kWordSize)); | 902 lw(RA, Address(FP, 1 * kWordSize)); |
| 873 | 903 |
| 874 // Load the pool pointer. offset has already been subtracted from temp. | 904 // Load the pool pointer. offset has already been subtracted from temp. |
| 875 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); | 905 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); |
| 876 | 906 |
| 877 // Reserve space for locals. | 907 // Reserve space for locals. |
| 878 AddImmediate(SP, -extra_size); | 908 AddImmediate(SP, -extra_size); |
| 879 } | 909 } |
| 880 | 910 |
| 881 | 911 |
| 882 void Assembler::LeaveDartFrame() { | 912 void Assembler::LeaveDartFrame() { |
| 913 ASSERT(!in_delay_slot_); |
| 883 addiu(SP, FP, Immediate(-kWordSize)); | 914 addiu(SP, FP, Immediate(-kWordSize)); |
| 884 | 915 |
| 885 lw(RA, Address(SP, 2 * kWordSize)); | 916 lw(RA, Address(SP, 2 * kWordSize)); |
| 886 lw(FP, Address(SP, 1 * kWordSize)); | 917 lw(FP, Address(SP, 1 * kWordSize)); |
| 887 lw(PP, Address(SP, 0 * kWordSize)); | 918 lw(PP, Address(SP, 0 * kWordSize)); |
| 888 | 919 |
| 889 // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame. | 920 // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame. |
| 890 addiu(SP, SP, Immediate(4 * kWordSize)); | 921 addiu(SP, SP, Immediate(4 * kWordSize)); |
| 891 } | 922 } |
| 892 | 923 |
| 893 | 924 |
| 894 void Assembler::LeaveDartFrameAndReturn() { | 925 void Assembler::LeaveDartFrameAndReturn() { |
| 926 ASSERT(!in_delay_slot_); |
| 895 addiu(SP, FP, Immediate(-kWordSize)); | 927 addiu(SP, FP, Immediate(-kWordSize)); |
| 896 | 928 |
| 897 lw(RA, Address(SP, 2 * kWordSize)); | 929 lw(RA, Address(SP, 2 * kWordSize)); |
| 898 lw(FP, Address(SP, 1 * kWordSize)); | 930 lw(FP, Address(SP, 1 * kWordSize)); |
| 899 lw(PP, Address(SP, 0 * kWordSize)); | 931 lw(PP, Address(SP, 0 * kWordSize)); |
| 900 | 932 |
| 901 // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame, and return. | 933 // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame, and return. |
| 902 Ret(); | 934 Ret(); |
| 903 delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize)); | 935 delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize)); |
| 904 } | 936 } |
| 905 | 937 |
| 906 | 938 |
| 907 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 939 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 940 ASSERT(!in_delay_slot_); |
| 908 // Reserve space for arguments and align frame before entering | 941 // Reserve space for arguments and align frame before entering |
| 909 // the C++ world. | 942 // the C++ world. |
| 910 AddImmediate(SP, -frame_space); | 943 AddImmediate(SP, -frame_space); |
| 911 if (OS::ActivationFrameAlignment() > 1) { | 944 if (OS::ActivationFrameAlignment() > 1) { |
| 912 LoadImmediate(TMP, ~(OS::ActivationFrameAlignment() - 1)); | 945 LoadImmediate(TMP, ~(OS::ActivationFrameAlignment() - 1)); |
| 913 and_(SP, SP, TMP); | 946 and_(SP, SP, TMP); |
| 914 } | 947 } |
| 915 } | 948 } |
| 916 | 949 |
| 917 | 950 |
| 918 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { | 951 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { |
| 952 ASSERT(!in_delay_slot_); |
| 919 const intptr_t kPushedRegistersSize = | 953 const intptr_t kPushedRegistersSize = |
| 920 kDartVolatileCpuRegCount * kWordSize + | 954 kDartVolatileCpuRegCount * kWordSize + |
| 921 2 * kWordSize + // FP and RA. | 955 2 * kWordSize + // FP and RA. |
| 922 kDartVolatileFpuRegCount * kWordSize; | 956 kDartVolatileFpuRegCount * kWordSize; |
| 923 | 957 |
| 924 SetPrologueOffset(); | 958 SetPrologueOffset(); |
| 925 | 959 |
| 926 TraceSimMsg("EnterCallRuntimeFrame"); | 960 TraceSimMsg("EnterCallRuntimeFrame"); |
| 927 | 961 |
| 928 // Save volatile CPU and FPU registers on the stack: | 962 // Save volatile CPU and FPU registers on the stack: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 951 } | 985 } |
| 952 sw(RA, Address(SP, 1 * kWordSize)); | 986 sw(RA, Address(SP, 1 * kWordSize)); |
| 953 sw(FP, Address(SP, 0 * kWordSize)); | 987 sw(FP, Address(SP, 0 * kWordSize)); |
| 954 mov(FP, SP); | 988 mov(FP, SP); |
| 955 | 989 |
| 956 ReserveAlignedFrameSpace(frame_space); | 990 ReserveAlignedFrameSpace(frame_space); |
| 957 } | 991 } |
| 958 | 992 |
| 959 | 993 |
| 960 void Assembler::LeaveCallRuntimeFrame() { | 994 void Assembler::LeaveCallRuntimeFrame() { |
| 995 ASSERT(!in_delay_slot_); |
| 961 const intptr_t kPushedRegistersSize = | 996 const intptr_t kPushedRegistersSize = |
| 962 kDartVolatileCpuRegCount * kWordSize + | 997 kDartVolatileCpuRegCount * kWordSize + |
| 963 2 * kWordSize + // FP and RA. | 998 2 * kWordSize + // FP and RA. |
| 964 kDartVolatileFpuRegCount * kWordSize; | 999 kDartVolatileFpuRegCount * kWordSize; |
| 965 | 1000 |
| 966 TraceSimMsg("LeaveCallRuntimeFrame"); | 1001 TraceSimMsg("LeaveCallRuntimeFrame"); |
| 967 | 1002 |
| 968 // SP might have been modified to reserve space for arguments | 1003 // SP might have been modified to reserve space for arguments |
| 969 // and ensure proper alignment of the stack frame. | 1004 // and ensure proper alignment of the stack frame. |
| 970 // We need to restore it before restoring registers. | 1005 // We need to restore it before restoring registers. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1055 Emit(reinterpret_cast<int32_t>(message)); | 1090 Emit(reinterpret_cast<int32_t>(message)); |
| 1056 Bind(&msg); | 1091 Bind(&msg); |
| 1057 break_(Instr::kMsgMessageCode); | 1092 break_(Instr::kMsgMessageCode); |
| 1058 } | 1093 } |
| 1059 #endif | 1094 #endif |
| 1060 } | 1095 } |
| 1061 | 1096 |
| 1062 } // namespace dart | 1097 } // namespace dart |
| 1063 | 1098 |
| 1064 #endif // defined TARGET_ARCH_MIPS | 1099 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |