OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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_PPC | 9 #if V8_TARGET_ARCH_PPC |
10 | 10 |
11 #include "src/assembler.h" | 11 #include "src/assembler.h" |
12 #include "src/base/bits.h" | 12 #include "src/base/bits.h" |
13 #include "src/codegen.h" | 13 #include "src/codegen.h" |
14 #include "src/disasm.h" | 14 #include "src/disasm.h" |
15 #include "src/ppc/constants-ppc.h" | 15 #include "src/ppc/constants-ppc.h" |
16 #include "src/ppc/frames-ppc.h" | 16 #include "src/ppc/frames-ppc.h" |
17 #include "src/ppc/simulator-ppc.h" | 17 #include "src/ppc/simulator-ppc.h" |
18 #include "src/runtime/runtime-utils.h" | 18 #include "src/runtime/runtime-utils.h" |
19 | 19 |
20 #if defined(USE_SIMULATOR) | 20 #if defined(USE_SIMULATOR) |
21 | 21 |
22 // Only build the simulator if not compiling for real PPC hardware. | 22 // Only build the simulator if not compiling for real PPC hardware. |
23 namespace v8 { | 23 namespace v8 { |
24 namespace internal { | 24 namespace internal { |
25 | 25 |
26 const auto GetRegConfig = RegisterConfiguration::Crankshaft; | 26 const auto GetRegConfig = RegisterConfiguration::Crankshaft; |
27 | 27 |
| 28 // static |
| 29 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ = |
| 30 LAZY_INSTANCE_INITIALIZER; |
| 31 |
28 // This macro provides a platform independent use of sscanf. The reason for | 32 // This macro provides a platform independent use of sscanf. The reason for |
29 // SScanF not being implemented in a platform independent way through | 33 // SScanF not being implemented in a platform independent way through |
30 // ::v8::internal::OS in the same way as SNPrintF is that the | 34 // ::v8::internal::OS in the same way as SNPrintF is that the |
31 // Windows C Run-Time Library does not provide vsscanf. | 35 // Windows C Run-Time Library does not provide vsscanf. |
32 #define SScanF sscanf // NOLINT | 36 #define SScanF sscanf // NOLINT |
33 | 37 |
34 // The PPCDebugger class is used by the simulator while debugging simulated | 38 // The PPCDebugger class is used by the simulator while debugging simulated |
35 // PowerPC code. | 39 // PowerPC code. |
36 class PPCDebugger { | 40 class PPCDebugger { |
37 public: | 41 public: |
(...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 | 778 |
775 // The sp is initialized to point to the bottom (high address) of the | 779 // The sp is initialized to point to the bottom (high address) of the |
776 // allocated stack area. To be safe in potential stack underflows we leave | 780 // allocated stack area. To be safe in potential stack underflows we leave |
777 // some buffer below. | 781 // some buffer below. |
778 registers_[sp] = | 782 registers_[sp] = |
779 reinterpret_cast<intptr_t>(stack_) + stack_size - stack_protection_size_; | 783 reinterpret_cast<intptr_t>(stack_) + stack_size - stack_protection_size_; |
780 | 784 |
781 last_debugger_input_ = NULL; | 785 last_debugger_input_ = NULL; |
782 } | 786 } |
783 | 787 |
784 | 788 Simulator::~Simulator() { |
785 Simulator::~Simulator() { free(stack_); } | 789 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_); |
786 | 790 free(stack_); |
| 791 } |
787 | 792 |
788 // When the generated code calls an external reference we need to catch that in | 793 // When the generated code calls an external reference we need to catch that in |
789 // the simulator. The external reference will be a function compiled for the | 794 // the simulator. The external reference will be a function compiled for the |
790 // host architecture. We need to call that function instead of trying to | 795 // host architecture. We need to call that function instead of trying to |
791 // execute it with the simulator. We do that by redirecting the external | 796 // execute it with the simulator. We do that by redirecting the external |
792 // reference to a svc (Supervisor Call) instruction that is handled by | 797 // reference to a svc (Supervisor Call) instruction that is handled by |
793 // the simulator. We write the original destination of the jump just at a known | 798 // the simulator. We write the original destination of the jump just at a known |
794 // offset from the svc instruction so the simulator knows what to call. | 799 // offset from the svc instruction so the simulator knows what to call. |
795 class Redirection { | 800 class Redirection { |
796 public: | 801 public: |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 // We don't trash the registers with the return value. | 985 // We don't trash the registers with the return value. |
981 #if 0 // A good idea to trash volatile registers, needs to be done | 986 #if 0 // A good idea to trash volatile registers, needs to be done |
982 registers_[2] = 0x50Bad4U; | 987 registers_[2] = 0x50Bad4U; |
983 registers_[3] = 0x50Bad4U; | 988 registers_[3] = 0x50Bad4U; |
984 registers_[12] = 0x50Bad4U; | 989 registers_[12] = 0x50Bad4U; |
985 #endif | 990 #endif |
986 } | 991 } |
987 | 992 |
988 | 993 |
989 uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) { | 994 uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) { |
| 995 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 996 // check the alignment here. |
| 997 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 998 local_monitor_.NotifyLoad(addr); |
990 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); | 999 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
991 return *ptr; | 1000 return *ptr; |
992 } | 1001 } |
993 | 1002 |
| 1003 uint32_t Simulator::ReadExWU(intptr_t addr, Instruction* instr) { |
| 1004 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1005 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word); |
| 1006 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, |
| 1007 &global_monitor_processor_); |
| 1008 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
| 1009 return *ptr; |
| 1010 } |
994 | 1011 |
995 int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) { | 1012 int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) { |
| 1013 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1014 // check the alignment here. |
| 1015 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1016 local_monitor_.NotifyLoad(addr); |
996 int32_t* ptr = reinterpret_cast<int32_t*>(addr); | 1017 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
997 return *ptr; | 1018 return *ptr; |
998 } | 1019 } |
999 | 1020 |
1000 | 1021 |
1001 void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) { | 1022 void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) { |
| 1023 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1024 // check the alignment here. |
| 1025 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1026 local_monitor_.NotifyStore(addr); |
| 1027 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1028 &global_monitor_processor_); |
1002 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); | 1029 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
1003 *ptr = value; | 1030 *ptr = value; |
1004 return; | 1031 return; |
1005 } | 1032 } |
1006 | 1033 |
| 1034 int Simulator::WriteExW(intptr_t addr, uint32_t value, Instruction* instr) { |
| 1035 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1036 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) && |
| 1037 global_monitor_.Pointer()->NotifyStoreExcl_Locked( |
| 1038 addr, &global_monitor_processor_)) { |
| 1039 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
| 1040 *ptr = value; |
| 1041 return 0; |
| 1042 } else { |
| 1043 return 1; |
| 1044 } |
| 1045 } |
1007 | 1046 |
1008 void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) { | 1047 void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) { |
| 1048 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1049 // check the alignment here. |
| 1050 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1051 local_monitor_.NotifyStore(addr); |
| 1052 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1053 &global_monitor_processor_); |
1009 int32_t* ptr = reinterpret_cast<int32_t*>(addr); | 1054 int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
1010 *ptr = value; | 1055 *ptr = value; |
1011 return; | 1056 return; |
1012 } | 1057 } |
1013 | 1058 |
1014 | |
1015 uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) { | 1059 uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) { |
| 1060 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1061 // check the alignment here. |
| 1062 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1063 local_monitor_.NotifyLoad(addr); |
1016 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 1064 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
1017 return *ptr; | 1065 return *ptr; |
1018 } | 1066 } |
1019 | 1067 |
| 1068 uint16_t Simulator::ReadExHU(intptr_t addr, Instruction* instr) { |
| 1069 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1070 local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord); |
| 1071 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, |
| 1072 &global_monitor_processor_); |
| 1073 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 1074 return *ptr; |
| 1075 } |
1020 | 1076 |
1021 int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) { | 1077 int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) { |
| 1078 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1079 // check the alignment here. |
| 1080 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1081 local_monitor_.NotifyLoad(addr); |
1022 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1082 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
1023 return *ptr; | 1083 return *ptr; |
1024 } | 1084 } |
1025 | 1085 |
1026 | 1086 |
1027 void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) { | 1087 void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) { |
| 1088 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1089 // check the alignment here. |
| 1090 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1091 local_monitor_.NotifyStore(addr); |
| 1092 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1093 &global_monitor_processor_); |
1028 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 1094 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
1029 *ptr = value; | 1095 *ptr = value; |
1030 return; | 1096 return; |
1031 } | 1097 } |
1032 | 1098 |
1033 | 1099 |
1034 void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) { | 1100 void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) { |
| 1101 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1102 // check the alignment here. |
| 1103 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1104 local_monitor_.NotifyStore(addr); |
| 1105 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1106 &global_monitor_processor_); |
1035 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 1107 int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
1036 *ptr = value; | 1108 *ptr = value; |
1037 return; | 1109 return; |
1038 } | 1110 } |
1039 | 1111 |
| 1112 int Simulator::WriteExH(intptr_t addr, uint16_t value, Instruction* instr) { |
| 1113 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1114 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) && |
| 1115 global_monitor_.Pointer()->NotifyStoreExcl_Locked( |
| 1116 addr, &global_monitor_processor_)) { |
| 1117 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
| 1118 *ptr = value; |
| 1119 return 0; |
| 1120 } else { |
| 1121 return 1; |
| 1122 } |
| 1123 } |
1040 | 1124 |
1041 uint8_t Simulator::ReadBU(intptr_t addr) { | 1125 uint8_t Simulator::ReadBU(intptr_t addr) { |
| 1126 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1127 // check the alignment here. |
| 1128 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1129 local_monitor_.NotifyLoad(addr); |
1042 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1130 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
1043 return *ptr; | 1131 return *ptr; |
1044 } | 1132 } |
1045 | 1133 |
1046 | 1134 |
1047 int8_t Simulator::ReadB(intptr_t addr) { | 1135 int8_t Simulator::ReadB(intptr_t addr) { |
| 1136 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1137 // check the alignment here. |
| 1138 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1139 local_monitor_.NotifyLoad(addr); |
1048 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1140 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
1049 return *ptr; | 1141 return *ptr; |
1050 } | 1142 } |
1051 | 1143 |
| 1144 uint8_t Simulator::ReadExBU(intptr_t addr) { |
| 1145 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1146 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte); |
| 1147 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr, |
| 1148 &global_monitor_processor_); |
| 1149 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 1150 return *ptr; |
| 1151 } |
1052 | 1152 |
1053 void Simulator::WriteB(intptr_t addr, uint8_t value) { | 1153 void Simulator::WriteB(intptr_t addr, uint8_t value) { |
| 1154 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1155 // check the alignment here. |
| 1156 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1157 local_monitor_.NotifyStore(addr); |
| 1158 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1159 &global_monitor_processor_); |
1054 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1160 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
1055 *ptr = value; | 1161 *ptr = value; |
1056 } | 1162 } |
1057 | 1163 |
1058 | 1164 |
1059 void Simulator::WriteB(intptr_t addr, int8_t value) { | 1165 void Simulator::WriteB(intptr_t addr, int8_t value) { |
| 1166 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1167 // check the alignment here. |
| 1168 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1169 local_monitor_.NotifyStore(addr); |
| 1170 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1171 &global_monitor_processor_); |
1060 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1172 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
1061 *ptr = value; | 1173 *ptr = value; |
1062 } | 1174 } |
1063 | 1175 |
| 1176 int Simulator::WriteExB(intptr_t addr, uint8_t value) { |
| 1177 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1178 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) && |
| 1179 global_monitor_.Pointer()->NotifyStoreExcl_Locked( |
| 1180 addr, &global_monitor_processor_)) { |
| 1181 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 1182 *ptr = value; |
| 1183 return 0; |
| 1184 } else { |
| 1185 return 1; |
| 1186 } |
| 1187 } |
1064 | 1188 |
1065 intptr_t* Simulator::ReadDW(intptr_t addr) { | 1189 intptr_t* Simulator::ReadDW(intptr_t addr) { |
| 1190 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1191 // check the alignment here. |
| 1192 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1193 local_monitor_.NotifyLoad(addr); |
1066 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 1194 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
1067 return ptr; | 1195 return ptr; |
1068 } | 1196 } |
1069 | 1197 |
1070 | 1198 |
1071 void Simulator::WriteDW(intptr_t addr, int64_t value) { | 1199 void Simulator::WriteDW(intptr_t addr, int64_t value) { |
| 1200 // All supported PPC targets allow unaligned accesses, so we don't need to |
| 1201 // check the alignment here. |
| 1202 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
| 1203 local_monitor_.NotifyStore(addr); |
| 1204 global_monitor_.Pointer()->NotifyStore_Locked(addr, |
| 1205 &global_monitor_processor_); |
1072 int64_t* ptr = reinterpret_cast<int64_t*>(addr); | 1206 int64_t* ptr = reinterpret_cast<int64_t*>(addr); |
1073 *ptr = value; | 1207 *ptr = value; |
1074 return; | 1208 return; |
1075 } | 1209 } |
1076 | 1210 |
1077 | 1211 |
1078 // Returns the limit of the stack area to enable checking for stack overflows. | 1212 // Returns the limit of the stack area to enable checking for stack overflows. |
1079 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { | 1213 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { |
1080 // The simulator uses a separate JS stack. If we have exhausted the C stack, | 1214 // The simulator uses a separate JS stack. If we have exhausted the C stack, |
1081 // we also drop down the JS limit to reflect the exhaustion on the JS stack. | 1215 // we also drop down the JS limit to reflect the exhaustion on the JS stack. |
(...skipping 1173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2255 int rs = instr->RSValue(); | 2389 int rs = instr->RSValue(); |
2256 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5)); | 2390 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5)); |
2257 intptr_t rs_val = get_register(rs); | 2391 intptr_t rs_val = get_register(rs); |
2258 intptr_t result = rs_val >> sh; | 2392 intptr_t result = rs_val >> sh; |
2259 set_register(ra, result); | 2393 set_register(ra, result); |
2260 if (instr->Bit(0)) { // RC bit set | 2394 if (instr->Bit(0)) { // RC bit set |
2261 SetCR0(result); | 2395 SetCR0(result); |
2262 } | 2396 } |
2263 break; | 2397 break; |
2264 } | 2398 } |
| 2399 case STBCX: { |
| 2400 int rs = instr->RSValue(); |
| 2401 int ra = instr->RAValue(); |
| 2402 int rb = instr->RBValue(); |
| 2403 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 2404 int8_t rs_val = get_register(rs); |
| 2405 intptr_t rb_val = get_register(rb); |
| 2406 SetCR0(WriteExB(ra_val + rb_val, rs_val)); |
| 2407 break; |
| 2408 } |
| 2409 case STHCX: { |
| 2410 int rs = instr->RSValue(); |
| 2411 int ra = instr->RAValue(); |
| 2412 int rb = instr->RBValue(); |
| 2413 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 2414 int16_t rs_val = get_register(rs); |
| 2415 intptr_t rb_val = get_register(rb); |
| 2416 SetCR0(WriteExH(ra_val + rb_val, rs_val, instr)); |
| 2417 break; |
| 2418 } |
| 2419 case STWCX: { |
| 2420 int rs = instr->RSValue(); |
| 2421 int ra = instr->RAValue(); |
| 2422 int rb = instr->RBValue(); |
| 2423 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 2424 int32_t rs_val = get_register(rs); |
| 2425 intptr_t rb_val = get_register(rb); |
| 2426 SetCR0(WriteExW(ra_val + rb_val, rs_val, instr)); |
| 2427 break; |
| 2428 } |
2265 case TW: { | 2429 case TW: { |
2266 // used for call redirection in simulation mode | 2430 // used for call redirection in simulation mode |
2267 SoftwareInterrupt(instr); | 2431 SoftwareInterrupt(instr); |
2268 break; | 2432 break; |
2269 } | 2433 } |
2270 case CMP: { | 2434 case CMP: { |
2271 int ra = instr->RAValue(); | 2435 int ra = instr->RAValue(); |
2272 int rb = instr->RBValue(); | 2436 int rb = instr->RBValue(); |
2273 int cr = instr->Bits(25, 23); | 2437 int cr = instr->Bits(25, 23); |
2274 uint32_t bf = 0; | 2438 uint32_t bf = 0; |
(...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2986 int rb = instr->RBValue(); | 3150 int rb = instr->RBValue(); |
2987 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); | 3151 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
2988 intptr_t rb_val = get_register(rb); | 3152 intptr_t rb_val = get_register(rb); |
2989 set_register(rt, ReadHU(ra_val + rb_val, instr) & 0xFFFF); | 3153 set_register(rt, ReadHU(ra_val + rb_val, instr) & 0xFFFF); |
2990 if (opcode == LHZUX) { | 3154 if (opcode == LHZUX) { |
2991 DCHECK(ra != 0 && ra != rt); | 3155 DCHECK(ra != 0 && ra != rt); |
2992 set_register(ra, ra_val + rb_val); | 3156 set_register(ra, ra_val + rb_val); |
2993 } | 3157 } |
2994 break; | 3158 break; |
2995 } | 3159 } |
2996 case LHAX: | 3160 case LHAX: { |
2997 case LHAUX: { | |
2998 int rt = instr->RTValue(); | 3161 int rt = instr->RTValue(); |
2999 int ra = instr->RAValue(); | 3162 int ra = instr->RAValue(); |
3000 int rb = instr->RBValue(); | 3163 int rb = instr->RBValue(); |
3001 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); | 3164 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
3002 intptr_t rb_val = get_register(rb); | 3165 intptr_t rb_val = get_register(rb); |
3003 set_register(rt, ReadH(ra_val + rb_val, instr)); | 3166 set_register(rt, ReadH(ra_val + rb_val, instr)); |
3004 if (opcode == LHAUX) { | 3167 break; |
3005 DCHECK(ra != 0 && ra != rt); | 3168 } |
3006 set_register(ra, ra_val + rb_val); | 3169 case LBARX: { |
3007 } | 3170 int rt = instr->RTValue(); |
| 3171 int ra = instr->RAValue(); |
| 3172 int rb = instr->RBValue(); |
| 3173 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 3174 intptr_t rb_val = get_register(rb); |
| 3175 set_register(rt, ReadExBU(ra_val + rb_val) & 0xFF); |
| 3176 break; |
| 3177 } |
| 3178 case LHARX: { |
| 3179 int rt = instr->RTValue(); |
| 3180 int ra = instr->RAValue(); |
| 3181 int rb = instr->RBValue(); |
| 3182 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 3183 intptr_t rb_val = get_register(rb); |
| 3184 set_register(rt, ReadExHU(ra_val + rb_val, instr)); |
| 3185 break; |
| 3186 } |
| 3187 case LWARX: { |
| 3188 int rt = instr->RTValue(); |
| 3189 int ra = instr->RAValue(); |
| 3190 int rb = instr->RBValue(); |
| 3191 intptr_t ra_val = ra == 0 ? 0 : get_register(ra); |
| 3192 intptr_t rb_val = get_register(rb); |
| 3193 set_register(rt, ReadExWU(ra_val + rb_val, instr)); |
3008 break; | 3194 break; |
3009 } | 3195 } |
3010 case DCBF: { | 3196 case DCBF: { |
3011 // todo - simulate dcbf | 3197 // todo - simulate dcbf |
3012 break; | 3198 break; |
3013 } | 3199 } |
3014 case ISEL: { | 3200 case ISEL: { |
3015 int rt = instr->RTValue(); | 3201 int rt = instr->RTValue(); |
3016 int ra = instr->RAValue(); | 3202 int ra = instr->RAValue(); |
3017 int rb = instr->RBValue(); | 3203 int rb = instr->RBValue(); |
(...skipping 1048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4066 } | 4252 } |
4067 | 4253 |
4068 | 4254 |
4069 uintptr_t Simulator::PopAddress() { | 4255 uintptr_t Simulator::PopAddress() { |
4070 uintptr_t current_sp = get_register(sp); | 4256 uintptr_t current_sp = get_register(sp); |
4071 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); | 4257 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
4072 uintptr_t address = *stack_slot; | 4258 uintptr_t address = *stack_slot; |
4073 set_register(sp, current_sp + sizeof(uintptr_t)); | 4259 set_register(sp, current_sp + sizeof(uintptr_t)); |
4074 return address; | 4260 return address; |
4075 } | 4261 } |
| 4262 |
| 4263 Simulator::LocalMonitor::LocalMonitor() |
| 4264 : access_state_(MonitorAccess::Open), |
| 4265 tagged_addr_(0), |
| 4266 size_(TransactionSize::None) {} |
| 4267 |
| 4268 void Simulator::LocalMonitor::Clear() { |
| 4269 access_state_ = MonitorAccess::Open; |
| 4270 tagged_addr_ = 0; |
| 4271 size_ = TransactionSize::None; |
| 4272 } |
| 4273 |
| 4274 void Simulator::LocalMonitor::NotifyLoad(int32_t addr) { |
| 4275 if (access_state_ == MonitorAccess::Exclusive) { |
| 4276 // A load could cause a cache eviction which will affect the monitor. As a |
| 4277 // result, it's most strict to unconditionally clear the local monitor on |
| 4278 // load. |
| 4279 Clear(); |
| 4280 } |
| 4281 } |
| 4282 |
| 4283 void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr, |
| 4284 TransactionSize size) { |
| 4285 access_state_ = MonitorAccess::Exclusive; |
| 4286 tagged_addr_ = addr; |
| 4287 size_ = size; |
| 4288 } |
| 4289 |
| 4290 void Simulator::LocalMonitor::NotifyStore(int32_t addr) { |
| 4291 if (access_state_ == MonitorAccess::Exclusive) { |
| 4292 // A store could cause a cache eviction which will affect the |
| 4293 // monitor. As a result, it's most strict to unconditionally clear the |
| 4294 // local monitor on store. |
| 4295 Clear(); |
| 4296 } |
| 4297 } |
| 4298 |
| 4299 bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr, |
| 4300 TransactionSize size) { |
| 4301 if (access_state_ == MonitorAccess::Exclusive) { |
| 4302 if (addr == tagged_addr_ && size_ == size) { |
| 4303 Clear(); |
| 4304 return true; |
| 4305 } else { |
| 4306 Clear(); |
| 4307 return false; |
| 4308 } |
| 4309 } else { |
| 4310 DCHECK(access_state_ == MonitorAccess::Open); |
| 4311 return false; |
| 4312 } |
| 4313 } |
| 4314 |
| 4315 Simulator::GlobalMonitor::Processor::Processor() |
| 4316 : access_state_(MonitorAccess::Open), |
| 4317 tagged_addr_(0), |
| 4318 next_(nullptr), |
| 4319 prev_(nullptr) {} |
| 4320 |
| 4321 void Simulator::GlobalMonitor::Processor::Clear_Locked() { |
| 4322 access_state_ = MonitorAccess::Open; |
| 4323 tagged_addr_ = 0; |
| 4324 } |
| 4325 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) { |
| 4326 access_state_ = MonitorAccess::Exclusive; |
| 4327 tagged_addr_ = addr; |
| 4328 } |
| 4329 |
| 4330 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked( |
| 4331 int32_t addr, bool is_requesting_processor) { |
| 4332 if (access_state_ == MonitorAccess::Exclusive) { |
| 4333 // It is possible that a store caused a cache eviction, |
| 4334 // which can affect the montior, so conservatively, |
| 4335 // we always clear the monitor. |
| 4336 Clear_Locked(); |
| 4337 } |
| 4338 } |
| 4339 |
| 4340 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked( |
| 4341 int32_t addr, bool is_requesting_processor) { |
| 4342 if (access_state_ == MonitorAccess::Exclusive) { |
| 4343 if (is_requesting_processor) { |
| 4344 if (addr == tagged_addr_) { |
| 4345 Clear_Locked(); |
| 4346 return true; |
| 4347 } |
| 4348 } else if (addr == tagged_addr_) { |
| 4349 Clear_Locked(); |
| 4350 return false; |
| 4351 } |
| 4352 } |
| 4353 return false; |
| 4354 } |
| 4355 |
| 4356 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {} |
| 4357 |
| 4358 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr, |
| 4359 Processor* processor) { |
| 4360 processor->NotifyLoadExcl_Locked(addr); |
| 4361 PrependProcessor_Locked(processor); |
| 4362 } |
| 4363 |
| 4364 void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr, |
| 4365 Processor* processor) { |
| 4366 // Notify each processor of the store operation. |
| 4367 for (Processor* iter = head_; iter; iter = iter->next_) { |
| 4368 bool is_requesting_processor = iter == processor; |
| 4369 iter->NotifyStore_Locked(addr, is_requesting_processor); |
| 4370 } |
| 4371 } |
| 4372 |
| 4373 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr, |
| 4374 Processor* processor) { |
| 4375 DCHECK(IsProcessorInLinkedList_Locked(processor)); |
| 4376 if (processor->NotifyStoreExcl_Locked(addr, true)) { |
| 4377 // Notify the other processors that this StoreExcl succeeded. |
| 4378 for (Processor* iter = head_; iter; iter = iter->next_) { |
| 4379 if (iter != processor) { |
| 4380 iter->NotifyStoreExcl_Locked(addr, false); |
| 4381 } |
| 4382 } |
| 4383 return true; |
| 4384 } else { |
| 4385 return false; |
| 4386 } |
| 4387 } |
| 4388 |
| 4389 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked( |
| 4390 Processor* processor) const { |
| 4391 return head_ == processor || processor->next_ || processor->prev_; |
| 4392 } |
| 4393 |
| 4394 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) { |
| 4395 if (IsProcessorInLinkedList_Locked(processor)) { |
| 4396 return; |
| 4397 } |
| 4398 |
| 4399 if (head_) { |
| 4400 head_->prev_ = processor; |
| 4401 } |
| 4402 processor->prev_ = nullptr; |
| 4403 processor->next_ = head_; |
| 4404 head_ = processor; |
| 4405 } |
| 4406 |
| 4407 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) { |
| 4408 base::LockGuard<base::Mutex> lock_guard(&mutex); |
| 4409 if (!IsProcessorInLinkedList_Locked(processor)) { |
| 4410 return; |
| 4411 } |
| 4412 |
| 4413 if (processor->prev_) { |
| 4414 processor->prev_->next_ = processor->next_; |
| 4415 } else { |
| 4416 head_ = processor->next_; |
| 4417 } |
| 4418 if (processor->next_) { |
| 4419 processor->next_->prev_ = processor->prev_; |
| 4420 } |
| 4421 processor->prev_ = nullptr; |
| 4422 processor->next_ = nullptr; |
| 4423 } |
| 4424 |
4076 } // namespace internal | 4425 } // namespace internal |
4077 } // namespace v8 | 4426 } // namespace v8 |
4078 | 4427 |
4079 #endif // USE_SIMULATOR | 4428 #endif // USE_SIMULATOR |
4080 #endif // V8_TARGET_ARCH_PPC | 4429 #endif // V8_TARGET_ARCH_PPC |
OLD | NEW |