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

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
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, 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698