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::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ = | |
27 LAZY_INSTANCE_INITIALIZER; | |
28 | |
25 // This macro provides a platform independent use of sscanf. The reason for | 29 // This macro provides a platform independent use of sscanf. The reason for |
26 // SScanF not being implemented in a platform independent way through | 30 // SScanF not being implemented in a platform independent way through |
27 // ::v8::internal::OS in the same way as SNPrintF is that the | 31 // ::v8::internal::OS in the same way as SNPrintF is that the |
28 // Windows C Run-Time Library does not provide vsscanf. | 32 // Windows C Run-Time Library does not provide vsscanf. |
29 #define SScanF sscanf // NOLINT | 33 #define SScanF sscanf // NOLINT |
30 | 34 |
31 // The ArmDebugger class is used by the simulator while debugging simulated ARM | 35 // The ArmDebugger class is used by the simulator while debugging simulated ARM |
32 // code. | 36 // code. |
33 class ArmDebugger { | 37 class ArmDebugger { |
34 public: | 38 public: |
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
762 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; | 766 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; |
763 // The lr and pc are initialized to a known bad value that will cause an | 767 // The lr and pc are initialized to a known bad value that will cause an |
764 // access violation if the simulator ever tries to execute it. | 768 // access violation if the simulator ever tries to execute it. |
765 registers_[pc] = bad_lr; | 769 registers_[pc] = bad_lr; |
766 registers_[lr] = bad_lr; | 770 registers_[lr] = bad_lr; |
767 InitializeCoverage(); | 771 InitializeCoverage(); |
768 | 772 |
769 last_debugger_input_ = NULL; | 773 last_debugger_input_ = NULL; |
770 } | 774 } |
771 | 775 |
772 | 776 Simulator::~Simulator() { |
773 Simulator::~Simulator() { free(stack_); } | 777 global_monitor_.Pointer()->RemoveNode(&global_monitor_node_); |
774 | 778 free(stack_); |
779 } | |
775 | 780 |
776 // When the generated code calls an external reference we need to catch that in | 781 // When the generated code calls an external reference we need to catch that in |
777 // the simulator. The external reference will be a function compiled for the | 782 // the simulator. The external reference will be a function compiled for the |
778 // host architecture. We need to call that function instead of trying to | 783 // host architecture. We need to call that function instead of trying to |
779 // execute it with the simulator. We do that by redirecting the external | 784 // execute it with the simulator. We do that by redirecting the external |
780 // reference to a svc (Supervisor Call) instruction that is handled by | 785 // reference to a svc (Supervisor Call) instruction that is handled by |
781 // the simulator. We write the original destination of the jump just at a known | 786 // the simulator. We write the original destination of the jump just at a known |
782 // offset from the svc instruction so the simulator knows what to call. | 787 // offset from the svc instruction so the simulator knows what to call. |
783 class Redirection { | 788 class Redirection { |
784 public: | 789 public: |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1127 return *ptr; | 1132 return *ptr; |
1128 } else { | 1133 } else { |
1129 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", | 1134 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
1130 addr, | 1135 addr, |
1131 reinterpret_cast<intptr_t>(instr)); | 1136 reinterpret_cast<intptr_t>(instr)); |
1132 UNIMPLEMENTED(); | 1137 UNIMPLEMENTED(); |
1133 return 0; | 1138 return 0; |
1134 } | 1139 } |
1135 } | 1140 } |
1136 | 1141 |
1137 | 1142 void Simulator::WriteW_Internal(int32_t addr, int value, Instruction* instr) { |
1138 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { | |
1139 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { | 1143 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { |
1140 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 1144 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
1141 *ptr = value; | 1145 *ptr = value; |
1142 } else { | 1146 } else { |
1143 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", | 1147 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
1144 addr, | 1148 addr, |
1145 reinterpret_cast<intptr_t>(instr)); | 1149 reinterpret_cast<intptr_t>(instr)); |
1146 UNIMPLEMENTED(); | 1150 UNIMPLEMENTED(); |
1147 } | 1151 } |
1148 } | 1152 } |
(...skipping 18 matching lines...) Expand all Loading... | |
1167 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { | 1171 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { |
1168 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1172 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
1169 return *ptr; | 1173 return *ptr; |
1170 } else { | 1174 } else { |
1171 PrintF("Unaligned signed halfword read at 0x%08x\n", addr); | 1175 PrintF("Unaligned signed halfword read at 0x%08x\n", addr); |
1172 UNIMPLEMENTED(); | 1176 UNIMPLEMENTED(); |
1173 return 0; | 1177 return 0; |
1174 } | 1178 } |
1175 } | 1179 } |
1176 | 1180 |
1177 | 1181 void Simulator::WriteH_Internal(int32_t addr, uint16_t value, |
1178 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { | 1182 Instruction* instr) { |
1179 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { | 1183 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { |
1180 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 1184 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
1181 *ptr = value; | 1185 *ptr = value; |
1182 } else { | 1186 } else { |
1183 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" | 1187 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" |
1184 V8PRIxPTR "\n", | 1188 V8PRIxPTR "\n", |
1185 addr, | 1189 addr, |
1186 reinterpret_cast<intptr_t>(instr)); | 1190 reinterpret_cast<intptr_t>(instr)); |
1187 UNIMPLEMENTED(); | 1191 UNIMPLEMENTED(); |
1188 } | 1192 } |
1189 } | 1193 } |
1190 | 1194 |
1191 | 1195 void Simulator::WriteH_Internal(int32_t addr, int16_t value, |
1192 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { | 1196 Instruction* instr) { |
1193 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { | 1197 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { |
1194 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1198 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
1195 *ptr = value; | 1199 *ptr = value; |
1196 } else { | 1200 } else { |
1197 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", | 1201 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
1198 addr, | 1202 addr, |
1199 reinterpret_cast<intptr_t>(instr)); | 1203 reinterpret_cast<intptr_t>(instr)); |
1200 UNIMPLEMENTED(); | 1204 UNIMPLEMENTED(); |
1201 } | 1205 } |
1202 } | 1206 } |
1203 | 1207 |
1204 | 1208 |
1205 uint8_t Simulator::ReadBU(int32_t addr) { | 1209 uint8_t Simulator::ReadBU(int32_t addr) { |
1206 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1210 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
1207 return *ptr; | 1211 return *ptr; |
1208 } | 1212 } |
1209 | 1213 |
1210 | 1214 |
1211 int8_t Simulator::ReadB(int32_t addr) { | 1215 int8_t Simulator::ReadB(int32_t addr) { |
1212 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1216 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
1213 return *ptr; | 1217 return *ptr; |
1214 } | 1218 } |
1215 | 1219 |
1216 | 1220 void Simulator::WriteB_Internal(int32_t addr, uint8_t value) { |
1217 void Simulator::WriteB(int32_t addr, uint8_t value) { | |
1218 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1221 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
1219 *ptr = value; | 1222 *ptr = value; |
1220 } | 1223 } |
1221 | 1224 |
1222 | 1225 void Simulator::WriteB_Internal(int32_t addr, int8_t value) { |
1223 void Simulator::WriteB(int32_t addr, int8_t value) { | |
1224 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1226 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
1225 *ptr = value; | 1227 *ptr = value; |
1226 } | 1228 } |
1227 | 1229 |
1228 | 1230 |
1229 int32_t* Simulator::ReadDW(int32_t addr) { | 1231 int32_t* Simulator::ReadDW(int32_t addr) { |
1230 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { | 1232 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { |
1231 int32_t* ptr = reinterpret_cast<int32_t*>(addr); | 1233 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
1232 return ptr; | 1234 return ptr; |
1233 } else { | 1235 } else { |
(...skipping 956 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2190 hi_res = static_cast<int32_t>(result >> 32); | 2192 hi_res = static_cast<int32_t>(result >> 32); |
2191 lo_res = static_cast<int32_t>(result & 0xffffffff); | 2193 lo_res = static_cast<int32_t>(result & 0xffffffff); |
2192 } | 2194 } |
2193 set_register(rd_lo, lo_res); | 2195 set_register(rd_lo, lo_res); |
2194 set_register(rd_hi, hi_res); | 2196 set_register(rd_hi, hi_res); |
2195 if (instr->HasS()) { | 2197 if (instr->HasS()) { |
2196 UNIMPLEMENTED(); | 2198 UNIMPLEMENTED(); |
2197 } | 2199 } |
2198 } | 2200 } |
2199 } else { | 2201 } else { |
2200 UNIMPLEMENTED(); // Not used by V8. | 2202 if (instr->Bits(24, 23) == 3) { |
2203 if (instr->Bit(20) == 1) { | |
2204 // ldrex | |
2205 int rt = instr->RtValue(); | |
2206 int rn = instr->RnValue(); | |
2207 int32_t addr = get_register(rn); | |
2208 switch (instr->Bits(22, 21)) { | |
2209 case 0: { | |
2210 // Format(instr, "ldrex'cond 'rt, ['rn]"); | |
2211 int value = ReadExW(addr, instr); | |
2212 set_register(rt, value); | |
2213 break; | |
2214 } | |
2215 case 2: { | |
2216 // Format(instr, "ldrexb'cond 'rt, ['rn]"); | |
2217 uint8_t value = ReadExBU(addr); | |
2218 set_register(rt, value); | |
2219 break; | |
2220 } | |
2221 case 3: { | |
2222 // Format(instr, "ldrexh'cond 'rt, ['rn]"); | |
2223 uint16_t value = ReadExHU(addr, instr); | |
2224 set_register(rt, value); | |
2225 break; | |
2226 } | |
2227 default: | |
2228 UNREACHABLE(); | |
2229 break; | |
2230 } | |
2231 } else { | |
2232 // The instruction is documented as strex rd, rt, [rn], but the | |
2233 // "rt" register is using the rm bits. | |
2234 int rd = instr->RdValue(); | |
2235 int rt = instr->RmValue(); | |
2236 int rn = instr->RnValue(); | |
2237 int32_t addr = get_register(rn); | |
2238 switch (instr->Bits(22, 21)) { | |
2239 case 0: { | |
2240 // Format(instr, "strex'cond 'rd, 'rm, ['rn]"); | |
2241 int value = get_register(rt); | |
2242 int status = WriteExW(addr, value, instr); | |
2243 set_register(rd, status); | |
2244 break; | |
2245 } | |
2246 case 2: { | |
2247 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]"); | |
2248 uint8_t value = get_register(rt); | |
2249 int status = WriteExB(addr, value); | |
2250 set_register(rd, status); | |
2251 break; | |
2252 } | |
2253 case 3: { | |
2254 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]"); | |
2255 uint16_t value = get_register(rt); | |
2256 int status = WriteExH(addr, value, instr); | |
2257 set_register(rd, status); | |
2258 break; | |
2259 } | |
2260 default: | |
2261 UNREACHABLE(); | |
2262 break; | |
2263 } | |
2264 } | |
2265 } else { | |
2266 UNIMPLEMENTED(); // Not used by V8. | |
2267 } | |
2201 } | 2268 } |
2202 } else { | 2269 } else { |
2203 // extra load/store instructions | 2270 // extra load/store instructions |
2204 int rd = instr->RdValue(); | 2271 int rd = instr->RdValue(); |
2205 int rn = instr->RnValue(); | 2272 int rn = instr->RnValue(); |
2206 int32_t rn_val = get_register(rn); | 2273 int32_t rn_val = get_register(rn); |
2207 int32_t addr = 0; | 2274 int32_t addr = 0; |
2208 if (instr->Bit(22) == 0) { | 2275 if (instr->Bit(22) == 0) { |
2209 int rm = instr->RmValue(); | 2276 int rm = instr->RmValue(); |
2210 int32_t rm_val = get_register(rm); | 2277 int32_t rm_val = get_register(rm); |
(...skipping 2092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4303 | 4370 |
4304 | 4371 |
4305 uintptr_t Simulator::PopAddress() { | 4372 uintptr_t Simulator::PopAddress() { |
4306 int current_sp = get_register(sp); | 4373 int current_sp = get_register(sp); |
4307 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); | 4374 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
4308 uintptr_t address = *stack_slot; | 4375 uintptr_t address = *stack_slot; |
4309 set_register(sp, current_sp + sizeof(uintptr_t)); | 4376 set_register(sp, current_sp + sizeof(uintptr_t)); |
4310 return address; | 4377 return address; |
4311 } | 4378 } |
4312 | 4379 |
4380 void Simulator::WriteB(int32_t addr, uint8_t value) { | |
4381 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4382 local_monitor_.Store(addr, TransactionSize::Byte); | |
4383 global_monitor_.Pointer()->Store_Locked(addr, &global_monitor_node_); | |
4384 WriteB_Internal(addr, value); | |
4385 } | |
4386 | |
4387 void Simulator::WriteB(int32_t addr, int8_t value) { | |
4388 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4389 local_monitor_.Store(addr, TransactionSize::Byte); | |
4390 global_monitor_.Pointer()->Store_Locked(addr, &global_monitor_node_); | |
4391 WriteB_Internal(addr, value); | |
4392 } | |
4393 | |
4394 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { | |
4395 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4396 local_monitor_.Store(addr, TransactionSize::HalfWord); | |
4397 global_monitor_.Pointer()->Store_Locked(addr, &global_monitor_node_); | |
4398 WriteH_Internal(addr, value, instr); | |
4399 } | |
4400 | |
4401 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { | |
4402 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4403 local_monitor_.Store(addr, TransactionSize::HalfWord); | |
4404 global_monitor_.Pointer()->Store_Locked(addr, &global_monitor_node_); | |
4405 WriteH_Internal(addr, value, instr); | |
4406 } | |
4407 | |
4408 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { | |
4409 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4410 local_monitor_.Store(addr, TransactionSize::Word); | |
4411 global_monitor_.Pointer()->Store_Locked(addr, &global_monitor_node_); | |
4412 WriteW_Internal(addr, value, instr); | |
4413 } | |
4414 | |
4415 uint8_t Simulator::ReadExBU(int32_t addr) { | |
4416 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4417 local_monitor_.LoadExcl(addr, TransactionSize::Byte); | |
4418 global_monitor_.Pointer()->LoadExcl_Locked(addr, &global_monitor_node_); | |
4419 return ReadBU(addr); | |
4420 } | |
4421 | |
4422 int Simulator::WriteExB(int32_t addr, uint8_t value) { | |
4423 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4424 if (local_monitor_.CheckStoreExcl(addr, TransactionSize::Byte) && | |
4425 global_monitor_.Pointer()->CheckStoreExcl_Locked(addr, | |
4426 &global_monitor_node_)) { | |
4427 WriteB_Internal(addr, value); | |
4428 return 0; | |
4429 } else { | |
4430 return 1; | |
4431 } | |
4432 } | |
4433 | |
4434 uint16_t Simulator::ReadExHU(int32_t addr, Instruction* instr) { | |
4435 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4436 local_monitor_.LoadExcl(addr, TransactionSize::HalfWord); | |
4437 global_monitor_.Pointer()->LoadExcl_Locked(addr, &global_monitor_node_); | |
4438 return ReadHU(addr, instr); | |
4439 } | |
4440 | |
4441 int Simulator::WriteExH(int32_t addr, uint16_t value, Instruction* instr) { | |
4442 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4443 if (local_monitor_.CheckStoreExcl(addr, TransactionSize::HalfWord) && | |
4444 global_monitor_.Pointer()->CheckStoreExcl_Locked(addr, | |
4445 &global_monitor_node_)) { | |
4446 WriteH_Internal(addr, value, instr); | |
4447 return 0; | |
4448 } else { | |
4449 return 1; | |
4450 } | |
4451 } | |
4452 | |
4453 int Simulator::ReadExW(int32_t addr, Instruction* instr) { | |
4454 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4455 local_monitor_.LoadExcl(addr, TransactionSize::Word); | |
4456 global_monitor_.Pointer()->LoadExcl_Locked(addr, &global_monitor_node_); | |
4457 return ReadW(addr, instr); | |
4458 } | |
4459 | |
4460 int Simulator::WriteExW(int32_t addr, int value, Instruction* instr) { | |
4461 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
4462 if (local_monitor_.CheckStoreExcl(addr, TransactionSize::Word) && | |
4463 global_monitor_.Pointer()->CheckStoreExcl_Locked(addr, | |
4464 &global_monitor_node_)) { | |
4465 WriteW_Internal(addr, value, instr); | |
4466 return 0; | |
4467 } else { | |
4468 return 1; | |
4469 } | |
4470 } | |
4471 | |
4472 Simulator::LocalMonitor::LocalMonitor() | |
4473 : access_state_(MonitorAccess::Open), | |
4474 tagged_addr_(0), | |
4475 size_(TransactionSize::None) {} | |
4476 | |
4477 void Simulator::LocalMonitor::LoadExcl(int32_t addr, TransactionSize size) { | |
4478 access_state_ = MonitorAccess::Exclusive; | |
4479 tagged_addr_ = addr & kTaggedAddrMask; | |
4480 size_ = size; | |
4481 } | |
4482 | |
4483 void Simulator::LocalMonitor::Store(int32_t addr, TransactionSize size) { | |
4484 if (access_state_ == MonitorAccess::Exclusive) { | |
4485 // It is implementation-defined whether a non-exclusive store to an address | |
4486 // covered by the local monitor during exclusive access transitions to open | |
4487 // or exclusive access. See ARM DDI 0406C.b, A3.4.1. | |
jbramley
2016/07/20 16:09:24
That's true, but also note that software should av
binji
2016/07/29 21:46:29
Done.
| |
4488 if ((addr & kTaggedAddrMask) == tagged_addr_) { | |
4489 access_state_ = MonitorAccess::Open; | |
4490 tagged_addr_ = 0; | |
4491 size_ = TransactionSize::None; | |
4492 } | |
4493 } | |
4494 } | |
4495 | |
4496 bool Simulator::LocalMonitor::CheckStoreExcl(int32_t addr, | |
4497 TransactionSize size) { | |
4498 if (access_state_ == MonitorAccess::Exclusive) { | |
4499 if ((addr & kTaggedAddrMask) == tagged_addr_ && size_ == size) { | |
jbramley
2016/07/20 16:09:24
I'd drop the mask here. The ARM ARM allows a proce
binji
2016/07/29 21:46:29
Done.
| |
4500 access_state_ = MonitorAccess::Open; | |
4501 tagged_addr_ = 0; | |
4502 size_ = TransactionSize::None; | |
4503 return true; | |
jbramley
2016/07/20 16:09:24
This should fail randomly from time to time. The A
binji
2016/07/29 21:46:29
Done, though I'm not sure this is the best way to
jbramley
2016/11/10 11:19:01
Some randomness would be useful but this is probab
| |
4504 } else { | |
4505 // It is implementation-defined whether an exclusive store to a | |
4506 // non-tagged address will update memory. Behavior is unpredictable if | |
4507 // the transaction size of the exclusive store differs from that of the | |
4508 // exclusive load. See ARM DDI 0406C.b, A3.4.5. | |
4509 access_state_ = MonitorAccess::Open; | |
4510 tagged_addr_ = 0; | |
4511 size_ = TransactionSize::None; | |
4512 return false; | |
4513 } | |
4514 } else { | |
4515 DCHECK(access_state_ == MonitorAccess::Open); | |
4516 return false; | |
4517 } | |
4518 } | |
4519 | |
4520 Simulator::GlobalMonitor::Node::Node() | |
4521 : access_state_(MonitorAccess::Open), | |
4522 tagged_addr_(0), | |
4523 next_(nullptr), | |
4524 prev_(nullptr) {} | |
4525 | |
4526 void Simulator::GlobalMonitor::Node::LoadExcl_Locked(int32_t addr) { | |
4527 access_state_ = MonitorAccess::Exclusive; | |
4528 tagged_addr_ = addr & kTaggedAddrMask; | |
4529 } | |
4530 | |
4531 void Simulator::GlobalMonitor::Node::Store_Locked( | |
4532 int32_t addr, bool is_requesting_processor) { | |
4533 if (access_state_ == MonitorAccess::Exclusive) { | |
4534 if ((addr & kTaggedAddrMask) == tagged_addr_) { | |
4535 // It is implementation-defined whether a non-exclusive store by the | |
4536 // requesting processor to an address covered by the global monitor | |
4537 // during exclusive access transitions to open or exclusive access. | |
4538 // | |
4539 // For any other processor, the access state always transitions to open | |
4540 // access. | |
4541 // | |
4542 // See ARM DDI 0406C.b, A3.4.2. | |
4543 access_state_ = MonitorAccess::Open; | |
4544 tagged_addr_ = 0; | |
4545 } | |
4546 } | |
4547 } | |
4548 | |
4549 bool Simulator::GlobalMonitor::Node::CheckStoreExcl_Locked( | |
4550 int32_t addr, bool is_requesting_processor) { | |
4551 if (access_state_ == MonitorAccess::Exclusive) { | |
4552 if ((addr & kTaggedAddrMask) == tagged_addr_) { | |
4553 if (is_requesting_processor) { | |
4554 // The access state for the requesting processor after a successful | |
4555 // exclusive store is implementation-defined, but according to the ARM | |
4556 // DDI, this has no effect on the subsequent operation of the global | |
4557 // monitor. | |
4558 access_state_ = MonitorAccess::Open; | |
4559 tagged_addr_ = 0; | |
4560 return true; | |
4561 } else { | |
4562 access_state_ = MonitorAccess::Open; | |
4563 tagged_addr_ = 0; | |
4564 return false; | |
4565 } | |
4566 } | |
4567 } | |
4568 return false; | |
4569 } | |
4570 | |
4571 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {} | |
4572 | |
4573 void Simulator::GlobalMonitor::LoadExcl_Locked(int32_t addr, Node* node) { | |
4574 node->LoadExcl_Locked(addr); | |
4575 PrependNode_Locked(node); | |
4576 } | |
4577 | |
4578 void Simulator::GlobalMonitor::Store_Locked(int32_t addr, Node* node) { | |
4579 // Notify each processor of the store operation. | |
4580 for (Node* iter = head_; iter; iter = iter->next_) { | |
4581 bool is_requesting_processor = iter == node; | |
4582 iter->Store_Locked(addr, is_requesting_processor); | |
4583 } | |
4584 } | |
4585 | |
4586 bool Simulator::GlobalMonitor::CheckStoreExcl_Locked(int32_t addr, Node* node) { | |
4587 DCHECK(IsNodeInLinkedList_Locked(node)); | |
4588 if (node->CheckStoreExcl_Locked(addr, true)) { | |
4589 // Notify the other processors that this StoreExcl succeeded. | |
4590 for (Node* iter = head_; iter; iter = iter->next_) { | |
4591 if (iter != node) { | |
4592 iter->CheckStoreExcl_Locked(addr, false); | |
4593 } | |
4594 } | |
4595 return true; | |
4596 } else { | |
4597 return false; | |
4598 } | |
4599 } | |
4600 | |
4601 bool Simulator::GlobalMonitor::IsNodeInLinkedList_Locked(Node* node) const { | |
4602 return head_ == node || node->next_ || node->prev_; | |
4603 } | |
4604 | |
4605 void Simulator::GlobalMonitor::PrependNode_Locked(Node* node) { | |
4606 if (IsNodeInLinkedList_Locked(node)) { | |
4607 return; | |
4608 } | |
4609 | |
4610 if (head_) { | |
4611 head_->prev_ = node; | |
4612 } | |
4613 node->prev_ = nullptr; | |
4614 node->next_ = head_; | |
4615 head_ = node; | |
4616 } | |
4617 | |
4618 void Simulator::GlobalMonitor::RemoveNode(Node* node) { | |
4619 base::LockGuard<base::Mutex> lock_guard(&mutex); | |
4620 if (!IsNodeInLinkedList_Locked(node)) { | |
4621 return; | |
4622 } | |
4623 | |
4624 if (node->prev_) { | |
4625 node->prev_->next_ = node->next_; | |
4626 } else { | |
4627 head_ = node->next_; | |
4628 } | |
4629 if (node->next_) { | |
4630 node->next_->prev_ = node->prev_; | |
4631 } | |
4632 node->prev_ = nullptr; | |
4633 node->next_ = nullptr; | |
4634 } | |
4635 | |
4313 } // namespace internal | 4636 } // namespace internal |
4314 } // namespace v8 | 4637 } // namespace v8 |
4315 | 4638 |
4316 #endif // USE_SIMULATOR | 4639 #endif // USE_SIMULATOR |
4317 | 4640 |
4318 #endif // V8_TARGET_ARCH_ARM | 4641 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |