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