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