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