2013-01-18 00:34:20 +00:00
|
|
|
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
2011-10-05 05:20:07 +00:00
|
|
|
// 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 "include/dart_api.h"
|
2012-01-16 12:28:10 +00:00
|
|
|
#include "platform/assert.h"
|
2013-04-04 18:48:24 +00:00
|
|
|
#include "platform/json.h"
|
2012-04-23 22:26:09 +00:00
|
|
|
#include "lib/mirrors.h"
|
2012-12-22 00:23:25 +00:00
|
|
|
#include "vm/code_observers.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/compiler_stats.h"
|
2013-09-10 17:21:59 +00:00
|
|
|
#include "vm/coverage.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/dart_api_state.h"
|
2011-12-14 18:27:58 +00:00
|
|
|
#include "vm/dart_entry.h"
|
2011-11-30 17:04:45 +00:00
|
|
|
#include "vm/debugger.h"
|
2013-10-01 19:34:12 +00:00
|
|
|
#include "vm/deopt_instructions.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/heap.h"
|
2012-04-19 19:47:27 +00:00
|
|
|
#include "vm/message_handler.h"
|
2013-07-22 15:39:03 +00:00
|
|
|
#include "vm/object_id_ring.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/object_store.h"
|
|
|
|
#include "vm/parser.h"
|
|
|
|
#include "vm/port.h"
|
2013-11-19 18:26:10 +00:00
|
|
|
#include "vm/profiler.h"
|
2013-08-13 01:19:25 +00:00
|
|
|
#include "vm/reusable_handles.h"
|
2013-07-22 15:39:03 +00:00
|
|
|
#include "vm/service.h"
|
2013-01-25 01:16:35 +00:00
|
|
|
#include "vm/simulator.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/stack_frame.h"
|
|
|
|
#include "vm/stub_code.h"
|
2012-07-25 23:41:53 +00:00
|
|
|
#include "vm/symbols.h"
|
2014-03-14 16:16:21 +00:00
|
|
|
#include "vm/tags.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/thread.h"
|
2013-12-16 18:52:15 +00:00
|
|
|
#include "vm/thread_interrupter.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/timer.h"
|
|
|
|
#include "vm/visitor.h"
|
2013-07-22 15:39:03 +00:00
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
2012-02-25 00:33:25 +00:00
|
|
|
DEFINE_FLAG(bool, report_usage_count, false,
|
|
|
|
"Track function usage and report.");
|
2012-01-18 21:46:27 +00:00
|
|
|
DEFINE_FLAG(bool, trace_isolates, false,
|
|
|
|
"Trace isolate creation and shut down.");
|
2014-03-18 23:32:36 +00:00
|
|
|
DEFINE_FLAG(bool, pause_isolates_on_start, false,
|
|
|
|
"Pause isolates before starting.");
|
|
|
|
DEFINE_FLAG(bool, pause_isolates_on_exit, false,
|
|
|
|
"Pause isolates exiting.");
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2013-06-13 09:06:43 +00:00
|
|
|
|
|
|
|
void Isolate::RegisterClass(const Class& cls) {
|
|
|
|
class_table()->Register(cls);
|
2014-03-05 19:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::RegisterClassAt(intptr_t index, const Class& cls) {
|
|
|
|
class_table()->RegisterAt(index, cls);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::ValidateClassTable() {
|
|
|
|
class_table()->Validate();
|
2013-06-13 09:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
class IsolateMessageHandler : public MessageHandler {
|
|
|
|
public:
|
|
|
|
explicit IsolateMessageHandler(Isolate* isolate);
|
|
|
|
~IsolateMessageHandler();
|
|
|
|
|
|
|
|
const char* name() const;
|
|
|
|
void MessageNotify(Message::Priority priority);
|
2012-04-19 19:47:27 +00:00
|
|
|
bool HandleMessage(Message* message);
|
2012-02-01 18:53:40 +00:00
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
// Check that it is safe to access this handler.
|
|
|
|
void CheckAccess();
|
|
|
|
#endif
|
2012-05-30 17:07:19 +00:00
|
|
|
bool IsCurrentIsolate() const;
|
2012-10-04 00:13:37 +00:00
|
|
|
virtual Isolate* GetIsolate() const { return isolate_; }
|
2012-12-15 00:20:07 +00:00
|
|
|
bool UnhandledExceptionCallbackHandler(const Object& message,
|
|
|
|
const UnhandledException& error);
|
2012-05-30 17:07:19 +00:00
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
private:
|
2012-12-15 00:20:07 +00:00
|
|
|
bool ProcessUnhandledException(const Object& message, const Error& result);
|
|
|
|
RawFunction* ResolveCallbackFunction();
|
2012-02-01 18:53:40 +00:00
|
|
|
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.
|
2012-03-12 23:51:03 +00:00
|
|
|
isolate_->ScheduleInterrupts(Isolate::kMessageInterrupt);
|
2012-02-01 18:53:40 +00:00
|
|
|
}
|
|
|
|
Dart_MessageNotifyCallback callback = isolate_->message_notify_callback();
|
|
|
|
if (callback) {
|
|
|
|
// Allow the embedder to handle message notification.
|
|
|
|
(*callback)(Api::CastIsolate(isolate_));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 19:47:27 +00:00
|
|
|
bool IsolateMessageHandler::HandleMessage(Message* message) {
|
|
|
|
StartIsolateScope start_scope(isolate_);
|
2012-10-05 19:52:55 +00:00
|
|
|
StackZone zone(isolate_);
|
2012-04-19 19:47:27 +00:00
|
|
|
HandleScope handle_scope(isolate_);
|
2014-02-24 12:15:55 +00:00
|
|
|
// TODO(turnidge): Rework collection total dart execution. This can
|
|
|
|
// overcount when other things (gc, compilation) are active.
|
2014-03-13 20:38:24 +00:00
|
|
|
TIMERSCOPE(isolate_, time_dart_execution);
|
2012-04-19 19:47:27 +00:00
|
|
|
|
2014-04-23 19:44:03 +00:00
|
|
|
// If the message is in band we lookup the handler to dispatch to. If the
|
|
|
|
// receive port was closed, we drop the message without deserializing it.
|
|
|
|
Object& msg_handler = Object::Handle();
|
2012-12-20 20:03:07 +00:00
|
|
|
if (!message->IsOOB()) {
|
2014-04-23 19:44:03 +00:00
|
|
|
msg_handler = DartLibraryCalls::LookupHandler(message->dest_port());
|
|
|
|
if (msg_handler.IsError()) {
|
2013-09-13 16:55:57 +00:00
|
|
|
return ProcessUnhandledException(Object::null_instance(),
|
2014-04-23 19:44:03 +00:00
|
|
|
Error::Cast(msg_handler));
|
2012-12-20 20:03:07 +00:00
|
|
|
}
|
2014-04-23 19:44:03 +00:00
|
|
|
if (msg_handler.IsNull()) {
|
2012-12-20 20:03:07 +00:00
|
|
|
delete message;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-27 20:25:44 +00:00
|
|
|
// Parse the message.
|
|
|
|
SnapshotReader reader(message->data(), message->len(),
|
|
|
|
Snapshot::kMessage, Isolate::Current());
|
|
|
|
const Object& msg_obj = Object::Handle(reader.ReadObject());
|
2012-12-07 01:41:53 +00:00
|
|
|
if (msg_obj.IsError()) {
|
|
|
|
// An error occurred while reading the message.
|
2013-09-13 16:55:57 +00:00
|
|
|
return ProcessUnhandledException(Object::null_instance(),
|
|
|
|
Error::Cast(msg_obj));
|
2012-12-07 01:41:53 +00:00
|
|
|
}
|
2012-08-27 20:25:44 +00:00
|
|
|
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.
|
|
|
|
|
2012-12-15 00:20:07 +00:00
|
|
|
bool success = true;
|
2012-04-19 19:47:27 +00:00
|
|
|
if (message->IsOOB()) {
|
2014-01-15 20:45:39 +00:00
|
|
|
Service::HandleIsolateMessage(isolate_, msg);
|
2012-04-19 19:47:27 +00:00
|
|
|
} else {
|
|
|
|
const Object& result = Object::Handle(
|
2014-04-23 19:44:03 +00:00
|
|
|
DartLibraryCalls::HandleMessage(msg_handler, msg));
|
2012-12-07 01:41:53 +00:00
|
|
|
if (result.IsError()) {
|
2012-12-15 00:20:07 +00:00
|
|
|
success = ProcessUnhandledException(msg, Error::Cast(result));
|
|
|
|
} else {
|
|
|
|
ASSERT(result.IsNull());
|
2012-04-19 19:47:27 +00:00
|
|
|
}
|
|
|
|
}
|
2012-12-15 00:20:07 +00:00
|
|
|
delete message;
|
|
|
|
return success;
|
2012-04-19 19:47:27 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:24:09 +00:00
|
|
|
|
2012-12-15 00:20:07 +00:00
|
|
|
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.
|
2012-12-18 23:47:35 +00:00
|
|
|
const Array& exception_args = Array::Handle(Array::New(3));
|
|
|
|
exception_args.SetAt(0, message);
|
|
|
|
exception_args.SetAt(1, cause);
|
|
|
|
exception_args.SetAt(2, stacktrace);
|
2012-12-15 00:20:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-12-18 21:36:01 +00:00
|
|
|
const Array& callback_args = Array::Handle(Array::New(1));
|
|
|
|
callback_args.SetAt(0, exception);
|
2012-12-15 00:20:07 +00:00
|
|
|
const Object& result =
|
2013-02-25 19:30:29 +00:00
|
|
|
Object::Handle(DartEntry::InvokeFunction(Function::Cast(function),
|
|
|
|
callback_args));
|
2012-12-15 00:20:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-04-19 19:47:27 +00:00
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
void IsolateMessageHandler::CheckAccess() {
|
2012-05-30 17:07:19 +00:00
|
|
|
ASSERT(IsCurrentIsolate());
|
2012-02-01 18:53:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2012-05-30 17:07:19 +00:00
|
|
|
bool IsolateMessageHandler::IsCurrentIsolate() const {
|
|
|
|
return (isolate_ == Isolate::Current());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-15 00:20:07 +00:00
|
|
|
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.
|
2012-12-07 01:41:53 +00:00
|
|
|
if (Isolate::UnhandledExceptionCallback() != NULL) {
|
|
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle error = Api::NewHandle(isolate_, result.raw());
|
|
|
|
(Isolate::UnhandledExceptionCallback())(error);
|
|
|
|
Dart_ExitScope();
|
|
|
|
}
|
2012-12-15 00:20:07 +00:00
|
|
|
|
|
|
|
isolate_->object_store()->set_sticky_error(result);
|
2012-12-07 01:41:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-06 18:00:51 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// static
|
|
|
|
void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
|
|
|
|
ASSERT(isolate == Isolate::Current());
|
|
|
|
}
|
2014-03-08 00:26:29 +00:00
|
|
|
#endif // defined(DEBUG)
|
2012-04-06 18:00:51 +00:00
|
|
|
|
2014-03-08 00:26:29 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
#define REUSABLE_HANDLE_SCOPE_INIT(object) \
|
|
|
|
reusable_##object##_handle_scope_active_(false),
|
|
|
|
#else
|
|
|
|
#define REUSABLE_HANDLE_SCOPE_INIT(object)
|
|
|
|
#endif // defined(DEBUG)
|
2012-04-06 18:00:51 +00:00
|
|
|
|
2013-06-24 22:41:01 +00:00
|
|
|
#define REUSABLE_HANDLE_INITIALIZERS(object) \
|
|
|
|
object##_handle_(NULL),
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
Isolate::Isolate()
|
2013-05-03 20:59:42 +00:00
|
|
|
: store_buffer_(),
|
2012-01-24 19:31:01 +00:00
|
|
|
message_notify_callback_(NULL),
|
2012-01-18 21:46:27 +00:00
|
|
|
name_(NULL),
|
2013-01-04 02:15:36 +00:00
|
|
|
start_time_(OS::GetCurrentTimeMicros()),
|
2011-11-29 21:55:13 +00:00
|
|
|
main_port_(0),
|
2011-10-05 05:20:07 +00:00
|
|
|
heap_(NULL),
|
|
|
|
object_store_(NULL),
|
|
|
|
top_context_(Context::null()),
|
|
|
|
top_exit_frame_info_(0),
|
|
|
|
init_callback_data_(NULL),
|
2013-10-31 05:46:57 +00:00
|
|
|
environment_callback_(NULL),
|
2011-10-05 05:20:07 +00:00
|
|
|
library_tag_handler_(NULL),
|
|
|
|
api_state_(NULL),
|
|
|
|
stub_code_(NULL),
|
2011-11-30 17:04:45 +00:00
|
|
|
debugger_(NULL),
|
2013-07-01 17:29:18 +00:00
|
|
|
single_step_(false),
|
2013-11-06 00:59:46 +00:00
|
|
|
random_(),
|
2013-01-25 01:16:35 +00:00
|
|
|
simulator_(NULL),
|
2011-10-05 05:20:07 +00:00
|
|
|
long_jump_base_(NULL),
|
|
|
|
timer_list_(),
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id_(0),
|
2011-12-16 18:41:20 +00:00
|
|
|
mutex_(new Mutex()),
|
2011-10-05 05:20:07 +00:00
|
|
|
stack_limit_(0),
|
2012-04-19 19:47:27 +00:00
|
|
|
saved_stack_limit_(0),
|
2014-04-09 18:27:37 +00:00
|
|
|
stack_overflow_flags_(0),
|
|
|
|
stack_overflow_count_(0),
|
2012-04-19 19:47:27 +00:00
|
|
|
message_handler_(NULL),
|
2014-01-29 18:40:12 +00:00
|
|
|
spawn_state_(NULL),
|
2013-04-09 17:51:24 +00:00
|
|
|
is_runnable_(false),
|
2014-03-12 22:39:15 +00:00
|
|
|
gc_prologue_callback_(NULL),
|
|
|
|
gc_epilogue_callback_(NULL),
|
2013-06-20 20:51:14 +00:00
|
|
|
defer_finalization_count_(0),
|
2013-10-01 19:34:12 +00:00
|
|
|
deopt_context_(NULL),
|
2013-04-04 18:48:24 +00:00
|
|
|
stacktrace_(NULL),
|
2013-06-13 09:06:43 +00:00
|
|
|
stack_frame_index_(-1),
|
2014-02-05 20:31:57 +00:00
|
|
|
cha_used_(false),
|
2013-07-16 18:31:25 +00:00
|
|
|
object_id_ring_(NULL),
|
2013-11-19 18:26:10 +00:00
|
|
|
profiler_data_(NULL),
|
2014-02-07 17:43:21 +00:00
|
|
|
thread_state_(NULL),
|
2014-04-10 22:32:45 +00:00
|
|
|
tag_table_(GrowableObjectArray::null()),
|
|
|
|
current_tag_(UserTag::null()),
|
2014-02-07 17:43:21 +00:00
|
|
|
next_(NULL),
|
2013-06-24 22:41:01 +00:00
|
|
|
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
|
2014-03-08 00:26:29 +00:00
|
|
|
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
|
2013-06-24 22:41:01 +00:00
|
|
|
reusable_handles_() {
|
2014-03-25 18:09:02 +00:00
|
|
|
set_vm_tag(VMTag::kIdleTagId);
|
2014-05-06 17:07:26 +00:00
|
|
|
set_user_tag(UserTags::kDefaultUserTag);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2014-03-08 00:26:29 +00:00
|
|
|
#undef REUSABLE_HANDLE_SCOPE_INIT
|
2013-06-24 22:41:01 +00:00
|
|
|
#undef REUSABLE_HANDLE_INITIALIZERS
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
Isolate::~Isolate() {
|
2012-01-18 21:46:27 +00:00
|
|
|
delete [] name_;
|
2011-10-05 05:20:07 +00:00
|
|
|
delete heap_;
|
|
|
|
delete object_store_;
|
|
|
|
delete api_state_;
|
|
|
|
delete stub_code_;
|
2012-01-19 18:33:32 +00:00
|
|
|
delete debugger_;
|
2013-01-25 01:16:35 +00:00
|
|
|
#if defined(USING_SIMULATOR)
|
|
|
|
delete simulator_;
|
|
|
|
#endif
|
2011-12-16 18:41:20 +00:00
|
|
|
delete mutex_;
|
|
|
|
mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate.
|
2012-02-01 18:53:40 +00:00
|
|
|
delete message_handler_;
|
|
|
|
message_handler_ = NULL; // Fail fast if we send messages to a dead isolate.
|
2013-10-01 19:34:12 +00:00
|
|
|
ASSERT(deopt_context_ == NULL); // No deopt in progress when isolate deleted.
|
2014-01-29 18:40:12 +00:00
|
|
|
delete spawn_state_;
|
2011-10-18 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
2014-02-07 17:43:21 +00:00
|
|
|
|
2012-02-07 09:18:22 +00:00
|
|
|
void Isolate::SetCurrent(Isolate* current) {
|
2013-12-16 18:52:15 +00:00
|
|
|
Isolate* old_current = Current();
|
2014-02-07 17:43:21 +00:00
|
|
|
if (old_current != NULL) {
|
2014-03-25 18:09:02 +00:00
|
|
|
old_current->set_vm_tag(VMTag::kIdleTagId);
|
2014-02-07 17:43:21 +00:00
|
|
|
old_current->set_thread_state(NULL);
|
2013-12-16 18:52:15 +00:00
|
|
|
Profiler::EndExecution(old_current);
|
2014-02-07 17:43:21 +00:00
|
|
|
}
|
|
|
|
Thread::SetThreadLocal(isolate_key, reinterpret_cast<uword>(current));
|
|
|
|
if (current != NULL) {
|
|
|
|
ASSERT(current->thread_state() == NULL);
|
|
|
|
InterruptableThreadState* thread_state =
|
|
|
|
ThreadInterrupter::GetCurrentThreadState();
|
|
|
|
#if defined(DEBUG)
|
|
|
|
CheckForDuplicateThreadState(thread_state);
|
|
|
|
#endif
|
2014-04-29 14:17:31 +00:00
|
|
|
ASSERT(thread_state != NULL);
|
2013-12-16 18:52:15 +00:00
|
|
|
Profiler::BeginExecution(current);
|
2014-02-07 17:43:21 +00:00
|
|
|
current->set_thread_state(thread_state);
|
2014-03-25 18:09:02 +00:00
|
|
|
current->set_vm_tag(VMTag::kVMTagId);
|
2013-11-19 18:26:10 +00:00
|
|
|
}
|
2012-02-07 09:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
2014-02-07 17:43:21 +00:00
|
|
|
isolates_list_monitor_ = new Monitor();
|
|
|
|
ASSERT(isolates_list_monitor_ != NULL);
|
2012-02-07 09:18:22 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 17:54:07 +00:00
|
|
|
|
2012-01-18 21:46:27 +00:00
|
|
|
Isolate* Isolate::Init(const char* name_prefix) {
|
2011-10-05 05:20:07 +00:00
|
|
|
Isolate* result = new Isolate();
|
|
|
|
ASSERT(result != NULL);
|
|
|
|
|
2014-02-07 17:43:21 +00:00
|
|
|
// Add to isolate list.
|
|
|
|
AddIsolateTolist(result);
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// TODO(5411455): For now just set the recently created isolate as
|
|
|
|
// the current isolate.
|
|
|
|
SetCurrent(result);
|
|
|
|
|
2013-06-24 22:41:01 +00:00
|
|
|
// Setup the isolate specific resuable handles.
|
|
|
|
#define REUSABLE_HANDLE_ALLOCATION(object) \
|
2014-03-08 00:26:29 +00:00
|
|
|
result->object##_handle_ = result->AllocateReusableHandle<object>();
|
2013-06-24 22:41:01 +00:00
|
|
|
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION)
|
|
|
|
#undef REUSABLE_HANDLE_ALLOCATION
|
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
// Setup the isolate message handler.
|
|
|
|
MessageHandler* handler = new IsolateMessageHandler(result);
|
|
|
|
ASSERT(handler != NULL);
|
|
|
|
result->set_message_handler(handler);
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
// 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));
|
2012-02-01 18:53:40 +00:00
|
|
|
result->set_main_port(PortMap::CreatePort(result->message_handler()));
|
2012-01-18 21:46:27 +00:00
|
|
|
result->BuildName(name_prefix);
|
2014-03-18 23:32:36 +00:00
|
|
|
result->message_handler()->set_pause_on_start(FLAG_pause_isolates_on_start);
|
|
|
|
result->message_handler()->set_pause_on_exit(FLAG_pause_isolates_on_exit);
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2011-11-30 17:04:45 +00:00
|
|
|
result->debugger_ = new Debugger();
|
2011-12-07 22:13:49 +00:00
|
|
|
result->debugger_->Initialize(result);
|
2012-01-18 21:46:27 +00:00
|
|
|
if (FLAG_trace_isolates) {
|
2012-02-01 18:53:40 +00:00
|
|
|
if (name_prefix == NULL || strcmp(name_prefix, "vm-isolate") != 0) {
|
2012-01-18 21:46:27 +00:00
|
|
|
OS::Print("[+] Starting isolate:\n"
|
|
|
|
"\tisolate: %s\n", result->name());
|
|
|
|
}
|
|
|
|
}
|
2013-11-19 18:26:10 +00:00
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-18 21:46:27 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// TODO(5411455): Use flag to override default value and Validate the
|
|
|
|
// stack size by querying OS.
|
|
|
|
uword Isolate::GetSpecifiedStackSize() {
|
2012-06-15 01:28:53 +00:00
|
|
|
ASSERT(Isolate::kStackSizeBuffer < Thread::GetMaxStackSize());
|
|
|
|
uword stack_size = Thread::GetMaxStackSize() - Isolate::kStackSizeBuffer;
|
2011-10-05 05:20:07 +00:00
|
|
|
return stack_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::SetStackLimitFromCurrentTOS(uword stack_top_value) {
|
2013-03-05 00:04:32 +00:00
|
|
|
#if defined(USING_SIMULATOR)
|
2013-02-27 17:13:51 +00:00
|
|
|
// 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
|
2011-10-05 05:20:07 +00:00
|
|
|
SetStackLimit(stack_top_value - GetSpecifiedStackSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::SetStackLimit(uword limit) {
|
2011-12-16 18:41:20 +00:00
|
|
|
MutexLocker ml(mutex_);
|
|
|
|
if (stack_limit_ == saved_stack_limit_) {
|
|
|
|
// No interrupt pending, set stack_limit_ too.
|
|
|
|
stack_limit_ = limit;
|
|
|
|
}
|
|
|
|
saved_stack_limit_ = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-19 19:15:16 +00:00
|
|
|
bool Isolate::GetStackBounds(uword* lower, uword* upper) {
|
|
|
|
uword stack_lower = stack_limit();
|
|
|
|
if (stack_lower == kUwordMax) {
|
2013-11-19 18:26:10 +00:00
|
|
|
stack_lower = saved_stack_limit();
|
|
|
|
}
|
2014-02-19 19:15:16 +00:00
|
|
|
if (stack_lower == kUwordMax) {
|
2013-11-19 18:26:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-19 19:15:16 +00:00
|
|
|
uword stack_upper = stack_lower + GetSpecifiedStackSize();
|
2013-11-19 18:26:10 +00:00
|
|
|
*lower = stack_lower;
|
|
|
|
*upper = stack_upper;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-16 18:41:20 +00:00
|
|
|
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_) {
|
2012-01-24 20:24:12 +00:00
|
|
|
stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
|
2011-12-16 18:41:20 +00:00
|
|
|
}
|
|
|
|
stack_limit_ |= interrupt_bits;
|
|
|
|
mutex_->Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-09 17:51:24 +00:00
|
|
|
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;
|
2014-01-29 18:40:12 +00:00
|
|
|
IsolateSpawnState* state = spawn_state();
|
2013-04-09 17:51:24 +00:00
|
|
|
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;
|
|
|
|
{
|
2014-01-29 18:40:12 +00:00
|
|
|
// TODO(turnidge): Is this locking required here at all anymore?
|
2013-04-09 17:51:24 +00:00
|
|
|
MutexLocker ml(isolate->mutex());
|
2014-01-29 18:40:12 +00:00
|
|
|
state = isolate->spawn_state();
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
StartIsolateScope start_scope(isolate);
|
|
|
|
StackZone zone(isolate);
|
|
|
|
HandleScope handle_scope(isolate);
|
2013-11-27 00:11:32 +00:00
|
|
|
if (!ClassFinalizer::ProcessPendingClasses()) {
|
2013-04-09 17:51:24 +00:00
|
|
|
// 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();
|
2013-10-25 19:23:00 +00:00
|
|
|
bool is_spawn_uri = state->is_spawn_uri();
|
2013-04-09 17:51:24 +00:00
|
|
|
if (result.IsError()) {
|
|
|
|
StoreError(isolate, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ASSERT(result.IsFunction());
|
|
|
|
Function& func = Function::Handle(isolate);
|
|
|
|
func ^= result.raw();
|
2013-10-25 19:23:00 +00:00
|
|
|
func = func.ImplicitClosureFunction();
|
|
|
|
|
|
|
|
// Instead of directly invoking the entry point we call '_startIsolate' with
|
|
|
|
// the entry point as argument. The '_startIsolate' function will
|
|
|
|
// communicate with the spawner to receive the initial message before it
|
|
|
|
// executes the real entry point.
|
|
|
|
// Since this function ("RunIsolate") is used for both Isolate.spawn and
|
|
|
|
// Isolate.spawnUri we also send a boolean flag as argument so that the
|
|
|
|
// "_startIsolate" function can act corresponding to how the isolate was
|
|
|
|
// created.
|
|
|
|
const Array& args = Array::Handle(Array::New(2));
|
|
|
|
args.SetAt(0, Instance::Handle(func.ImplicitStaticClosure()));
|
|
|
|
args.SetAt(1, is_spawn_uri ? Bool::True() : Bool::False());
|
|
|
|
|
|
|
|
const Library& lib = Library::Handle(Library::IsolateLibrary());
|
|
|
|
const String& entry_name = String::Handle(String::New("_startIsolate"));
|
|
|
|
const Function& entry_point =
|
|
|
|
Function::Handle(lib.LookupLocalFunction(entry_name));
|
|
|
|
ASSERT(entry_point.IsFunction() && !entry_point.IsNull());
|
|
|
|
|
|
|
|
result = DartEntry::InvokeFunction(entry_point, args);
|
2013-04-09 17:51:24 +00:00
|
|
|
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());
|
|
|
|
}
|
2013-07-09 14:59:01 +00:00
|
|
|
Dart::RunShutdownCallback();
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-16 18:41:20 +00:00
|
|
|
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;
|
2012-08-01 17:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-09 18:27:37 +00:00
|
|
|
uword Isolate::GetAndClearStackOverflowFlags() {
|
|
|
|
uword stack_overflow_flags = stack_overflow_flags_;
|
|
|
|
stack_overflow_flags_ = 0;
|
|
|
|
return stack_overflow_flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-25 00:33:25 +00:00
|
|
|
static int MostUsedFunctionFirst(const Function* const* a,
|
|
|
|
const Function* const* b) {
|
|
|
|
if ((*a)->usage_counter() > (*b)->usage_counter()) {
|
2011-10-05 05:20:07 +00:00
|
|
|
return -1;
|
2012-02-25 00:33:25 +00:00
|
|
|
} else if ((*a)->usage_counter() < (*b)->usage_counter()) {
|
2011-10-05 05:20:07 +00:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-13 14:23:10 +00:00
|
|
|
static void AddFunctionsFromClass(const Class& cls,
|
|
|
|
GrowableArray<const Function*>* functions) {
|
|
|
|
const Array& class_functions = Array::Handle(cls.functions());
|
2012-10-12 22:40:24 +00:00
|
|
|
// Class 'dynamic' is allocated/initialized in a special way, leaving
|
2012-02-13 14:23:10 +00:00
|
|
|
// 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();
|
2013-01-23 20:01:31 +00:00
|
|
|
function ^= class_functions.At(j);
|
2012-02-25 00:33:25 +00:00
|
|
|
if (function.usage_counter() > 0) {
|
2012-02-13 14:23:10 +00:00
|
|
|
functions->Add(&function);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
void Isolate::PrintInvokedFunctions() {
|
2011-11-12 05:55:22 +00:00
|
|
|
ASSERT(this == Isolate::Current());
|
2012-05-23 20:28:21 +00:00
|
|
|
const GrowableObjectArray& libraries =
|
|
|
|
GrowableObjectArray::Handle(object_store()->libraries());
|
2011-10-05 05:20:07 +00:00
|
|
|
Library& library = Library::Handle();
|
|
|
|
GrowableArray<const Function*> invoked_functions;
|
2012-05-23 20:28:21 +00:00
|
|
|
for (int i = 0; i < libraries.Length(); i++) {
|
2013-01-23 20:01:31 +00:00
|
|
|
library ^= libraries.At(i);
|
2011-10-05 05:20:07 +00:00
|
|
|
Class& cls = Class::Handle();
|
2013-08-14 17:54:18 +00:00
|
|
|
ClassDictionaryIterator iter(library,
|
|
|
|
ClassDictionaryIterator::kIteratePrivate);
|
2011-10-05 05:20:07 +00:00
|
|
|
while (iter.HasNext()) {
|
2011-10-20 23:29:06 +00:00
|
|
|
cls = iter.GetNextClass();
|
2012-02-13 14:23:10 +00:00
|
|
|
AddFunctionsFromClass(cls, &invoked_functions);
|
|
|
|
}
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2012-02-25 00:33:25 +00:00
|
|
|
invoked_functions.Sort(MostUsedFunctionFirst);
|
2011-10-05 05:20:07 +00:00
|
|
|
for (int i = 0; i < invoked_functions.length(); i++) {
|
2013-08-20 20:24:11 +00:00
|
|
|
OS::Print("%10" Pd " x %s\n",
|
2012-02-25 00:33:25 +00:00
|
|
|
invoked_functions[i]->usage_counter(),
|
2011-10-05 05:20:07 +00:00
|
|
|
invoked_functions[i]->ToFullyQualifiedCString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-07 22:17:56 +00:00
|
|
|
class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
|
|
|
|
public:
|
2014-03-04 18:11:19 +00:00
|
|
|
FinalizeWeakPersistentHandlesVisitor() : HandleVisitor(Isolate::Current()) {
|
2012-09-07 22:17:56 +00:00
|
|
|
}
|
|
|
|
|
2014-03-21 17:23:33 +00:00
|
|
|
void VisitHandle(uword addr) {
|
2012-09-07 22:17:56 +00:00
|
|
|
FinalizablePersistentHandle* handle =
|
|
|
|
reinterpret_cast<FinalizablePersistentHandle*>(addr);
|
2014-03-21 17:23:33 +00:00
|
|
|
handle->UpdateUnreachable(isolate());
|
2012-09-07 22:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(FinalizeWeakPersistentHandlesVisitor);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
void Isolate::Shutdown() {
|
|
|
|
ASSERT(this == Isolate::Current());
|
2012-04-06 18:00:51 +00:00
|
|
|
ASSERT(top_resource() == NULL);
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT((heap_ == NULL) || heap_->Verify());
|
|
|
|
|
2013-09-10 17:21:59 +00:00
|
|
|
// 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.
|
|
|
|
{
|
2013-06-13 09:06:43 +00:00
|
|
|
StackZone stack_zone(this);
|
|
|
|
HandleScope handle_scope(this);
|
|
|
|
|
2013-09-10 17:21:59 +00:00
|
|
|
// Clean up debugger resources.
|
|
|
|
debugger()->Shutdown();
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2013-09-10 17:21:59 +00:00
|
|
|
// Close all the ports owned by this isolate.
|
|
|
|
PortMap::ClosePorts(message_handler());
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2013-09-10 17:21:59 +00:00
|
|
|
// Fail fast if anybody tries to post any more messsages to this isolate.
|
|
|
|
delete message_handler();
|
|
|
|
set_message_handler(NULL);
|
2012-09-07 22:17:56 +00:00
|
|
|
|
2013-09-10 17:21:59 +00:00
|
|
|
// Dump all accumalated timer data for the isolate.
|
|
|
|
timer_list_.ReportTimers();
|
|
|
|
if (FLAG_report_usage_count) {
|
|
|
|
PrintInvokedFunctions();
|
|
|
|
}
|
|
|
|
|
2013-12-16 18:52:15 +00:00
|
|
|
// Write out profiler data if requested.
|
2014-01-03 19:55:50 +00:00
|
|
|
Profiler::WriteProfile(this);
|
2013-12-16 18:52:15 +00:00
|
|
|
|
2013-09-20 21:37:48 +00:00
|
|
|
// Write out the coverage data if collection has been enabled.
|
|
|
|
CodeCoverage::Write(this);
|
2013-09-10 17:21:59 +00:00
|
|
|
|
|
|
|
// Finalize any weak persistent handles with a non-null referent.
|
|
|
|
FinalizeWeakPersistentHandlesVisitor visitor;
|
2014-03-21 17:23:33 +00:00
|
|
|
api_state()->weak_persistent_handles().VisitHandles(&visitor);
|
|
|
|
api_state()->prologue_weak_persistent_handles().VisitHandles(&visitor);
|
2013-09-10 17:21:59 +00:00
|
|
|
|
|
|
|
CompilerStats::Print();
|
|
|
|
if (FLAG_trace_isolates) {
|
|
|
|
heap()->PrintSizes();
|
|
|
|
megamorphic_cache_table()->PrintSizes();
|
|
|
|
Symbols::DumpStats();
|
|
|
|
OS::Print("[-] Stopping isolate:\n"
|
|
|
|
"\tisolate: %s\n", name());
|
|
|
|
}
|
2012-01-18 21:46:27 +00:00
|
|
|
}
|
2013-09-10 17:21:59 +00:00
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// TODO(5411455): For now just make sure there are no current isolates
|
|
|
|
// as we are shutting down the isolate.
|
|
|
|
SetCurrent(NULL);
|
2014-02-07 17:43:21 +00:00
|
|
|
RemoveIsolateFromList(this);
|
2013-12-16 18:52:15 +00:00
|
|
|
Profiler::ShutdownProfilingForIsolate(this);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-01 00:30:25 +00:00
|
|
|
Dart_IsolateCreateCallback Isolate::create_callback_ = NULL;
|
2011-12-16 18:41:20 +00:00
|
|
|
Dart_IsolateInterruptCallback Isolate::interrupt_callback_ = NULL;
|
2012-11-26 23:31:47 +00:00
|
|
|
Dart_IsolateUnhandledExceptionCallback
|
|
|
|
Isolate::unhandled_exception_callback_ = NULL;
|
2012-06-28 18:15:17 +00:00
|
|
|
Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = NULL;
|
2012-12-06 21:56:31 +00:00
|
|
|
Dart_FileOpenCallback Isolate::file_open_callback_ = NULL;
|
2013-05-03 22:50:26 +00:00
|
|
|
Dart_FileReadCallback Isolate::file_read_callback_ = NULL;
|
2012-12-06 21:56:31 +00:00
|
|
|
Dart_FileWriteCallback Isolate::file_write_callback_ = NULL;
|
|
|
|
Dart_FileCloseCallback Isolate::file_close_callback_ = NULL;
|
2013-11-06 00:59:46 +00:00
|
|
|
Dart_EntropySource Isolate::entropy_source_callback_ = NULL;
|
2013-04-04 18:48:24 +00:00
|
|
|
Dart_IsolateInterruptCallback Isolate::vmstats_callback_ = NULL;
|
2014-01-14 22:34:43 +00:00
|
|
|
Dart_ServiceIsolateCreateCalback Isolate::service_create_callback_ = NULL;
|
2011-12-16 18:41:20 +00:00
|
|
|
|
2014-02-07 17:43:21 +00:00
|
|
|
Monitor* Isolate::isolates_list_monitor_ = NULL;
|
|
|
|
Isolate* Isolate::isolates_list_head_ = NULL;
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
|
2012-03-13 23:41:59 +00:00
|
|
|
bool visit_prologue_weak_handles,
|
2011-10-05 05:20:07 +00:00
|
|
|
bool validate_frames) {
|
|
|
|
ASSERT(visitor != NULL);
|
|
|
|
|
|
|
|
// Visit objects in the object store.
|
|
|
|
object_store()->VisitObjectPointers(visitor);
|
|
|
|
|
2012-05-01 09:20:40 +00:00
|
|
|
// Visit objects in the class table.
|
|
|
|
class_table()->VisitObjectPointers(visitor);
|
|
|
|
|
2012-12-10 09:48:52 +00:00
|
|
|
// Visit objects in the megamorphic cache.
|
|
|
|
megamorphic_cache_table()->VisitObjectPointers(visitor);
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// Visit objects in per isolate stubs.
|
|
|
|
StubCode::VisitObjectPointers(visitor);
|
|
|
|
|
|
|
|
// Visit objects in zones.
|
|
|
|
current_zone()->VisitObjectPointers(visitor);
|
|
|
|
|
2013-06-24 22:41:01 +00:00
|
|
|
// Visit objects in isolate specific handles area.
|
|
|
|
reusable_handles_.VisitObjectPointers(visitor);
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// 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) {
|
2012-03-13 23:41:59 +00:00
|
|
|
api_state()->VisitObjectPointers(visitor, visit_prologue_weak_handles);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Visit the top context which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_context_));
|
2011-11-30 17:04:45 +00:00
|
|
|
|
2014-04-10 22:32:45 +00:00
|
|
|
// Visit the current tag which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(reinterpret_cast<RawObject**>(¤t_tag_));
|
|
|
|
|
|
|
|
// Visit the tag table which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(reinterpret_cast<RawObject**>(&tag_table_));
|
|
|
|
|
2011-11-30 17:04:45 +00:00
|
|
|
// Visit objects in the debugger.
|
|
|
|
debugger()->VisitObjectPointers(visitor);
|
2013-10-01 19:34:12 +00:00
|
|
|
|
|
|
|
// Visit objects that are being used for deoptimization.
|
|
|
|
if (deopt_context() != NULL) {
|
|
|
|
deopt_context()->VisitObjectPointers(visitor);
|
|
|
|
}
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2011-12-20 01:44:53 +00:00
|
|
|
|
2012-03-13 23:41:59 +00:00
|
|
|
void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor,
|
|
|
|
bool visit_prologue_weak_handles) {
|
2011-12-20 01:44:53 +00:00
|
|
|
if (api_state() != NULL) {
|
2012-03-13 23:41:59 +00:00
|
|
|
api_state()->VisitWeakHandles(visitor, visit_prologue_weak_handles);
|
2011-12-20 01:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 22:34:08 +00:00
|
|
|
|
2014-04-15 16:32:55 +00:00
|
|
|
void Isolate::VisitPrologueWeakPersistentHandles(HandleVisitor* visitor) {
|
|
|
|
if (api_state() != NULL) {
|
|
|
|
api_state()->VisitPrologueWeakHandles(visitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-29 18:10:02 +00:00
|
|
|
void Isolate::PrintJSON(JSONStream* stream, bool ref) {
|
2014-01-29 18:40:12 +00:00
|
|
|
JSONObject jsobj(stream);
|
2014-03-20 21:00:10 +00:00
|
|
|
jsobj.AddProperty("type", (ref ? "@Isolate" : "Isolate"));
|
2014-01-29 18:40:12 +00:00
|
|
|
jsobj.AddPropertyF("id", "isolates/%" Pd "",
|
|
|
|
static_cast<intptr_t>(main_port()));
|
2014-03-20 21:00:10 +00:00
|
|
|
jsobj.AddPropertyF("mainPort", "%" Pd "",
|
2014-01-29 18:40:12 +00:00
|
|
|
static_cast<intptr_t>(main_port()));
|
2014-03-20 21:00:10 +00:00
|
|
|
|
|
|
|
// Assign an isolate name based on the entry function.
|
2014-01-29 18:40:12 +00:00
|
|
|
IsolateSpawnState* state = spawn_state();
|
2014-03-20 21:00:10 +00:00
|
|
|
if (state == NULL) {
|
|
|
|
jsobj.AddPropertyF("name", "root");
|
|
|
|
} else if (state->class_name() != NULL) {
|
|
|
|
jsobj.AddPropertyF("name", "%s.%s",
|
|
|
|
state->class_name(),
|
|
|
|
state->function_name());
|
|
|
|
} else {
|
|
|
|
jsobj.AddPropertyF("name", "%s", state->function_name());
|
|
|
|
}
|
|
|
|
if (ref) {
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 18:40:12 +00:00
|
|
|
if (state != NULL) {
|
|
|
|
const Object& entry = Object::Handle(this, state->ResolveFunction());
|
|
|
|
if (!entry.IsNull() && entry.IsFunction()) {
|
|
|
|
Function& func = Function::Handle(this);
|
|
|
|
func ^= entry.raw();
|
|
|
|
jsobj.AddProperty("entry", func);
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
2013-04-16 21:05:37 +00:00
|
|
|
}
|
2014-01-29 18:40:12 +00:00
|
|
|
{
|
|
|
|
JSONObject jsheap(&jsobj, "heap");
|
2014-04-15 14:16:15 +00:00
|
|
|
jsheap.AddProperty("usedNew",
|
|
|
|
heap()->UsedInWords(Heap::kNew) * kWordSize);
|
|
|
|
jsheap.AddProperty("capacityNew",
|
|
|
|
heap()->CapacityInWords(Heap::kNew) * kWordSize);
|
|
|
|
jsheap.AddProperty("usedOld",
|
|
|
|
heap()->UsedInWords(Heap::kOld) * kWordSize);
|
|
|
|
jsheap.AddProperty("capacityOld",
|
|
|
|
heap()->CapacityInWords(Heap::kOld) * kWordSize);
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 17:13:03 +00:00
|
|
|
// TODO(turnidge): Don't compute a full stack trace every time we
|
|
|
|
// request an isolate's info.
|
2014-01-29 18:40:12 +00:00
|
|
|
DebuggerStackTrace* stack = debugger()->StackTrace();
|
|
|
|
if (stack->Length() > 0) {
|
|
|
|
JSONObject jsframe(&jsobj, "topFrame");
|
2013-04-04 18:48:24 +00:00
|
|
|
|
2014-01-29 18:40:12 +00:00
|
|
|
ActivationFrame* frame = stack->FrameAt(0);
|
|
|
|
frame->PrintToJSONObject(&jsobj);
|
|
|
|
// TODO(turnidge): Implement depth differently -- differentiate
|
|
|
|
// inlined frames.
|
|
|
|
jsobj.AddProperty("depth", (intptr_t)0);
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
2014-03-18 23:32:36 +00:00
|
|
|
intptr_t live_ports = message_handler()->live_ports();
|
|
|
|
intptr_t control_ports = message_handler()->control_ports();
|
|
|
|
bool paused_on_exit = message_handler()->paused_on_exit();
|
|
|
|
bool pause_on_start = message_handler()->pause_on_start();
|
|
|
|
bool pause_on_exit = message_handler()->pause_on_exit();
|
2014-03-20 21:00:10 +00:00
|
|
|
jsobj.AddProperty("livePorts", live_ports);
|
|
|
|
jsobj.AddProperty("controlPorts", control_ports);
|
|
|
|
jsobj.AddProperty("pausedOnStart", pause_on_start);
|
|
|
|
jsobj.AddProperty("pausedOnExit", paused_on_exit);
|
|
|
|
jsobj.AddProperty("pauseOnExit", pause_on_exit);
|
2014-01-29 18:40:12 +00:00
|
|
|
const Library& lib =
|
|
|
|
Library::Handle(object_store()->root_library());
|
|
|
|
jsobj.AddProperty("rootLib", lib);
|
2013-04-04 18:48:24 +00:00
|
|
|
|
2014-01-29 18:40:12 +00:00
|
|
|
timer_list().PrintTimersToJSONProperty(&jsobj);
|
2014-04-02 18:30:01 +00:00
|
|
|
{
|
|
|
|
JSONObject tagCounters(&jsobj, "tagCounters");
|
|
|
|
vm_tag_counters()->PrintToJSONObject(&tagCounters);
|
|
|
|
}
|
2014-03-25 18:09:02 +00:00
|
|
|
if (object_store()->sticky_error() != Object::null()) {
|
|
|
|
Error& error = Error::Handle(this, object_store()->sticky_error());
|
|
|
|
ASSERT(!error.IsNull());
|
|
|
|
jsobj.AddProperty("error", error, false);
|
|
|
|
}
|
|
|
|
|
2014-03-20 16:41:59 +00:00
|
|
|
{
|
|
|
|
JSONObject typeargsRef(&jsobj, "canonicalTypeArguments");
|
|
|
|
typeargsRef.AddProperty("type", "@TypeArgumentsList");
|
|
|
|
typeargsRef.AddProperty("id", "typearguments");
|
|
|
|
typeargsRef.AddProperty("name", "canonical type arguments");
|
|
|
|
}
|
2014-05-05 16:54:59 +00:00
|
|
|
{
|
|
|
|
const GrowableObjectArray& libs =
|
|
|
|
GrowableObjectArray::Handle(object_store()->libraries());
|
|
|
|
intptr_t num_libs = libs.Length();
|
|
|
|
Library &lib = Library::Handle();
|
|
|
|
|
|
|
|
JSONArray lib_array(&jsobj, "libraries");
|
|
|
|
for (intptr_t i = 0; i < num_libs; i++) {
|
|
|
|
lib ^= libs.At(i);
|
|
|
|
ASSERT(!lib.IsNull());
|
|
|
|
lib_array.AddValue(lib);
|
|
|
|
}
|
|
|
|
}
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
|
|
|
|
2013-04-09 17:51:24 +00:00
|
|
|
|
2014-03-25 18:09:02 +00:00
|
|
|
void Isolate::ProfileInterrupt() {
|
|
|
|
InterruptableThreadState* state = thread_state();
|
|
|
|
if (state == NULL) {
|
|
|
|
// Isolate is not scheduled on a thread.
|
|
|
|
ProfileIdle();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(state->id != Thread::kInvalidThreadId);
|
|
|
|
ThreadInterrupter::InterruptThread(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::ProfileIdle() {
|
|
|
|
vm_tag_counters_.Increment(vm_tag());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-10 22:32:45 +00:00
|
|
|
void Isolate::set_tag_table(const GrowableObjectArray& value) {
|
|
|
|
tag_table_ = value.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::set_current_tag(const UserTag& tag) {
|
|
|
|
intptr_t user_tag = tag.tag();
|
|
|
|
set_user_tag(static_cast<uword>(user_tag));
|
|
|
|
current_tag_ = tag.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-07 17:43:21 +00:00
|
|
|
void Isolate::VisitIsolates(IsolateVisitor* visitor) {
|
|
|
|
if (visitor == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
Isolate* current = isolates_list_head_;
|
|
|
|
while (current) {
|
|
|
|
visitor->VisitIsolate(current);
|
|
|
|
current = current->next_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::AddIsolateTolist(Isolate* isolate) {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
ASSERT(isolate->next_ == NULL);
|
|
|
|
isolate->next_ = isolates_list_head_;
|
|
|
|
isolates_list_head_ = isolate;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::RemoveIsolateFromList(Isolate* isolate) {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
if (isolate == isolates_list_head_) {
|
|
|
|
isolates_list_head_ = isolate->next_;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Isolate* previous = NULL;
|
|
|
|
Isolate* current = isolates_list_head_;
|
|
|
|
while (current) {
|
|
|
|
if (current == isolate) {
|
|
|
|
ASSERT(previous != NULL);
|
|
|
|
previous->next_ = current->next_;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
previous = current;
|
|
|
|
current = current->next_;
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
void Isolate::CheckForDuplicateThreadState(InterruptableThreadState* state) {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
ASSERT(state != NULL);
|
|
|
|
Isolate* current = isolates_list_head_;
|
|
|
|
while (current) {
|
|
|
|
ASSERT(current->thread_state() != state);
|
|
|
|
current = current->next_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-06-24 22:41:01 +00:00
|
|
|
template<class T>
|
|
|
|
T* Isolate::AllocateReusableHandle() {
|
|
|
|
T* handle = reinterpret_cast<T*>(reusable_handles_.AllocateScopedHandle());
|
|
|
|
T::initializeHandle(handle, T::null());
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-25 19:23:00 +00:00
|
|
|
IsolateSpawnState::IsolateSpawnState(const Function& func)
|
2013-04-09 17:51:24 +00:00
|
|
|
: isolate_(NULL),
|
|
|
|
script_url_(NULL),
|
|
|
|
library_url_(NULL),
|
2013-11-20 09:14:30 +00:00
|
|
|
class_name_(NULL),
|
2013-04-09 17:51:24 +00:00
|
|
|
function_name_(NULL),
|
|
|
|
exception_callback_name_(NULL) {
|
2013-10-24 16:41:22 +00:00
|
|
|
script_url_ = NULL;
|
2013-04-09 17:51:24 +00:00
|
|
|
const Class& cls = Class::Handle(func.Owner());
|
|
|
|
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());
|
2013-11-20 09:14:30 +00:00
|
|
|
if (!cls.IsTopLevel()) {
|
|
|
|
const String& class_name = String::Handle(cls.Name());
|
|
|
|
class_name_ = strdup(class_name.ToCString());
|
|
|
|
}
|
2013-10-25 19:23:00 +00:00
|
|
|
exception_callback_name_ = strdup("_unhandledExceptionCallback");
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IsolateSpawnState::IsolateSpawnState(const char* script_url)
|
|
|
|
: isolate_(NULL),
|
|
|
|
library_url_(NULL),
|
2013-11-20 09:14:30 +00:00
|
|
|
class_name_(NULL),
|
2013-04-09 17:51:24 +00:00
|
|
|
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_);
|
2013-11-20 09:14:30 +00:00
|
|
|
free(class_name_);
|
2013-04-09 17:51:24 +00:00
|
|
|
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.
|
2013-11-20 09:14:30 +00:00
|
|
|
const String& func_name = String::Handle(String::New(function_name()));
|
|
|
|
|
|
|
|
if (class_name() == NULL) {
|
|
|
|
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() != NULL ? library_url() : script_url())));
|
|
|
|
return LanguageError::New(msg);
|
|
|
|
}
|
|
|
|
return func.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
const String& cls_name = String::Handle(String::New(class_name()));
|
|
|
|
const Class& cls = Class::Handle(lib.LookupLocalClass(cls_name));
|
|
|
|
if (cls.IsNull()) {
|
|
|
|
const String& msg = String::Handle(String::NewFormatted(
|
|
|
|
"Unable to resolve class '%s' in library '%s'.",
|
|
|
|
class_name(),
|
|
|
|
(library_url() != NULL ? library_url() : script_url())));
|
|
|
|
return LanguageError::New(msg);
|
|
|
|
}
|
|
|
|
const Function& func =
|
|
|
|
Function::Handle(cls.LookupStaticFunctionAllowPrivate(func_name));
|
2013-04-09 17:51:24 +00:00
|
|
|
if (func.IsNull()) {
|
|
|
|
const String& msg = String::Handle(String::NewFormatted(
|
2013-11-20 09:14:30 +00:00
|
|
|
"Unable to resolve static method '%s.%s' in library '%s'.",
|
|
|
|
class_name(), function_name(),
|
|
|
|
(library_url() != NULL ? library_url() : script_url())));
|
2013-04-09 17:51:24 +00:00
|
|
|
return LanguageError::New(msg);
|
|
|
|
}
|
|
|
|
return func.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IsolateSpawnState::Cleanup() {
|
|
|
|
SwitchIsolateScope switch_scope(isolate());
|
|
|
|
Dart::ShutdownIsolate();
|
|
|
|
}
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
} // namespace dart
|