| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 <stdlib.h> | 5 #include <stdlib.h> |
| 6 #include <cmath> | 6 #include <cmath> |
| 7 #include <cstdarg> | 7 #include <cstdarg> |
| 8 | 8 |
| 9 #if V8_TARGET_ARCH_ARM64 | 9 #if V8_TARGET_ARCH_ARM64 |
| 10 | 10 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; | 48 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; |
| 49 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; | 49 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; |
| 50 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; | 50 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; |
| 51 TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; | 51 TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; |
| 52 TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; | 52 TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; |
| 53 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; | 53 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; |
| 54 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; | 54 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; |
| 55 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; | 55 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; |
| 56 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; | 56 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; |
| 57 | 57 |
| 58 // static | |
| 59 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ = | |
| 60 LAZY_INSTANCE_INITIALIZER; | |
| 61 | 58 |
| 62 // This is basically the same as PrintF, with a guard for FLAG_trace_sim. | 59 // This is basically the same as PrintF, with a guard for FLAG_trace_sim. |
| 63 void Simulator::TraceSim(const char* format, ...) { | 60 void Simulator::TraceSim(const char* format, ...) { |
| 64 if (FLAG_trace_sim) { | 61 if (FLAG_trace_sim) { |
| 65 va_list arguments; | 62 va_list arguments; |
| 66 va_start(arguments, format); | 63 va_start(arguments, format); |
| 67 base::OS::VFPrint(stream_, format, arguments); | 64 base::OS::VFPrint(stream_, format, arguments); |
| 68 va_end(arguments); | 65 va_end(arguments); |
| 69 } | 66 } |
| 70 } | 67 } |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 // Returning to address 0 exits the Simulator. | 422 // Returning to address 0 exits the Simulator. |
| 426 set_lr(kEndOfSimAddress); | 423 set_lr(kEndOfSimAddress); |
| 427 | 424 |
| 428 // Reset debug helpers. | 425 // Reset debug helpers. |
| 429 breakpoints_.empty(); | 426 breakpoints_.empty(); |
| 430 break_on_next_ = false; | 427 break_on_next_ = false; |
| 431 } | 428 } |
| 432 | 429 |
| 433 | 430 |
| 434 Simulator::~Simulator() { | 431 Simulator::~Simulator() { |
| 435 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_); | |
| 436 delete[] reinterpret_cast<byte*>(stack_); | 432 delete[] reinterpret_cast<byte*>(stack_); |
| 437 if (FLAG_log_instruction_stats) { | 433 if (FLAG_log_instruction_stats) { |
| 438 delete instrument_; | 434 delete instrument_; |
| 439 } | 435 } |
| 440 delete disassembler_decoder_; | 436 delete disassembler_decoder_; |
| 441 delete print_disasm_; | 437 delete print_disasm_; |
| 442 DeleteArray(last_debugger_input_); | 438 DeleteArray(last_debugger_input_); |
| 443 delete decoder_; | 439 delete decoder_; |
| 444 } | 440 } |
| 445 | 441 |
| (...skipping 1179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 | 1621 |
| 1626 | 1622 |
| 1627 void Simulator::LoadStoreHelper(Instruction* instr, | 1623 void Simulator::LoadStoreHelper(Instruction* instr, |
| 1628 int64_t offset, | 1624 int64_t offset, |
| 1629 AddrMode addrmode) { | 1625 AddrMode addrmode) { |
| 1630 unsigned srcdst = instr->Rt(); | 1626 unsigned srcdst = instr->Rt(); |
| 1631 unsigned addr_reg = instr->Rn(); | 1627 unsigned addr_reg = instr->Rn(); |
| 1632 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); | 1628 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); |
| 1633 uintptr_t stack = 0; | 1629 uintptr_t stack = 0; |
| 1634 | 1630 |
| 1635 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1636 if (instr->IsLoad()) { | |
| 1637 local_monitor_.NotifyLoad(address); | |
| 1638 } else { | |
| 1639 local_monitor_.NotifyStore(address); | |
| 1640 global_monitor_.Pointer()->NotifyStore_Locked(address, | |
| 1641 &global_monitor_processor_); | |
| 1642 } | |
| 1643 | |
| 1644 // Handle the writeback for stores before the store. On a CPU the writeback | 1631 // Handle the writeback for stores before the store. On a CPU the writeback |
| 1645 // and the store are atomic, but when running on the simulator it is possible | 1632 // and the store are atomic, but when running on the simulator it is possible |
| 1646 // to be interrupted in between. The simulator is not thread safe and V8 does | 1633 // to be interrupted in between. The simulator is not thread safe and V8 does |
| 1647 // not require it to be to run JavaScript therefore the profiler may sample | 1634 // not require it to be to run JavaScript therefore the profiler may sample |
| 1648 // the "simulated" CPU in the middle of load/store with writeback. The code | 1635 // the "simulated" CPU in the middle of load/store with writeback. The code |
| 1649 // below ensures that push operations are safe even when interrupted: the | 1636 // below ensures that push operations are safe even when interrupted: the |
| 1650 // stack pointer will be decremented before adding an element to the stack. | 1637 // stack pointer will be decremented before adding an element to the stack. |
| 1651 if (instr->IsStore()) { | 1638 if (instr->IsStore()) { |
| 1652 LoadStoreWriteBack(addr_reg, offset, addrmode); | 1639 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1653 | 1640 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1736 AddrMode addrmode) { | 1723 AddrMode addrmode) { |
| 1737 unsigned rt = instr->Rt(); | 1724 unsigned rt = instr->Rt(); |
| 1738 unsigned rt2 = instr->Rt2(); | 1725 unsigned rt2 = instr->Rt2(); |
| 1739 unsigned addr_reg = instr->Rn(); | 1726 unsigned addr_reg = instr->Rn(); |
| 1740 size_t access_size = 1 << instr->SizeLSPair(); | 1727 size_t access_size = 1 << instr->SizeLSPair(); |
| 1741 int64_t offset = instr->ImmLSPair() * access_size; | 1728 int64_t offset = instr->ImmLSPair() * access_size; |
| 1742 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); | 1729 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); |
| 1743 uintptr_t address2 = address + access_size; | 1730 uintptr_t address2 = address + access_size; |
| 1744 uintptr_t stack = 0; | 1731 uintptr_t stack = 0; |
| 1745 | 1732 |
| 1746 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1747 if (instr->IsLoad()) { | |
| 1748 local_monitor_.NotifyLoad(address); | |
| 1749 local_monitor_.NotifyLoad(address2); | |
| 1750 } else { | |
| 1751 local_monitor_.NotifyStore(address); | |
| 1752 local_monitor_.NotifyStore(address2); | |
| 1753 global_monitor_.Pointer()->NotifyStore_Locked(address, | |
| 1754 &global_monitor_processor_); | |
| 1755 global_monitor_.Pointer()->NotifyStore_Locked(address2, | |
| 1756 &global_monitor_processor_); | |
| 1757 } | |
| 1758 | |
| 1759 // Handle the writeback for stores before the store. On a CPU the writeback | 1733 // Handle the writeback for stores before the store. On a CPU the writeback |
| 1760 // and the store are atomic, but when running on the simulator it is possible | 1734 // and the store are atomic, but when running on the simulator it is possible |
| 1761 // to be interrupted in between. The simulator is not thread safe and V8 does | 1735 // to be interrupted in between. The simulator is not thread safe and V8 does |
| 1762 // not require it to be to run JavaScript therefore the profiler may sample | 1736 // not require it to be to run JavaScript therefore the profiler may sample |
| 1763 // the "simulated" CPU in the middle of load/store with writeback. The code | 1737 // the "simulated" CPU in the middle of load/store with writeback. The code |
| 1764 // below ensures that push operations are safe even when interrupted: the | 1738 // below ensures that push operations are safe even when interrupted: the |
| 1765 // stack pointer will be decremented before adding an element to the stack. | 1739 // stack pointer will be decremented before adding an element to the stack. |
| 1766 if (instr->IsStore()) { | 1740 if (instr->IsStore()) { |
| 1767 LoadStoreWriteBack(addr_reg, offset, addrmode); | 1741 LoadStoreWriteBack(addr_reg, offset, addrmode); |
| 1768 | 1742 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1872 // Accesses below the stack pointer (but above the platform stack limit) are | 1846 // Accesses below the stack pointer (but above the platform stack limit) are |
| 1873 // not allowed in the ABI. | 1847 // not allowed in the ABI. |
| 1874 CheckMemoryAccess(address, stack); | 1848 CheckMemoryAccess(address, stack); |
| 1875 } | 1849 } |
| 1876 | 1850 |
| 1877 | 1851 |
| 1878 void Simulator::VisitLoadLiteral(Instruction* instr) { | 1852 void Simulator::VisitLoadLiteral(Instruction* instr) { |
| 1879 uintptr_t address = instr->LiteralAddress(); | 1853 uintptr_t address = instr->LiteralAddress(); |
| 1880 unsigned rt = instr->Rt(); | 1854 unsigned rt = instr->Rt(); |
| 1881 | 1855 |
| 1882 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1883 local_monitor_.NotifyLoad(address); | |
| 1884 | |
| 1885 switch (instr->Mask(LoadLiteralMask)) { | 1856 switch (instr->Mask(LoadLiteralMask)) { |
| 1886 // Use _no_log variants to suppress the register trace (LOG_REGS, | 1857 // Use _no_log variants to suppress the register trace (LOG_REGS, |
| 1887 // LOG_FP_REGS), then print a more detailed log. | 1858 // LOG_FP_REGS), then print a more detailed log. |
| 1888 case LDR_w_lit: | 1859 case LDR_w_lit: |
| 1889 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); | 1860 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
| 1890 LogRead(address, kWRegSize, rt); | 1861 LogRead(address, kWRegSize, rt); |
| 1891 break; | 1862 break; |
| 1892 case LDR_x_lit: | 1863 case LDR_x_lit: |
| 1893 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); | 1864 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); |
| 1894 LogRead(address, kXRegSize, rt); | 1865 LogRead(address, kXRegSize, rt); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1928 void Simulator::LoadStoreWriteBack(unsigned addr_reg, | 1899 void Simulator::LoadStoreWriteBack(unsigned addr_reg, |
| 1929 int64_t offset, | 1900 int64_t offset, |
| 1930 AddrMode addrmode) { | 1901 AddrMode addrmode) { |
| 1931 if ((addrmode == PreIndex) || (addrmode == PostIndex)) { | 1902 if ((addrmode == PreIndex) || (addrmode == PostIndex)) { |
| 1932 DCHECK(offset != 0); | 1903 DCHECK(offset != 0); |
| 1933 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); | 1904 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); |
| 1934 set_reg(addr_reg, address + offset, Reg31IsStackPointer); | 1905 set_reg(addr_reg, address + offset, Reg31IsStackPointer); |
| 1935 } | 1906 } |
| 1936 } | 1907 } |
| 1937 | 1908 |
| 1938 Simulator::TransactionSize Simulator::get_transaction_size(unsigned size) { | |
| 1939 switch (size) { | |
| 1940 case 0: | |
| 1941 return TransactionSize::None; | |
| 1942 case 1: | |
| 1943 return TransactionSize::Byte; | |
| 1944 case 2: | |
| 1945 return TransactionSize::HalfWord; | |
| 1946 case 4: | |
| 1947 return TransactionSize::Word; | |
| 1948 default: | |
| 1949 UNREACHABLE(); | |
| 1950 } | |
| 1951 return TransactionSize::None; | |
| 1952 } | |
| 1953 | |
| 1954 void Simulator::VisitLoadStoreAcquireRelease(Instruction* instr) { | 1909 void Simulator::VisitLoadStoreAcquireRelease(Instruction* instr) { |
| 1955 unsigned rs = instr->Rs(); | 1910 // TODO(binji) |
| 1956 unsigned rt = instr->Rt(); | |
| 1957 unsigned rn = instr->Rn(); | |
| 1958 LoadStoreAcquireReleaseOp op = static_cast<LoadStoreAcquireReleaseOp>( | |
| 1959 instr->Mask(LoadStoreAcquireReleaseMask)); | |
| 1960 int32_t is_acquire_release = instr->LoadStoreXAcquireRelease(); | |
| 1961 int32_t is_not_exclusive = instr->LoadStoreXNotExclusive(); | |
| 1962 int32_t is_load = instr->LoadStoreXLoad(); | |
| 1963 int32_t is_pair = instr->LoadStoreXPair(); | |
| 1964 DCHECK_NE(is_acquire_release, 0); | |
| 1965 DCHECK_EQ(is_not_exclusive, 0); // Non exclusive unimplemented. | |
| 1966 DCHECK_EQ(is_pair, 0); // Pair unimplemented. | |
| 1967 unsigned access_size = 1 << instr->LoadStoreXSizeLog2(); | |
| 1968 uintptr_t address = LoadStoreAddress(rn, 0, AddrMode::Offset); | |
| 1969 DCHECK(address % access_size == 0); | |
| 1970 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | |
| 1971 if (is_load != 0) { | |
| 1972 local_monitor_.NotifyLoadExcl(address, get_transaction_size(access_size)); | |
| 1973 global_monitor_.Pointer()->NotifyLoadExcl_Locked( | |
| 1974 address, &global_monitor_processor_); | |
| 1975 switch (op) { | |
| 1976 case LDAXR_b: | |
| 1977 set_wreg_no_log(rt, MemoryRead<uint8_t>(address)); | |
| 1978 break; | |
| 1979 case LDAXR_h: | |
| 1980 set_wreg_no_log(rt, MemoryRead<uint16_t>(address)); | |
| 1981 break; | |
| 1982 case LDAXR_w: | |
| 1983 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); | |
| 1984 break; | |
| 1985 default: | |
| 1986 UNIMPLEMENTED(); | |
| 1987 } | |
| 1988 LogRead(address, access_size, rt); | |
| 1989 } else { | |
| 1990 if (local_monitor_.NotifyStoreExcl(address, | |
| 1991 get_transaction_size(access_size)) && | |
| 1992 global_monitor_.Pointer()->NotifyStoreExcl_Locked( | |
| 1993 address, &global_monitor_processor_)) { | |
| 1994 switch (op) { | |
| 1995 case STLXR_b: | |
| 1996 MemoryWrite<uint8_t>(address, wreg(rt)); | |
| 1997 break; | |
| 1998 case STLXR_h: | |
| 1999 MemoryWrite<uint16_t>(address, wreg(rt)); | |
| 2000 break; | |
| 2001 case STLXR_w: | |
| 2002 MemoryWrite<uint32_t>(address, wreg(rt)); | |
| 2003 break; | |
| 2004 default: | |
| 2005 UNIMPLEMENTED(); | |
| 2006 } | |
| 2007 LogWrite(address, access_size, rt); | |
| 2008 set_wreg(rs, 0); | |
| 2009 } else { | |
| 2010 set_wreg(rs, 1); | |
| 2011 } | |
| 2012 } | |
| 2013 } | 1911 } |
| 2014 | 1912 |
| 2015 void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) { | 1913 void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) { |
| 2016 if ((address >= stack_limit_) && (address < stack)) { | 1914 if ((address >= stack_limit_) && (address < stack)) { |
| 2017 fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); | 1915 fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); |
| 2018 fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", | 1916 fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", |
| 2019 static_cast<uint64_t>(stack)); | 1917 static_cast<uint64_t>(stack)); |
| 2020 fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", | 1918 fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", |
| 2021 static_cast<uint64_t>(address)); | 1919 static_cast<uint64_t>(address)); |
| 2022 fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", | 1920 fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", |
| (...skipping 1949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3972 | 3870 |
| 3973 // The printf parameters are inlined in the code, so skip them. | 3871 // The printf parameters are inlined in the code, so skip them. |
| 3974 set_pc(instr->InstructionAtOffset(kPrintfLength)); | 3872 set_pc(instr->InstructionAtOffset(kPrintfLength)); |
| 3975 | 3873 |
| 3976 // Set LR as if we'd just called a native printf function. | 3874 // Set LR as if we'd just called a native printf function. |
| 3977 set_lr(pc()); | 3875 set_lr(pc()); |
| 3978 | 3876 |
| 3979 delete[] format; | 3877 delete[] format; |
| 3980 } | 3878 } |
| 3981 | 3879 |
| 3982 Simulator::LocalMonitor::LocalMonitor() | |
| 3983 : access_state_(MonitorAccess::Open), | |
| 3984 tagged_addr_(0), | |
| 3985 size_(TransactionSize::None) {} | |
| 3986 | |
| 3987 void Simulator::LocalMonitor::Clear() { | |
| 3988 access_state_ = MonitorAccess::Open; | |
| 3989 tagged_addr_ = 0; | |
| 3990 size_ = TransactionSize::None; | |
| 3991 } | |
| 3992 | |
| 3993 void Simulator::LocalMonitor::NotifyLoad(uintptr_t addr) { | |
| 3994 if (access_state_ == MonitorAccess::Exclusive) { | |
| 3995 // A non exclusive load could clear the local monitor. As a result, it's | |
| 3996 // most strict to unconditionally clear the local monitor on load. | |
| 3997 Clear(); | |
| 3998 } | |
| 3999 } | |
| 4000 | |
| 4001 void Simulator::LocalMonitor::NotifyLoadExcl(uintptr_t addr, | |
| 4002 TransactionSize size) { | |
| 4003 access_state_ = MonitorAccess::Exclusive; | |
| 4004 tagged_addr_ = addr; | |
| 4005 size_ = size; | |
| 4006 } | |
| 4007 | |
| 4008 void Simulator::LocalMonitor::NotifyStore(uintptr_t addr) { | |
| 4009 if (access_state_ == MonitorAccess::Exclusive) { | |
| 4010 // A non exclusive store could clear the local monitor. As a result, it's | |
| 4011 // most strict to unconditionally clear the local monitor on store. | |
| 4012 Clear(); | |
| 4013 } | |
| 4014 } | |
| 4015 | |
| 4016 bool Simulator::LocalMonitor::NotifyStoreExcl(uintptr_t addr, | |
| 4017 TransactionSize size) { | |
| 4018 if (access_state_ == MonitorAccess::Exclusive) { | |
| 4019 // It is allowed for a processor to require that the address matches | |
| 4020 // exactly (B2.10.1), so this comparison does not mask addr. | |
| 4021 if (addr == tagged_addr_ && size_ == size) { | |
| 4022 Clear(); | |
| 4023 return true; | |
| 4024 } else { | |
| 4025 // It is implementation-defined whether an exclusive store to a | |
| 4026 // non-tagged address will update memory. As a result, it's most strict | |
| 4027 // to unconditionally clear the local monitor. | |
| 4028 Clear(); | |
| 4029 return false; | |
| 4030 } | |
| 4031 } else { | |
| 4032 DCHECK(access_state_ == MonitorAccess::Open); | |
| 4033 return false; | |
| 4034 } | |
| 4035 } | |
| 4036 | |
| 4037 Simulator::GlobalMonitor::Processor::Processor() | |
| 4038 : access_state_(MonitorAccess::Open), | |
| 4039 tagged_addr_(0), | |
| 4040 next_(nullptr), | |
| 4041 prev_(nullptr), | |
| 4042 failure_counter_(0) {} | |
| 4043 | |
| 4044 void Simulator::GlobalMonitor::Processor::Clear_Locked() { | |
| 4045 access_state_ = MonitorAccess::Open; | |
| 4046 tagged_addr_ = 0; | |
| 4047 } | |
| 4048 | |
| 4049 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked( | |
| 4050 uintptr_t addr) { | |
| 4051 access_state_ = MonitorAccess::Exclusive; | |
| 4052 tagged_addr_ = addr; | |
| 4053 } | |
| 4054 | |
| 4055 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked( | |
| 4056 uintptr_t addr, bool is_requesting_processor) { | |
| 4057 if (access_state_ == MonitorAccess::Exclusive) { | |
| 4058 // A non exclusive store could clear the global monitor. As a result, it's | |
| 4059 // most strict to unconditionally clear global monitors on store. | |
| 4060 Clear_Locked(); | |
| 4061 } | |
| 4062 } | |
| 4063 | |
| 4064 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked( | |
| 4065 uintptr_t addr, bool is_requesting_processor) { | |
| 4066 if (access_state_ == MonitorAccess::Exclusive) { | |
| 4067 if (is_requesting_processor) { | |
| 4068 // It is allowed for a processor to require that the address matches | |
| 4069 // exactly (B2.10.2), so this comparison does not mask addr. | |
| 4070 if (addr == tagged_addr_) { | |
| 4071 Clear_Locked(); | |
| 4072 // Introduce occasional stxr failures. This is to simulate the | |
| 4073 // behavior of hardware, which can randomly fail due to background | |
| 4074 // cache evictions. | |
| 4075 if (failure_counter_++ >= kMaxFailureCounter) { | |
| 4076 failure_counter_ = 0; | |
| 4077 return false; | |
| 4078 } else { | |
| 4079 return true; | |
| 4080 } | |
| 4081 } | |
| 4082 } else if ((addr & kExclusiveTaggedAddrMask) == | |
| 4083 (tagged_addr_ & kExclusiveTaggedAddrMask)) { | |
| 4084 // Check the masked addresses when responding to a successful lock by | |
| 4085 // another processor so the implementation is more conservative (i.e. the | |
| 4086 // granularity of locking is as large as possible.) | |
| 4087 Clear_Locked(); | |
| 4088 return false; | |
| 4089 } | |
| 4090 } | |
| 4091 return false; | |
| 4092 } | |
| 4093 | |
| 4094 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {} | |
| 4095 | |
| 4096 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(uintptr_t addr, | |
| 4097 Processor* processor) { | |
| 4098 processor->NotifyLoadExcl_Locked(addr); | |
| 4099 PrependProcessor_Locked(processor); | |
| 4100 } | |
| 4101 | |
| 4102 void Simulator::GlobalMonitor::NotifyStore_Locked(uintptr_t addr, | |
| 4103 Processor* processor) { | |
| 4104 // Notify each processor of the store operation. | |
| 4105 for (Processor* iter = head_; iter; iter = iter->next_) { | |
| 4106 bool is_requesting_processor = iter == processor; | |
| 4107 iter->NotifyStore_Locked(addr, is_requesting_processor); | |
| 4108 } | |
| 4109 } | |
| 4110 | |
| 4111 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(uintptr_t addr, | |
| 4112 Processor* processor) { | |
| 4113 DCHECK(IsProcessorInLinkedList_Locked(processor)); | |
| 4114 if (processor->NotifyStoreExcl_Locked(addr, true)) { | |
| 4115 // Notify the other processors that this StoreExcl succeeded. | |
| 4116 for (Processor* iter = head_; iter; iter = iter->next_) { | |
| 4117 if (iter != processor) { | |
| 4118 iter->NotifyStoreExcl_Locked(addr, false); | |
| 4119 } | |
| 4120 } | |
| 4121 return true; | |
| 4122 } else { | |
| 4123 return false; | |
| 4124 } | |
| 4125 } | |
| 4126 | |
| 4127 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked( | |
| 4128 Processor* processor) const { | |
| 4129 return head_ == processor || processor->next_ || processor->prev_; | |
| 4130 } | |
| 4131 | |
| 4132 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) { | |
| 4133 if (IsProcessorInLinkedList_Locked(processor)) { | |
| 4134 return; | |
| 4135 } | |
| 4136 | |
| 4137 if (head_) { | |
| 4138 head_->prev_ = processor; | |
| 4139 } | |
| 4140 processor->prev_ = nullptr; | |
| 4141 processor->next_ = head_; | |
| 4142 head_ = processor; | |
| 4143 } | |
| 4144 | |
| 4145 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) { | |
| 4146 base::LockGuard<base::Mutex> lock_guard(&mutex); | |
| 4147 if (!IsProcessorInLinkedList_Locked(processor)) { | |
| 4148 return; | |
| 4149 } | |
| 4150 | |
| 4151 if (processor->prev_) { | |
| 4152 processor->prev_->next_ = processor->next_; | |
| 4153 } else { | |
| 4154 head_ = processor->next_; | |
| 4155 } | |
| 4156 if (processor->next_) { | |
| 4157 processor->next_->prev_ = processor->prev_; | |
| 4158 } | |
| 4159 processor->prev_ = nullptr; | |
| 4160 processor->next_ = nullptr; | |
| 4161 } | |
| 4162 | 3880 |
| 4163 #endif // USE_SIMULATOR | 3881 #endif // USE_SIMULATOR |
| 4164 | 3882 |
| 4165 } // namespace internal | 3883 } // namespace internal |
| 4166 } // namespace v8 | 3884 } // namespace v8 |
| 4167 | 3885 |
| 4168 #endif // V8_TARGET_ARCH_ARM64 | 3886 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |