- 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
This commit is contained in:
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
|
||||
+54
-51
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<uword>(address));
|
||||
} else {
|
||||
// Same effect on exclusive access state as an LDREX.
|
||||
SetExclusiveAccess(reinterpret_cast<uword>(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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<uword>(address));
|
||||
} else {
|
||||
// Same effect on exclusive access state as an LL.
|
||||
SetExclusiveAccess(reinterpret_cast<uword>(address));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
bool Simulator::OverflowFrom(int32_t alu_out,
|
||||
int32_t left, int32_t right, bool addition) {
|
||||
bool overflow;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user