| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 int64_t offset = ExtendValue(kXRegSize, xreg(instr->Rm()), ext, | 1228 int64_t offset = ExtendValue(kXRegSize, xreg(instr->Rm()), ext, |
| 1229 shift_amount); | 1229 shift_amount); |
| 1230 LoadStoreHelper(instr, offset, Offset); | 1230 LoadStoreHelper(instr, offset, Offset); |
| 1231 } | 1231 } |
| 1232 | 1232 |
| 1233 | 1233 |
| 1234 void Simulator::LoadStoreHelper(Instruction* instr, | 1234 void Simulator::LoadStoreHelper(Instruction* instr, |
| 1235 int64_t offset, | 1235 int64_t offset, |
| 1236 AddrMode addrmode) { | 1236 AddrMode addrmode) { |
| 1237 unsigned srcdst = instr->Rt(); | 1237 unsigned srcdst = instr->Rt(); |
| 1238 uint8_t* address = AddressModeHelper(instr->Rn(), offset, addrmode); | 1238 unsigned addr_reg = instr->Rn(); |
| 1239 uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); |
| 1239 int num_bytes = 1 << instr->SizeLS(); | 1240 int num_bytes = 1 << instr->SizeLS(); |
| 1241 uint8_t* stack = NULL; |
| 1240 | 1242 |
| 1241 // Accesses below the stack pointer (but above the platform stack limit) are | 1243 // Handle the writeback for stores before the store. On a CPU the writeback |
| 1242 // not allowed in the ABI. | 1244 // and the store are atomic, but when running on the simulator it is possible |
| 1243 uint64_t access_address = reinterpret_cast<uint64_t>(address); | 1245 // to be interrupted in between. The simulator is not thread safe and V8 does |
| 1244 uint64_t stack_limit = reinterpret_cast<uint64_t>(stack_limit_); | 1246 // not require it to be to run JavaScript therefore the profiler may sample |
| 1245 uint64_t stack_address = sp(); | 1247 // the "simulated" CPU in the middle of load/store with writeback. The code |
| 1246 if ((access_address >= stack_limit) && (access_address < stack_address)) { | 1248 // below ensures that push operations are safe even when interrupted: the |
| 1247 fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); | 1249 // stack pointer will be decremented before adding an element to the stack. |
| 1248 fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", | 1250 if (instr->IsStore()) { |
| 1249 stack_address); | 1251 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1250 fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", | 1252 |
| 1251 access_address); | 1253 // For store the address post writeback is used to check access below the |
| 1252 fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", stack_limit); | 1254 // stack. |
| 1253 fprintf(stream_, "\n"); | 1255 stack = reinterpret_cast<uint8_t*>(sp()); |
| 1254 ABORT(); | |
| 1255 } | 1256 } |
| 1256 | 1257 |
| 1257 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask)); | 1258 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask)); |
| 1258 switch (op) { | 1259 switch (op) { |
| 1259 case LDRB_w: | 1260 case LDRB_w: |
| 1260 case LDRH_w: | 1261 case LDRH_w: |
| 1261 case LDR_w: | 1262 case LDR_w: |
| 1262 case LDR_x: set_xreg(srcdst, MemoryRead(address, num_bytes)); break; | 1263 case LDR_x: set_xreg(srcdst, MemoryRead(address, num_bytes)); break; |
| 1263 case STRB_w: | 1264 case STRB_w: |
| 1264 case STRH_w: | 1265 case STRH_w: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1283 case LDRSW_x: { | 1284 case LDRSW_x: { |
| 1284 set_xreg(srcdst, ExtendValue(kXRegSize, MemoryRead32(address), SXTW)); | 1285 set_xreg(srcdst, ExtendValue(kXRegSize, MemoryRead32(address), SXTW)); |
| 1285 break; | 1286 break; |
| 1286 } | 1287 } |
| 1287 case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break; | 1288 case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break; |
| 1288 case LDR_d: set_dreg(srcdst, MemoryReadFP64(address)); break; | 1289 case LDR_d: set_dreg(srcdst, MemoryReadFP64(address)); break; |
| 1289 case STR_s: MemoryWriteFP32(address, sreg(srcdst)); break; | 1290 case STR_s: MemoryWriteFP32(address, sreg(srcdst)); break; |
| 1290 case STR_d: MemoryWriteFP64(address, dreg(srcdst)); break; | 1291 case STR_d: MemoryWriteFP64(address, dreg(srcdst)); break; |
| 1291 default: UNIMPLEMENTED(); | 1292 default: UNIMPLEMENTED(); |
| 1292 } | 1293 } |
| 1294 |
| 1295 // Handle the writeback for loads after the load to ensure safe pop |
| 1296 // operation even when interrupted in the middle of it. The stack pointer |
| 1297 // is only updated after the load so pop(fp) will never break the invariant |
| 1298 // sp <= fp expected while walking the stack in the sampler. |
| 1299 if (instr->IsLoad()) { |
| 1300 // For loads the address pre writeback is used to check access below the |
| 1301 // stack. |
| 1302 stack = reinterpret_cast<uint8_t*>(sp()); |
| 1303 |
| 1304 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1305 } |
| 1306 |
| 1307 // Accesses below the stack pointer (but above the platform stack limit) are |
| 1308 // not allowed in the ABI. |
| 1309 CheckMemoryAccess(address, stack); |
| 1293 } | 1310 } |
| 1294 | 1311 |
| 1295 | 1312 |
| 1296 void Simulator::VisitLoadStorePairOffset(Instruction* instr) { | 1313 void Simulator::VisitLoadStorePairOffset(Instruction* instr) { |
| 1297 LoadStorePairHelper(instr, Offset); | 1314 LoadStorePairHelper(instr, Offset); |
| 1298 } | 1315 } |
| 1299 | 1316 |
| 1300 | 1317 |
| 1301 void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) { | 1318 void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) { |
| 1302 LoadStorePairHelper(instr, PreIndex); | 1319 LoadStorePairHelper(instr, PreIndex); |
| 1303 } | 1320 } |
| 1304 | 1321 |
| 1305 | 1322 |
| 1306 void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) { | 1323 void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) { |
| 1307 LoadStorePairHelper(instr, PostIndex); | 1324 LoadStorePairHelper(instr, PostIndex); |
| 1308 } | 1325 } |
| 1309 | 1326 |
| 1310 | 1327 |
| 1311 void Simulator::VisitLoadStorePairNonTemporal(Instruction* instr) { | 1328 void Simulator::VisitLoadStorePairNonTemporal(Instruction* instr) { |
| 1312 LoadStorePairHelper(instr, Offset); | 1329 LoadStorePairHelper(instr, Offset); |
| 1313 } | 1330 } |
| 1314 | 1331 |
| 1315 | 1332 |
| 1316 void Simulator::LoadStorePairHelper(Instruction* instr, | 1333 void Simulator::LoadStorePairHelper(Instruction* instr, |
| 1317 AddrMode addrmode) { | 1334 AddrMode addrmode) { |
| 1318 unsigned rt = instr->Rt(); | 1335 unsigned rt = instr->Rt(); |
| 1319 unsigned rt2 = instr->Rt2(); | 1336 unsigned rt2 = instr->Rt2(); |
| 1337 unsigned addr_reg = instr->Rn(); |
| 1320 int offset = instr->ImmLSPair() << instr->SizeLSPair(); | 1338 int offset = instr->ImmLSPair() << instr->SizeLSPair(); |
| 1321 uint8_t* address = AddressModeHelper(instr->Rn(), offset, addrmode); | 1339 uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); |
| 1340 uint8_t* stack = NULL; |
| 1341 |
| 1342 // Handle the writeback for stores before the store. On a CPU the writeback |
| 1343 // and the store are atomic, but when running on the simulator it is possible |
| 1344 // to be interrupted in between. The simulator is not thread safe and V8 does |
| 1345 // not require it to be to run JavaScript therefore the profiler may sample |
| 1346 // the "simulated" CPU in the middle of load/store with writeback. The code |
| 1347 // below ensures that push operations are safe even when interrupted: the |
| 1348 // stack pointer will be decremented before adding an element to the stack. |
| 1349 if (instr->IsStore()) { |
| 1350 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1351 |
| 1352 // For store the address post writeback is used to check access below the |
| 1353 // stack. |
| 1354 stack = reinterpret_cast<uint8_t*>(sp()); |
| 1355 } |
| 1322 | 1356 |
| 1323 LoadStorePairOp op = | 1357 LoadStorePairOp op = |
| 1324 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask)); | 1358 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask)); |
| 1325 | 1359 |
| 1326 // 'rt' and 'rt2' can only be aliased for stores. | 1360 // 'rt' and 'rt2' can only be aliased for stores. |
| 1327 ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2)); | 1361 ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2)); |
| 1328 | 1362 |
| 1329 switch (op) { | 1363 switch (op) { |
| 1330 case LDP_w: { | 1364 case LDP_w: { |
| 1331 set_wreg(rt, MemoryRead32(address)); | 1365 set_wreg(rt, MemoryRead32(address)); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1368 MemoryWrite64(address + kXRegSizeInBytes, xreg(rt2)); | 1402 MemoryWrite64(address + kXRegSizeInBytes, xreg(rt2)); |
| 1369 break; | 1403 break; |
| 1370 } | 1404 } |
| 1371 case STP_d: { | 1405 case STP_d: { |
| 1372 MemoryWriteFP64(address, dreg(rt)); | 1406 MemoryWriteFP64(address, dreg(rt)); |
| 1373 MemoryWriteFP64(address + kDRegSizeInBytes, dreg(rt2)); | 1407 MemoryWriteFP64(address + kDRegSizeInBytes, dreg(rt2)); |
| 1374 break; | 1408 break; |
| 1375 } | 1409 } |
| 1376 default: UNREACHABLE(); | 1410 default: UNREACHABLE(); |
| 1377 } | 1411 } |
| 1412 |
| 1413 // Handle the writeback for loads after the load to ensure safe pop |
| 1414 // operation even when interrupted in the middle of it. The stack pointer |
| 1415 // is only updated after the load so pop(fp) will never break the invariant |
| 1416 // sp <= fp expected while walking the stack in the sampler. |
| 1417 if (instr->IsLoad()) { |
| 1418 // For loads the address pre writeback is used to check access below the |
| 1419 // stack. |
| 1420 stack = reinterpret_cast<uint8_t*>(sp()); |
| 1421 |
| 1422 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1423 } |
| 1424 |
| 1425 // Accesses below the stack pointer (but above the platform stack limit) are |
| 1426 // not allowed in the ABI. |
| 1427 CheckMemoryAccess(address, stack); |
| 1378 } | 1428 } |
| 1379 | 1429 |
| 1380 | 1430 |
| 1381 void Simulator::VisitLoadLiteral(Instruction* instr) { | 1431 void Simulator::VisitLoadLiteral(Instruction* instr) { |
| 1382 uint8_t* address = instr->LiteralAddress(); | 1432 uint8_t* address = instr->LiteralAddress(); |
| 1383 unsigned rt = instr->Rt(); | 1433 unsigned rt = instr->Rt(); |
| 1384 | 1434 |
| 1385 switch (instr->Mask(LoadLiteralMask)) { | 1435 switch (instr->Mask(LoadLiteralMask)) { |
| 1386 case LDR_w_lit: set_wreg(rt, MemoryRead32(address)); break; | 1436 case LDR_w_lit: set_wreg(rt, MemoryRead32(address)); break; |
| 1387 case LDR_x_lit: set_xreg(rt, MemoryRead64(address)); break; | 1437 case LDR_x_lit: set_xreg(rt, MemoryRead64(address)); break; |
| 1388 case LDR_s_lit: set_sreg(rt, MemoryReadFP32(address)); break; | 1438 case LDR_s_lit: set_sreg(rt, MemoryReadFP32(address)); break; |
| 1389 case LDR_d_lit: set_dreg(rt, MemoryReadFP64(address)); break; | 1439 case LDR_d_lit: set_dreg(rt, MemoryReadFP64(address)); break; |
| 1390 default: UNREACHABLE(); | 1440 default: UNREACHABLE(); |
| 1391 } | 1441 } |
| 1392 } | 1442 } |
| 1393 | 1443 |
| 1394 | 1444 |
| 1395 uint8_t* Simulator::AddressModeHelper(unsigned addr_reg, | 1445 uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, |
| 1396 int64_t offset, | 1446 int64_t offset, |
| 1397 AddrMode addrmode) { | 1447 AddrMode addrmode) { |
| 1398 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); | 1448 const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; |
| 1399 ASSERT((sizeof(uintptr_t) == kXRegSizeInBytes) || | 1449 int64_t address = xreg(addr_reg, Reg31IsStackPointer); |
| 1400 (address < 0x100000000UL)); | 1450 if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) { |
| 1401 if ((addr_reg == 31) && ((address % 16) != 0)) { | |
| 1402 // When the base register is SP the stack pointer is required to be | 1451 // When the base register is SP the stack pointer is required to be |
| 1403 // quadword aligned prior to the address calculation and write-backs. | 1452 // quadword aligned prior to the address calculation and write-backs. |
| 1404 // Misalignment will cause a stack alignment fault. | 1453 // Misalignment will cause a stack alignment fault. |
| 1405 ALIGNMENT_EXCEPTION(); | 1454 ALIGNMENT_EXCEPTION(); |
| 1406 } | 1455 } |
| 1407 if ((addrmode == PreIndex) || (addrmode == PostIndex)) { | |
| 1408 ASSERT(offset != 0); | |
| 1409 set_xreg(addr_reg, address + offset, Reg31IsStackPointer); | |
| 1410 } | |
| 1411 | 1456 |
| 1412 if ((addrmode == Offset) || (addrmode == PreIndex)) { | 1457 if ((addrmode == Offset) || (addrmode == PreIndex)) { |
| 1413 address += offset; | 1458 address += offset; |
| 1414 } | 1459 } |
| 1415 | 1460 |
| 1416 return reinterpret_cast<uint8_t*>(address); | 1461 return reinterpret_cast<uint8_t*>(address); |
| 1417 } | 1462 } |
| 1418 | 1463 |
| 1419 | 1464 |
| 1465 void Simulator::LoadStoreWriteBack(unsigned addr_reg, |
| 1466 int64_t offset, |
| 1467 AddrMode addrmode) { |
| 1468 if ((addrmode == PreIndex) || (addrmode == PostIndex)) { |
| 1469 ASSERT(offset != 0); |
| 1470 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); |
| 1471 set_reg(addr_reg, address + offset, Reg31IsStackPointer); |
| 1472 } |
| 1473 } |
| 1474 |
| 1475 |
| 1476 void Simulator::CheckMemoryAccess(uint8_t* address, uint8_t* stack) { |
| 1477 if ((address >= stack_limit_) && (address < stack)) { |
| 1478 fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); |
| 1479 fprintf(stream_, " sp is here: 0x%16p\n", stack); |
| 1480 fprintf(stream_, " access was here: 0x%16p\n", address); |
| 1481 fprintf(stream_, " stack limit is here: 0x%16p\n", stack_limit_); |
| 1482 fprintf(stream_, "\n"); |
| 1483 ABORT(); |
| 1484 } |
| 1485 } |
| 1486 |
| 1487 |
| 1420 uint64_t Simulator::MemoryRead(uint8_t* address, unsigned num_bytes) { | 1488 uint64_t Simulator::MemoryRead(uint8_t* address, unsigned num_bytes) { |
| 1421 ASSERT(address != NULL); | 1489 ASSERT(address != NULL); |
| 1422 ASSERT((num_bytes > 0) && (num_bytes <= sizeof(uint64_t))); | 1490 ASSERT((num_bytes > 0) && (num_bytes <= sizeof(uint64_t))); |
| 1423 uint64_t read = 0; | 1491 uint64_t read = 0; |
| 1424 memcpy(&read, address, num_bytes); | 1492 memcpy(&read, address, num_bytes); |
| 1425 return read; | 1493 return read; |
| 1426 } | 1494 } |
| 1427 | 1495 |
| 1428 | 1496 |
| 1429 uint8_t Simulator::MemoryRead8(uint8_t* address) { | 1497 uint8_t Simulator::MemoryRead8(uint8_t* address) { |
| (...skipping 1922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3352 default: | 3420 default: |
| 3353 UNIMPLEMENTED(); | 3421 UNIMPLEMENTED(); |
| 3354 } | 3422 } |
| 3355 } | 3423 } |
| 3356 | 3424 |
| 3357 #endif // USE_SIMULATOR | 3425 #endif // USE_SIMULATOR |
| 3358 | 3426 |
| 3359 } } // namespace v8::internal | 3427 } } // namespace v8::internal |
| 3360 | 3428 |
| 3361 #endif // V8_TARGET_ARCH_A64 | 3429 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |