| 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 void Assembler::Bind(Label* label) { |
| 34 ASSERT(!label->IsBound()); | 35 ASSERT(!label->IsBound()); |
| 35 int bound_pc = buffer_.Size(); | 36 int bound_pc = buffer_.Size(); |
| 36 while (label->IsLinked()) { | 37 while (label->IsLinked()) { |
| 37 const int32_t position = label->Position(); | 38 if (FLAG_mips_far_branches) { |
| 38 const int32_t next = buffer_.Load<int32_t>(position); | 39 const int32_t position = label->Position(); |
| 39 // Relative destination from an instruction after the branch. | 40 const int32_t high = buffer_.Load<int32_t>(position); |
| 40 const int32_t dest = bound_pc - (position + Instr::kInstrSize); | 41 const int32_t low = buffer_.Load<int32_t>(position + Instr::kInstrSize); |
| 41 const int32_t encoded = Assembler::EncodeBranchOffset(dest, next); | 42 |
| 42 buffer_.Store<int32_t>(position, encoded); | 43 // Relative destination from an instruction after the branch. |
| 43 label->position_ = Assembler::DecodeBranchOffset(next); | 44 const int32_t dest = bound_pc - (position + 7 * Instr::kInstrSize); |
| 45 const int32_t encoded_low = |
| 46 Assembler::EncodeLoadImmediate(dest & kBranchOffsetMask, low); |
| 47 const int32_t encoded_high = |
| 48 Assembler::EncodeLoadImmediate(dest >> 16, high); |
| 49 |
| 50 buffer_.Store<int32_t>(position, encoded_high); |
| 51 buffer_.Store<int32_t>(position + Instr::kInstrSize, encoded_low); |
| 52 label->position_ = Assembler::DecodeLoadImmediate(low, high); |
| 53 } else { |
| 54 const int32_t position = label->Position(); |
| 55 const int32_t next = buffer_.Load<int32_t>(position); |
| 56 // Relative destination from an instruction after the branch. |
| 57 const int32_t dest = bound_pc - (position + Instr::kInstrSize); |
| 58 const int32_t encoded = Assembler::EncodeBranchOffset(dest, next); |
| 59 buffer_.Store<int32_t>(position, encoded); |
| 60 label->position_ = Assembler::DecodeBranchOffset(next); |
| 61 } |
| 44 } | 62 } |
| 45 label->BindTo(bound_pc); | 63 label->BindTo(bound_pc); |
| 46 delay_slot_available_ = false; | 64 delay_slot_available_ = false; |
| 47 } | 65 } |
| 48 | 66 |
| 49 | 67 |
| 50 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) { | 68 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) { |
| 51 ASSERT(Utils::IsAligned(offset, 4)); | 69 ASSERT(Utils::IsAligned(offset, 4)); |
| 52 ASSERT(Utils::IsInt(18, offset)); | 70 ASSERT(Utils::IsInt(18, offset)); |
| 53 | 71 |
| 54 // Properly preserve only the bits supported in the instruction. | 72 // Properly preserve only the bits supported in the instruction. |
| 55 offset >>= 2; | 73 offset >>= 2; |
| 56 offset &= kBranchOffsetMask; | 74 offset &= kBranchOffsetMask; |
| 57 return (instr & ~kBranchOffsetMask) | offset; | 75 return (instr & ~kBranchOffsetMask) | offset; |
| 58 } | 76 } |
| 59 | 77 |
| 60 | 78 |
| 61 int Assembler::DecodeBranchOffset(int32_t instr) { | 79 int Assembler::DecodeBranchOffset(int32_t instr) { |
| 62 // Sign-extend, left-shift by 2. | 80 // Sign-extend, left-shift by 2. |
| 63 return (((instr & kBranchOffsetMask) << 16) >> 14); | 81 return (((instr & kBranchOffsetMask) << 16) >> 14); |
| 64 } | 82 } |
| 65 | 83 |
| 66 | 84 |
| 85 int32_t Assembler::DecodeLoadImmediate(int32_t low, int32_t high) { |
| 86 return (((high & kBranchOffsetMask) << 16) | (low & kBranchOffsetMask)); |
| 87 } |
| 88 |
| 89 |
| 90 int32_t Assembler::EncodeLoadImmediate(int32_t dest, int32_t instr) { |
| 91 return ((instr & ~kBranchOffsetMask) | (dest & kBranchOffsetMask)); |
| 92 } |
| 93 |
| 94 |
| 67 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { | 95 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { |
| 68 ASSERT(rd != PP); | 96 ASSERT(rd != PP); |
| 69 if (Address::CanHoldOffset(offset)) { | 97 if (Address::CanHoldOffset(offset)) { |
| 70 lw(rd, Address(PP, offset)); | 98 lw(rd, Address(PP, offset)); |
| 71 } else { | 99 } else { |
| 72 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. | 100 const int16_t offset_low = Utils::Low16Bits(offset); // Signed. |
| 73 offset -= offset_low; | 101 offset -= offset_low; |
| 74 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. | 102 const uint16_t offset_high = Utils::High16Bits(offset); // Unsigned. |
| 75 if (offset_high != 0) { | 103 if (offset_high != 0) { |
| 76 lui(rd, Immediate(offset_high)); | 104 lui(rd, Immediate(offset_high)); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 Label* no_update) { | 252 Label* no_update) { |
| 225 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 253 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 226 (kOldObjectAlignmentOffset == 0), young_alignment); | 254 (kOldObjectAlignmentOffset == 0), young_alignment); |
| 227 | 255 |
| 228 // Write-barrier triggers if the value is in the new space (has bit set) and | 256 // 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). | 257 // the object is in the old space (has bit cleared). |
| 230 // To check that, we compute value & ~object and skip the write barrier | 258 // 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. | 259 // if the bit is not set. We can't destroy the object. |
| 232 nor(TMP1, ZR, object); | 260 nor(TMP1, ZR, object); |
| 233 and_(TMP1, value, TMP1); | 261 and_(TMP1, value, TMP1); |
| 234 andi(TMP1, TMP1, Immediate(kNewObjectAlignmentOffset)); | 262 andi(CMPRES1, TMP1, Immediate(kNewObjectAlignmentOffset)); |
| 235 beq(TMP1, ZR, no_update); | 263 beq(CMPRES1, ZR, no_update); |
| 236 } | 264 } |
| 237 | 265 |
| 238 | 266 |
| 239 // Preserves object and value registers. | 267 // Preserves object and value registers. |
| 240 void Assembler::StoreIntoObjectFilter(Register object, | 268 void Assembler::StoreIntoObjectFilter(Register object, |
| 241 Register value, | 269 Register value, |
| 242 Label* no_update) { | 270 Label* no_update) { |
| 243 // For the value we are only interested in the new/old bit and the tag bit. | 271 // 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. | 272 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. |
| 245 sll(TMP1, value, kObjectAlignmentLog2 - 1); | 273 sll(TMP1, value, kObjectAlignmentLog2 - 1); |
| 246 and_(TMP1, value, TMP1); | 274 and_(TMP1, value, TMP1); |
| 247 // And the result with the negated space bit of the object. | 275 // And the result with the negated space bit of the object. |
| 248 nor(CMPRES, ZR, object); | 276 nor(CMPRES1, ZR, object); |
| 249 and_(TMP1, TMP1, CMPRES); | 277 and_(TMP1, TMP1, CMPRES1); |
| 250 andi(TMP1, TMP1, Immediate(kNewObjectAlignmentOffset)); | 278 andi(CMPRES1, TMP1, Immediate(kNewObjectAlignmentOffset)); |
| 251 beq(TMP1, ZR, no_update); | 279 beq(CMPRES1, ZR, no_update); |
| 252 } | 280 } |
| 253 | 281 |
| 254 | 282 |
| 255 void Assembler::StoreIntoObject(Register object, | 283 void Assembler::StoreIntoObject(Register object, |
| 256 const Address& dest, | 284 const Address& dest, |
| 257 Register value, | 285 Register value, |
| 258 bool can_value_be_smi) { | 286 bool can_value_be_smi) { |
| 259 ASSERT(object != value); | 287 ASSERT(object != value); |
| 260 sw(value, dest); | 288 sw(value, dest); |
| 261 Label done; | 289 Label done; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 void Assembler::EnterStubFrame(bool uses_pp) { | 380 void Assembler::EnterStubFrame(bool uses_pp) { |
| 353 SetPrologueOffset(); | 381 SetPrologueOffset(); |
| 354 if (uses_pp) { | 382 if (uses_pp) { |
| 355 addiu(SP, SP, Immediate(-4 * kWordSize)); | 383 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 356 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. | 384 sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs. |
| 357 sw(RA, Address(SP, 2 * kWordSize)); | 385 sw(RA, Address(SP, 2 * kWordSize)); |
| 358 sw(FP, Address(SP, 1 * kWordSize)); | 386 sw(FP, Address(SP, 1 * kWordSize)); |
| 359 sw(PP, Address(SP, 0 * kWordSize)); | 387 sw(PP, Address(SP, 0 * kWordSize)); |
| 360 addiu(FP, SP, Immediate(1 * kWordSize)); | 388 addiu(FP, SP, Immediate(1 * kWordSize)); |
| 361 // Setup pool pointer for this stub. | 389 // Setup pool pointer for this stub. |
| 362 Label next; | 390 |
| 363 bal(&next); | 391 GetNextPC(TMP1, false); // TMP1 gets the address of the next instruction. |
| 364 delay_slot()->mov(TMP1, RA); | |
| 365 | 392 |
| 366 const intptr_t object_pool_pc_dist = | 393 const intptr_t object_pool_pc_dist = |
| 367 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 394 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 368 CodeSize(); | 395 CodeSize(); |
| 369 | 396 |
| 370 Bind(&next); | |
| 371 lw(PP, Address(TMP1, -object_pool_pc_dist)); | 397 lw(PP, Address(TMP1, -object_pool_pc_dist)); |
| 372 } else { | 398 } else { |
| 373 addiu(SP, SP, Immediate(-3 * kWordSize)); | 399 addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 374 sw(ZR, Address(SP, 2 * kWordSize)); // PC marker is 0 in stubs. | 400 sw(ZR, Address(SP, 2 * kWordSize)); // PC marker is 0 in stubs. |
| 375 sw(RA, Address(SP, 1 * kWordSize)); | 401 sw(RA, Address(SP, 1 * kWordSize)); |
| 376 sw(FP, Address(SP, 0 * kWordSize)); | 402 sw(FP, Address(SP, 0 * kWordSize)); |
| 377 mov(FP, SP); | 403 mov(FP, SP); |
| 378 } | 404 } |
| 379 } | 405 } |
| 380 | 406 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 void Assembler::EnterDartFrame(intptr_t frame_size) { | 484 void Assembler::EnterDartFrame(intptr_t frame_size) { |
| 459 const intptr_t offset = CodeSize(); | 485 const intptr_t offset = CodeSize(); |
| 460 | 486 |
| 461 SetPrologueOffset(); | 487 SetPrologueOffset(); |
| 462 | 488 |
| 463 addiu(SP, SP, Immediate(-4 * kWordSize)); | 489 addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 464 sw(RA, Address(SP, 2 * kWordSize)); | 490 sw(RA, Address(SP, 2 * kWordSize)); |
| 465 sw(FP, Address(SP, 1 * kWordSize)); | 491 sw(FP, Address(SP, 1 * kWordSize)); |
| 466 sw(PP, Address(SP, 0 * kWordSize)); | 492 sw(PP, Address(SP, 0 * kWordSize)); |
| 467 | 493 |
| 468 Label next; | 494 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 | 495 |
| 474 // Calculate the offset of the pool pointer from the PC. | 496 // Calculate the offset of the pool pointer from the PC. |
| 475 const intptr_t object_pool_pc_dist = | 497 const intptr_t object_pool_pc_dist = |
| 476 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 498 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 477 CodeSize(); | 499 CodeSize(); |
| 478 | 500 |
| 479 // TMP1 has the address of the next instruction. | |
| 480 Bind(&next); | |
| 481 | |
| 482 // Save PC in frame for fast identification of corresponding code. | 501 // Save PC in frame for fast identification of corresponding code. |
| 483 AddImmediate(TMP1, -offset); | 502 AddImmediate(TMP1, -offset); |
| 484 sw(TMP1, Address(SP, 3 * kWordSize)); | 503 sw(TMP1, Address(SP, 3 * kWordSize)); |
| 485 | 504 |
| 486 // Set FP to the saved previous FP. | 505 // Set FP to the saved previous FP. |
| 487 addiu(FP, SP, Immediate(kWordSize)); | 506 addiu(FP, SP, Immediate(kWordSize)); |
| 488 | 507 |
| 489 // Load the pool pointer. offset has already been subtracted from TMP1. | 508 // Load the pool pointer. offset has already been subtracted from TMP1. |
| 490 lw(PP, Address(TMP1, -object_pool_pc_dist + offset)); | 509 lw(PP, Address(TMP1, -object_pool_pc_dist + offset)); |
| 491 | 510 |
| 492 // Reserve space for locals. | 511 // Reserve space for locals. |
| 493 AddImmediate(SP, -frame_size); | 512 AddImmediate(SP, -frame_size); |
| 494 } | 513 } |
| 495 | 514 |
| 496 | 515 |
| 497 // On entry to a function compiled for OSR, the caller's frame pointer, the | 516 // 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 | 517 // 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 | 518 // 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 | 519 // 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. | 520 // allocate. We must also set up the pool pointer for the function. |
| 502 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 521 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
| 503 Comment("EnterOsrFrame"); | 522 Comment("EnterOsrFrame"); |
| 504 Label next; | 523 |
| 505 // Branch and link to the instruction after the delay slot to get the PC. | 524 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 | 525 |
| 510 // The runtime system assumes that the code marker address is | 526 // The runtime system assumes that the code marker address is |
| 511 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no | 527 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no |
| 512 // code to set up the frame pointer, etc., the address needs to be adjusted. | 528 // code to set up the frame pointer, etc., the address needs to be adjusted. |
| 513 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | 529 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); |
| 514 // Calculate the offset of the pool pointer from the PC. | 530 // Calculate the offset of the pool pointer from the PC. |
| 515 const intptr_t object_pool_pc_dist = | 531 const intptr_t object_pool_pc_dist = |
| 516 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 532 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 517 CodeSize(); | 533 CodeSize(); |
| 518 | 534 |
| 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. | 535 // Adjust PC by the offset, and store it in the stack frame. |
| 523 AddImmediate(TMP, TMP, offset); | 536 AddImmediate(TMP, TMP, offset); |
| 524 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); | 537 sw(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
| 525 | 538 |
| 526 // Restore return address. | 539 // Restore return address. |
| 527 lw(RA, Address(FP, 1 * kWordSize)); | 540 lw(RA, Address(FP, 1 * kWordSize)); |
| 528 | 541 |
| 529 // Load the pool pointer. offset has already been subtracted from temp. | 542 // Load the pool pointer. offset has already been subtracted from temp. |
| 530 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); | 543 lw(PP, Address(TMP, -object_pool_pc_dist - offset)); |
| 531 | 544 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 Bind(&msg); | 724 Bind(&msg); |
| 712 break_(Instr::kMsgMessageCode); | 725 break_(Instr::kMsgMessageCode); |
| 713 } | 726 } |
| 714 #endif | 727 #endif |
| 715 } | 728 } |
| 716 | 729 |
| 717 } // namespace dart | 730 } // namespace dart |
| 718 | 731 |
| 719 #endif // defined TARGET_ARCH_MIPS | 732 #endif // defined TARGET_ARCH_MIPS |
| 720 | 733 |
| OLD | NEW |