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 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 // some buffer below. | 707 // some buffer below. |
| 704 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; | 708 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; |
| 705 // The lr and pc are initialized to a known bad value that will cause an | 709 // The lr and pc are initialized to a known bad value that will cause an |
| 706 // access violation if the simulator ever tries to execute it. | 710 // access violation if the simulator ever tries to execute it. |
| 707 registers_[pc] = bad_lr; | 711 registers_[pc] = bad_lr; |
| 708 registers_[lr] = bad_lr; | 712 registers_[lr] = bad_lr; |
| 709 | 713 |
| 710 last_debugger_input_ = NULL; | 714 last_debugger_input_ = NULL; |
| 711 } | 715 } |
| 712 | 716 |
| 713 | 717 Simulator::~Simulator() { |
| 714 Simulator::~Simulator() { free(stack_); } | 718 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_); |
| 715 | 719 free(stack_); |
| 720 } | |
| 716 | 721 |
| 717 // When the generated code calls an external reference we need to catch that in | 722 // When the generated code calls an external reference we need to catch that in |
| 718 // the simulator. The external reference will be a function compiled for the | 723 // the simulator. The external reference will be a function compiled for the |
| 719 // host architecture. We need to call that function instead of trying to | 724 // host architecture. We need to call that function instead of trying to |
| 720 // execute it with the simulator. We do that by redirecting the external | 725 // execute it with the simulator. We do that by redirecting the external |
| 721 // reference to a svc (Supervisor Call) instruction that is handled by | 726 // reference to a svc (Supervisor Call) instruction that is handled by |
| 722 // the simulator. We write the original destination of the jump just at a known | 727 // the simulator. We write the original destination of the jump just at a known |
| 723 // offset from the svc instruction so the simulator knows what to call. | 728 // offset from the svc instruction so the simulator knows what to call. |
| 724 class Redirection { | 729 class Redirection { |
| 725 public: | 730 public: |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1045 // We don't trash the registers with the return value. | 1050 // We don't trash the registers with the return value. |
| 1046 registers_[2] = 0x50Bad4U; | 1051 registers_[2] = 0x50Bad4U; |
| 1047 registers_[3] = 0x50Bad4U; | 1052 registers_[3] = 0x50Bad4U; |
| 1048 registers_[12] = 0x50Bad4U; | 1053 registers_[12] = 0x50Bad4U; |
| 1049 } | 1054 } |
| 1050 | 1055 |
| 1051 | 1056 |
| 1052 int Simulator::ReadW(int32_t addr, Instruction* instr) { | 1057 int Simulator::ReadW(int32_t addr, Instruction* instr) { |
| 1053 // All supported ARM targets allow unaligned accesses, so we don't need to | 1058 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1054 // check the alignment here. | 1059 // check the alignment here. |
| 1060 local_monitor_.NotifyLoad(addr); | |
| 1055 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 1061 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 1056 return *ptr; | 1062 return *ptr; |
|
Jarin
2017/01/13 07:56:29
Would not this be a data race with writes in other
binji
2017/01/17 22:22:00
Done.
| |
| 1057 } | 1063 } |
| 1058 | 1064 |
| 1065 int Simulator::ReadExW(int32_t addr, Instruction* instr) { | |
| 1066 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1067 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word); | |
| 1068 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, | |
| 1069 &global_monitor_processor_); | |
| 1070 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
| 1071 return *ptr; | |
| 1072 } | |
| 1059 | 1073 |
| 1060 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { | 1074 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { |
| 1061 // All supported ARM targets allow unaligned accesses, so we don't need to | 1075 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1062 // check the alignment here. | 1076 // check the alignment here. |
| 1077 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1078 local_monitor_.NotifyStore(addr); | |
| 1079 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1080 &global_monitor_processor_); | |
| 1063 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 1081 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
| 1064 *ptr = value; | 1082 *ptr = value; |
| 1065 } | 1083 } |
| 1066 | 1084 |
| 1085 int Simulator::WriteExW(int32_t addr, int value, Instruction* instr) { | |
| 1086 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1087 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) && | |
| 1088 global_monitor_.Pointer()->NotifyStoreExcl_Locked( | |
| 1089 addr, &global_monitor_processor_)) { | |
| 1090 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
| 1091 *ptr = value; | |
| 1092 return 0; | |
| 1093 } else { | |
| 1094 return 1; | |
| 1095 } | |
| 1096 } | |
| 1067 | 1097 |
| 1068 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { | 1098 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { |
| 1069 // All supported ARM targets allow unaligned accesses, so we don't need to | 1099 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1070 // check the alignment here. | 1100 // check the alignment here. |
| 1101 local_monitor_.NotifyLoad(addr); | |
| 1071 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 1102 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 1072 return *ptr; | 1103 return *ptr; |
| 1073 } | 1104 } |
| 1074 | 1105 |
| 1075 | |
| 1076 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { | 1106 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { |
| 1077 // All supported ARM targets allow unaligned accesses, so we don't need to | 1107 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1078 // check the alignment here. | 1108 // check the alignment here. |
| 1109 local_monitor_.NotifyLoad(addr); | |
| 1079 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1110 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 1080 return *ptr; | 1111 return *ptr; |
| 1081 } | 1112 } |
| 1082 | 1113 |
| 1114 uint16_t Simulator::ReadExHU(int32_t addr, Instruction* instr) { | |
| 1115 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1116 local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord); | |
| 1117 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, | |
| 1118 &global_monitor_processor_); | |
| 1119 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
| 1120 return *ptr; | |
| 1121 } | |
| 1083 | 1122 |
| 1084 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { | 1123 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { |
| 1085 // All supported ARM targets allow unaligned accesses, so we don't need to | 1124 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1086 // check the alignment here. | 1125 // check the alignment here. |
| 1126 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1127 local_monitor_.NotifyStore(addr); | |
| 1128 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1129 &global_monitor_processor_); | |
| 1087 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 1130 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 1088 *ptr = value; | 1131 *ptr = value; |
| 1089 } | 1132 } |
| 1090 | 1133 |
| 1091 | |
| 1092 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { | 1134 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { |
| 1093 // All supported ARM targets allow unaligned accesses, so we don't need to | 1135 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1094 // check the alignment here. | 1136 // check the alignment here. |
| 1137 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1138 local_monitor_.NotifyStore(addr); | |
| 1139 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1140 &global_monitor_processor_); | |
| 1095 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1141 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
| 1096 *ptr = value; | 1142 *ptr = value; |
| 1097 } | 1143 } |
| 1098 | 1144 |
| 1145 int Simulator::WriteExH(int32_t addr, uint16_t value, Instruction* instr) { | |
| 1146 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1147 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) && | |
| 1148 global_monitor_.Pointer()->NotifyStoreExcl_Locked( | |
| 1149 addr, &global_monitor_processor_)) { | |
| 1150 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
| 1151 *ptr = value; | |
| 1152 return 0; | |
| 1153 } else { | |
| 1154 return 1; | |
| 1155 } | |
| 1156 } | |
| 1099 | 1157 |
| 1100 uint8_t Simulator::ReadBU(int32_t addr) { | 1158 uint8_t Simulator::ReadBU(int32_t addr) { |
| 1159 local_monitor_.NotifyLoad(addr); | |
| 1101 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1160 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 1102 return *ptr; | 1161 return *ptr; |
| 1103 } | 1162 } |
| 1104 | 1163 |
| 1105 | |
| 1106 int8_t Simulator::ReadB(int32_t addr) { | 1164 int8_t Simulator::ReadB(int32_t addr) { |
| 1165 local_monitor_.NotifyLoad(addr); | |
| 1107 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1166 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 1108 return *ptr; | 1167 return *ptr; |
| 1109 } | 1168 } |
| 1110 | 1169 |
| 1170 uint8_t Simulator::ReadExBU(int32_t addr) { | |
| 1171 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1172 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte); | |
| 1173 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, | |
| 1174 &global_monitor_processor_); | |
| 1175 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
| 1176 return *ptr; | |
| 1177 } | |
| 1111 | 1178 |
| 1112 void Simulator::WriteB(int32_t addr, uint8_t value) { | 1179 void Simulator::WriteB(int32_t addr, uint8_t value) { |
| 1180 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1181 local_monitor_.NotifyStore(addr); | |
| 1182 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1183 &global_monitor_processor_); | |
| 1113 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1184 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 1114 *ptr = value; | 1185 *ptr = value; |
| 1115 } | 1186 } |
| 1116 | 1187 |
| 1117 | |
| 1118 void Simulator::WriteB(int32_t addr, int8_t value) { | 1188 void Simulator::WriteB(int32_t addr, int8_t value) { |
| 1189 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1190 local_monitor_.NotifyStore(addr); | |
| 1191 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1192 &global_monitor_processor_); | |
| 1119 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1193 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 1120 *ptr = value; | 1194 *ptr = value; |
| 1121 } | 1195 } |
| 1122 | 1196 |
| 1197 int Simulator::WriteExB(int32_t addr, uint8_t value) { | |
| 1198 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1199 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) && | |
| 1200 global_monitor_.Pointer()->NotifyStoreExcl_Locked( | |
| 1201 addr, &global_monitor_processor_)) { | |
| 1202 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
| 1203 *ptr = value; | |
| 1204 return 0; | |
| 1205 } else { | |
| 1206 return 1; | |
| 1207 } | |
| 1208 } | |
| 1123 | 1209 |
| 1124 int32_t* Simulator::ReadDW(int32_t addr) { | 1210 int32_t* Simulator::ReadDW(int32_t addr) { |
| 1125 // All supported ARM targets allow unaligned accesses, so we don't need to | 1211 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1126 // check the alignment here. | 1212 // check the alignment here. |
| 1213 local_monitor_.NotifyLoad(addr); | |
| 1127 int32_t* ptr = reinterpret_cast<int32_t*>(addr); | 1214 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
| 1128 return ptr; | 1215 return ptr; |
| 1129 } | 1216 } |
| 1130 | 1217 |
| 1131 | 1218 |
| 1132 void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) { | 1219 void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) { |
| 1133 // All supported ARM targets allow unaligned accesses, so we don't need to | 1220 // All supported ARM targets allow unaligned accesses, so we don't need to |
| 1134 // check the alignment here. | 1221 // check the alignment here. |
| 1222 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1223 local_monitor_.NotifyStore(addr); | |
| 1224 global_monitor_.Pointer()->NotifyStore_Locked(addr, | |
| 1225 &global_monitor_processor_); | |
| 1135 int32_t* ptr = reinterpret_cast<int32_t*>(addr); | 1226 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
| 1136 *ptr++ = value1; | 1227 *ptr++ = value1; |
| 1137 *ptr = value2; | 1228 *ptr = value2; |
| 1138 } | 1229 } |
| 1139 | 1230 |
| 1140 | 1231 |
| 1141 // Returns the limit of the stack area to enable checking for stack overflows. | 1232 // Returns the limit of the stack area to enable checking for stack overflows. |
| 1142 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { | 1233 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { |
| 1143 // The simulator uses a separate JS stack. If we have exhausted the C stack, | 1234 // The simulator uses a separate JS stack. If we have exhausted the C stack, |
| 1144 // we also drop down the JS limit to reflect the exhaustion on the JS stack. | 1235 // we also drop down the JS limit to reflect the exhaustion on the JS stack. |
| (...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2078 hi_res = static_cast<int32_t>(result >> 32); | 2169 hi_res = static_cast<int32_t>(result >> 32); |
| 2079 lo_res = static_cast<int32_t>(result & 0xffffffff); | 2170 lo_res = static_cast<int32_t>(result & 0xffffffff); |
| 2080 } | 2171 } |
| 2081 set_register(rd_lo, lo_res); | 2172 set_register(rd_lo, lo_res); |
| 2082 set_register(rd_hi, hi_res); | 2173 set_register(rd_hi, hi_res); |
| 2083 if (instr->HasS()) { | 2174 if (instr->HasS()) { |
| 2084 UNIMPLEMENTED(); | 2175 UNIMPLEMENTED(); |
| 2085 } | 2176 } |
| 2086 } | 2177 } |
| 2087 } else { | 2178 } else { |
| 2088 UNIMPLEMENTED(); // Not used by V8. | 2179 if (instr->Bits(24, 23) == 3) { |
| 2180 if (instr->Bit(20) == 1) { | |
| 2181 // ldrex | |
| 2182 int rt = instr->RtValue(); | |
| 2183 int rn = instr->RnValue(); | |
| 2184 int32_t addr = get_register(rn); | |
| 2185 switch (instr->Bits(22, 21)) { | |
| 2186 case 0: { | |
| 2187 // Format(instr, "ldrex'cond 'rt, ['rn]"); | |
| 2188 int value = ReadExW(addr, instr); | |
| 2189 set_register(rt, value); | |
| 2190 break; | |
| 2191 } | |
| 2192 case 2: { | |
| 2193 // Format(instr, "ldrexb'cond 'rt, ['rn]"); | |
| 2194 uint8_t value = ReadExBU(addr); | |
| 2195 set_register(rt, value); | |
| 2196 break; | |
| 2197 } | |
| 2198 case 3: { | |
| 2199 // Format(instr, "ldrexh'cond 'rt, ['rn]"); | |
| 2200 uint16_t value = ReadExHU(addr, instr); | |
| 2201 set_register(rt, value); | |
| 2202 break; | |
| 2203 } | |
| 2204 default: | |
| 2205 UNREACHABLE(); | |
| 2206 break; | |
| 2207 } | |
| 2208 } else { | |
| 2209 // The instruction is documented as strex rd, rt, [rn], but the | |
| 2210 // "rt" register is using the rm bits. | |
| 2211 int rd = instr->RdValue(); | |
| 2212 int rt = instr->RmValue(); | |
| 2213 int rn = instr->RnValue(); | |
| 2214 int32_t addr = get_register(rn); | |
| 2215 switch (instr->Bits(22, 21)) { | |
| 2216 case 0: { | |
| 2217 // Format(instr, "strex'cond 'rd, 'rm, ['rn]"); | |
| 2218 int value = get_register(rt); | |
| 2219 int status = WriteExW(addr, value, instr); | |
| 2220 set_register(rd, status); | |
| 2221 break; | |
| 2222 } | |
| 2223 case 2: { | |
| 2224 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]"); | |
| 2225 uint8_t value = get_register(rt); | |
| 2226 int status = WriteExB(addr, value); | |
| 2227 set_register(rd, status); | |
| 2228 break; | |
| 2229 } | |
| 2230 case 3: { | |
| 2231 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]"); | |
| 2232 uint16_t value = get_register(rt); | |
| 2233 int status = WriteExH(addr, value, instr); | |
| 2234 set_register(rd, status); | |
| 2235 break; | |
| 2236 } | |
| 2237 default: | |
| 2238 UNREACHABLE(); | |
| 2239 break; | |
| 2240 } | |
| 2241 } | |
| 2242 } else { | |
| 2243 UNIMPLEMENTED(); // Not used by V8. | |
| 2244 } | |
| 2089 } | 2245 } |
| 2090 } else { | 2246 } else { |
| 2091 // extra load/store instructions | 2247 // extra load/store instructions |
| 2092 int rd = instr->RdValue(); | 2248 int rd = instr->RdValue(); |
| 2093 int rn = instr->RnValue(); | 2249 int rn = instr->RnValue(); |
| 2094 int32_t rn_val = get_register(rn); | 2250 int32_t rn_val = get_register(rn); |
| 2095 int32_t addr = 0; | 2251 int32_t addr = 0; |
| 2096 if (instr->Bit(22) == 0) { | 2252 if (instr->Bit(22) == 0) { |
| 2097 int rm = instr->RmValue(); | 2253 int rm = instr->RmValue(); |
| 2098 int32_t rm_val = get_register(rm); | 2254 int32_t rm_val = get_register(rm); |
| (...skipping 2918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5017 | 5173 |
| 5018 | 5174 |
| 5019 uintptr_t Simulator::PopAddress() { | 5175 uintptr_t Simulator::PopAddress() { |
| 5020 int current_sp = get_register(sp); | 5176 int current_sp = get_register(sp); |
| 5021 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); | 5177 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
| 5022 uintptr_t address = *stack_slot; | 5178 uintptr_t address = *stack_slot; |
| 5023 set_register(sp, current_sp + sizeof(uintptr_t)); | 5179 set_register(sp, current_sp + sizeof(uintptr_t)); |
| 5024 return address; | 5180 return address; |
| 5025 } | 5181 } |
| 5026 | 5182 |
| 5183 Simulator::LocalMonitor::LocalMonitor() | |
| 5184 : access_state_(MonitorAccess::Open), | |
| 5185 tagged_addr_(0), | |
| 5186 size_(TransactionSize::None) {} | |
| 5187 | |
| 5188 void Simulator::LocalMonitor::NotifyLoad(int32_t addr) { | |
| 5189 if (access_state_ == MonitorAccess::Exclusive) { | |
| 5190 // A load could cause a cache eviction which will affect the monitor. As a | |
| 5191 // result, it's most strict to unconditionally clear the local monitor on | |
| 5192 // load. | |
| 5193 access_state_ = MonitorAccess::Open; | |
| 5194 tagged_addr_ = 0; | |
| 5195 size_ = TransactionSize::None; | |
|
Jarin
2017/01/13 07:56:29
Perhaps it would be better to introduce
void Sim
binji
2017/01/17 22:22:00
Done.
| |
| 5196 } | |
| 5197 } | |
| 5198 | |
| 5199 void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr, | |
| 5200 TransactionSize size) { | |
| 5201 access_state_ = MonitorAccess::Exclusive; | |
| 5202 tagged_addr_ = addr; | |
| 5203 size_ = size; | |
| 5204 } | |
| 5205 | |
| 5206 void Simulator::LocalMonitor::NotifyStore(int32_t addr) { | |
| 5207 if (access_state_ == MonitorAccess::Exclusive) { | |
| 5208 // It is implementation-defined whether a non-exclusive store to an address | |
| 5209 // covered by the local monitor during exclusive access transitions to open | |
| 5210 // or exclusive access. See ARM DDI 0406C.b, A3.4.1. | |
| 5211 // | |
| 5212 // However, a store could cause a cache eviction which will affect the | |
| 5213 // monitor. As a result, it's most strict to unconditionally clear the | |
| 5214 // local monitor on store. | |
| 5215 access_state_ = MonitorAccess::Open; | |
| 5216 tagged_addr_ = 0; | |
| 5217 size_ = TransactionSize::None; | |
| 5218 } | |
| 5219 } | |
| 5220 | |
| 5221 bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr, | |
| 5222 TransactionSize size) { | |
| 5223 if (access_state_ == MonitorAccess::Exclusive) { | |
| 5224 // It is allowed for a processor to require that the address matches | |
| 5225 // exactly (A3.4.5), so this comparison does not mask addr. | |
| 5226 if (addr == tagged_addr_ && size_ == size) { | |
| 5227 access_state_ = MonitorAccess::Open; | |
| 5228 tagged_addr_ = 0; | |
| 5229 size_ = TransactionSize::None; | |
| 5230 return true; | |
| 5231 } else { | |
| 5232 // It is implementation-defined whether an exclusive store to a | |
| 5233 // non-tagged address will update memory. Behavior is unpredictable if | |
| 5234 // the transaction size of the exclusive store differs from that of the | |
| 5235 // exclusive load. See ARM DDI 0406C.b, A3.4.5. | |
| 5236 access_state_ = MonitorAccess::Open; | |
| 5237 tagged_addr_ = 0; | |
| 5238 size_ = TransactionSize::None; | |
| 5239 return false; | |
| 5240 } | |
| 5241 } else { | |
| 5242 DCHECK(access_state_ == MonitorAccess::Open); | |
| 5243 return false; | |
| 5244 } | |
| 5245 } | |
| 5246 | |
| 5247 Simulator::GlobalMonitor::Processor::Processor() | |
| 5248 : access_state_(MonitorAccess::Open), | |
| 5249 tagged_addr_(0), | |
| 5250 next_(nullptr), | |
| 5251 prev_(nullptr), | |
| 5252 failure_counter_(0) {} | |
| 5253 | |
| 5254 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) { | |
| 5255 access_state_ = MonitorAccess::Exclusive; | |
| 5256 tagged_addr_ = addr; | |
| 5257 } | |
| 5258 | |
| 5259 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked( | |
| 5260 int32_t addr, bool is_requesting_processor) { | |
| 5261 if (access_state_ == MonitorAccess::Exclusive) { | |
| 5262 // It is implementation-defined whether a non-exclusive store by the | |
| 5263 // requesting processor to an address covered by the global monitor | |
| 5264 // during exclusive access transitions to open or exclusive access. | |
| 5265 // | |
| 5266 // For any other processor, the access state always transitions to open | |
| 5267 // access. | |
| 5268 // | |
| 5269 // See ARM DDI 0406C.b, A3.4.2. | |
| 5270 // | |
| 5271 // However, similar to the local monitor, it is possible that a store | |
| 5272 // caused a cache eviction, which can affect the montior, so | |
| 5273 // conservatively, we always clear the monitor. | |
| 5274 access_state_ = MonitorAccess::Open; | |
| 5275 tagged_addr_ = 0; | |
| 5276 } | |
| 5277 } | |
| 5278 | |
| 5279 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked( | |
| 5280 int32_t addr, bool is_requesting_processor) { | |
| 5281 if (access_state_ == MonitorAccess::Exclusive) { | |
| 5282 if (is_requesting_processor) { | |
| 5283 // It is allowed for a processor to require that the address matches | |
| 5284 // exactly (A3.4.5), so this comparison does not mask addr. | |
| 5285 if (addr == tagged_addr_) { | |
| 5286 // The access state for the requesting processor after a successful | |
| 5287 // exclusive store is implementation-defined, but according to the ARM | |
| 5288 // DDI, this has no effect on the subsequent operation of the global | |
| 5289 // monitor. | |
| 5290 access_state_ = MonitorAccess::Open; | |
| 5291 tagged_addr_ = 0; | |
| 5292 // Introduce occasional strex failures. This is to simulate the | |
| 5293 // behavior of hardware, which can randomly fail due to background | |
| 5294 // cache evictions. | |
| 5295 if (failure_counter_++ >= kMaxFailureCounter) { | |
| 5296 failure_counter_ = 0; | |
| 5297 return false; | |
| 5298 } else { | |
| 5299 return true; | |
| 5300 } | |
| 5301 } | |
| 5302 } else if ((addr & kExclusiveTaggedAddrMask) == | |
| 5303 (tagged_addr_ & kExclusiveTaggedAddrMask)) { | |
| 5304 // Check the masked addresses when responding to a successful lock by | |
| 5305 // another processor so the implementation is more conservative (i.e. the | |
| 5306 // granularity of locking is as large as possible.) | |
| 5307 access_state_ = MonitorAccess::Open; | |
| 5308 tagged_addr_ = 0; | |
| 5309 return false; | |
| 5310 } | |
| 5311 } | |
| 5312 return false; | |
| 5313 } | |
| 5314 | |
| 5315 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {} | |
| 5316 | |
| 5317 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr, | |
| 5318 Processor* processor) { | |
| 5319 processor->NotifyLoadExcl_Locked(addr); | |
| 5320 PrependProcessor_Locked(processor); | |
| 5321 } | |
| 5322 | |
| 5323 void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr, | |
| 5324 Processor* processor) { | |
| 5325 // Notify each processor of the store operation. | |
| 5326 for (Processor* iter = head_; iter; iter = iter->next_) { | |
| 5327 bool is_requesting_processor = iter == processor; | |
| 5328 iter->NotifyStore_Locked(addr, is_requesting_processor); | |
| 5329 } | |
| 5330 } | |
| 5331 | |
| 5332 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr, | |
| 5333 Processor* processor) { | |
| 5334 DCHECK(IsProcessorInLinkedList_Locked(processor)); | |
| 5335 if (processor->NotifyStoreExcl_Locked(addr, true)) { | |
| 5336 // Notify the other processors that this StoreExcl succeeded. | |
| 5337 for (Processor* iter = head_; iter; iter = iter->next_) { | |
| 5338 if (iter != processor) { | |
| 5339 iter->NotifyStoreExcl_Locked(addr, false); | |
| 5340 } | |
| 5341 } | |
| 5342 return true; | |
| 5343 } else { | |
| 5344 return false; | |
| 5345 } | |
| 5346 } | |
| 5347 | |
| 5348 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked( | |
| 5349 Processor* processor) const { | |
| 5350 return head_ == processor || processor->next_ || processor->prev_; | |
| 5351 } | |
| 5352 | |
| 5353 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) { | |
| 5354 if (IsProcessorInLinkedList_Locked(processor)) { | |
| 5355 return; | |
| 5356 } | |
| 5357 | |
| 5358 if (head_) { | |
| 5359 head_->prev_ = processor; | |
| 5360 } | |
| 5361 processor->prev_ = nullptr; | |
| 5362 processor->next_ = head_; | |
| 5363 head_ = processor; | |
| 5364 } | |
| 5365 | |
| 5366 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) { | |
| 5367 base::LockGuard<base::Mutex> lock_guard(&mutex); | |
| 5368 if (!IsProcessorInLinkedList_Locked(processor)) { | |
| 5369 return; | |
| 5370 } | |
| 5371 | |
| 5372 if (processor->prev_) { | |
| 5373 processor->prev_->next_ = processor->next_; | |
| 5374 } else { | |
| 5375 head_ = processor->next_; | |
| 5376 } | |
| 5377 if (processor->next_) { | |
| 5378 processor->next_->prev_ = processor->prev_; | |
| 5379 } | |
| 5380 processor->prev_ = nullptr; | |
| 5381 processor->next_ = nullptr; | |
| 5382 } | |
| 5383 | |
| 5027 } // namespace internal | 5384 } // namespace internal |
| 5028 } // namespace v8 | 5385 } // namespace v8 |
| 5029 | 5386 |
| 5030 #endif // USE_SIMULATOR | 5387 #endif // USE_SIMULATOR |
| 5031 | 5388 |
| 5032 #endif // V8_TARGET_ARCH_ARM | 5389 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |