Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: runtime/vm/assembler_mips.cc

Issue 20369003: Implements far branch targets for MIPS. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/assembler_mips.h ('k') | runtime/vm/assembler_mips_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/assembler_mips.h ('k') | runtime/vm/assembler_mips_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698