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