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 |