From 55357d2993263bd0ccb9b6ec52dcb07fa0f53444 Mon Sep 17 00:00:00 2001 From: "iposva@google.com" Date: Mon, 27 Oct 2014 19:21:33 +0000 Subject: [PATCH] - Use the simulator to do atomic operations that could also be executed in generated code. R=koda@google.com, zra@google.com Review URL: https://codereview.chromium.org//677193002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@41332 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/CPPLINT.cfg | 7 +++ runtime/vm/atomic.h | 8 +++ runtime/vm/atomic_android.h | 2 + runtime/vm/atomic_linux.h | 2 + runtime/vm/atomic_macos.h | 2 + runtime/vm/atomic_simulator.h | 25 ++++++++ runtime/vm/atomic_win.h | 2 + runtime/vm/simulator_arm.cc | 105 +++++++++++++++++----------------- runtime/vm/simulator_arm.h | 3 +- runtime/vm/simulator_arm64.cc | 105 ++++++++++++++++++++++++++++++++++ runtime/vm/simulator_arm64.h | 43 +++++++++++++- runtime/vm/simulator_mips.cc | 101 ++++++++++++++++++++++++++++++++ runtime/vm/simulator_mips.h | 41 ++++++++++++- runtime/vm/vm_sources.gypi | 1 + 14 files changed, 392 insertions(+), 55 deletions(-) create mode 100644 runtime/CPPLINT.cfg create mode 100644 runtime/vm/atomic_simulator.h diff --git a/runtime/CPPLINT.cfg b/runtime/CPPLINT.cfg new file mode 100644 index 00000000000..64aa482f95c --- /dev/null +++ b/runtime/CPPLINT.cfg @@ -0,0 +1,7 @@ +# Do not continue looking up the directory hierarchy +# for more config files. +set noparent + +# Do not limit function size. For example parts of +# the simulator are really large. +filter=-readability/fn_size diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h index 85ef8463525..c256fe5e0a4 100644 --- a/runtime/vm/atomic.h +++ b/runtime/vm/atomic.h @@ -8,6 +8,7 @@ #include "platform/globals.h" #include "vm/allocation.h" +#include "vm/simulator.h" namespace dart { @@ -15,6 +16,9 @@ class AtomicOperations : public AllStatic { public: // Atomically fetch the value at p and increment the value at p. // Returns the original value at p. + // + // NOTE: Not to be used for any atomic operations involving memory locations + // that are accessed by generated code static uintptr_t FetchAndIncrement(uintptr_t* p); static uword CompareAndSwapWord(uword* ptr, uword old_value, uword new_value); @@ -23,6 +27,10 @@ class AtomicOperations : public AllStatic { } // namespace dart +// We need to use the simulator to ensure that atomic operations are observed +// both in C++ and in generated code if the simulator is active. +#include "vm/atomic_simulator.h" + #if defined(TARGET_OS_ANDROID) #include "vm/atomic_android.h" #elif defined(TARGET_OS_LINUX) diff --git a/runtime/vm/atomic_android.h b/runtime/vm/atomic_android.h index a0414090d63..06208f2293d 100644 --- a/runtime/vm/atomic_android.h +++ b/runtime/vm/atomic_android.h @@ -21,11 +21,13 @@ inline uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) { } +#if !defined(USING_SIMULATOR) inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, uword old_value, uword new_value) { return __sync_val_compare_and_swap(ptr, old_value, new_value); } +#endif // !defined(USING_SIMULATOR) } // namespace dart diff --git a/runtime/vm/atomic_linux.h b/runtime/vm/atomic_linux.h index da7102b4b18..9789ae593d1 100644 --- a/runtime/vm/atomic_linux.h +++ b/runtime/vm/atomic_linux.h @@ -21,11 +21,13 @@ inline uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) { } +#if !defined(USING_SIMULATOR) inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, uword old_value, uword new_value) { return __sync_val_compare_and_swap(ptr, old_value, new_value); } +#endif // !defined(USING_SIMULATOR) } // namespace dart diff --git a/runtime/vm/atomic_macos.h b/runtime/vm/atomic_macos.h index 649384a6ffa..288fe3cbcdf 100644 --- a/runtime/vm/atomic_macos.h +++ b/runtime/vm/atomic_macos.h @@ -21,11 +21,13 @@ inline uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) { } +#if !defined(USING_SIMULATOR) inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, uword old_value, uword new_value) { return __sync_val_compare_and_swap(ptr, old_value, new_value); } +#endif // !defined(USING_SIMULATOR) } // namespace dart diff --git a/runtime/vm/atomic_simulator.h b/runtime/vm/atomic_simulator.h new file mode 100644 index 00000000000..26cde3c668a --- /dev/null +++ b/runtime/vm/atomic_simulator.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef VM_ATOMIC_SIMULATOR_H_ +#define VM_ATOMIC_SIMULATOR_H_ + +#if !defined VM_ATOMIC_H_ +#error Do not include atomic_simulator.h directly. Use atomic.h instead. +#endif + +namespace dart { + +#if defined(USING_SIMULATOR) +// Forward atomic operations to the simulator if the simulator is active. +inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, + uword old_value, + uword new_value) { + return Simulator::CompareExchange(ptr, old_value, new_value); +} +#endif // defined(USING_SIMULATOR) + +} // namespace dart + +#endif // VM_ATOMIC_SIMULATOR_H_ diff --git a/runtime/vm/atomic_win.h b/runtime/vm/atomic_win.h index 6124803d48b..24be3b12c8b 100644 --- a/runtime/vm/atomic_win.h +++ b/runtime/vm/atomic_win.h @@ -28,6 +28,7 @@ inline uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) { } +#if !defined(USING_SIMULATOR) inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, uword old_value, uword new_value) { @@ -45,6 +46,7 @@ inline uword AtomicOperations::CompareAndSwapWord(uword* ptr, UNIMPLEMENTED(); #endif } +#endif // !defined(USING_SIMULATOR) } // namespace dart diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index 17810a1c9d6..399079c9efd 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc @@ -678,55 +678,14 @@ char* SimulatorDebugger::ReadLine(const char* prompt) { // Synchronization primitives support. Mutex* Simulator::exclusive_access_lock_ = NULL; -Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags]; -int Simulator::next_address_tag_; - - -void Simulator::SetExclusiveAccess(uword addr) { - Isolate* isolate = Isolate::Current(); - ASSERT(isolate != NULL); - int i = 0; - while ((i < kNumAddressTags) && - (exclusive_access_state_[i].isolate != isolate)) { - i++; - } - if (i == kNumAddressTags) { - i = next_address_tag_; - if (++next_address_tag_ == kNumAddressTags) next_address_tag_ = 0; - exclusive_access_state_[i].isolate = isolate; - } - exclusive_access_state_[i].addr = addr; -} - - -bool Simulator::HasExclusiveAccessAndOpen(uword addr) { - Isolate* isolate = Isolate::Current(); - ASSERT(isolate != NULL); - bool result = false; - for (int i = 0; i < kNumAddressTags; i++) { - if (exclusive_access_state_[i].isolate == isolate) { - if (exclusive_access_state_[i].addr == addr) { - result = true; - } - exclusive_access_state_[i].addr = NULL; - continue; - } - if (exclusive_access_state_[i].addr == addr) { - exclusive_access_state_[i].addr = NULL; - } - } - return result; -} +Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = + {{NULL, 0}}; +int Simulator::next_address_tag_ = 0; void Simulator::InitOnce() { - // Setup exclusive access state. + // Setup exclusive access state lock. exclusive_access_lock_ = new Mutex(); - for (int i = 0; i < kNumAddressTags; i++) { - exclusive_access_state_[i].isolate = NULL; - exclusive_access_state_[i].addr = NULL; - } - next_address_tag_ = 0; } @@ -1112,16 +1071,59 @@ void Simulator::WriteB(uword addr, uint8_t value) { // Synchronization primitives support. +void Simulator::SetExclusiveAccess(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate); + int i = 0; + // Find an entry for this isolate in the exclusive access state. + while ((i < kNumAddressTags) && + (exclusive_access_state_[i].isolate != isolate)) { + i++; + } + // Round-robin replacement of previously used entries. + if (i == kNumAddressTags) { + i = next_address_tag_; + if (++next_address_tag_ == kNumAddressTags) { + next_address_tag_ = 0; + } + exclusive_access_state_[i].isolate = isolate; + } + // Remember the address being reserved. + exclusive_access_state_[i].addr = addr; +} + + +bool Simulator::HasExclusiveAccessAndOpen(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + ASSERT(addr != 0); + DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate); + bool result = false; + for (int i = 0; i < kNumAddressTags; i++) { + if (exclusive_access_state_[i].isolate == isolate) { + // Check whether the current isolate's address reservation matches. + if (exclusive_access_state_[i].addr == addr) { + result = true; + } + exclusive_access_state_[i].addr = 0; + } else if (exclusive_access_state_[i].addr == addr) { + // Other isolates with matching address lose their reservations. + exclusive_access_state_[i].addr = 0; + } + } + return result; +} + + void Simulator::ClearExclusive() { - // This lock is initialized in Simulator::InitOnce(). MutexLocker ml(exclusive_access_lock_); - // Set exclusive access to open state for this isolate. - HasExclusiveAccessAndOpen(NULL); + // Remove the reservation for this isolate. + SetExclusiveAccess(NULL); } intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { - // This lock is initialized in Simulator::InitOnce(). MutexLocker ml(exclusive_access_lock_); SetExclusiveAccess(addr); return ReadW(addr, instr); @@ -1129,7 +1131,6 @@ intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { - // This lock is initialized in Simulator::InitOnce(). MutexLocker ml(exclusive_access_lock_); bool write_allowed = HasExclusiveAccessAndOpen(addr); if (write_allowed) { @@ -1143,8 +1144,10 @@ intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { uword Simulator::CompareExchange(uword* address, uword compare_value, uword new_value) { - // This lock is initialized in Simulator::InitOnce(). MutexLocker ml(exclusive_access_lock_); + // We do not get a reservation as it would be guaranteed to be found when + // writing below. No other isolate is able to make a reservation while we + // hold the lock. uword value = *address; if (value == compare_value) { *address = new_value; diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h index 5136aba6a0d..b858b00fe8d 100644 --- a/runtime/vm/simulator_arm.h +++ b/runtime/vm/simulator_arm.h @@ -17,11 +17,12 @@ #endif #include "vm/constants_arm.h" -#include "vm/object.h" namespace dart { class Isolate; +class Mutex; +class RawObject; class SimulatorSetjmpBuffer; typedef struct { diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc index 6607c53b4d0..dedb0d2bd72 100644 --- a/runtime/vm/simulator_arm64.cc +++ b/runtime/vm/simulator_arm64.cc @@ -17,6 +17,7 @@ #include "vm/constants_arm64.h" #include "vm/cpu.h" #include "vm/disassembler.h" +#include "vm/lockers.h" #include "vm/native_arguments.h" #include "vm/stack_frame.h" #include "vm/thread.h" @@ -529,6 +530,19 @@ char* SimulatorDebugger::ReadLine(const char* prompt) { } +// Synchronization primitives support. +Mutex* Simulator::exclusive_access_lock_ = NULL; +Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = + {{NULL, 0}}; +int Simulator::next_address_tag_ = 0; + + +void Simulator::InitOnce() { + // Setup exclusive access state lock. + exclusive_access_lock_ = new Mutex(); +} + + Simulator::Simulator() { // Setup simulator support first. Some of this information is needed to // setup the architecture state. @@ -923,6 +937,97 @@ void Simulator::WriteB(uword addr, uint8_t value) { } +// Synchronization primitives support. +void Simulator::SetExclusiveAccess(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + ASSERT(exclusive_access_lock_->Owner() == isolate); + int i = 0; + // Find an entry for this isolate in the exclusive access state. + while ((i < kNumAddressTags) && + (exclusive_access_state_[i].isolate != isolate)) { + i++; + } + // Round-robin replacement of previously used entries. + if (i == kNumAddressTags) { + i = next_address_tag_; + if (++next_address_tag_ == kNumAddressTags) { + next_address_tag_ = 0; + } + exclusive_access_state_[i].isolate = isolate; + } + // Remember the address being reserved. + exclusive_access_state_[i].addr = addr; +} + + +bool Simulator::HasExclusiveAccessAndOpen(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + ASSERT(addr != 0); + ASSERT(exclusive_access_lock_->Owner() == isolate); + bool result = false; + for (int i = 0; i < kNumAddressTags; i++) { + if (exclusive_access_state_[i].isolate == isolate) { + // Check whether the current isolates address reservation matches. + if (exclusive_access_state_[i].addr == addr) { + result = true; + } + exclusive_access_state_[i].addr = 0; + } else if (exclusive_access_state_[i].addr == addr) { + // Other isolates with matching address lose their reservations. + exclusive_access_state_[i].addr = 0; + } + } + return result; +} + + +void Simulator::ClearExclusive() { + MutexLocker ml(exclusive_access_lock_); + // Remove the reservation for this isolate. + SetExclusiveAccess(NULL); +} + + +intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { + MutexLocker ml(exclusive_access_lock_); + SetExclusiveAccess(addr); + return ReadW(addr, instr); +} + + +intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { + MutexLocker ml(exclusive_access_lock_); + bool write_allowed = HasExclusiveAccessAndOpen(addr); + if (write_allowed) { + WriteW(addr, value, instr); + return 0; // Success. + } + return 1; // Failure. +} + + +uword Simulator::CompareExchange(uword* address, + uword compare_value, + uword new_value) { + MutexLocker ml(exclusive_access_lock_); + // We do not get a reservation as it would be guaranteed to be found when + // writing below. No other isolate is able to make a reservation while we + // hold the lock. + uword value = *address; + if (value == compare_value) { + *address = new_value; + // Same effect on exclusive access state as a successful STREX. + HasExclusiveAccessAndOpen(reinterpret_cast(address)); + } else { + // Same effect on exclusive access state as an LDREX. + SetExclusiveAccess(reinterpret_cast(address)); + } + return value; +} + + // Unsupported instructions use Format to print an error and stop execution. void Simulator::Format(Instr* instr, const char* format) { OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h index b63975aab4b..be1679d1651 100644 --- a/runtime/vm/simulator_arm64.h +++ b/runtime/vm/simulator_arm64.h @@ -17,11 +17,12 @@ #endif #include "vm/constants_arm64.h" -#include "vm/object.h" namespace dart { class Isolate; +class Mutex; +class RawObject; class SimulatorSetjmpBuffer; typedef struct { @@ -77,7 +78,7 @@ class Simulator { void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; } // Call on program start. - static void InitOnce() {} + static void InitOnce(); // Dart generally calls into generated code with 5 parameters. This is a // convenience function, which sets up the simulator state and grabs the @@ -91,6 +92,12 @@ class Simulator { bool fp_return = false, bool fp_args = false); + // Implementation of atomic compare and exchange in the same synchronization + // domain as other synchronization primitive instructions (e.g. ldrex, strex). + static uword CompareExchange(uword* address, + uword compare_value, + uword new_value); + // Runtime and native call support. enum CallKind { kRuntimeCall, @@ -173,6 +180,38 @@ class Simulator { inline intptr_t ReadX(uword addr, Instr* instr); inline void WriteX(uword addr, intptr_t value, Instr* instr); + // In Dart, there is at most one thread per isolate. + // We keep track of 16 exclusive access address tags across all isolates. + // Since we cannot simulate a native context switch, which clears + // the exclusive access state of the local monitor (using the CLREX + // instruction), we associate the isolate requesting exclusive access to the + // address tag. Multiple isolates requesting exclusive access (using the LDREX + // instruction) to the same address will result in multiple address tags being + // created for the same address, one per isolate. + // At any given time, each isolate is associated to at most one address tag. + static Mutex* exclusive_access_lock_; + static const int kNumAddressTags = 16; + static struct AddressTag { + Isolate* isolate; + uword addr; + } exclusive_access_state_[kNumAddressTags]; + static int next_address_tag_; + + // Synchronization primitives support. + void ClearExclusive(); + intptr_t ReadExclusiveW(uword addr, Instr* instr); + intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr); + + // Set access to given address to 'exclusive state' for current isolate. + static void SetExclusiveAccess(uword addr); + + // Returns true if the current isolate has exclusive access to given address, + // returns false otherwise. In either case, set access to given address to + // 'open state' for all isolates. + // If given addr is NULL, set access to 'open state' for current + // isolate (CLREX). + static bool HasExclusiveAccessAndOpen(uword addr); + // Helper functions to set the conditional flags in the architecture state. void SetNZFlagsW(int32_t val); bool CarryFromW(int32_t left, int32_t right, int32_t carry); diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc index 36019a08a2a..f9b192d2ec0 100644 --- a/runtime/vm/simulator_mips.cc +++ b/runtime/vm/simulator_mips.cc @@ -16,6 +16,7 @@ #include "vm/assembler.h" #include "vm/constants_mips.h" #include "vm/disassembler.h" +#include "vm/lockers.h" #include "vm/native_arguments.h" #include "vm/thread.h" @@ -558,7 +559,16 @@ char* SimulatorDebugger::ReadLine(const char* prompt) { } +// Synchronization primitives support. +Mutex* Simulator::exclusive_access_lock_ = NULL; +Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = + {{NULL, 0}}; +int Simulator::next_address_tag_ = 0; + + void Simulator::InitOnce() { + // Setup exclusive access state lock. + exclusive_access_lock_ = new Mutex(); } @@ -943,6 +953,97 @@ void Simulator::WriteD(uword addr, double value, Instr* instr) { } +// Synchronization primitives support. +void Simulator::SetExclusiveAccess(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + ASSERT(exclusive_access_lock_->Owner() == isolate); + int i = 0; + // Find an entry for this isolate in the exclusive access state. + while ((i < kNumAddressTags) && + (exclusive_access_state_[i].isolate != isolate)) { + i++; + } + // Round-robin replacement of previously used entries. + if (i == kNumAddressTags) { + i = next_address_tag_; + if (++next_address_tag_ == kNumAddressTags) { + next_address_tag_ = 0; + } + exclusive_access_state_[i].isolate = isolate; + } + // Remember the address being reserved. + exclusive_access_state_[i].addr = addr; +} + + +bool Simulator::HasExclusiveAccessAndOpen(uword addr) { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate != NULL); + ASSERT(addr != 0); + ASSERT(exclusive_access_lock_->Owner() == isolate); + bool result = false; + for (int i = 0; i < kNumAddressTags; i++) { + if (exclusive_access_state_[i].isolate == isolate) { + // Check whether the current isolates address reservation matches. + if (exclusive_access_state_[i].addr == addr) { + result = true; + } + exclusive_access_state_[i].addr = 0; + } else if (exclusive_access_state_[i].addr == addr) { + // Other isolates with matching address lose their reservations. + exclusive_access_state_[i].addr = 0; + } + } + return result; +} + + +void Simulator::ClearExclusive() { + MutexLocker ml(exclusive_access_lock_); + // Remove the reservation for this isolate. + SetExclusiveAccess(NULL); +} + + +intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { + MutexLocker ml(exclusive_access_lock_); + SetExclusiveAccess(addr); + return ReadW(addr, instr); +} + + +intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { + MutexLocker ml(exclusive_access_lock_); + bool write_allowed = HasExclusiveAccessAndOpen(addr); + if (write_allowed) { + WriteW(addr, value, instr); + return 0; // Success. + } + return 1; // Failure. +} + + +uword Simulator::CompareExchange(uword* address, + uword compare_value, + uword new_value) { + MutexLocker ml(exclusive_access_lock_); + // We do not get a reservation as it would be guaranteed to be found when + // writing below. No other isolate is able to make a reservation while we + // hold the lock. + uword value = *address; + if (value == compare_value) { + *address = new_value; + // Same effect on exclusive access state as a successful SC. + HasExclusiveAccessAndOpen(reinterpret_cast(address)); + } else { + // Same effect on exclusive access state as an LL. + SetExclusiveAccess(reinterpret_cast(address)); + } + return value; +} + + bool Simulator::OverflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition) { bool overflow; diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h index 45f45d8eca3..1df5523c0c4 100644 --- a/runtime/vm/simulator_mips.h +++ b/runtime/vm/simulator_mips.h @@ -17,11 +17,12 @@ #endif #include "vm/constants_mips.h" -#include "vm/object.h" namespace dart { class Isolate; +class Mutex; +class RawObject; class SimulatorSetjmpBuffer; class Simulator { @@ -110,6 +111,12 @@ class Simulator { bool fp_return = false, bool fp_args = false); + // Implementation of atomic compare and exchange in the same synchronization + // domain as other synchronization primitive instructions (e.g. ldrex, strex). + static uword CompareExchange(uword* address, + uword compare_value, + uword new_value); + // Runtime and native call support. enum CallKind { kRuntimeCall, @@ -190,6 +197,38 @@ class Simulator { inline double ReadD(uword addr, Instr* instr); inline void WriteD(uword addr, double value, Instr* instr); + // In Dart, there is at most one thread per isolate. + // We keep track of 16 exclusive access address tags across all isolates. + // Since we cannot simulate a native context switch, which clears + // the exclusive access state of the local monitor, we associate the isolate + // requesting exclusive access to the address tag. + // Multiple isolates requesting exclusive access (using the LL instruction) + // to the same address will result in multiple address tags being created for + // the same address, one per isolate. + // At any given time, each isolate is associated to at most one address tag. + static Mutex* exclusive_access_lock_; + static const int kNumAddressTags = 16; + static struct AddressTag { + Isolate* isolate; + uword addr; + } exclusive_access_state_[kNumAddressTags]; + static int next_address_tag_; + + // Synchronization primitives support. + void ClearExclusive(); + intptr_t ReadExclusiveW(uword addr, Instr* instr); + intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr); + + // Set access to given address to 'exclusive state' for current isolate. + static void SetExclusiveAccess(uword addr); + + // Returns true if the current isolate has exclusive access to given address, + // returns false otherwise. In either case, set access to given address to + // 'open state' for all isolates. + // If given addr is NULL, set access to 'open state' for current + // isolate (CLREX). + static bool HasExclusiveAccessAndOpen(uword addr); + void DoBranch(Instr* instr, bool taken, bool likely); void DoBreak(Instr *instr); diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi index 30915cd9c5d..a490cdd6b3c 100644 --- a/runtime/vm/vm_sources.gypi +++ b/runtime/vm/vm_sources.gypi @@ -40,6 +40,7 @@ 'atomic_android.h', 'atomic_linux.h', 'atomic_macos.h', + 'atomic_simulator.h', 'atomic_win.h', 'base_isolate.h', 'benchmark_test.cc',