Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdarg.h> | 5 #include <stdarg.h> |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #if V8_TARGET_ARCH_ARM | 9 #if V8_TARGET_ARCH_ARM |
| 10 | 10 |
| 11 #include "src/arm/constants-arm.h" | 11 #include "src/arm/constants-arm.h" |
| 12 #include "src/arm/simulator-arm.h" | 12 #include "src/arm/simulator-arm.h" |
| 13 #include "src/assembler.h" | 13 #include "src/assembler.h" |
| 14 #include "src/base/bits.h" | 14 #include "src/base/bits.h" |
| 15 #include "src/codegen.h" | 15 #include "src/codegen.h" |
| 16 #include "src/disasm.h" | 16 #include "src/disasm.h" |
| 17 #include "src/runtime/runtime-utils.h" | 17 #include "src/runtime/runtime-utils.h" |
| 18 | 18 |
| 19 #if defined(USE_SIMULATOR) | 19 #if defined(USE_SIMULATOR) |
| 20 | 20 |
| 21 // Only build the simulator if not compiling for real ARM hardware. | 21 // Only build the simulator if not compiling for real ARM hardware. |
| 22 namespace v8 { | 22 namespace v8 { |
| 23 namespace internal { | 23 namespace internal { |
| 24 | 24 |
| 25 // static | |
| 26 base::LazyMutex Simulator::DataMonitor::mutex_ = | |
| 27 LAZY_STATIC_INSTANCE_INITIALIZER; | |
| 28 // static | |
| 29 Simulator::DataMonitor* Simulator::DataMonitor::head_; | |
| 30 | |
| 25 // This macro provides a platform independent use of sscanf. The reason for | 31 // This macro provides a platform independent use of sscanf. The reason for |
| 26 // SScanF not being implemented in a platform independent way through | 32 // SScanF not being implemented in a platform independent way through |
| 27 // ::v8::internal::OS in the same way as SNPrintF is that the | 33 // ::v8::internal::OS in the same way as SNPrintF is that the |
| 28 // Windows C Run-Time Library does not provide vsscanf. | 34 // Windows C Run-Time Library does not provide vsscanf. |
| 29 #define SScanF sscanf // NOLINT | 35 #define SScanF sscanf // NOLINT |
| 30 | 36 |
| 31 // The ArmDebugger class is used by the simulator while debugging simulated ARM | 37 // The ArmDebugger class is used by the simulator while debugging simulated ARM |
| 32 // code. | 38 // code. |
| 33 class ArmDebugger { | 39 class ArmDebugger { |
| 34 public: | 40 public: |
| (...skipping 2161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2196 hi_res = static_cast<int32_t>(result >> 32); | 2202 hi_res = static_cast<int32_t>(result >> 32); |
| 2197 lo_res = static_cast<int32_t>(result & 0xffffffff); | 2203 lo_res = static_cast<int32_t>(result & 0xffffffff); |
| 2198 } | 2204 } |
| 2199 set_register(rd_lo, lo_res); | 2205 set_register(rd_lo, lo_res); |
| 2200 set_register(rd_hi, hi_res); | 2206 set_register(rd_hi, hi_res); |
| 2201 if (instr->HasS()) { | 2207 if (instr->HasS()) { |
| 2202 UNIMPLEMENTED(); | 2208 UNIMPLEMENTED(); |
| 2203 } | 2209 } |
| 2204 } | 2210 } |
| 2205 } else { | 2211 } else { |
| 2206 UNIMPLEMENTED(); // Not used by V8. | 2212 if (instr->Bits(24, 23) == 3) { |
| 2213 if (instr->Bit(20) == 1) { | |
| 2214 // ldrex | |
| 2215 int rt = instr->RtValue(); | |
| 2216 int rn = instr->RnValue(); | |
| 2217 int32_t addr = get_register(rn); | |
| 2218 switch (instr->Bits(22, 21)) { | |
| 2219 case 0: { | |
| 2220 // Format(instr, "ldrex'cond 'rt, ['rn]"); | |
| 2221 int value = data_monitor_.ReadExW(this, addr, instr); | |
| 2222 set_register(rt, value); | |
| 2223 break; | |
| 2224 } | |
| 2225 case 2: { | |
| 2226 // Format(instr, "ldrexb'cond 'rt, ['rn]"); | |
| 2227 uint8_t value = data_monitor_.ReadExBU(this, addr); | |
| 2228 set_register(rt, value); | |
| 2229 break; | |
| 2230 } | |
| 2231 case 3: { | |
| 2232 // Format(instr, "ldrexh'cond 'rt, ['rn]"); | |
| 2233 uint16_t value = data_monitor_.ReadExHU(this, addr, instr); | |
| 2234 set_register(rt, value); | |
| 2235 break; | |
| 2236 } | |
| 2237 default: | |
| 2238 UNREACHABLE(); | |
| 2239 break; | |
| 2240 } | |
| 2241 } else { | |
| 2242 // The instruction is documented as strex rd, rt, [rn], but the | |
| 2243 // "rt" register is using the rm bits. | |
| 2244 int rd = instr->RdValue(); | |
| 2245 int rt = instr->RmValue(); | |
| 2246 int rn = instr->RnValue(); | |
| 2247 int32_t addr = get_register(rn); | |
| 2248 switch (instr->Bits(22, 21)) { | |
| 2249 case 0: { | |
| 2250 // Format(instr, "strex'cond 'rd, 'rm, ['rn]"); | |
| 2251 int value = get_register(rt); | |
| 2252 int status = data_monitor_.WriteExW(this, addr, value, instr); | |
| 2253 set_register(rd, status); | |
| 2254 break; | |
| 2255 } | |
| 2256 case 2: { | |
| 2257 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]"); | |
| 2258 uint8_t value = get_register(rt); | |
| 2259 int status = data_monitor_.WriteExB(this, addr, value); | |
| 2260 set_register(rd, status); | |
| 2261 break; | |
| 2262 } | |
| 2263 case 3: { | |
| 2264 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]"); | |
| 2265 uint16_t value = get_register(rt); | |
| 2266 int status = data_monitor_.WriteExH(this, addr, value, instr); | |
| 2267 set_register(rd, status); | |
| 2268 break; | |
| 2269 } | |
| 2270 default: | |
| 2271 UNREACHABLE(); | |
| 2272 break; | |
| 2273 } | |
| 2274 } | |
| 2275 } else { | |
| 2276 UNIMPLEMENTED(); // Not used by V8. | |
| 2277 } | |
| 2207 } | 2278 } |
| 2208 } else { | 2279 } else { |
| 2209 // extra load/store instructions | 2280 // extra load/store instructions |
| 2210 int rd = instr->RdValue(); | 2281 int rd = instr->RdValue(); |
| 2211 int rn = instr->RnValue(); | 2282 int rn = instr->RnValue(); |
| 2212 int32_t rn_val = get_register(rn); | 2283 int32_t rn_val = get_register(rn); |
| 2213 int32_t addr = 0; | 2284 int32_t addr = 0; |
| 2214 if (instr->Bit(22) == 0) { | 2285 if (instr->Bit(22) == 0) { |
| 2215 int rm = instr->RmValue(); | 2286 int rm = instr->RmValue(); |
| 2216 int32_t rm_val = get_register(rm); | 2287 int32_t rm_val = get_register(rm); |
| (...skipping 2092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4309 | 4380 |
| 4310 | 4381 |
| 4311 uintptr_t Simulator::PopAddress() { | 4382 uintptr_t Simulator::PopAddress() { |
| 4312 int current_sp = get_register(sp); | 4383 int current_sp = get_register(sp); |
| 4313 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); | 4384 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
| 4314 uintptr_t address = *stack_slot; | 4385 uintptr_t address = *stack_slot; |
| 4315 set_register(sp, current_sp + sizeof(uintptr_t)); | 4386 set_register(sp, current_sp + sizeof(uintptr_t)); |
| 4316 return address; | 4387 return address; |
| 4317 } | 4388 } |
| 4318 | 4389 |
| 4390 | |
| 4391 // Syncronization primitives. See ARM DDI 0406C.b, A2.9. | |
| 4392 uint8_t Simulator::DataMonitor::ReadExBU(Simulator* simulator, int32_t addr) { | |
| 4393 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4394 ReadExInternal_Locked(addr); | |
| 4395 return simulator->ReadBU(addr); | |
| 4396 } | |
| 4397 | |
| 4398 | |
| 4399 int Simulator::DataMonitor::WriteExB(Simulator* simulator, | |
| 4400 int32_t addr, | |
| 4401 uint8_t value) { | |
| 4402 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4403 if (WriteExInternal_Locked(addr)) { | |
| 4404 simulator->WriteB(addr, value); | |
|
jbramley
2016/05/31 16:58:47
Also, _any_ unrelated memory operation should _som
binji
2016/06/01 21:06:40
OK, makes sense.
| |
| 4405 return 1; | |
|
Rodolph Perfetta (ARM)
2016/05/25 17:38:29
it is 0 on success and 1 for failure.
binji
2016/06/01 21:06:40
Oops! done.
| |
| 4406 } | |
| 4407 return 0; | |
| 4408 } | |
| 4409 | |
| 4410 | |
| 4411 uint16_t Simulator::DataMonitor::ReadExHU(Simulator* simulator, | |
| 4412 int32_t addr, | |
| 4413 Instruction* instr) { | |
| 4414 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4415 ReadExInternal_Locked(addr); | |
| 4416 return simulator->ReadHU(addr, instr); | |
| 4417 } | |
| 4418 | |
| 4419 | |
| 4420 int Simulator::DataMonitor::WriteExH(Simulator* simulator, | |
| 4421 int32_t addr, | |
| 4422 uint16_t value, | |
| 4423 Instruction* instr) { | |
| 4424 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4425 if (WriteExInternal_Locked(addr)) { | |
| 4426 simulator->WriteH(addr, value, instr); | |
| 4427 return 1; | |
|
Rodolph Perfetta (ARM)
2016/05/25 17:38:29
0
binji
2016/06/01 21:06:40
Done.
| |
| 4428 } | |
| 4429 return 0; | |
| 4430 } | |
| 4431 | |
| 4432 | |
| 4433 int Simulator::DataMonitor::ReadExW(Simulator* simulator, | |
| 4434 int32_t addr, | |
| 4435 Instruction* instr) { | |
| 4436 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4437 ReadExInternal_Locked(addr); | |
| 4438 return simulator->ReadW(addr, instr); | |
| 4439 } | |
| 4440 | |
| 4441 | |
| 4442 int Simulator::DataMonitor::WriteExW(Simulator* simulator, | |
| 4443 int32_t addr, | |
| 4444 int value, | |
| 4445 Instruction* instr) { | |
| 4446 base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer()); | |
| 4447 if (WriteExInternal_Locked(addr)) { | |
| 4448 simulator->WriteW(addr, value, instr); | |
| 4449 return 1; | |
|
Rodolph Perfetta (ARM)
2016/05/25 17:38:29
0
binji
2016/06/01 21:06:40
Done.
| |
| 4450 } | |
| 4451 return 0; | |
| 4452 } | |
| 4453 | |
| 4454 | |
| 4455 Simulator::DataMonitor::DataMonitor() | |
| 4456 : access_state_(Access::Open), | |
| 4457 tagged_addr_(0), | |
| 4458 next_(nullptr), | |
| 4459 prev_(nullptr) {} | |
| 4460 | |
| 4461 | |
| 4462 void Simulator::DataMonitor::ReadExInternal_Locked(int32_t addr) { | |
| 4463 if (access_state_ == Access::Exclusive) { | |
| 4464 // This DataMonitor is already in the linked list; remove it so can be | |
| 4465 // added below. | |
| 4466 RemoveNode_Locked(); | |
| 4467 } | |
| 4468 | |
| 4469 PrependNode_Locked(); | |
| 4470 access_state_ = Access::Exclusive; | |
| 4471 tagged_addr_ = addr & kAddrMask; | |
| 4472 } | |
| 4473 | |
| 4474 | |
| 4475 bool Simulator::DataMonitor::WriteExInternal_Locked(int32_t addr) { | |
| 4476 if (access_state_ == Access::Exclusive) { | |
|
jbramley
2016/05/31 16:58:47
This should be more strict, and check that the add
binji
2016/06/01 21:06:40
OK, I'll work on this after these simple fixes.
| |
| 4477 // This DataMonitor is in the linked list, check if there is another | |
| 4478 // thread that has more recent exclusive access to this address. | |
| 4479 DataMonitor* node = FirstNodeWithTaggedAddr_Locked(addr); | |
| 4480 if (node != this) { | |
| 4481 // This thread does not have exclusive access (either it never called | |
| 4482 // ldrex or another thread took it away. Either way, this write will | |
| 4483 // fail. | |
| 4484 return false; | |
| 4485 } | |
| 4486 | |
| 4487 RemoveNode_Locked(); | |
| 4488 access_state_ = Access::Open; | |
|
Rodolph Perfetta (ARM)
2016/05/25 17:38:29
You should make sure any other nodes with the same
binji
2016/06/01 21:06:40
OK, I'll work on this after these simple fixes.
| |
| 4489 return true; | |
| 4490 } else { | |
| 4491 // Not marked for exclusive access. | |
| 4492 return false; | |
| 4493 } | |
| 4494 } | |
| 4495 | |
| 4496 | |
| 4497 void Simulator::DataMonitor::RemoveNode_Locked() { | |
| 4498 if (prev_) { | |
| 4499 prev_->next_ = next_; | |
| 4500 } else { | |
| 4501 head_ = next_; | |
| 4502 } | |
| 4503 if (next_) { | |
| 4504 next_->prev_ = prev_; | |
| 4505 } | |
| 4506 prev_ = nullptr; | |
| 4507 next_ = nullptr; | |
| 4508 } | |
| 4509 | |
| 4510 | |
| 4511 void Simulator::DataMonitor::PrependNode_Locked() { | |
| 4512 if (head_) { | |
| 4513 head_->prev_ = this; | |
| 4514 } | |
|
Rodolph Perfetta (ARM)
2016/05/25 17:38:29
shouldn't next_ point to head_?
binji
2016/06/01 21:06:40
Done.
| |
| 4515 head_ = this; | |
| 4516 } | |
| 4517 | |
| 4518 | |
| 4519 Simulator::DataMonitor* Simulator::DataMonitor::FirstNodeWithTaggedAddr_Locked( | |
| 4520 int32_t addr) { | |
| 4521 for (DataMonitor* node = head_; node; node = node->next_) { | |
| 4522 if ((addr & kAddrMask) == node->tagged_addr_) { | |
| 4523 return node; | |
| 4524 } | |
| 4525 } | |
| 4526 return nullptr; | |
| 4527 } | |
| 4528 | |
| 4529 | |
| 4319 } // namespace internal | 4530 } // namespace internal |
| 4320 } // namespace v8 | 4531 } // namespace v8 |
| 4321 | 4532 |
| 4322 #endif // USE_SIMULATOR | 4533 #endif // USE_SIMULATOR |
| 4323 | 4534 |
| 4324 #endif // V8_TARGET_ARCH_ARM | 4535 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |