| Index: runtime/vm/deferred_objects.cc
|
| ===================================================================
|
| --- runtime/vm/deferred_objects.cc (revision 27855)
|
| +++ runtime/vm/deferred_objects.cc (working copy)
|
| @@ -2,274 +2,17 @@
|
| // 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.
|
|
|
| -#include "vm/isolate.h"
|
| +#include "vm/deferred_objects.h"
|
|
|
| -#include "include/dart_api.h"
|
| -#include "platform/assert.h"
|
| -#include "platform/json.h"
|
| -#include "lib/mirrors.h"
|
| -#include "vm/code_observers.h"
|
| -#include "vm/compiler_stats.h"
|
| -#include "vm/coverage.h"
|
| -#include "vm/dart_api_state.h"
|
| -#include "vm/dart_entry.h"
|
| -#include "vm/debugger.h"
|
| -#include "vm/heap.h"
|
| -#include "vm/heap_histogram.h"
|
| -#include "vm/message_handler.h"
|
| -#include "vm/object_id_ring.h"
|
| -#include "vm/object_store.h"
|
| -#include "vm/parser.h"
|
| -#include "vm/port.h"
|
| -#include "vm/reusable_handles.h"
|
| -#include "vm/service.h"
|
| -#include "vm/simulator.h"
|
| -#include "vm/stack_frame.h"
|
| -#include "vm/stub_code.h"
|
| -#include "vm/symbols.h"
|
| -#include "vm/thread.h"
|
| -#include "vm/timer.h"
|
| -#include "vm/visitor.h"
|
| +#include "vm/deopt_instructions.h"
|
| +#include "vm/flags.h"
|
| +#include "vm/object.h"
|
|
|
| -
|
| namespace dart {
|
|
|
| -DEFINE_FLAG(bool, report_usage_count, false,
|
| - "Track function usage and report.");
|
| -DEFINE_FLAG(bool, trace_isolates, false,
|
| - "Trace isolate creation and shut down.");
|
| DECLARE_FLAG(bool, trace_deoptimization_verbose);
|
|
|
|
|
| -void Isolate::RegisterClass(const Class& cls) {
|
| - class_table()->Register(cls);
|
| - if (object_histogram() != NULL) object_histogram()->RegisterClass(cls);
|
| -}
|
| -
|
| -
|
| -class IsolateMessageHandler : public MessageHandler {
|
| - public:
|
| - explicit IsolateMessageHandler(Isolate* isolate);
|
| - ~IsolateMessageHandler();
|
| -
|
| - const char* name() const;
|
| - void MessageNotify(Message::Priority priority);
|
| - bool HandleMessage(Message* message);
|
| -
|
| -#if defined(DEBUG)
|
| - // Check that it is safe to access this handler.
|
| - void CheckAccess();
|
| -#endif
|
| - bool IsCurrentIsolate() const;
|
| - virtual Isolate* GetIsolate() const { return isolate_; }
|
| - bool UnhandledExceptionCallbackHandler(const Object& message,
|
| - const UnhandledException& error);
|
| -
|
| - private:
|
| - bool ProcessUnhandledException(const Object& message, const Error& result);
|
| - RawFunction* ResolveCallbackFunction();
|
| - Isolate* isolate_;
|
| -};
|
| -
|
| -
|
| -IsolateMessageHandler::IsolateMessageHandler(Isolate* isolate)
|
| - : isolate_(isolate) {
|
| -}
|
| -
|
| -
|
| -IsolateMessageHandler::~IsolateMessageHandler() {
|
| -}
|
| -
|
| -const char* IsolateMessageHandler::name() const {
|
| - return isolate_->name();
|
| -}
|
| -
|
| -
|
| -void IsolateMessageHandler::MessageNotify(Message::Priority priority) {
|
| - if (priority >= Message::kOOBPriority) {
|
| - // Handle out of band messages even if the isolate is busy.
|
| - isolate_->ScheduleInterrupts(Isolate::kMessageInterrupt);
|
| - }
|
| - Dart_MessageNotifyCallback callback = isolate_->message_notify_callback();
|
| - if (callback) {
|
| - // Allow the embedder to handle message notification.
|
| - (*callback)(Api::CastIsolate(isolate_));
|
| - }
|
| -}
|
| -
|
| -
|
| -bool IsolateMessageHandler::HandleMessage(Message* message) {
|
| - StartIsolateScope start_scope(isolate_);
|
| - StackZone zone(isolate_);
|
| - HandleScope handle_scope(isolate_);
|
| -
|
| - // If the message is in band we lookup the receive port to dispatch to. If
|
| - // the receive port is closed, we drop the message without deserializing it.
|
| - Object& receive_port = Object::Handle();
|
| - if (!message->IsOOB()) {
|
| - receive_port = DartLibraryCalls::LookupReceivePort(message->dest_port());
|
| - if (receive_port.IsError()) {
|
| - return ProcessUnhandledException(Object::null_instance(),
|
| - Error::Cast(receive_port));
|
| - }
|
| - if (receive_port.IsNull()) {
|
| - delete message;
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // Parse the message.
|
| - SnapshotReader reader(message->data(), message->len(),
|
| - Snapshot::kMessage, Isolate::Current());
|
| - const Object& msg_obj = Object::Handle(reader.ReadObject());
|
| - if (msg_obj.IsError()) {
|
| - // An error occurred while reading the message.
|
| - return ProcessUnhandledException(Object::null_instance(),
|
| - Error::Cast(msg_obj));
|
| - }
|
| - if (!msg_obj.IsNull() && !msg_obj.IsInstance()) {
|
| - // TODO(turnidge): We need to decide what an isolate does with
|
| - // malformed messages. If they (eventually) come from a remote
|
| - // machine, then it might make sense to drop the message entirely.
|
| - // In the case that the message originated locally, which is
|
| - // always true for now, then this should never occur.
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - Instance& msg = Instance::Handle();
|
| - msg ^= msg_obj.raw(); // Can't use Instance::Cast because may be null.
|
| -
|
| - bool success = true;
|
| - if (message->IsOOB()) {
|
| - Service::HandleServiceMessage(isolate_, message->reply_port(), msg);
|
| - } else {
|
| - const Object& result = Object::Handle(
|
| - DartLibraryCalls::HandleMessage(
|
| - receive_port, message->reply_port(), msg));
|
| - if (result.IsError()) {
|
| - success = ProcessUnhandledException(msg, Error::Cast(result));
|
| - } else {
|
| - ASSERT(result.IsNull());
|
| - }
|
| - }
|
| - delete message;
|
| - return success;
|
| -}
|
| -
|
| -
|
| -RawFunction* IsolateMessageHandler::ResolveCallbackFunction() {
|
| - ASSERT(isolate_->object_store()->unhandled_exception_handler() != NULL);
|
| - String& callback_name = String::Handle(isolate_);
|
| - if (isolate_->object_store()->unhandled_exception_handler() !=
|
| - String::null()) {
|
| - callback_name = isolate_->object_store()->unhandled_exception_handler();
|
| - } else {
|
| - callback_name = String::New("_unhandledExceptionCallback");
|
| - }
|
| - Library& lib =
|
| - Library::Handle(isolate_, isolate_->object_store()->isolate_library());
|
| - Function& func =
|
| - Function::Handle(isolate_, lib.LookupLocalFunction(callback_name));
|
| - if (func.IsNull()) {
|
| - lib = isolate_->object_store()->root_library();
|
| - func = lib.LookupLocalFunction(callback_name);
|
| - }
|
| - return func.raw();
|
| -}
|
| -
|
| -
|
| -bool IsolateMessageHandler::UnhandledExceptionCallbackHandler(
|
| - const Object& message, const UnhandledException& error) {
|
| - const Instance& cause = Instance::Handle(isolate_, error.exception());
|
| - const Instance& stacktrace =
|
| - Instance::Handle(isolate_, error.stacktrace());
|
| -
|
| - // Wrap these args into an IsolateUncaughtException object.
|
| - const Array& exception_args = Array::Handle(Array::New(3));
|
| - exception_args.SetAt(0, message);
|
| - exception_args.SetAt(1, cause);
|
| - exception_args.SetAt(2, stacktrace);
|
| - const Object& exception =
|
| - Object::Handle(isolate_,
|
| - Exceptions::Create(Exceptions::kIsolateUnhandledException,
|
| - exception_args));
|
| - if (exception.IsError()) {
|
| - return false;
|
| - }
|
| - ASSERT(exception.IsInstance());
|
| -
|
| - // Invoke script's callback function.
|
| - Object& function = Object::Handle(isolate_, ResolveCallbackFunction());
|
| - if (function.IsNull() || function.IsError()) {
|
| - return false;
|
| - }
|
| - const Array& callback_args = Array::Handle(Array::New(1));
|
| - callback_args.SetAt(0, exception);
|
| - const Object& result =
|
| - Object::Handle(DartEntry::InvokeFunction(Function::Cast(function),
|
| - callback_args));
|
| - if (result.IsError()) {
|
| - const Error& err = Error::Cast(result);
|
| - OS::PrintErr("failed calling unhandled exception callback: %s\n",
|
| - err.ToErrorCString());
|
| - return false;
|
| - }
|
| -
|
| - ASSERT(result.IsBool());
|
| - bool continue_from_exception = Bool::Cast(result).value();
|
| - if (continue_from_exception) {
|
| - isolate_->object_store()->clear_sticky_error();
|
| - }
|
| - return continue_from_exception;
|
| -}
|
| -
|
| -#if defined(DEBUG)
|
| -void IsolateMessageHandler::CheckAccess() {
|
| - ASSERT(IsCurrentIsolate());
|
| -}
|
| -#endif
|
| -
|
| -
|
| -bool IsolateMessageHandler::IsCurrentIsolate() const {
|
| - return (isolate_ == Isolate::Current());
|
| -}
|
| -
|
| -
|
| -bool IsolateMessageHandler::ProcessUnhandledException(
|
| - const Object& message, const Error& result) {
|
| - if (result.IsUnhandledException()) {
|
| - // Invoke the isolate's uncaught exception handler, if it exists.
|
| - const UnhandledException& error = UnhandledException::Cast(result);
|
| - RawInstance* exception = error.exception();
|
| - if ((exception != isolate_->object_store()->out_of_memory()) &&
|
| - (exception != isolate_->object_store()->stack_overflow())) {
|
| - if (UnhandledExceptionCallbackHandler(message, error)) {
|
| - return true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Invoke the isolate's unhandled exception callback if there is one.
|
| - if (Isolate::UnhandledExceptionCallback() != NULL) {
|
| - Dart_EnterScope();
|
| - Dart_Handle error = Api::NewHandle(isolate_, result.raw());
|
| - (Isolate::UnhandledExceptionCallback())(error);
|
| - Dart_ExitScope();
|
| - }
|
| -
|
| - isolate_->object_store()->set_sticky_error(result);
|
| - return false;
|
| -}
|
| -
|
| -
|
| -#if defined(DEBUG)
|
| -// static
|
| -void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
|
| - ASSERT(isolate == Isolate::Current());
|
| -}
|
| -#endif
|
| -
|
| -
|
| void DeferredDouble::Materialize() {
|
| RawDouble** double_slot = reinterpret_cast<RawDouble**>(slot());
|
| *double_slot = Double::New(value());
|
| @@ -328,7 +71,12 @@
|
|
|
|
|
| void DeferredObjectRef::Materialize() {
|
| - DeferredObject* obj = Isolate::Current()->GetDeferredObject(index());
|
| + // TODO(turnidge): Consider passing the deopt_context to materialize
|
| + // instead of accessing it through the current isolate. It would
|
| + // make it easier to test deferred object materialization in a unit
|
| + // test eventually.
|
| + DeferredObject* obj =
|
| + Isolate::Current()->deopt_context()->GetDeferredObject(index());
|
| *slot() = obj->object();
|
| if (FLAG_trace_deoptimization_verbose) {
|
| OS::PrintErr("writing instance ref at %" Px ": %s\n",
|
| @@ -376,821 +124,4 @@
|
| object_ = &obj;
|
| }
|
|
|
| -
|
| -#define REUSABLE_HANDLE_INITIALIZERS(object) \
|
| - object##_handle_(NULL),
|
| -
|
| -Isolate::Isolate()
|
| - : store_buffer_(),
|
| - message_notify_callback_(NULL),
|
| - name_(NULL),
|
| - start_time_(OS::GetCurrentTimeMicros()),
|
| - main_port_(0),
|
| - heap_(NULL),
|
| - object_store_(NULL),
|
| - top_context_(Context::null()),
|
| - top_exit_frame_info_(0),
|
| - init_callback_data_(NULL),
|
| - library_tag_handler_(NULL),
|
| - api_state_(NULL),
|
| - stub_code_(NULL),
|
| - debugger_(NULL),
|
| - single_step_(false),
|
| - simulator_(NULL),
|
| - long_jump_base_(NULL),
|
| - timer_list_(),
|
| - deopt_id_(0),
|
| - mutex_(new Mutex()),
|
| - stack_limit_(0),
|
| - saved_stack_limit_(0),
|
| - message_handler_(NULL),
|
| - spawn_data_(0),
|
| - is_runnable_(false),
|
| - gc_prologue_callbacks_(),
|
| - gc_epilogue_callbacks_(),
|
| - defer_finalization_count_(0),
|
| - deopt_cpu_registers_copy_(NULL),
|
| - deopt_fpu_registers_copy_(NULL),
|
| - deopt_frame_copy_(NULL),
|
| - deopt_frame_copy_size_(0),
|
| - deferred_boxes_(NULL),
|
| - deferred_object_refs_(NULL),
|
| - deferred_objects_count_(0),
|
| - deferred_objects_(NULL),
|
| - stacktrace_(NULL),
|
| - stack_frame_index_(-1),
|
| - object_histogram_(NULL),
|
| - object_id_ring_(NULL),
|
| - REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
|
| - reusable_handles_() {
|
| - if (FLAG_print_object_histogram && (Dart::vm_isolate() != NULL)) {
|
| - object_histogram_ = new ObjectHistogram(this);
|
| - }
|
| -}
|
| -#undef REUSABLE_HANDLE_INITIALIZERS
|
| -
|
| -
|
| -Isolate::~Isolate() {
|
| - delete [] name_;
|
| - delete heap_;
|
| - delete object_store_;
|
| - delete api_state_;
|
| - delete stub_code_;
|
| - delete debugger_;
|
| -#if defined(USING_SIMULATOR)
|
| - delete simulator_;
|
| -#endif
|
| - delete mutex_;
|
| - mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate.
|
| - delete message_handler_;
|
| - message_handler_ = NULL; // Fail fast if we send messages to a dead isolate.
|
| - delete object_histogram_;
|
| -}
|
| -
|
| -void Isolate::SetCurrent(Isolate* current) {
|
| - Thread::SetThreadLocal(isolate_key, reinterpret_cast<uword>(current));
|
| -}
|
| -
|
| -
|
| -// The single thread local key which stores all the thread local data
|
| -// for a thread. Since an Isolate is the central repository for
|
| -// storing all isolate specific information a single thread local key
|
| -// is sufficient.
|
| -ThreadLocalKey Isolate::isolate_key = Thread::kUnsetThreadLocalKey;
|
| -
|
| -
|
| -void Isolate::InitOnce() {
|
| - ASSERT(isolate_key == Thread::kUnsetThreadLocalKey);
|
| - isolate_key = Thread::CreateThreadLocal();
|
| - ASSERT(isolate_key != Thread::kUnsetThreadLocalKey);
|
| - create_callback_ = NULL;
|
| -}
|
| -
|
| -
|
| -Isolate* Isolate::Init(const char* name_prefix) {
|
| - Isolate* result = new Isolate();
|
| - ASSERT(result != NULL);
|
| -
|
| - // TODO(5411455): For now just set the recently created isolate as
|
| - // the current isolate.
|
| - SetCurrent(result);
|
| -
|
| - // Setup the isolate specific resuable handles.
|
| -#define REUSABLE_HANDLE_ALLOCATION(object) \
|
| - result->object##_handle_ = result->AllocateReusableHandle<object>(); \
|
| -
|
| - REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION)
|
| -#undef REUSABLE_HANDLE_ALLOCATION
|
| -
|
| - // Setup the isolate message handler.
|
| - MessageHandler* handler = new IsolateMessageHandler(result);
|
| - ASSERT(handler != NULL);
|
| - result->set_message_handler(handler);
|
| -
|
| - // Setup the Dart API state.
|
| - ApiState* state = new ApiState();
|
| - ASSERT(state != NULL);
|
| - result->set_api_state(state);
|
| -
|
| - // Initialize stack top and limit in case we are running the isolate in the
|
| - // main thread.
|
| - // TODO(5411455): Need to figure out how to set the stack limit for the
|
| - // main thread.
|
| - result->SetStackLimitFromCurrentTOS(reinterpret_cast<uword>(&result));
|
| - result->set_main_port(PortMap::CreatePort(result->message_handler()));
|
| - result->BuildName(name_prefix);
|
| -
|
| - result->debugger_ = new Debugger();
|
| - result->debugger_->Initialize(result);
|
| - if (FLAG_trace_isolates) {
|
| - if (name_prefix == NULL || strcmp(name_prefix, "vm-isolate") != 0) {
|
| - OS::Print("[+] Starting isolate:\n"
|
| - "\tisolate: %s\n", result->name());
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -
|
| -void Isolate::BuildName(const char* name_prefix) {
|
| - ASSERT(name_ == NULL);
|
| - if (name_prefix == NULL) {
|
| - name_prefix = "isolate";
|
| - }
|
| - const char* kFormat = "%s-%lld";
|
| - intptr_t len = OS::SNPrint(NULL, 0, kFormat, name_prefix, main_port()) + 1;
|
| - name_ = new char[len];
|
| - OS::SNPrint(name_, len, kFormat, name_prefix, main_port());
|
| -}
|
| -
|
| -
|
| -// TODO(5411455): Use flag to override default value and Validate the
|
| -// stack size by querying OS.
|
| -uword Isolate::GetSpecifiedStackSize() {
|
| - ASSERT(Isolate::kStackSizeBuffer < Thread::GetMaxStackSize());
|
| - uword stack_size = Thread::GetMaxStackSize() - Isolate::kStackSizeBuffer;
|
| - return stack_size;
|
| -}
|
| -
|
| -
|
| -void Isolate::SetStackLimitFromCurrentTOS(uword stack_top_value) {
|
| -#if defined(USING_SIMULATOR)
|
| - // Ignore passed-in native stack top and use Simulator stack top.
|
| - Simulator* sim = Simulator::Current(); // May allocate a simulator.
|
| - ASSERT(simulator() == sim); // This isolate's simulator is the current one.
|
| - stack_top_value = sim->StackTop();
|
| - // The overflow area is accounted for by the simulator.
|
| -#endif
|
| - SetStackLimit(stack_top_value - GetSpecifiedStackSize());
|
| -}
|
| -
|
| -
|
| -void Isolate::SetStackLimit(uword limit) {
|
| - MutexLocker ml(mutex_);
|
| - if (stack_limit_ == saved_stack_limit_) {
|
| - // No interrupt pending, set stack_limit_ too.
|
| - stack_limit_ = limit;
|
| - }
|
| - saved_stack_limit_ = limit;
|
| -}
|
| -
|
| -
|
| -void Isolate::ScheduleInterrupts(uword interrupt_bits) {
|
| - // TODO(turnidge): Can't use MutexLocker here because MutexLocker is
|
| - // a StackResource, which requires a current isolate. Should
|
| - // MutexLocker really be a StackResource?
|
| - mutex_->Lock();
|
| - ASSERT((interrupt_bits & ~kInterruptsMask) == 0); // Must fit in mask.
|
| - if (stack_limit_ == saved_stack_limit_) {
|
| - stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
|
| - }
|
| - stack_limit_ |= interrupt_bits;
|
| - mutex_->Unlock();
|
| -}
|
| -
|
| -
|
| -bool Isolate::MakeRunnable() {
|
| - ASSERT(Isolate::Current() == NULL);
|
| - // Can't use MutexLocker here because MutexLocker is
|
| - // a StackResource, which requires a current isolate.
|
| - mutex_->Lock();
|
| - // Check if we are in a valid state to make the isolate runnable.
|
| - if (is_runnable_ == true) {
|
| - mutex_->Unlock();
|
| - return false; // Already runnable.
|
| - }
|
| - // Set the isolate as runnable and if we are being spawned schedule
|
| - // isolate on thread pool for execution.
|
| - is_runnable_ = true;
|
| - IsolateSpawnState* state = reinterpret_cast<IsolateSpawnState*>(spawn_data());
|
| - if (state != NULL) {
|
| - ASSERT(this == state->isolate());
|
| - Run();
|
| - }
|
| - mutex_->Unlock();
|
| - return true;
|
| -}
|
| -
|
| -
|
| -static void StoreError(Isolate* isolate, const Object& obj) {
|
| - ASSERT(obj.IsError());
|
| - isolate->object_store()->set_sticky_error(Error::Cast(obj));
|
| -}
|
| -
|
| -
|
| -static bool RunIsolate(uword parameter) {
|
| - Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
|
| - IsolateSpawnState* state = NULL;
|
| - {
|
| - MutexLocker ml(isolate->mutex());
|
| - state = reinterpret_cast<IsolateSpawnState*>(isolate->spawn_data());
|
| - isolate->set_spawn_data(0);
|
| - }
|
| - {
|
| - StartIsolateScope start_scope(isolate);
|
| - StackZone zone(isolate);
|
| - HandleScope handle_scope(isolate);
|
| - if (!ClassFinalizer::FinalizePendingClasses()) {
|
| - // Error is in sticky error already.
|
| - return false;
|
| - }
|
| -
|
| - // Set up specific unhandled exception handler.
|
| - const String& callback_name = String::Handle(
|
| - isolate, String::New(state->exception_callback_name()));
|
| - isolate->object_store()->
|
| - set_unhandled_exception_handler(callback_name);
|
| -
|
| - Object& result = Object::Handle();
|
| - result = state->ResolveFunction();
|
| - delete state;
|
| - state = NULL;
|
| - if (result.IsError()) {
|
| - StoreError(isolate, result);
|
| - return false;
|
| - }
|
| - ASSERT(result.IsFunction());
|
| - Function& func = Function::Handle(isolate);
|
| - func ^= result.raw();
|
| - result = DartEntry::InvokeFunction(func, Object::empty_array());
|
| - if (result.IsError()) {
|
| - StoreError(isolate, result);
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| -static void ShutdownIsolate(uword parameter) {
|
| - Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
|
| - {
|
| - // Print the error if there is one. This may execute dart code to
|
| - // print the exception object, so we need to use a StartIsolateScope.
|
| - StartIsolateScope start_scope(isolate);
|
| - StackZone zone(isolate);
|
| - HandleScope handle_scope(isolate);
|
| - Error& error = Error::Handle();
|
| - error = isolate->object_store()->sticky_error();
|
| - if (!error.IsNull()) {
|
| - OS::PrintErr("in ShutdownIsolate: %s\n", error.ToErrorCString());
|
| - }
|
| - Dart::RunShutdownCallback();
|
| - }
|
| - {
|
| - // Shut the isolate down.
|
| - SwitchIsolateScope switch_scope(isolate);
|
| - Dart::ShutdownIsolate();
|
| - }
|
| -}
|
| -
|
| -
|
| -void Isolate::Run() {
|
| - message_handler()->Run(Dart::thread_pool(),
|
| - RunIsolate,
|
| - ShutdownIsolate,
|
| - reinterpret_cast<uword>(this));
|
| -}
|
| -
|
| -
|
| -uword Isolate::GetAndClearInterrupts() {
|
| - MutexLocker ml(mutex_);
|
| - if (stack_limit_ == saved_stack_limit_) {
|
| - return 0; // No interrupt was requested.
|
| - }
|
| - uword interrupt_bits = stack_limit_ & kInterruptsMask;
|
| - stack_limit_ = saved_stack_limit_;
|
| - return interrupt_bits;
|
| -}
|
| -
|
| -
|
| -static int MostUsedFunctionFirst(const Function* const* a,
|
| - const Function* const* b) {
|
| - if ((*a)->usage_counter() > (*b)->usage_counter()) {
|
| - return -1;
|
| - } else if ((*a)->usage_counter() < (*b)->usage_counter()) {
|
| - return 1;
|
| - } else {
|
| - return 0;
|
| - }
|
| -}
|
| -
|
| -
|
| -static void AddFunctionsFromClass(const Class& cls,
|
| - GrowableArray<const Function*>* functions) {
|
| - const Array& class_functions = Array::Handle(cls.functions());
|
| - // Class 'dynamic' is allocated/initialized in a special way, leaving
|
| - // the functions field NULL instead of empty.
|
| - const int func_len = class_functions.IsNull() ? 0 : class_functions.Length();
|
| - for (int j = 0; j < func_len; j++) {
|
| - Function& function = Function::Handle();
|
| - function ^= class_functions.At(j);
|
| - if (function.usage_counter() > 0) {
|
| - functions->Add(&function);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void Isolate::PrintInvokedFunctions() {
|
| - ASSERT(this == Isolate::Current());
|
| - const GrowableObjectArray& libraries =
|
| - GrowableObjectArray::Handle(object_store()->libraries());
|
| - Library& library = Library::Handle();
|
| - GrowableArray<const Function*> invoked_functions;
|
| - for (int i = 0; i < libraries.Length(); i++) {
|
| - library ^= libraries.At(i);
|
| - Class& cls = Class::Handle();
|
| - ClassDictionaryIterator iter(library,
|
| - ClassDictionaryIterator::kIteratePrivate);
|
| - while (iter.HasNext()) {
|
| - cls = iter.GetNextClass();
|
| - AddFunctionsFromClass(cls, &invoked_functions);
|
| - }
|
| - }
|
| - invoked_functions.Sort(MostUsedFunctionFirst);
|
| - for (int i = 0; i < invoked_functions.length(); i++) {
|
| - OS::Print("%10" Pd " x %s\n",
|
| - invoked_functions[i]->usage_counter(),
|
| - invoked_functions[i]->ToFullyQualifiedCString());
|
| - }
|
| -}
|
| -
|
| -
|
| -class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
|
| - public:
|
| - FinalizeWeakPersistentHandlesVisitor() {
|
| - }
|
| -
|
| - void VisitHandle(uword addr) {
|
| - FinalizablePersistentHandle* handle =
|
| - reinterpret_cast<FinalizablePersistentHandle*>(addr);
|
| - FinalizablePersistentHandle::Finalize(handle);
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(FinalizeWeakPersistentHandlesVisitor);
|
| -};
|
| -
|
| -
|
| -void Isolate::Shutdown() {
|
| - ASSERT(this == Isolate::Current());
|
| - ASSERT(top_resource() == NULL);
|
| - ASSERT((heap_ == NULL) || heap_->Verify());
|
| -
|
| - // Create an area where we do have a zone and a handle scope so that we can
|
| - // call VM functions while tearing this isolate down.
|
| - {
|
| - StackZone stack_zone(this);
|
| - HandleScope handle_scope(this);
|
| -
|
| - if (FLAG_print_object_histogram) {
|
| - heap()->CollectAllGarbage();
|
| - object_histogram()->Print();
|
| - }
|
| -
|
| - // Clean up debugger resources.
|
| - debugger()->Shutdown();
|
| -
|
| - // Close all the ports owned by this isolate.
|
| - PortMap::ClosePorts(message_handler());
|
| -
|
| - // Fail fast if anybody tries to post any more messsages to this isolate.
|
| - delete message_handler();
|
| - set_message_handler(NULL);
|
| -
|
| - // Dump all accumalated timer data for the isolate.
|
| - timer_list_.ReportTimers();
|
| - if (FLAG_report_usage_count) {
|
| - PrintInvokedFunctions();
|
| - }
|
| -
|
| - // Write out the coverage data if collection has been enabled.
|
| - CodeCoverage::Write(this);
|
| -
|
| - // Finalize any weak persistent handles with a non-null referent.
|
| - FinalizeWeakPersistentHandlesVisitor visitor;
|
| - api_state()->weak_persistent_handles().VisitHandles(&visitor);
|
| -
|
| - CompilerStats::Print();
|
| - // TODO(asiva): Move this code to Dart::Cleanup when we have that method
|
| - // as the cleanup for Dart::InitOnce.
|
| - CodeObservers::DeleteAll();
|
| - if (FLAG_trace_isolates) {
|
| - heap()->PrintSizes();
|
| - megamorphic_cache_table()->PrintSizes();
|
| - Symbols::DumpStats();
|
| - OS::Print("[-] Stopping isolate:\n"
|
| - "\tisolate: %s\n", name());
|
| - }
|
| - }
|
| -
|
| - // TODO(5411455): For now just make sure there are no current isolates
|
| - // as we are shutting down the isolate.
|
| - SetCurrent(NULL);
|
| -}
|
| -
|
| -
|
| -Dart_IsolateCreateCallback Isolate::create_callback_ = NULL;
|
| -Dart_IsolateInterruptCallback Isolate::interrupt_callback_ = NULL;
|
| -Dart_IsolateUnhandledExceptionCallback
|
| - Isolate::unhandled_exception_callback_ = NULL;
|
| -Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = NULL;
|
| -Dart_FileOpenCallback Isolate::file_open_callback_ = NULL;
|
| -Dart_FileReadCallback Isolate::file_read_callback_ = NULL;
|
| -Dart_FileWriteCallback Isolate::file_write_callback_ = NULL;
|
| -Dart_FileCloseCallback Isolate::file_close_callback_ = NULL;
|
| -Dart_IsolateInterruptCallback Isolate::vmstats_callback_ = NULL;
|
| -
|
| -
|
| -void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
|
| - bool visit_prologue_weak_handles,
|
| - bool validate_frames) {
|
| - ASSERT(visitor != NULL);
|
| -
|
| - // Visit objects in the object store.
|
| - object_store()->VisitObjectPointers(visitor);
|
| -
|
| - // Visit objects in the class table.
|
| - class_table()->VisitObjectPointers(visitor);
|
| -
|
| - // Visit objects in the megamorphic cache.
|
| - megamorphic_cache_table()->VisitObjectPointers(visitor);
|
| -
|
| - // Visit objects in per isolate stubs.
|
| - StubCode::VisitObjectPointers(visitor);
|
| -
|
| - // Visit objects in zones.
|
| - current_zone()->VisitObjectPointers(visitor);
|
| -
|
| - // Visit objects in isolate specific handles area.
|
| - reusable_handles_.VisitObjectPointers(visitor);
|
| -
|
| - // Iterate over all the stack frames and visit objects on the stack.
|
| - StackFrameIterator frames_iterator(validate_frames);
|
| - StackFrame* frame = frames_iterator.NextFrame();
|
| - while (frame != NULL) {
|
| - frame->VisitObjectPointers(visitor);
|
| - frame = frames_iterator.NextFrame();
|
| - }
|
| -
|
| - // Visit the dart api state for all local and persistent handles.
|
| - if (api_state() != NULL) {
|
| - api_state()->VisitObjectPointers(visitor, visit_prologue_weak_handles);
|
| - }
|
| -
|
| - // Visit the top context which is stored in the isolate.
|
| - visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_context_));
|
| -
|
| - // Visit objects in the debugger.
|
| - debugger()->VisitObjectPointers(visitor);
|
| -}
|
| -
|
| -
|
| -void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor,
|
| - bool visit_prologue_weak_handles) {
|
| - if (api_state() != NULL) {
|
| - api_state()->VisitWeakHandles(visitor, visit_prologue_weak_handles);
|
| - }
|
| -}
|
| -
|
| -
|
| -static Monitor* status_sync = NULL;
|
| -
|
| -
|
| -bool Isolate::FetchStacktrace() {
|
| - Isolate* isolate = Isolate::Current();
|
| - MonitorLocker ml(status_sync);
|
| - DebuggerStackTrace* stack = Debugger::CollectStackTrace();
|
| - TextBuffer buffer(256);
|
| - buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"stacktrace\": [ ",
|
| - reinterpret_cast<int64_t>(isolate));
|
| - intptr_t n_frames = stack->Length();
|
| - String& url = String::Handle();
|
| - String& function = String::Handle();
|
| - for (int i = 0; i < n_frames; i++) {
|
| - if (i > 0) {
|
| - buffer.Printf(", ");
|
| - }
|
| - ActivationFrame* frame = stack->FrameAt(i);
|
| - url ^= frame->SourceUrl();
|
| - function ^= frame->function().UserVisibleName();
|
| - buffer.Printf("{ \"url\": \"%s\", ", url.ToCString());
|
| - buffer.Printf("\"line\": %" Pd ", ", frame->LineNumber());
|
| - buffer.Printf("\"function\": \"%s\", ", function.ToCString());
|
| -
|
| - const Code& code = frame->code();
|
| - buffer.Printf("\"code\": { ");
|
| - buffer.Printf("\"alive\": %s, ", code.is_alive() ? "false" : "true");
|
| - buffer.Printf("\"optimized\": %s }}",
|
| - code.is_optimized() ? "false" : "true");
|
| - }
|
| - buffer.Printf("]}");
|
| - isolate->stacktrace_ = OS::StrNDup(buffer.buf(), buffer.length());
|
| - ml.Notify();
|
| - return true;
|
| -}
|
| -
|
| -
|
| -bool Isolate::FetchStackFrameDetails() {
|
| - Isolate* isolate = Isolate::Current();
|
| - ASSERT(isolate->stack_frame_index_ >= 0);
|
| - MonitorLocker ml(status_sync);
|
| - DebuggerStackTrace* stack = Debugger::CollectStackTrace();
|
| - intptr_t frame_index = isolate->stack_frame_index_;
|
| - if (frame_index >= stack->Length()) {
|
| - // Frame no longer available.
|
| - return false;
|
| - }
|
| - ActivationFrame* frame = stack->FrameAt(frame_index);
|
| - TextBuffer buffer(256);
|
| - buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"frame_index\": %" Pd ", ",
|
| - reinterpret_cast<int64_t>(isolate), frame_index);
|
| -
|
| - const Code& code = frame->code();
|
| - buffer.Printf("\"code\": { \"size\": %" Pd ", ", code.Size());
|
| - buffer.Printf("\"alive\": %s, ", code.is_alive() ? "false" : "true");
|
| - buffer.Printf("\"optimized\": %s }, ",
|
| - code.is_optimized() ? "false" : "true");
|
| - // TODO(tball): add compilation stats (time, etc.), when available.
|
| -
|
| - buffer.Printf("\"local_vars\": [ ");
|
| - intptr_t n_local_vars = frame->NumLocalVariables();
|
| - String& var_name = String::Handle();
|
| - Instance& value = Instance::Handle();
|
| - for (int i = 0; i < n_local_vars; i++) {
|
| - if (i > 0) {
|
| - buffer.Printf(", ");
|
| - }
|
| - intptr_t token_pos, end_pos;
|
| - frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value);
|
| - buffer.Printf(
|
| - "{ \"name\": \"%s\", \"pos\": %" Pd ", \"end_pos\": %" Pd ", "
|
| - "\"value\": \"%s\" }",
|
| - var_name.ToCString(), token_pos, end_pos, value.ToCString());
|
| - }
|
| - buffer.Printf("]}");
|
| - isolate->stacktrace_ = OS::StrNDup(buffer.buf(), buffer.length());
|
| - ml.Notify();
|
| - return true;
|
| -}
|
| -
|
| -
|
| -char* Isolate::DoStacktraceInterrupt(Dart_IsolateInterruptCallback cb) {
|
| - ASSERT(stacktrace_ == NULL);
|
| - SetVmStatsCallback(cb);
|
| - if (status_sync == NULL) {
|
| - status_sync = new Monitor();
|
| - }
|
| - if (is_runnable()) {
|
| - ScheduleInterrupts(Isolate::kVmStatusInterrupt);
|
| - {
|
| - MonitorLocker ml(status_sync);
|
| - if (stacktrace_ == NULL) { // It may already be available.
|
| - ml.Wait(1000);
|
| - }
|
| - }
|
| - SetVmStatsCallback(NULL);
|
| - }
|
| - char* result = stacktrace_;
|
| - stacktrace_ = NULL;
|
| - if (result == NULL) {
|
| - // Return empty stack.
|
| - TextBuffer buffer(256);
|
| - buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"stacktrace\": []}",
|
| - reinterpret_cast<int64_t>(this));
|
| -
|
| - result = OS::StrNDup(buffer.buf(), buffer.length());
|
| - }
|
| - ASSERT(result != NULL);
|
| - // result is freed by VmStats::WebServer().
|
| - return result;
|
| -}
|
| -
|
| -
|
| -char* Isolate::GetStatusStacktrace() {
|
| - return DoStacktraceInterrupt(&FetchStacktrace);
|
| -}
|
| -
|
| -char* Isolate::GetStatusStackFrame(intptr_t index) {
|
| - ASSERT(index >= 0);
|
| - stack_frame_index_ = index;
|
| - char* result = DoStacktraceInterrupt(&FetchStackFrameDetails);
|
| - stack_frame_index_ = -1;
|
| - return result;
|
| -}
|
| -
|
| -
|
| -// Returns the isolate's general detail information.
|
| -char* Isolate::GetStatusDetails() {
|
| - const char* format = "{\n"
|
| - " \"handle\": \"0x%" Px64 "\",\n"
|
| - " \"name\": \"%s\",\n"
|
| - " \"port\": %" Pd ",\n"
|
| - " \"starttime\": %" Pd ",\n"
|
| - " \"stacklimit\": %" Pd ",\n"
|
| - " \"newspace\": {\n"
|
| - " \"used\": %" Pd ",\n"
|
| - " \"capacity\": %" Pd "\n"
|
| - " },\n"
|
| - " \"oldspace\": {\n"
|
| - " \"used\": %" Pd ",\n"
|
| - " \"capacity\": %" Pd "\n"
|
| - " }\n"
|
| - "}";
|
| - char buffer[300];
|
| - int64_t address = reinterpret_cast<int64_t>(this);
|
| - int n = OS::SNPrint(buffer, 300, format, address, name(), main_port(),
|
| - (start_time() / 1000L), saved_stack_limit(),
|
| - heap()->Used(Heap::kNew) / KB,
|
| - heap()->Capacity(Heap::kNew) / KB,
|
| - heap()->Used(Heap::kOld) / KB,
|
| - heap()->Capacity(Heap::kOld) / KB);
|
| - ASSERT(n < 300);
|
| - return strdup(buffer);
|
| -}
|
| -
|
| -
|
| -char* Isolate::GetStatus(const char* request) {
|
| - char* p = const_cast<char*>(request);
|
| - const char* service_type = "/isolate/";
|
| - ASSERT(!strncmp(p, service_type, strlen(service_type)));
|
| - p += strlen(service_type);
|
| -
|
| - // Extract isolate handle.
|
| - int64_t addr;
|
| - OS::StringToInt64(p, &addr);
|
| - // TODO(tball): add validity check when issue 9600 is fixed.
|
| - Isolate* isolate = reinterpret_cast<Isolate*>(addr);
|
| - p += strcspn(p, "/");
|
| -
|
| - // Query "/isolate/<handle>".
|
| - if (strlen(p) == 0) {
|
| - return isolate->GetStatusDetails();
|
| - }
|
| -
|
| - // Query "/isolate/<handle>/stacktrace"
|
| - if (!strcmp(p, "/stacktrace")) {
|
| - return isolate->GetStatusStacktrace();
|
| - }
|
| -
|
| - // Query "/isolate/<handle>/stacktrace/<frame-index>"
|
| - const char* stacktrace_query = "/stacktrace/";
|
| - int64_t frame_index = -1;
|
| - if (!strncmp(p, stacktrace_query, strlen(stacktrace_query))) {
|
| - p += strlen(stacktrace_query);
|
| - OS::StringToInt64(p, &frame_index);
|
| - if (frame_index >= 0) {
|
| - return isolate->GetStatusStackFrame(frame_index);
|
| - }
|
| - }
|
| -
|
| - // TODO(tball): "/isolate/<handle>/stacktrace/<frame-index>"/disassemble"
|
| -
|
| - return NULL; // Unimplemented query.
|
| -}
|
| -
|
| -
|
| -template<class T>
|
| -T* Isolate::AllocateReusableHandle() {
|
| - T* handle = reinterpret_cast<T*>(reusable_handles_.AllocateScopedHandle());
|
| - T::initializeHandle(handle, T::null());
|
| - return handle;
|
| -}
|
| -
|
| -
|
| -static void FillDeferredSlots(DeferredSlot** slot_list) {
|
| - DeferredSlot* slot = *slot_list;
|
| - *slot_list = NULL;
|
| -
|
| - while (slot != NULL) {
|
| - DeferredSlot* current = slot;
|
| - slot = slot->next();
|
| -
|
| - current->Materialize();
|
| -
|
| - delete current;
|
| - }
|
| -}
|
| -
|
| -
|
| -void Isolate::MaterializeDeferredBoxes() {
|
| - FillDeferredSlots(&deferred_boxes_);
|
| -}
|
| -
|
| -
|
| -void Isolate::MaterializeDeferredObjects() {
|
| - FillDeferredSlots(&deferred_object_refs_);
|
| -}
|
| -
|
| -
|
| -static char* GetRootScriptUri(Isolate* isolate) {
|
| - const Library& library =
|
| - Library::Handle(isolate->object_store()->root_library());
|
| - ASSERT(!library.IsNull());
|
| - const String& script_name = String::Handle(library.url());
|
| - return isolate->current_zone()->MakeCopyOfString(script_name.ToCString());
|
| -}
|
| -
|
| -
|
| -IsolateSpawnState::IsolateSpawnState(const Function& func,
|
| - const Function& callback_func)
|
| - : isolate_(NULL),
|
| - script_url_(NULL),
|
| - library_url_(NULL),
|
| - function_name_(NULL),
|
| - exception_callback_name_(NULL) {
|
| - script_url_ = strdup(GetRootScriptUri(Isolate::Current()));
|
| - const Class& cls = Class::Handle(func.Owner());
|
| - ASSERT(cls.IsTopLevel());
|
| - const Library& lib = Library::Handle(cls.library());
|
| - const String& lib_url = String::Handle(lib.url());
|
| - library_url_ = strdup(lib_url.ToCString());
|
| -
|
| - const String& func_name = String::Handle(func.name());
|
| - function_name_ = strdup(func_name.ToCString());
|
| - if (!callback_func.IsNull()) {
|
| - const String& callback_name = String::Handle(callback_func.name());
|
| - exception_callback_name_ = strdup(callback_name.ToCString());
|
| - } else {
|
| - exception_callback_name_ = strdup("_unhandledExceptionCallback");
|
| - }
|
| -}
|
| -
|
| -
|
| -IsolateSpawnState::IsolateSpawnState(const char* script_url)
|
| - : isolate_(NULL),
|
| - library_url_(NULL),
|
| - function_name_(NULL),
|
| - exception_callback_name_(NULL) {
|
| - script_url_ = strdup(script_url);
|
| - library_url_ = NULL;
|
| - function_name_ = strdup("main");
|
| - exception_callback_name_ = strdup("_unhandledExceptionCallback");
|
| -}
|
| -
|
| -
|
| -IsolateSpawnState::~IsolateSpawnState() {
|
| - free(script_url_);
|
| - free(library_url_);
|
| - free(function_name_);
|
| - free(exception_callback_name_);
|
| -}
|
| -
|
| -
|
| -RawObject* IsolateSpawnState::ResolveFunction() {
|
| - // Resolve the library.
|
| - Library& lib = Library::Handle();
|
| - if (library_url()) {
|
| - const String& lib_url = String::Handle(String::New(library_url()));
|
| - lib = Library::LookupLibrary(lib_url);
|
| - if (lib.IsNull() || lib.IsError()) {
|
| - const String& msg = String::Handle(String::NewFormatted(
|
| - "Unable to find library '%s'.", library_url()));
|
| - return LanguageError::New(msg);
|
| - }
|
| - } else {
|
| - lib = isolate()->object_store()->root_library();
|
| - }
|
| - ASSERT(!lib.IsNull());
|
| -
|
| - // Resolve the function.
|
| - const String& func_name =
|
| - String::Handle(String::New(function_name()));
|
| - const Function& func = Function::Handle(lib.LookupLocalFunction(func_name));
|
| - if (func.IsNull()) {
|
| - const String& msg = String::Handle(String::NewFormatted(
|
| - "Unable to resolve function '%s' in library '%s'.",
|
| - function_name(), (library_url() ? library_url() : script_url())));
|
| - return LanguageError::New(msg);
|
| - }
|
| - return func.raw();
|
| -}
|
| -
|
| -
|
| -void IsolateSpawnState::Cleanup() {
|
| - SwitchIsolateScope switch_scope(isolate());
|
| - Dart::ShutdownIsolate();
|
| -}
|
| -
|
| } // namespace dart
|
|
|