- 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:
iposva@google.com
2014-10-27 19:21:33 +00:00
parent 36e340dea1
commit 55357d2993
14 changed files with 392 additions and 55 deletions
+7
View File
@@ -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
View File
@@ -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)
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+25
View File
@@ -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_
+2
View File
@@ -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
View File
@@ -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;
+2 -1
View File
@@ -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 {
+105
View File
@@ -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",
+41 -2
View File
@@ -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);
+101
View File
@@ -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;
+40 -1
View File
@@ -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);
+1
View File
@@ -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',