blob: 2b2d343e94f419e3a95eae2745efe4f669e25254 [file] [log] [blame]
// Copyright (c) 2015, 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_THREAD_H_
#define VM_THREAD_H_
#include "vm/globals.h"
#include "vm/os_thread.h"
#include "vm/store_buffer.h"
namespace dart {
class CHA;
class HandleScope;
class Heap;
class Isolate;
class Object;
class RawBool;
class RawObject;
class StackResource;
class Zone;
// List of VM-global objects/addresses cached in each Thread object.
#define CACHED_VM_OBJECTS_LIST(V) \
V(RawObject*, object_null_, Object::null(), NULL) \
V(RawBool*, bool_true_, Object::bool_true().raw(), NULL) \
V(RawBool*, bool_false_, Object::bool_false().raw(), NULL) \
#define CACHED_ADDRESSES_LIST(V) \
V(uword, update_store_buffer_entry_point_, \
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)
#define CACHED_CONSTANTS_LIST(V) \
CACHED_VM_OBJECTS_LIST(V) \
CACHED_ADDRESSES_LIST(V)
// A VM thread; may be executing Dart code or performing helper tasks like
// garbage collection or compilation. The Thread structure associated with
// a thread is allocated by EnsureInit before entering an isolate, and destroyed
// automatically when the underlying OS thread exits. NOTE: On Windows, CleanUp
// must currently be called manually (issue 23474).
class Thread {
public:
// The currently executing thread, or NULL if not yet initialized.
static Thread* Current() {
return reinterpret_cast<Thread*>(OSThread::GetThreadLocal(thread_key_));
}
// Initializes the current thread as a VM thread, if not already done.
static void EnsureInit();
// Makes the current thread enter 'isolate'.
static void EnterIsolate(Isolate* isolate);
// Makes the current thread exit its isolate.
static void ExitIsolate();
// A VM thread other than the main mutator thread can enter an isolate as a
// "helper" to gain limited concurrent access to the isolate. One example is
// SweeperTask (which uses the class table, which is copy-on-write).
// TODO(koda): Properly synchronize heap access to expand allowed operations.
static void EnterIsolateAsHelper(Isolate* isolate);
static void ExitIsolateAsHelper();
// Called when the current thread transitions from mutator to collector.
// Empties the store buffer block into the isolate.
// TODO(koda): Always run GC in separate thread.
static void PrepareForGC();
#if defined(TARGET_OS_WINDOWS)
// Clears the state of the current thread and frees the allocation.
static void CleanUp();
#endif
// Called at VM startup.
static void InitOnceBeforeIsolate();
static void InitOnceAfterObjectAndStubCode();
~Thread();
// The topmost zone used for allocation in this thread.
Zone* zone() const { return state_.zone; }
// The isolate that this thread is operating on, or NULL if none.
Isolate* isolate() const { return isolate_; }
static intptr_t isolate_offset() {
return OFFSET_OF(Thread, isolate_);
}
// The (topmost) CHA for the compilation in the isolate of this thread.
// TODO(23153): Move this out of Isolate/Thread.
CHA* cha() const;
void set_cha(CHA* value);
void StoreBufferAddObject(RawObject* obj);
void StoreBufferAddObjectGC(RawObject* obj);
#if defined(TESTING)
bool StoreBufferContains(RawObject* obj) const {
return store_buffer_block_->Contains(obj);
}
#endif
void StoreBufferBlockProcess(bool check_threshold);
static intptr_t store_buffer_block_offset() {
return OFFSET_OF(Thread, store_buffer_block_);
}
uword top_exit_frame_info() const { return state_.top_exit_frame_info; }
static intptr_t top_exit_frame_info_offset() {
return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_exit_frame_info);
}
StackResource* top_resource() const { return state_.top_resource; }
void set_top_resource(StackResource* value) {
state_.top_resource = value;
}
static intptr_t top_resource_offset() {
return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_resource);
}
static intptr_t heap_offset() {
return OFFSET_OF(Thread, heap_);
}
int32_t no_handle_scope_depth() const {
#if defined(DEBUG)
return state_.no_handle_scope_depth;
#else
return 0;
#endif
}
void IncrementNoHandleScopeDepth() {
#if defined(DEBUG)
ASSERT(state_.no_handle_scope_depth < INT_MAX);
state_.no_handle_scope_depth += 1;
#endif
}
void DecrementNoHandleScopeDepth() {
#if defined(DEBUG)
ASSERT(state_.no_handle_scope_depth > 0);
state_.no_handle_scope_depth -= 1;
#endif
}
HandleScope* top_handle_scope() const {
#if defined(DEBUG)
return state_.top_handle_scope;
#else
return 0;
#endif
}
void set_top_handle_scope(HandleScope* handle_scope) {
#if defined(DEBUG)
state_.top_handle_scope = handle_scope;
#endif
}
int32_t no_safepoint_scope_depth() const {
#if defined(DEBUG)
return state_.no_safepoint_scope_depth;
#else
return 0;
#endif
}
void IncrementNoSafepointScopeDepth() {
#if defined(DEBUG)
ASSERT(state_.no_safepoint_scope_depth < INT_MAX);
state_.no_safepoint_scope_depth += 1;
#endif
}
void DecrementNoSafepointScopeDepth() {
#if defined(DEBUG)
ASSERT(state_.no_safepoint_scope_depth > 0);
state_.no_safepoint_scope_depth -= 1;
#endif
}
// Collection of isolate-specific state of a thread that is saved/restored
// on isolate exit/re-entry.
struct State {
Zone* zone;
uword top_exit_frame_info;
StackResource* top_resource;
#if defined(DEBUG)
HandleScope* top_handle_scope;
intptr_t no_handle_scope_depth;
int32_t no_safepoint_scope_depth;
#endif
};
#define DEFINE_OFFSET_METHOD(type_name, member_name, expr, default_init_value) \
static intptr_t member_name##offset() { \
return OFFSET_OF(Thread, member_name); \
}
CACHED_CONSTANTS_LIST(DEFINE_OFFSET_METHOD)
#undef DEFINE_OFFSET_METHOD
static bool CanLoadFromThread(const Object& object);
static intptr_t OffsetFromThread(const Object& object);
private:
static ThreadLocalKey thread_key_;
Isolate* isolate_;
Heap* heap_;
State state_;
StoreBufferBlock* store_buffer_block_;
#define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value) \
type_name member_name;
CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
#undef DECLARE_MEMBERS
explicit Thread(bool init_vm_constants = true);
void InitVMConstants();
void ClearState() {
memset(&state_, 0, sizeof(state_));
}
void set_zone(Zone* zone) {
state_.zone = zone;
}
void set_top_exit_frame_info(uword top_exit_frame_info) {
state_.top_exit_frame_info = top_exit_frame_info;
}
static void SetCurrent(Thread* current);
void Schedule(Isolate* isolate);
void Unschedule();
friend class ApiZone;
friend class Isolate;
friend class StackZone;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
} // namespace dart
#endif // VM_THREAD_H_