| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <setjmp.h> // NOLINT | 5 #include <setjmp.h> // NOLINT |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 | 7 |
| 8 #include "vm/globals.h" | 8 #include "vm/globals.h" |
| 9 #if defined(TARGET_ARCH_ARM) | 9 #if defined(TARGET_ARCH_ARM) |
| 10 | 10 |
| 11 // Only build the simulator if not compiling for real ARM hardware. | 11 // Only build the simulator if not compiling for real ARM hardware. |
| 12 #if defined(USING_SIMULATOR) | 12 #if defined(USING_SIMULATOR) |
| 13 | 13 |
| 14 #include "vm/simulator.h" | 14 #include "vm/simulator.h" |
| 15 | 15 |
| 16 #include "vm/assembler.h" | 16 #include "vm/assembler.h" |
| 17 #include "vm/constants_arm.h" | 17 #include "vm/constants_arm.h" |
| 18 #include "vm/cpu.h" | 18 #include "vm/cpu.h" |
| 19 #include "vm/disassembler.h" | 19 #include "vm/disassembler.h" |
| 20 #include "vm/lockers.h" |
| 20 #include "vm/native_arguments.h" | 21 #include "vm/native_arguments.h" |
| 21 #include "vm/os_thread.h" | 22 #include "vm/os_thread.h" |
| 22 #include "vm/stack_frame.h" | 23 #include "vm/stack_frame.h" |
| 23 | 24 |
| 24 namespace dart { | 25 namespace dart { |
| 25 | 26 |
| 26 DEFINE_FLAG(uint64_t, | 27 DEFINE_FLAG(uint64_t, |
| 27 trace_sim_after, | 28 trace_sim_after, |
| 28 ULLONG_MAX, | 29 ULLONG_MAX, |
| 29 "Trace simulator execution after instruction count reached."); | 30 "Trace simulator execution after instruction count reached."); |
| (...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 } | 652 } |
| 652 // Copy the newly read line into the result. | 653 // Copy the newly read line into the result. |
| 653 memmove(result + offset, line_buf, len); | 654 memmove(result + offset, line_buf, len); |
| 654 offset += len; | 655 offset += len; |
| 655 } | 656 } |
| 656 ASSERT(result != NULL); | 657 ASSERT(result != NULL); |
| 657 result[offset] = '\0'; | 658 result[offset] = '\0'; |
| 658 return result; | 659 return result; |
| 659 } | 660 } |
| 660 | 661 |
| 662 // Synchronization primitives support. |
| 663 Mutex* Simulator::exclusive_access_lock_ = NULL; |
| 664 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = { |
| 665 {NULL, 0}}; |
| 666 int Simulator::next_address_tag_ = 0; |
| 667 |
| 661 void Simulator::InitOnce() { | 668 void Simulator::InitOnce() { |
| 669 // Setup exclusive access state lock. |
| 670 exclusive_access_lock_ = new Mutex(); |
| 662 } | 671 } |
| 663 | 672 |
| 664 Simulator::Simulator() : exclusive_access_addr_(0), exclusive_access_value_(0) { | 673 Simulator::Simulator() { |
| 665 // Setup simulator support first. Some of this information is needed to | 674 // Setup simulator support first. Some of this information is needed to |
| 666 // setup the architecture state. | 675 // setup the architecture state. |
| 667 // We allocate the stack here, the size is computed as the sum of | 676 // We allocate the stack here, the size is computed as the sum of |
| 668 // the size specified by the user and the buffer space needed for | 677 // the size specified by the user and the buffer space needed for |
| 669 // handling stack overflow exceptions. To be safe in potential | 678 // handling stack overflow exceptions. To be safe in potential |
| 670 // stack underflows we also add some underflow buffer space. | 679 // stack underflows we also add some underflow buffer space. |
| 671 stack_ = | 680 stack_ = |
| 672 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + | 681 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + |
| 673 kSimulatorStackUnderflowSize)]; | 682 kSimulatorStackUnderflowSize)]; |
| 674 pc_modified_ = false; | 683 pc_modified_ = false; |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 int8_t Simulator::ReadB(uword addr) { | 1017 int8_t Simulator::ReadB(uword addr) { |
| 1009 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 1018 int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
| 1010 return *ptr; | 1019 return *ptr; |
| 1011 } | 1020 } |
| 1012 | 1021 |
| 1013 void Simulator::WriteB(uword addr, uint8_t value) { | 1022 void Simulator::WriteB(uword addr, uint8_t value) { |
| 1014 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | 1023 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
| 1015 *ptr = value; | 1024 *ptr = value; |
| 1016 } | 1025 } |
| 1017 | 1026 |
| 1027 // Synchronization primitives support. |
| 1028 void Simulator::SetExclusiveAccess(uword addr) { |
| 1029 Thread* thread = Thread::Current(); |
| 1030 ASSERT(thread != NULL); |
| 1031 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread()); |
| 1032 int i = 0; |
| 1033 // Find an entry for this thread in the exclusive access state. |
| 1034 while ((i < kNumAddressTags) && |
| 1035 (exclusive_access_state_[i].thread != thread)) { |
| 1036 i++; |
| 1037 } |
| 1038 // Round-robin replacement of previously used entries. |
| 1039 if (i == kNumAddressTags) { |
| 1040 i = next_address_tag_; |
| 1041 if (++next_address_tag_ == kNumAddressTags) { |
| 1042 next_address_tag_ = 0; |
| 1043 } |
| 1044 exclusive_access_state_[i].thread = thread; |
| 1045 } |
| 1046 // Remember the address being reserved. |
| 1047 exclusive_access_state_[i].addr = addr; |
| 1048 } |
| 1049 |
| 1050 bool Simulator::HasExclusiveAccessAndOpen(uword addr) { |
| 1051 Thread* thread = Thread::Current(); |
| 1052 ASSERT(thread != NULL); |
| 1053 ASSERT(addr != 0); |
| 1054 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread()); |
| 1055 bool result = false; |
| 1056 for (int i = 0; i < kNumAddressTags; i++) { |
| 1057 if (exclusive_access_state_[i].thread == thread) { |
| 1058 // Check whether the current thread's address reservation matches. |
| 1059 if (exclusive_access_state_[i].addr == addr) { |
| 1060 result = true; |
| 1061 } |
| 1062 exclusive_access_state_[i].addr = 0; |
| 1063 } else if (exclusive_access_state_[i].addr == addr) { |
| 1064 // Other threads with matching address lose their reservations. |
| 1065 exclusive_access_state_[i].addr = 0; |
| 1066 } |
| 1067 } |
| 1068 return result; |
| 1069 } |
| 1070 |
| 1018 void Simulator::ClearExclusive() { | 1071 void Simulator::ClearExclusive() { |
| 1019 exclusive_access_addr_ = 0; | 1072 MutexLocker ml(exclusive_access_lock_); |
| 1020 exclusive_access_value_ = 0; | 1073 // Remove the reservation for this thread. |
| 1074 SetExclusiveAccess(0); |
| 1021 } | 1075 } |
| 1022 | 1076 |
| 1023 intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { | 1077 intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { |
| 1024 exclusive_access_addr_ = addr; | 1078 MutexLocker ml(exclusive_access_lock_); |
| 1025 exclusive_access_value_ = ReadW(addr, instr); | 1079 SetExclusiveAccess(addr); |
| 1026 return exclusive_access_value_; | 1080 return ReadW(addr, instr); |
| 1027 } | 1081 } |
| 1028 | 1082 |
| 1029 intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { | 1083 intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { |
| 1030 // In a well-formed code store-exclusive instruction should always follow | 1084 MutexLocker ml(exclusive_access_lock_); |
| 1031 // a corresponding load-exclusive instruction with the same address. | 1085 bool write_allowed = HasExclusiveAccessAndOpen(addr); |
| 1032 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr)); | 1086 if (write_allowed) { |
| 1033 if (exclusive_access_addr_ != addr) { | 1087 WriteW(addr, value, instr); |
| 1034 return 1; // Failure. | |
| 1035 } | |
| 1036 | |
| 1037 uword old_value = exclusive_access_value_; | |
| 1038 ClearExclusive(); | |
| 1039 | |
| 1040 if (AtomicOperations::CompareAndSwapWord(reinterpret_cast<uword*>(addr), | |
| 1041 old_value, value) == old_value) { | |
| 1042 return 0; // Success. | 1088 return 0; // Success. |
| 1043 } | 1089 } |
| 1044 return 1; // Failure. | 1090 return 1; // Failure. |
| 1045 } | 1091 } |
| 1046 | 1092 |
| 1093 uword Simulator::CompareExchange(uword* address, |
| 1094 uword compare_value, |
| 1095 uword new_value) { |
| 1096 MutexLocker ml(exclusive_access_lock_); |
| 1097 // We do not get a reservation as it would be guaranteed to be found when |
| 1098 // writing below. No other thread is able to make a reservation while we |
| 1099 // hold the lock. |
| 1100 uword value = *address; |
| 1101 if (value == compare_value) { |
| 1102 *address = new_value; |
| 1103 // Same effect on exclusive access state as a successful STREX. |
| 1104 HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address)); |
| 1105 } else { |
| 1106 // Same effect on exclusive access state as an LDREX. |
| 1107 SetExclusiveAccess(reinterpret_cast<uword>(address)); |
| 1108 } |
| 1109 return value; |
| 1110 } |
| 1111 |
| 1112 uint32_t Simulator::CompareExchangeUint32(uint32_t* address, |
| 1113 uint32_t compare_value, |
| 1114 uint32_t new_value) { |
| 1115 COMPILE_ASSERT(sizeof(uword) == sizeof(uint32_t)); |
| 1116 return CompareExchange(reinterpret_cast<uword*>(address), |
| 1117 static_cast<uword>(compare_value), |
| 1118 static_cast<uword>(new_value)); |
| 1119 } |
| 1120 |
| 1047 // Returns the top of the stack area to enable checking for stack pointer | 1121 // Returns the top of the stack area to enable checking for stack pointer |
| 1048 // validity. | 1122 // validity. |
| 1049 uword Simulator::StackTop() const { | 1123 uword Simulator::StackTop() const { |
| 1050 // To be safe in potential stack underflows we leave some buffer above and | 1124 // To be safe in potential stack underflows we leave some buffer above and |
| 1051 // set the stack top. | 1125 // set the stack top. |
| 1052 return StackBase() + | 1126 return StackBase() + |
| 1053 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); | 1127 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); |
| 1054 } | 1128 } |
| 1055 | 1129 |
| 1056 bool Simulator::IsTracingExecution() const { | 1130 bool Simulator::IsTracingExecution() const { |
| (...skipping 2699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3756 set_register(CODE_REG, code); | 3830 set_register(CODE_REG, code); |
| 3757 set_register(PP, pp); | 3831 set_register(PP, pp); |
| 3758 buf->Longjmp(); | 3832 buf->Longjmp(); |
| 3759 } | 3833 } |
| 3760 | 3834 |
| 3761 } // namespace dart | 3835 } // namespace dart |
| 3762 | 3836 |
| 3763 #endif // defined(USING_SIMULATOR) | 3837 #endif // defined(USING_SIMULATOR) |
| 3764 | 3838 |
| 3765 #endif // defined TARGET_ARCH_ARM | 3839 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |