| Index: runtime/vm/safepoint.h
 | 
| diff --git a/runtime/vm/safepoint.h b/runtime/vm/safepoint.h
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..1c13a872f379371d8ea07cf0f64274b3df16b917
 | 
| --- /dev/null
 | 
| +++ b/runtime/vm/safepoint.h
 | 
| @@ -0,0 +1,328 @@
 | 
| +// Copyright (c) 2016, 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_SAFEPOINT_H_
 | 
| +#define VM_SAFEPOINT_H_
 | 
| +
 | 
| +#include "vm/globals.h"
 | 
| +#include "vm/lockers.h"
 | 
| +#include "vm/thread.h"
 | 
| +
 | 
| +namespace dart {
 | 
| +
 | 
| +// A stack based scope that can be used to perform an operation after getting
 | 
| +// all threads to a safepoint. At the end of the operation all the threads are
 | 
| +// resumed.
 | 
| +class SafepointOperationScope : public StackResource {
 | 
| + public:
 | 
| +  explicit SafepointOperationScope(Thread* T);
 | 
| +  ~SafepointOperationScope();
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// Implements handling of safepoint operations for all threads in an Isolate.
 | 
| +class SafepointHandler {
 | 
| + public:
 | 
| +  explicit SafepointHandler(Isolate* I);
 | 
| +  ~SafepointHandler();
 | 
| +
 | 
| +  void EnterSafepointUsingLock(Thread* T);
 | 
| +  void ExitSafepointUsingLock(Thread* T);
 | 
| +
 | 
| +  void SafepointThreads(Thread* T);
 | 
| +  void ResumeThreads(Thread* T);
 | 
| +
 | 
| +  void BlockForSafepoint(Thread* T);
 | 
| +
 | 
| + private:
 | 
| +  Isolate* isolate() const { return isolate_; }
 | 
| +  Monitor* threads_lock() const { return isolate_->threads_lock(); }
 | 
| +  bool safepoint_in_progress() const {
 | 
| +    ASSERT(threads_lock()->IsOwnedByCurrentThread());
 | 
| +    return safepoint_in_progress_;
 | 
| +  }
 | 
| +  void set_safepoint_in_progress(bool value) {
 | 
| +    ASSERT(threads_lock()->IsOwnedByCurrentThread());
 | 
| +    safepoint_in_progress_ = value;
 | 
| +  }
 | 
| +
 | 
| +  Isolate* isolate_;
 | 
| +
 | 
| +  // Monitor used by thread initiating a safepoint operation to track threads
 | 
| +  // not at a safepoint and wait for these threads to reach a safepoint.
 | 
| +  Monitor* safepoint_lock_;
 | 
| +  int32_t number_threads_not_at_safepoint_;
 | 
| +
 | 
| +  // Flag to indicate if a safepoint operation is currently in progress.
 | 
| +  bool safepoint_in_progress_;
 | 
| +
 | 
| +  friend class Isolate;
 | 
| +  friend class SafepointOperationScope;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +/*
 | 
| + * Set of StackResource classes to track thread execution state transitions:
 | 
| + *
 | 
| + * kThreadInGenerated transitioning to
 | 
| + *   ==> kThreadInVM:
 | 
| + *       - set_execution_state(kThreadInVM).
 | 
| + *       - block if safepoint is requested.
 | 
| + *   ==> kThreadInNative:
 | 
| + *       - set_execution_state(kThreadInNative).
 | 
| + *       - EnterSafepoint().
 | 
| + *   ==> kThreadInBlockedState:
 | 
| + *       - Invalid transition
 | 
| + *
 | 
| + * kThreadInVM transitioning to
 | 
| + *   ==> kThreadInGenerated
 | 
| + *       - set_execution_state(kThreadInGenerated).
 | 
| + *   ==> kThreadInNative
 | 
| + *       - set_execution_state(kThreadInNative).
 | 
| + *       - EnterSafepoint.
 | 
| + *   ==> kThreadInBlockedState
 | 
| + *       - set_execution_state(kThreadInBlockedState).
 | 
| + *       - EnterSafepoint.
 | 
| + *
 | 
| + * kThreadInNative transitioning to
 | 
| + *   ==> kThreadInGenerated
 | 
| + *       - ExitSafepoint.
 | 
| + *       - set_execution_state(kThreadInGenerated).
 | 
| + *   ==> kThreadInVM
 | 
| + *       - ExitSafepoint.
 | 
| + *       - set_execution_state(kThreadInVM).
 | 
| + *   ==> kThreadInBlocked
 | 
| + *       - Invalid transition.
 | 
| + *
 | 
| + * kThreadInBlocked transitioning to
 | 
| + *   ==> kThreadInVM
 | 
| + *       - ExitSafepoint.
 | 
| + *       - set_execution_state(kThreadInVM).
 | 
| + *   ==> kThreadInNative
 | 
| + *       - Invalid transition.
 | 
| + *   ==> kThreadInGenerated
 | 
| + *       - Invalid transition.
 | 
| + */
 | 
| +class TransitionSafepointState : public StackResource {
 | 
| + public:
 | 
| +  explicit TransitionSafepointState(Thread* T) : StackResource(T) {}
 | 
| +  ~TransitionSafepointState() {}
 | 
| +
 | 
| +  SafepointHandler* handler() const {
 | 
| +    ASSERT(thread()->isolate() != NULL);
 | 
| +    ASSERT(thread()->isolate()->safepoint_handler() != NULL);
 | 
| +    return thread()->isolate()->safepoint_handler();
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionGeneratedToVM is used to transition the safepoint state of a
 | 
| +// thread from "running generated code" to "running vm code" and ensures
 | 
| +// that the state is reverted back to "running generated code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionGeneratedToVM : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) {
 | 
| +    ASSERT(T == Thread::Current());
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInGenerated);
 | 
| +    T->set_execution_state(Thread::kThreadInVM);
 | 
| +    // Fast check to see if a safepoint is requested or not.
 | 
| +    // We do the more expensive operation of blocking the thread
 | 
| +    // only if a safepoint is requested.
 | 
| +    if (T->IsSafepointRequested()) {
 | 
| +      handler()->BlockForSafepoint(T);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionGeneratedToVM() {
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInVM);
 | 
| +    thread()->set_execution_state(Thread::kThreadInGenerated);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionGeneratedToNative is used to transition the safepoint state of a
 | 
| +// thread from "running generated code" to "running native code" and ensures
 | 
| +// that the state is reverted back to "running generated code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionGeneratedToNative : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionGeneratedToNative(Thread* T)
 | 
| +      : TransitionSafepointState(T) {
 | 
| +    // Native code is considered to be at a safepoint and so we mark it
 | 
| +    // accordingly.
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInGenerated);
 | 
| +    T->set_execution_state(Thread::kThreadInNative);
 | 
| +    T->EnterSafepoint();
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionGeneratedToNative() {
 | 
| +    // We are returning to generated code and so we are not at a safepoint
 | 
| +    // anymore.
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInNative);
 | 
| +    thread()->ExitSafepoint();
 | 
| +    thread()->set_execution_state(Thread::kThreadInGenerated);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionVMToBlocked is used to transition the safepoint state of a
 | 
| +// thread from "running vm code" to "blocked on a monitor" and ensures
 | 
| +// that the state is reverted back to "running vm code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionVMToBlocked : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) {
 | 
| +    // A thread blocked on a monitor is considered to be at a safepoint.
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInVM);
 | 
| +    T->set_execution_state(Thread::kThreadInBlockedState);
 | 
| +    T->EnterSafepoint();
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionVMToBlocked() {
 | 
| +    // We are returning to vm code and so we are not at a safepoint anymore.
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState);
 | 
| +    thread()->ExitSafepoint();
 | 
| +    thread()->set_execution_state(Thread::kThreadInVM);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionVMToNative is used to transition the safepoint state of a
 | 
| +// thread from "running vm code" to "running native code" and ensures
 | 
| +// that the state is reverted back to "running vm code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionVMToNative : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) {
 | 
| +    // A thread running native code is considered to be at a safepoint.
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInVM);
 | 
| +    T->set_execution_state(Thread::kThreadInNative);
 | 
| +    T->EnterSafepoint();
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionVMToNative() {
 | 
| +    // We are returning to vm code and so we are not at a safepoint anymore.
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInNative);
 | 
| +    thread()->ExitSafepoint();
 | 
| +    thread()->set_execution_state(Thread::kThreadInVM);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionVMToGenerated is used to transition the safepoint state of a
 | 
| +// thread from "running vm code" to "running generated code" and ensures
 | 
| +// that the state is reverted back to "running vm code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionVMToGenerated : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) {
 | 
| +    ASSERT(T == Thread::Current());
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInVM);
 | 
| +    T->set_execution_state(Thread::kThreadInGenerated);
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionVMToGenerated() {
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
 | 
| +    thread()->set_execution_state(Thread::kThreadInVM);
 | 
| +    // Fast check to see if a safepoint is requested or not.
 | 
| +    // We do the more expensive operation of blocking the thread
 | 
| +    // only if a safepoint is requested.
 | 
| +    if (thread()->IsSafepointRequested()) {
 | 
| +      handler()->BlockForSafepoint(thread());
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionNativeToVM is used to transition the safepoint state of a
 | 
| +// thread from "running native code" to "running vm code" and ensures
 | 
| +// that the state is reverted back to "running native code" when
 | 
| +// exiting the scope/frame.
 | 
| +class TransitionNativeToVM : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) {
 | 
| +    // We are about to execute vm code and so we are not at a safepoint anymore.
 | 
| +    ASSERT(T->execution_state() == Thread::kThreadInNative);
 | 
| +    T->ExitSafepoint();
 | 
| +    T->set_execution_state(Thread::kThreadInVM);
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionNativeToVM() {
 | 
| +    // We are returning to native code and so we are at a safepoint.
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInVM);
 | 
| +    thread()->set_execution_state(Thread::kThreadInNative);
 | 
| +    thread()->EnterSafepoint();
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +// TransitionToGenerated is used to transition the safepoint state of a
 | 
| +// thread from "running vm code" or "running native code" to
 | 
| +// "running generated code" and ensures that the state is reverted back
 | 
| +// to "running vm code" or "running native code" when exiting the
 | 
| +// scope/frame.
 | 
| +class TransitionToGenerated : public TransitionSafepointState {
 | 
| + public:
 | 
| +  explicit TransitionToGenerated(Thread* T)
 | 
| +      : TransitionSafepointState(T),
 | 
| +        execution_state_(T->execution_state()) {
 | 
| +    ASSERT(T == Thread::Current());
 | 
| +    ASSERT((execution_state_ == Thread::kThreadInVM) ||
 | 
| +           (execution_state_ == Thread::kThreadInNative));
 | 
| +    if (execution_state_ == Thread::kThreadInNative) {
 | 
| +      T->ExitSafepoint();
 | 
| +    }
 | 
| +    T->set_execution_state(Thread::kThreadInGenerated);
 | 
| +  }
 | 
| +
 | 
| +  ~TransitionToGenerated() {
 | 
| +    ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
 | 
| +    if (execution_state_ == Thread::kThreadInNative) {
 | 
| +      thread()->set_execution_state(Thread::kThreadInNative);
 | 
| +      thread()->EnterSafepoint();
 | 
| +    } else {
 | 
| +      ASSERT(execution_state_ == Thread::kThreadInVM);
 | 
| +      thread()->set_execution_state(Thread::kThreadInVM);
 | 
| +      // Fast check to see if a safepoint is requested or not.
 | 
| +      // We do the more expensive operation of blocking the thread
 | 
| +      // only if a safepoint is requested.
 | 
| +      if (thread()->IsSafepointRequested()) {
 | 
| +        handler()->BlockForSafepoint(thread());
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  int16_t execution_state_;
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated);
 | 
| +};
 | 
| +
 | 
| +}  // namespace dart
 | 
| +
 | 
| +#endif  // VM_SAFEPOINT_H_
 | 
| 
 |