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/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
10 #include "vm/simulator.h" | 11 #include "vm/simulator.h" |
11 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
12 #include "vm/stub_code.h" | 13 #include "vm/stub_code.h" |
13 | 14 |
14 namespace dart { | 15 namespace dart { |
15 | 16 |
16 #if defined(USING_SIMULATOR) | 17 #if defined(USING_SIMULATOR) |
17 DECLARE_FLAG(bool, trace_sim); | 18 DECLARE_FLAG(bool, trace_sim); |
18 #endif | 19 #endif |
(...skipping 22 matching lines...) Expand all Loading... |
41 } | 42 } |
42 } | 43 } |
43 | 44 |
44 | 45 |
45 static bool CanEncodeBranchOffset(int32_t offset) { | 46 static bool CanEncodeBranchOffset(int32_t offset) { |
46 ASSERT(Utils::IsAligned(offset, 4)); | 47 ASSERT(Utils::IsAligned(offset, 4)); |
47 return Utils::IsInt(18, offset); | 48 return Utils::IsInt(18, offset); |
48 } | 49 } |
49 | 50 |
50 | 51 |
51 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr) { | 52 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) { |
52 ASSERT(Utils::IsAligned(offset, 4)); | 53 if (!CanEncodeBranchOffset(offset)) { |
53 ASSERT(Utils::IsInt(18, offset)); | 54 ASSERT(!use_far_branches()); |
| 55 const Error& error = Error::Handle(LanguageError::New( |
| 56 String::Handle(String::New("Branch offset overflow")))); |
| 57 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 58 } |
54 | 59 |
55 // Properly preserve only the bits supported in the instruction. | 60 // Properly preserve only the bits supported in the instruction. |
56 offset >>= 2; | 61 offset >>= 2; |
57 offset &= kBranchOffsetMask; | 62 offset &= kBranchOffsetMask; |
58 return (instr & ~kBranchOffsetMask) | offset; | 63 return (instr & ~kBranchOffsetMask) | offset; |
59 } | 64 } |
60 | 65 |
61 | 66 |
62 static int DecodeBranchOffset(int32_t instr) { | 67 static int DecodeBranchOffset(int32_t instr) { |
63 // Sign-extend, left-shift by 2. | 68 // Sign-extend, left-shift by 2. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 return; | 104 return; |
100 } | 105 } |
101 // If the offset loading instructions aren't there, we must have replaced | 106 // If the offset loading instructions aren't there, we must have replaced |
102 // the far branch with a near one, and so these instructions should be NOPs. | 107 // the far branch with a near one, and so these instructions should be NOPs. |
103 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); | 108 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); |
104 } | 109 } |
105 }; | 110 }; |
106 | 111 |
107 | 112 |
108 void Assembler::EmitFarJump(int32_t offset, bool link) { | 113 void Assembler::EmitFarJump(int32_t offset, bool link) { |
| 114 ASSERT(use_far_branches()); |
109 const uint16_t low = Utils::Low16Bits(offset); | 115 const uint16_t low = Utils::Low16Bits(offset); |
110 const uint16_t high = Utils::High16Bits(offset); | 116 const uint16_t high = Utils::High16Bits(offset); |
111 buffer_.EmitFixup(new PatchFarJump()); | 117 buffer_.EmitFixup(new PatchFarJump()); |
112 lui(TMP, Immediate(high)); | 118 lui(TMP, Immediate(high)); |
113 ori(TMP, TMP, Immediate(low)); | 119 ori(TMP, TMP, Immediate(low)); |
114 if (link) { | 120 if (link) { |
115 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); | 121 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); |
116 } else { | 122 } else { |
117 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); | 123 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); |
118 } | 124 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 nop(); | 178 nop(); |
173 EmitFarJump(offset, false); | 179 EmitFarJump(offset, false); |
174 } | 180 } |
175 | 181 |
176 | 182 |
177 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | 183 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
178 if (label->IsBound()) { | 184 if (label->IsBound()) { |
179 // Relative destination from an instruction after the branch. | 185 // Relative destination from an instruction after the branch. |
180 const int32_t dest = | 186 const int32_t dest = |
181 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 187 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
182 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 188 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
183 EmitFarBranch(b, rs, rt, label->Position()); | 189 EmitFarBranch(b, rs, rt, label->Position()); |
184 } else { | 190 } else { |
185 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 191 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
186 EmitIType(b, rs, rt, dest_off); | 192 EmitIType(b, rs, rt, dest_off); |
187 } | 193 } |
188 } else { | 194 } else { |
189 const int position = buffer_.Size(); | 195 const int position = buffer_.Size(); |
190 if (FLAG_use_far_branches) { | 196 if (use_far_branches()) { |
191 const uint32_t dest_off = label->position_; | 197 const uint32_t dest_off = label->position_; |
192 EmitFarBranch(b, rs, rt, dest_off); | 198 EmitFarBranch(b, rs, rt, dest_off); |
193 } else { | 199 } else { |
194 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 200 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
195 EmitIType(b, rs, rt, dest_off); | 201 EmitIType(b, rs, rt, dest_off); |
196 } | 202 } |
197 label->LinkTo(position); | 203 label->LinkTo(position); |
198 } | 204 } |
199 } | 205 } |
200 | 206 |
201 | 207 |
202 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 208 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
203 if (label->IsBound()) { | 209 if (label->IsBound()) { |
204 // Relative destination from an instruction after the branch. | 210 // Relative destination from an instruction after the branch. |
205 const int32_t dest = | 211 const int32_t dest = |
206 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 212 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
207 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 213 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
208 EmitFarRegImmBranch(b, rs, label->Position()); | 214 EmitFarRegImmBranch(b, rs, label->Position()); |
209 } else { | 215 } else { |
210 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 216 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
211 EmitRegImmType(REGIMM, rs, b, dest_off); | 217 EmitRegImmType(REGIMM, rs, b, dest_off); |
212 } | 218 } |
213 } else { | 219 } else { |
214 const int position = buffer_.Size(); | 220 const int position = buffer_.Size(); |
215 if (FLAG_use_far_branches) { | 221 if (use_far_branches()) { |
216 const uint32_t dest_off = label->position_; | 222 const uint32_t dest_off = label->position_; |
217 EmitFarRegImmBranch(b, rs, dest_off); | 223 EmitFarRegImmBranch(b, rs, dest_off); |
218 } else { | 224 } else { |
219 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 225 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
220 EmitRegImmType(REGIMM, rs, b, dest_off); | 226 EmitRegImmType(REGIMM, rs, b, dest_off); |
221 } | 227 } |
222 label->LinkTo(position); | 228 label->LinkTo(position); |
223 } | 229 } |
224 } | 230 } |
225 | 231 |
226 | 232 |
227 void Assembler::EmitFpuBranch(bool kind, Label *label) { | 233 void Assembler::EmitFpuBranch(bool kind, Label *label) { |
228 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. | 234 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. |
229 if (label->IsBound()) { | 235 if (label->IsBound()) { |
230 // Relative destination from an instruction after the branch. | 236 // Relative destination from an instruction after the branch. |
231 const int32_t dest = | 237 const int32_t dest = |
232 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 238 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
233 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 239 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
234 EmitFarFpuBranch(kind, label->Position()); | 240 EmitFarFpuBranch(kind, label->Position()); |
235 } else { | 241 } else { |
236 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 242 const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
237 Emit(COP1 << kOpcodeShift | | 243 Emit(COP1 << kOpcodeShift | |
238 COP1_BC << kCop1SubShift | | 244 COP1_BC << kCop1SubShift | |
239 b16 | | 245 b16 | |
240 dest_off); | 246 dest_off); |
241 } | 247 } |
242 } else { | 248 } else { |
243 const int position = buffer_.Size(); | 249 const int position = buffer_.Size(); |
244 if (FLAG_use_far_branches) { | 250 if (use_far_branches()) { |
245 const uint32_t dest_off = label->position_; | 251 const uint32_t dest_off = label->position_; |
246 EmitFarFpuBranch(kind, dest_off); | 252 EmitFarFpuBranch(kind, dest_off); |
247 } else { | 253 } else { |
248 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 254 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
249 Emit(COP1 << kOpcodeShift | | 255 Emit(COP1 << kOpcodeShift | |
250 COP1_BC << kCop1SubShift | | 256 COP1_BC << kCop1SubShift | |
251 b16 | | 257 b16 | |
252 dest_off); | 258 dest_off); |
253 } | 259 } |
254 label->LinkTo(position); | 260 label->LinkTo(position); |
(...skipping 17 matching lines...) Expand all Loading... |
272 | 278 |
273 | 279 |
274 void Assembler::Bind(Label* label) { | 280 void Assembler::Bind(Label* label) { |
275 ASSERT(!label->IsBound()); | 281 ASSERT(!label->IsBound()); |
276 int bound_pc = buffer_.Size(); | 282 int bound_pc = buffer_.Size(); |
277 | 283 |
278 while (label->IsLinked()) { | 284 while (label->IsLinked()) { |
279 int32_t position = label->Position(); | 285 int32_t position = label->Position(); |
280 int32_t dest = bound_pc - (position + Instr::kInstrSize); | 286 int32_t dest = bound_pc - (position + Instr::kInstrSize); |
281 | 287 |
282 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 288 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
283 // Far branches are enabled and we can't encode the branch offset. | 289 // Far branches are enabled and we can't encode the branch offset. |
284 | 290 |
285 // Grab the branch instruction. We'll need to flip it later. | 291 // Grab the branch instruction. We'll need to flip it later. |
286 const int32_t branch = buffer_.Load<int32_t>(position); | 292 const int32_t branch = buffer_.Load<int32_t>(position); |
287 | 293 |
288 // Grab instructions that load the offset. | 294 // Grab instructions that load the offset. |
289 const int32_t high = | 295 const int32_t high = |
290 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | 296 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
291 const int32_t low = | 297 const int32_t low = |
292 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); | 298 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); |
293 | 299 |
294 // Change from relative to the branch to relative to the assembler buffer. | 300 // Change from relative to the branch to relative to the assembler buffer. |
295 dest = buffer_.Size(); | 301 dest = buffer_.Size(); |
296 const int32_t encoded_low = | 302 const int32_t encoded_low = |
297 EncodeLoadImmediate(dest & kBranchOffsetMask, low); | 303 EncodeLoadImmediate(dest & kBranchOffsetMask, low); |
298 const int32_t encoded_high = | 304 const int32_t encoded_high = |
299 EncodeLoadImmediate(dest >> 16, high); | 305 EncodeLoadImmediate(dest >> 16, high); |
300 | 306 |
301 // Skip the unconditional far jump if the test fails by flipping the | 307 // Skip the unconditional far jump if the test fails by flipping the |
302 // sense of the branch instruction. | 308 // sense of the branch instruction. |
303 buffer_.Store<int32_t>(position, FlipBranchInstruction(branch)); | 309 buffer_.Store<int32_t>(position, FlipBranchInstruction(branch)); |
304 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, encoded_high); | 310 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, encoded_high); |
305 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, encoded_low); | 311 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, encoded_low); |
306 label->position_ = DecodeLoadImmediate(low, high); | 312 label->position_ = DecodeLoadImmediate(low, high); |
307 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) { | 313 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) { |
308 // We assembled a far branch, but we don't need it. Replace with a near | 314 // We assembled a far branch, but we don't need it. Replace with a near |
309 // branch. | 315 // branch. |
310 | 316 |
311 // Grab the link to the next branch. | 317 // Grab the link to the next branch. |
312 const int32_t high = | 318 const int32_t high = |
313 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | 319 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
314 const int32_t low = | 320 const int32_t low = |
315 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); | 321 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); |
316 | 322 |
317 // Grab the original branch instruction. | 323 // Grab the original branch instruction. |
(...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
972 Bind(&msg); | 978 Bind(&msg); |
973 break_(Instr::kMsgMessageCode); | 979 break_(Instr::kMsgMessageCode); |
974 } | 980 } |
975 #endif | 981 #endif |
976 } | 982 } |
977 | 983 |
978 } // namespace dart | 984 } // namespace dart |
979 | 985 |
980 #endif // defined TARGET_ARCH_MIPS | 986 #endif // defined TARGET_ARCH_MIPS |
981 | 987 |
OLD | NEW |