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"
|
2015-09-15 19:49:52 +00:00
|
|
|
#include "include/dart_native_api.h"
|
2012-01-16 12:28:10 +00:00
|
|
|
#include "platform/assert.h"
|
2015-12-04 01:46:02 +00:00
|
|
|
#include "platform/text_buffer.h"
|
2015-10-05 19:29:22 +00:00
|
|
|
#include "vm/class_finalizer.h"
|
2012-12-22 00:23:25 +00:00
|
|
|
#include "vm/code_observers.h"
|
2015-10-05 19:29:22 +00:00
|
|
|
#include "vm/compiler.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"
|
2015-09-15 19:49:52 +00:00
|
|
|
#include "vm/dart_api_message.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"
|
2014-08-12 23:19:53 +00:00
|
|
|
#include "vm/lockers.h"
|
2015-02-09 18:54:20 +00:00
|
|
|
#include "vm/log.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"
|
2015-02-26 18:48:55 +00:00
|
|
|
#include "vm/object.h"
|
|
|
|
#include "vm/os_thread.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#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"
|
2015-03-05 19:02:42 +00:00
|
|
|
#include "vm/service_event.h"
|
2015-02-12 19:10:55 +00:00
|
|
|
#include "vm/service_isolate.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"
|
2015-06-18 23:16:50 +00:00
|
|
|
#include "vm/store_buffer.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#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"
|
2013-12-16 18:52:15 +00:00
|
|
|
#include "vm/thread_interrupter.h"
|
2015-07-09 18:22:26 +00:00
|
|
|
#include "vm/thread_registry.h"
|
2015-06-16 17:10:14 +00:00
|
|
|
#include "vm/timeline.h"
|
2015-09-10 16:31:16 +00:00
|
|
|
#include "vm/timeline_analysis.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 {
|
|
|
|
|
2015-08-26 17:05:26 +00:00
|
|
|
DECLARE_FLAG(bool, print_metrics);
|
2015-09-10 16:31:16 +00:00
|
|
|
DECLARE_FLAG(bool, timing);
|
2015-08-26 23:45:36 +00:00
|
|
|
DECLARE_FLAG(bool, trace_service);
|
2015-08-18 22:18:02 +00:00
|
|
|
|
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.");
|
2014-09-04 16:53:44 +00:00
|
|
|
DEFINE_FLAG(bool, break_at_isolate_spawn, false,
|
|
|
|
"Insert a one-time breakpoint at the entrypoint for all spawned "
|
|
|
|
"isolates");
|
2013-06-13 09:06:43 +00:00
|
|
|
|
2015-08-03 14:26:23 +00:00
|
|
|
DEFINE_FLAG(int, new_gen_semi_max_size, (kWordSize <= 4) ? 16 : 32,
|
|
|
|
"Max size of new gen semi space in MB");
|
|
|
|
DEFINE_FLAG(int, old_gen_heap_size, 0,
|
|
|
|
"Max size of old gen heap size in MB, or 0 for unlimited,"
|
|
|
|
"e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap");
|
|
|
|
DEFINE_FLAG(int, external_max_size, (kWordSize <= 4) ? 512 : 1024,
|
|
|
|
"Max total size of external allocations in MB, or 0 for unlimited,"
|
|
|
|
"e.g: --external_max_size=1024 allows up to 1024MB of externals");
|
2015-06-16 17:10:14 +00:00
|
|
|
|
2015-06-07 15:57:34 +00:00
|
|
|
// TODO(iposva): Make these isolate specific flags inaccessible using the
|
|
|
|
// regular FLAG_xyz pattern.
|
|
|
|
// These flags are per-isolate and only influence the defaults.
|
|
|
|
DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
|
|
|
|
DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
|
|
|
|
DEFINE_FLAG(bool, error_on_bad_override, false,
|
|
|
|
"Report error for bad overrides.");
|
|
|
|
DEFINE_FLAG(bool, error_on_bad_type, false,
|
|
|
|
"Report error for malformed types.");
|
|
|
|
|
|
|
|
static void CheckedModeHandler(bool value) {
|
|
|
|
FLAG_enable_asserts = value;
|
|
|
|
FLAG_enable_type_checks = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --enable-checked-mode and --checked both enable checked mode which is
|
|
|
|
// equivalent to setting --enable-asserts and --enable-type-checks.
|
|
|
|
DEFINE_FLAG_HANDLER(CheckedModeHandler,
|
|
|
|
enable_checked_mode,
|
|
|
|
"Enable checked mode.");
|
|
|
|
|
|
|
|
DEFINE_FLAG_HANDLER(CheckedModeHandler,
|
|
|
|
checked,
|
|
|
|
"Enable checked mode.");
|
|
|
|
|
|
|
|
|
2015-09-02 23:07:48 +00:00
|
|
|
// Quick access to the locally defined thread() and isolate() methods.
|
|
|
|
#define T (thread())
|
2014-05-28 21:58:33 +00:00
|
|
|
#define I (isolate())
|
|
|
|
|
2015-01-12 23:14:30 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// Helper class to ensure that a live origin_id is never reused
|
|
|
|
// and assigned to an isolate.
|
|
|
|
class VerifyOriginId : public IsolateVisitor {
|
|
|
|
public:
|
|
|
|
explicit VerifyOriginId(Dart_Port id) : id_(id) {}
|
|
|
|
|
|
|
|
void VisitIsolate(Isolate* isolate) {
|
|
|
|
ASSERT(isolate->origin_id() != id_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Dart_Port id_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(VerifyOriginId);
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2014-12-08 22:45:10 +00:00
|
|
|
static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
|
|
|
|
void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
|
|
|
|
return reinterpret_cast<uint8_t*>(new_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void SerializeObject(const Instance& obj,
|
|
|
|
uint8_t** obj_data,
|
2015-01-12 23:14:30 +00:00
|
|
|
intptr_t* obj_len,
|
|
|
|
bool allow_any_object) {
|
|
|
|
MessageWriter writer(obj_data, &allocator, allow_any_object);
|
2014-12-08 22:45:10 +00:00
|
|
|
writer.WriteMessage(obj);
|
|
|
|
*obj_len = writer.BytesWritten();
|
|
|
|
}
|
|
|
|
|
2015-12-12 00:07:16 +00:00
|
|
|
// TODO(zra): Allocation of Message objects should be centralized.
|
|
|
|
static Message* SerializeMessage(
|
|
|
|
Dart_Port dest_port, const Instance& obj) {
|
|
|
|
if (ApiObjectConverter::CanConvert(obj.raw())) {
|
|
|
|
return new Message(dest_port, obj.raw(), Message::kNormalPriority);
|
|
|
|
} else {
|
|
|
|
uint8_t* obj_data;
|
|
|
|
intptr_t obj_len;
|
|
|
|
SerializeObject(obj, &obj_data, &obj_len, false);
|
|
|
|
return new Message(dest_port, obj_data, obj_len, Message::kNormalPriority);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 22:45:10 +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
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-23 19:13:25 +00:00
|
|
|
void Isolate::SendInternalLibMessage(LibMsgId msg_id, uint64_t capability) {
|
|
|
|
const Array& msg = Array::Handle(Array::New(3));
|
|
|
|
Object& element = Object::Handle();
|
|
|
|
|
|
|
|
element = Smi::New(Message::kIsolateLibOOBMsg);
|
|
|
|
msg.SetAt(0, element);
|
|
|
|
element = Smi::New(msg_id);
|
|
|
|
msg.SetAt(1, element);
|
|
|
|
element = Capability::New(capability);
|
|
|
|
msg.SetAt(2, element);
|
|
|
|
|
|
|
|
uint8_t* data = NULL;
|
|
|
|
MessageWriter writer(&data, &allocator, false);
|
|
|
|
writer.WriteMessage(msg);
|
|
|
|
|
|
|
|
PortMap::PostMessage(new Message(main_port(),
|
|
|
|
data, writer.BytesWritten(),
|
|
|
|
Message::kOOBPriority));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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);
|
2015-10-06 18:27:26 +00:00
|
|
|
MessageStatus HandleMessage(Message* message);
|
2015-03-05 19:02:42 +00:00
|
|
|
void NotifyPauseOnStart();
|
|
|
|
void NotifyPauseOnExit();
|
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;
|
2014-05-28 21:58:33 +00:00
|
|
|
virtual Isolate* isolate() const { return isolate_; }
|
2012-05-30 17:07:19 +00:00
|
|
|
|
2015-09-15 19:49:52 +00:00
|
|
|
private:
|
2014-12-13 00:39:16 +00:00
|
|
|
// A result of false indicates that the isolate should terminate the
|
|
|
|
// processing of further events.
|
2015-09-23 19:13:25 +00:00
|
|
|
RawError* HandleLibMessage(const Array& message);
|
2014-12-13 00:39:16 +00:00
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
MessageStatus ProcessUnhandledException(const Error& result);
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-03 12:56:02 +00:00
|
|
|
// Isolate library OOB messages are fixed sized arrays which have the
|
|
|
|
// following format:
|
|
|
|
// [ OOB dispatch, Isolate library dispatch, <message specific data> ]
|
2015-09-23 19:13:25 +00:00
|
|
|
RawError* IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
|
|
|
if (message.Length() < 2) return Error::null();
|
2015-10-19 17:27:36 +00:00
|
|
|
Zone* zone = T->zone();
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& type = Object::Handle(zone, message.At(1));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!type.IsSmi()) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
const intptr_t msg_type = Smi::Cast(type).Value();
|
|
|
|
switch (msg_type) {
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kPauseMsg: {
|
2014-07-03 12:56:02 +00:00
|
|
|
// [ OOB, kPauseMsg, pause capability, resume capability ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() != 4) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
Object& obj = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!I->VerifyPauseCapability(obj)) return Error::null();
|
2014-07-03 12:56:02 +00:00
|
|
|
obj = message.At(3);
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj.IsCapability()) return Error::null();
|
2014-07-03 12:56:02 +00:00
|
|
|
if (I->AddResumeCapability(Capability::Cast(obj))) {
|
|
|
|
increment_paused();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kResumeMsg: {
|
2014-07-03 12:56:02 +00:00
|
|
|
// [ OOB, kResumeMsg, pause capability, resume capability ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() != 4) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
Object& obj = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!I->VerifyPauseCapability(obj)) return Error::null();
|
2014-07-03 12:56:02 +00:00
|
|
|
obj = message.At(3);
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj.IsCapability()) return Error::null();
|
2014-07-03 12:56:02 +00:00
|
|
|
if (I->RemoveResumeCapability(Capability::Cast(obj))) {
|
|
|
|
decrement_paused();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kPingMsg: {
|
2015-04-13 10:29:54 +00:00
|
|
|
// [ OOB, kPingMsg, responsePort, priority, response ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() != 5) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& obj2 = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj2.IsSendPort()) return Error::null();
|
2014-12-08 22:45:10 +00:00
|
|
|
const SendPort& send_port = SendPort::Cast(obj2);
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& obj3 = Object::Handle(zone, message.At(3));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj3.IsSmi()) return Error::null();
|
2014-12-13 00:39:16 +00:00
|
|
|
const intptr_t priority = Smi::Cast(obj3).Value();
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& obj4 = Object::Handle(zone, message.At(4));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj4.IsInstance() && !obj4.IsNull()) return Error::null();
|
2015-04-13 10:29:54 +00:00
|
|
|
const Instance& response =
|
|
|
|
obj4.IsNull() ? Instance::null_instance() : Instance::Cast(obj4);
|
2015-09-23 19:13:25 +00:00
|
|
|
if (priority == Isolate::kImmediateAction) {
|
2015-12-12 00:07:16 +00:00
|
|
|
PortMap::PostMessage(SerializeMessage(
|
|
|
|
send_port.Id(), response));
|
2014-12-13 00:39:16 +00:00
|
|
|
} else {
|
2015-09-23 19:13:25 +00:00
|
|
|
ASSERT((priority == Isolate::kBeforeNextEventAction) ||
|
|
|
|
(priority == Isolate::kAsEventAction));
|
2014-12-08 22:45:10 +00:00
|
|
|
// Update the message so that it will be handled immediately when it
|
|
|
|
// is picked up from the message queue the next time.
|
2015-10-12 22:51:06 +00:00
|
|
|
message.SetAt(0, Smi::Handle(zone,
|
|
|
|
Smi::New(Message::kDelayedIsolateLibOOBMsg)));
|
|
|
|
message.SetAt(3, Smi::Handle(zone,
|
|
|
|
Smi::New(Isolate::kImmediateAction)));
|
2015-12-12 00:07:16 +00:00
|
|
|
this->PostMessage(SerializeMessage(
|
|
|
|
Message::kIllegalPort, message),
|
2015-09-23 19:13:25 +00:00
|
|
|
priority == Isolate::kBeforeNextEventAction /* at_head */);
|
2014-12-13 00:39:16 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-24 17:22:05 +00:00
|
|
|
case Isolate::kKillMsg:
|
2015-10-06 18:27:26 +00:00
|
|
|
case Isolate::kInternalKillMsg:
|
|
|
|
case Isolate::kVMRestartMsg: {
|
2014-12-13 00:39:16 +00:00
|
|
|
// [ OOB, kKillMsg, terminate capability, priority ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() != 4) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
Object& obj = Object::Handle(zone, message.At(3));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj.IsSmi()) return Error::null();
|
2014-12-13 00:39:16 +00:00
|
|
|
const intptr_t priority = Smi::Cast(obj).Value();
|
2015-09-23 19:13:25 +00:00
|
|
|
if (priority == Isolate::kImmediateAction) {
|
2014-12-13 00:39:16 +00:00
|
|
|
obj = message.At(2);
|
2015-09-23 19:13:25 +00:00
|
|
|
if (I->VerifyTerminateCapability(obj)) {
|
2015-10-06 18:27:26 +00:00
|
|
|
// We will kill the current isolate by returning an UnwindError.
|
2015-09-24 17:22:05 +00:00
|
|
|
if (msg_type == Isolate::kKillMsg) {
|
|
|
|
const String& msg = String::Handle(String::New(
|
|
|
|
"isolate terminated by Isolate.kill"));
|
|
|
|
const UnwindError& error =
|
|
|
|
UnwindError::Handle(UnwindError::New(msg));
|
|
|
|
error.set_is_user_initiated(true);
|
|
|
|
return error.raw();
|
2015-10-06 18:27:26 +00:00
|
|
|
} else if (msg_type == Isolate::kInternalKillMsg) {
|
2015-09-24 17:22:05 +00:00
|
|
|
const String& msg = String::Handle(String::New(
|
|
|
|
"isolate terminated by vm"));
|
|
|
|
return UnwindError::New(msg);
|
2015-10-06 18:27:26 +00:00
|
|
|
} else if (msg_type == Isolate::kVMRestartMsg) {
|
|
|
|
// If this is the main isolate, this request to restart
|
|
|
|
// will be caught and handled in the embedder. Otherwise
|
|
|
|
// this unwind error will cause the isolate to exit.
|
|
|
|
const String& msg = String::Handle(String::New(
|
|
|
|
"isolate terminated for vm restart"));
|
|
|
|
const UnwindError& error =
|
|
|
|
UnwindError::Handle(UnwindError::New(msg));
|
|
|
|
error.set_is_vm_restart(true);
|
|
|
|
return error.raw();
|
|
|
|
} else {
|
|
|
|
UNREACHABLE();
|
2015-09-24 17:22:05 +00:00
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
} else {
|
|
|
|
return Error::null();
|
|
|
|
}
|
2014-12-13 00:39:16 +00:00
|
|
|
} else {
|
2015-09-23 19:13:25 +00:00
|
|
|
ASSERT((priority == Isolate::kBeforeNextEventAction) ||
|
|
|
|
(priority == Isolate::kAsEventAction));
|
2014-12-08 22:45:10 +00:00
|
|
|
// Update the message so that it will be handled immediately when it
|
|
|
|
// is picked up from the message queue the next time.
|
2015-10-12 22:51:06 +00:00
|
|
|
message.SetAt(0, Smi::Handle(zone,
|
|
|
|
Smi::New(Message::kDelayedIsolateLibOOBMsg)));
|
|
|
|
message.SetAt(3, Smi::Handle(zone,
|
|
|
|
Smi::New(Isolate::kImmediateAction)));
|
2015-12-12 00:07:16 +00:00
|
|
|
this->PostMessage(SerializeMessage(
|
|
|
|
Message::kIllegalPort, message),
|
2015-09-23 19:13:25 +00:00
|
|
|
priority == Isolate::kBeforeNextEventAction /* at_head */);
|
2014-12-08 22:45:10 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kInterruptMsg: {
|
|
|
|
// [ OOB, kInterruptMsg, pause capability ]
|
|
|
|
if (message.Length() != 3) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
Object& obj = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!I->VerifyPauseCapability(obj)) return Error::null();
|
|
|
|
|
|
|
|
// If we are already paused, don't pause again.
|
|
|
|
if (I->debugger()->PauseEvent() == NULL) {
|
|
|
|
return I->debugger()->SignalIsolateInterrupted();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Isolate::kAddExitMsg:
|
|
|
|
case Isolate::kDelExitMsg:
|
|
|
|
case Isolate::kAddErrorMsg:
|
|
|
|
case Isolate::kDelErrorMsg: {
|
2015-03-07 01:04:19 +00:00
|
|
|
// [ OOB, msg, listener port ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() < 3) return Error::null();
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& obj = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj.IsSendPort()) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
const SendPort& listener = SendPort::Cast(obj);
|
|
|
|
switch (msg_type) {
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kAddExitMsg: {
|
|
|
|
if (message.Length() != 4) return Error::null();
|
2015-04-13 10:29:54 +00:00
|
|
|
// [ OOB, msg, listener port, response object ]
|
2015-10-12 22:51:06 +00:00
|
|
|
const Object& response = Object::Handle(zone, message.At(3));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!response.IsInstance() && !response.IsNull()) {
|
|
|
|
return Error::null();
|
|
|
|
}
|
2015-04-13 10:29:54 +00:00
|
|
|
I->AddExitListener(listener,
|
|
|
|
response.IsNull() ? Instance::null_instance()
|
|
|
|
: Instance::Cast(response));
|
2015-03-07 01:04:19 +00:00
|
|
|
break;
|
2015-04-13 10:29:54 +00:00
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kDelExitMsg:
|
|
|
|
if (message.Length() != 3) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
I->RemoveExitListener(listener);
|
|
|
|
break;
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kAddErrorMsg:
|
|
|
|
if (message.Length() != 3) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
I->AddErrorListener(listener);
|
|
|
|
break;
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kDelErrorMsg:
|
|
|
|
if (message.Length() != 3) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
I->RemoveErrorListener(listener);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
case Isolate::kErrorFatalMsg: {
|
2015-03-07 01:04:19 +00:00
|
|
|
// [ OOB, kErrorFatalMsg, terminate capability, val ]
|
2015-09-23 19:13:25 +00:00
|
|
|
if (message.Length() != 4) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
// Check that the terminate capability has been passed correctly.
|
2015-10-12 22:51:06 +00:00
|
|
|
Object& obj = Object::Handle(zone, message.At(2));
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!I->VerifyTerminateCapability(obj)) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
// Get the value to be set.
|
|
|
|
obj = message.At(3);
|
2015-09-23 19:13:25 +00:00
|
|
|
if (!obj.IsBool()) return Error::null();
|
2015-03-07 01:04:19 +00:00
|
|
|
I->SetErrorsFatal(Bool::Cast(obj).value());
|
|
|
|
break;
|
|
|
|
}
|
2014-07-03 12:56:02 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// Malformed OOB messages are silently ignored in release builds.
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
#endif // defined(DEBUG)
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
return Error::null();
|
2014-07-03 12:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
void IsolateMessageHandler::MessageNotify(Message::Priority priority) {
|
|
|
|
if (priority >= Message::kOOBPriority) {
|
|
|
|
// Handle out of band messages even if the isolate is busy.
|
2014-05-28 21:58:33 +00:00
|
|
|
I->ScheduleInterrupts(Isolate::kMessageInterrupt);
|
2012-02-01 18:53:40 +00:00
|
|
|
}
|
2014-05-28 21:58:33 +00:00
|
|
|
Dart_MessageNotifyCallback callback = I->message_notify_callback();
|
2012-02-01 18:53:40 +00:00
|
|
|
if (callback) {
|
|
|
|
// Allow the embedder to handle message notification.
|
2014-05-28 21:58:33 +00:00
|
|
|
(*callback)(Api::CastIsolate(I));
|
2012-02-01 18:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
|
|
|
|
Message* message) {
|
2015-08-19 22:16:47 +00:00
|
|
|
ASSERT(IsCurrentIsolate());
|
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
StackZone stack_zone(thread);
|
|
|
|
Zone* zone = stack_zone.GetZone();
|
|
|
|
HandleScope handle_scope(thread);
|
|
|
|
TimelineDurationScope tds(thread, I->GetIsolateStream(), "HandleMessage");
|
2015-08-18 22:18:02 +00:00
|
|
|
tds.SetNumArguments(1);
|
|
|
|
tds.CopyArgument(0, "isolateName", I->name());
|
2015-06-16 17:10:14 +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.
|
2014-12-08 22:45:10 +00:00
|
|
|
// Illegal port is a special case for artificially enqueued isolate library
|
|
|
|
// messages which are handled in C++ code below.
|
2015-08-19 22:16:47 +00:00
|
|
|
Object& msg_handler = Object::Handle(zone);
|
2014-12-08 22:45:10 +00:00
|
|
|
if (!message->IsOOB() && (message->dest_port() != Message::kIllegalPort)) {
|
2014-04-23 19:44:03 +00:00
|
|
|
msg_handler = DartLibraryCalls::LookupHandler(message->dest_port());
|
|
|
|
if (msg_handler.IsError()) {
|
2014-07-03 12:56:02 +00:00
|
|
|
delete message;
|
2015-01-09 22:39:42 +00:00
|
|
|
return ProcessUnhandledException(Error::Cast(msg_handler));
|
2012-12-20 20:03:07 +00:00
|
|
|
}
|
2014-04-23 19:44:03 +00:00
|
|
|
if (msg_handler.IsNull()) {
|
2014-05-28 21:58:33 +00:00
|
|
|
// If the port has been closed then the message will be dropped at this
|
|
|
|
// point. Make sure to post to the delivery failure port in that case.
|
|
|
|
if (message->RedirectToDeliveryFailurePort()) {
|
|
|
|
PortMap::PostMessage(message);
|
|
|
|
} else {
|
|
|
|
delete message;
|
|
|
|
}
|
2015-10-06 18:27:26 +00:00
|
|
|
return kOK;
|
2012-12-20 20:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-27 20:25:44 +00:00
|
|
|
// Parse the message.
|
2015-12-12 00:07:16 +00:00
|
|
|
Object& msg_obj = Object::Handle(zone);
|
|
|
|
if (message->IsRaw()) {
|
|
|
|
msg_obj = message->raw_obj();
|
|
|
|
// We should only be sending RawObjects that can be converted to CObjects.
|
|
|
|
ASSERT(ApiObjectConverter::CanConvert(msg_obj.raw()));
|
|
|
|
} else {
|
|
|
|
MessageSnapshotReader reader(message->data(), message->len(), thread);
|
|
|
|
msg_obj = reader.ReadObject();
|
|
|
|
}
|
2012-12-07 01:41:53 +00:00
|
|
|
if (msg_obj.IsError()) {
|
|
|
|
// An error occurred while reading the message.
|
2014-07-03 12:56:02 +00:00
|
|
|
delete message;
|
2015-01-09 22:39:42 +00:00
|
|
|
return ProcessUnhandledException(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();
|
|
|
|
}
|
2015-08-19 22:16:47 +00:00
|
|
|
Instance& msg = Instance::Handle(zone);
|
2012-08-27 20:25:44 +00:00
|
|
|
msg ^= msg_obj.raw(); // Can't use Instance::Cast because may be null.
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
MessageStatus status = kOK;
|
2012-04-19 19:47:27 +00:00
|
|
|
if (message->IsOOB()) {
|
2014-07-03 12:56:02 +00:00
|
|
|
// OOB messages are expected to be fixed length arrays where the first
|
|
|
|
// element is a Smi describing the OOB destination. Messages that do not
|
|
|
|
// confirm to this layout are silently ignored.
|
|
|
|
if (msg.IsArray()) {
|
|
|
|
const Array& oob_msg = Array::Cast(msg);
|
|
|
|
if (oob_msg.Length() > 0) {
|
2015-08-19 22:16:47 +00:00
|
|
|
const Object& oob_tag = Object::Handle(zone, oob_msg.At(0));
|
2014-07-03 12:56:02 +00:00
|
|
|
if (oob_tag.IsSmi()) {
|
|
|
|
switch (Smi::Cast(oob_tag).Value()) {
|
|
|
|
case Message::kServiceOOBMsg: {
|
|
|
|
Service::HandleIsolateMessage(I, oob_msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Message::kIsolateLibOOBMsg: {
|
2015-09-23 19:13:25 +00:00
|
|
|
const Error& error = Error::Handle(HandleLibMessage(oob_msg));
|
|
|
|
if (!error.IsNull()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
status = ProcessUnhandledException(error);
|
2015-09-23 19:13:25 +00:00
|
|
|
}
|
2014-07-03 12:56:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
|
|
// Malformed OOB messages are silently ignored in release builds.
|
|
|
|
default: {
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif // defined(DEBUG)
|
|
|
|
}
|
|
|
|
}
|
2014-05-28 21:58:33 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-08 22:45:10 +00:00
|
|
|
} else if (message->dest_port() == Message::kIllegalPort) {
|
|
|
|
// Check whether this is a delayed OOB message which needed handling as
|
|
|
|
// part of the regular message dispatch. All other messages are dropped on
|
|
|
|
// the floor.
|
|
|
|
if (msg.IsArray()) {
|
|
|
|
const Array& msg_arr = Array::Cast(msg);
|
|
|
|
if (msg_arr.Length() > 0) {
|
2015-08-19 22:16:47 +00:00
|
|
|
const Object& oob_tag = Object::Handle(zone, msg_arr.At(0));
|
2014-12-08 22:45:10 +00:00
|
|
|
if (oob_tag.IsSmi() &&
|
|
|
|
(Smi::Cast(oob_tag).Value() == Message::kDelayedIsolateLibOOBMsg)) {
|
2015-09-23 19:13:25 +00:00
|
|
|
const Error& error = Error::Handle(HandleLibMessage(msg_arr));
|
|
|
|
if (!error.IsNull()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
status = ProcessUnhandledException(error);
|
2015-09-23 19:13:25 +00:00
|
|
|
}
|
2014-12-08 22:45:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-19 19:47:27 +00:00
|
|
|
} else {
|
2015-08-19 22:16:47 +00:00
|
|
|
const Object& result = Object::Handle(zone,
|
2014-04-23 19:44:03 +00:00
|
|
|
DartLibraryCalls::HandleMessage(msg_handler, msg));
|
2012-12-07 01:41:53 +00:00
|
|
|
if (result.IsError()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
status = ProcessUnhandledException(Error::Cast(result));
|
2012-12-15 00:20:07 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(result.IsNull());
|
2012-04-19 19:47:27 +00:00
|
|
|
}
|
|
|
|
}
|
2012-12-15 00:20:07 +00:00
|
|
|
delete message;
|
2015-10-06 18:27:26 +00:00
|
|
|
if (status == kOK) {
|
2015-08-27 18:23:39 +00:00
|
|
|
const Object& result =
|
|
|
|
Object::Handle(zone, I->InvokePendingServiceExtensionCalls());
|
|
|
|
if (result.IsError()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
status = ProcessUnhandledException(Error::Cast(result));
|
2015-08-27 18:23:39 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(result.IsNull());
|
|
|
|
}
|
|
|
|
}
|
2015-10-06 18:27:26 +00:00
|
|
|
return status;
|
2012-04-19 19:47:27 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:24:09 +00:00
|
|
|
|
2015-03-05 19:02:42 +00:00
|
|
|
void IsolateMessageHandler::NotifyPauseOnStart() {
|
2015-07-14 19:54:07 +00:00
|
|
|
if (Service::debug_stream.enabled()) {
|
2015-09-02 23:07:48 +00:00
|
|
|
StartIsolateScope start_isolate(I);
|
|
|
|
StackZone zone(T);
|
|
|
|
HandleScope handle_scope(T);
|
|
|
|
ServiceEvent pause_event(I, ServiceEvent::kPauseStart);
|
2015-06-04 16:57:22 +00:00
|
|
|
Service::HandleEvent(&pause_event);
|
2015-08-27 18:23:39 +00:00
|
|
|
} else if (FLAG_trace_service) {
|
2015-08-26 23:45:36 +00:00
|
|
|
OS::Print("vm-service: Dropping event of type PauseStart (%s)\n",
|
2015-09-02 23:07:48 +00:00
|
|
|
I->name());
|
2015-06-04 16:57:22 +00:00
|
|
|
}
|
2015-03-05 19:02:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IsolateMessageHandler::NotifyPauseOnExit() {
|
2015-07-14 19:54:07 +00:00
|
|
|
if (Service::debug_stream.enabled()) {
|
2015-09-02 23:07:48 +00:00
|
|
|
StartIsolateScope start_isolate(I);
|
|
|
|
StackZone zone(T);
|
|
|
|
HandleScope handle_scope(T);
|
|
|
|
ServiceEvent pause_event(I, ServiceEvent::kPauseExit);
|
2015-06-04 16:57:22 +00:00
|
|
|
Service::HandleEvent(&pause_event);
|
2015-08-27 18:23:39 +00:00
|
|
|
} else if (FLAG_trace_service) {
|
2015-08-26 23:45:36 +00:00
|
|
|
OS::Print("vm-service: Dropping event of type PauseExit (%s)\n",
|
2015-09-02 23:07:48 +00:00
|
|
|
I->name());
|
2015-06-04 16:57:22 +00:00
|
|
|
}
|
2015-03-05 19:02:42 +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 {
|
2014-05-28 21:58:33 +00:00
|
|
|
return (I == Isolate::Current());
|
2012-05-30 17:07:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
static MessageHandler::MessageStatus StoreError(Isolate* isolate,
|
|
|
|
const Error& error) {
|
|
|
|
isolate->object_store()->set_sticky_error(error);
|
|
|
|
if (error.IsUnwindError()) {
|
|
|
|
const UnwindError& unwind = UnwindError::Cast(error);
|
|
|
|
if (!unwind.is_user_initiated()) {
|
|
|
|
if (unwind.is_vm_restart()) {
|
|
|
|
return MessageHandler::kRestart;
|
|
|
|
} else {
|
|
|
|
return MessageHandler::kShutdown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return MessageHandler::kError;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
|
|
|
|
const Error& result) {
|
2015-01-09 22:39:42 +00:00
|
|
|
// Notify the debugger about specific unhandled exceptions which are withheld
|
|
|
|
// when being thrown.
|
2012-12-15 00:20:07 +00:00
|
|
|
if (result.IsUnhandledException()) {
|
|
|
|
const UnhandledException& error = UnhandledException::Cast(result);
|
|
|
|
RawInstance* exception = error.exception();
|
2014-07-09 16:09:14 +00:00
|
|
|
if ((exception == I->object_store()->out_of_memory()) ||
|
|
|
|
(exception == I->object_store()->stack_overflow())) {
|
|
|
|
// We didn't notify the debugger when the stack was full. Do it now.
|
2014-07-10 17:44:33 +00:00
|
|
|
I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
|
2014-07-09 16:09:14 +00:00
|
|
|
}
|
2012-12-15 00:20:07 +00:00
|
|
|
}
|
|
|
|
|
2015-03-07 01:04:19 +00:00
|
|
|
// Generate the error and stacktrace strings for the error message.
|
2015-10-19 17:27:36 +00:00
|
|
|
String& exc_str = String::Handle(T->zone());
|
|
|
|
String& stacktrace_str = String::Handle(T->zone());
|
2015-03-07 01:04:19 +00:00
|
|
|
if (result.IsUnhandledException()) {
|
2015-10-19 17:27:36 +00:00
|
|
|
Zone* zone = T->zone();
|
2015-03-07 01:04:19 +00:00
|
|
|
const UnhandledException& uhe = UnhandledException::Cast(result);
|
2015-10-12 22:51:06 +00:00
|
|
|
const Instance& exception = Instance::Handle(zone, uhe.exception());
|
|
|
|
Object& tmp = Object::Handle(zone);
|
2015-03-07 01:04:19 +00:00
|
|
|
tmp = DartLibraryCalls::ToString(exception);
|
|
|
|
if (!tmp.IsString()) {
|
|
|
|
tmp = String::New(exception.ToCString());
|
|
|
|
}
|
|
|
|
exc_str ^= tmp.raw();
|
|
|
|
|
2015-10-12 22:51:06 +00:00
|
|
|
const Instance& stacktrace = Instance::Handle(zone, uhe.stacktrace());
|
2015-03-07 01:04:19 +00:00
|
|
|
tmp = DartLibraryCalls::ToString(stacktrace);
|
|
|
|
if (!tmp.IsString()) {
|
|
|
|
tmp = String::New(stacktrace.ToCString());
|
|
|
|
}
|
|
|
|
stacktrace_str ^= tmp.raw();;
|
|
|
|
} else {
|
|
|
|
exc_str = String::New(result.ToErrorCString());
|
|
|
|
}
|
2015-09-23 19:13:25 +00:00
|
|
|
if (result.IsUnwindError()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
// When unwinding we don't notify error listeners and we ignore
|
|
|
|
// whether errors are fatal for the current isolate.
|
|
|
|
return StoreError(I, result);
|
2015-09-23 19:13:25 +00:00
|
|
|
} else {
|
|
|
|
bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str);
|
|
|
|
if (I->ErrorsFatal()) {
|
|
|
|
if (has_listener) {
|
|
|
|
I->object_store()->clear_sticky_error();
|
|
|
|
} else {
|
|
|
|
I->object_store()->set_sticky_error(result);
|
|
|
|
}
|
2015-10-06 18:27:26 +00:00
|
|
|
return kError;
|
2015-09-23 19:13:25 +00:00
|
|
|
}
|
2015-03-07 01:04:19 +00:00
|
|
|
}
|
2015-10-06 18:27:26 +00:00
|
|
|
return kOK;
|
2012-12-07 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-07 15:57:34 +00:00
|
|
|
Isolate::Flags::Flags()
|
|
|
|
: type_checks_(FLAG_enable_type_checks),
|
|
|
|
asserts_(FLAG_enable_asserts),
|
|
|
|
error_on_bad_type_(FLAG_error_on_bad_type),
|
|
|
|
error_on_bad_override_(FLAG_error_on_bad_override) {}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::Flags::CopyFrom(const Flags& orig) {
|
|
|
|
type_checks_ = orig.type_checks();
|
|
|
|
asserts_ = orig.asserts();
|
|
|
|
error_on_bad_type_ = orig.error_on_bad_type();
|
|
|
|
error_on_bad_override_ = orig.error_on_bad_override();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::Flags::CopyFrom(const Dart_IsolateFlags& api_flags) {
|
|
|
|
type_checks_ = api_flags.enable_type_checks;
|
|
|
|
asserts_ = api_flags.enable_asserts;
|
|
|
|
// Leave others at defaults.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::Flags::CopyTo(Dart_IsolateFlags* api_flags) const {
|
|
|
|
api_flags->version = DART_FLAGS_CURRENT_VERSION;
|
|
|
|
api_flags->enable_type_checks = type_checks();
|
|
|
|
api_flags->enable_asserts = asserts();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-06 18:00:51 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// static
|
|
|
|
void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
|
|
|
|
ASSERT(isolate == Isolate::Current());
|
|
|
|
}
|
2015-06-17 15:25:26 +00:00
|
|
|
|
|
|
|
void BaseIsolate::AssertCurrentThreadIsMutator() const {
|
|
|
|
ASSERT(Isolate::Current() == this);
|
2015-10-26 20:12:10 +00:00
|
|
|
ASSERT(Thread::Current()->IsMutatorThread());
|
2015-06-17 15:25:26 +00:00
|
|
|
}
|
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),
|
|
|
|
|
2015-06-07 15:57:34 +00:00
|
|
|
Isolate::Isolate(const Dart_IsolateFlags& api_flags)
|
2015-10-01 22:01:20 +00:00
|
|
|
: stack_limit_(0),
|
2015-06-18 23:16:50 +00:00
|
|
|
store_buffer_(new StoreBuffer()),
|
2015-09-16 00:42:15 +00:00
|
|
|
heap_(NULL),
|
2015-10-01 22:01:20 +00:00
|
|
|
user_tag_(0),
|
|
|
|
current_tag_(UserTag::null()),
|
|
|
|
default_tag_(UserTag::null()),
|
|
|
|
class_table_(),
|
|
|
|
single_step_(false),
|
2015-07-09 18:22:26 +00:00
|
|
|
thread_registry_(new ThreadRegistry()),
|
2012-01-24 19:31:01 +00:00
|
|
|
message_notify_callback_(NULL),
|
2012-01-18 21:46:27 +00:00
|
|
|
name_(NULL),
|
2015-03-26 19:06:18 +00:00
|
|
|
debugger_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),
|
2015-01-12 23:14:30 +00:00
|
|
|
origin_id_(0),
|
2014-07-03 12:56:02 +00:00
|
|
|
pause_capability_(0),
|
|
|
|
terminate_capability_(0),
|
2015-03-07 01:04:19 +00:00
|
|
|
errors_fatal_(true),
|
2011-10-05 05:20:07 +00:00
|
|
|
object_store_(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),
|
2011-11-30 17:04:45 +00:00
|
|
|
debugger_(NULL),
|
2014-05-20 17:09:08 +00:00
|
|
|
resume_request_(false),
|
2015-08-26 17:57:59 +00:00
|
|
|
last_resume_timestamp_(OS::GetCurrentTimeMillis()),
|
2015-10-13 17:08:14 +00:00
|
|
|
has_compiled_code_(false),
|
2015-06-07 15:57:34 +00:00
|
|
|
flags_(),
|
2013-11-06 00:59:46 +00:00
|
|
|
random_(),
|
2013-01-25 01:16:35 +00:00
|
|
|
simulator_(NULL),
|
2011-12-16 18:41:20 +00:00
|
|
|
mutex_(new Mutex()),
|
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),
|
2015-05-12 23:03:48 +00:00
|
|
|
compiler_stats_(NULL),
|
2015-02-09 18:54:20 +00:00
|
|
|
is_service_isolate_(false),
|
2013-04-04 18:48:24 +00:00
|
|
|
stacktrace_(NULL),
|
2013-06-13 09:06:43 +00:00
|
|
|
stack_frame_index_(-1),
|
2014-06-18 17:39:37 +00:00
|
|
|
last_allocationprofile_accumulator_reset_timestamp_(0),
|
|
|
|
last_allocationprofile_gc_timestamp_(0),
|
2013-07-16 18:31:25 +00:00
|
|
|
object_id_ring_(NULL),
|
2014-06-10 17:06:02 +00:00
|
|
|
trace_buffer_(NULL),
|
2014-04-10 22:32:45 +00:00
|
|
|
tag_table_(GrowableObjectArray::null()),
|
2015-02-26 18:48:55 +00:00
|
|
|
deoptimized_code_array_(GrowableObjectArray::null()),
|
2015-10-17 00:02:43 +00:00
|
|
|
background_compiler_(NULL),
|
2015-08-27 18:23:39 +00:00
|
|
|
pending_service_extension_calls_(GrowableObjectArray::null()),
|
|
|
|
registered_service_extension_handlers_(GrowableObjectArray::null()),
|
2014-08-15 17:35:00 +00:00
|
|
|
metrics_list_head_(NULL),
|
2015-07-30 22:29:19 +00:00
|
|
|
compilation_allowed_(true),
|
2015-10-14 20:18:10 +00:00
|
|
|
all_classes_finalized_(false),
|
2014-02-07 17:43:21 +00:00
|
|
|
next_(NULL),
|
2015-10-30 19:18:52 +00:00
|
|
|
pause_loop_monitor_(NULL),
|
2015-11-05 20:13:37 +00:00
|
|
|
cha_invalidation_gen_(kInvalidGen),
|
|
|
|
field_invalidation_gen_(kInvalidGen),
|
|
|
|
prefix_invalidation_gen_(kInvalidGen) {
|
2015-06-07 15:57:34 +00:00
|
|
|
flags_.CopyFrom(api_flags);
|
2015-11-19 21:45:10 +00:00
|
|
|
// TODO(asiva): A Thread is not available here, need to figure out
|
|
|
|
// how the vm_tag (kEmbedderTagId) can be set, these tags need to
|
|
|
|
// move to the OSThread structure.
|
2014-05-06 17:07:26 +00:00
|
|
|
set_user_tag(UserTags::kDefaultUserTag);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2014-08-27 13:37:55 +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() {
|
2015-01-29 18:31:27 +00:00
|
|
|
free(name_);
|
2015-03-26 19:06:18 +00:00
|
|
|
free(debugger_name_);
|
2015-06-18 23:16:50 +00:00
|
|
|
delete store_buffer_;
|
2011-10-05 05:20:07 +00:00
|
|
|
delete heap_;
|
|
|
|
delete object_store_;
|
|
|
|
delete api_state_;
|
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_;
|
2015-05-12 23:48:01 +00:00
|
|
|
delete object_id_ring_;
|
|
|
|
object_id_ring_ = NULL;
|
2015-05-01 17:56:35 +00:00
|
|
|
delete pause_loop_monitor_;
|
|
|
|
pause_loop_monitor_ = NULL;
|
2015-05-12 23:03:48 +00:00
|
|
|
if (compiler_stats_ != NULL) {
|
|
|
|
delete compiler_stats_;
|
|
|
|
compiler_stats_ = NULL;
|
|
|
|
}
|
2015-07-09 18:22:26 +00:00
|
|
|
delete thread_registry_;
|
2011-10-18 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
2014-02-07 17:43:21 +00:00
|
|
|
|
2015-03-25 22:41:33 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
bool Isolate::IsIsolateOf(Thread* thread) {
|
|
|
|
return this == thread->isolate();
|
|
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
|
2012-02-07 09:18:22 +00:00
|
|
|
void Isolate::InitOnce() {
|
|
|
|
create_callback_ = NULL;
|
2014-02-07 17:43:21 +00:00
|
|
|
isolates_list_monitor_ = new Monitor();
|
|
|
|
ASSERT(isolates_list_monitor_ != NULL);
|
2015-09-15 19:49:52 +00:00
|
|
|
EnableIsolateCreation();
|
2012-02-07 09:18:22 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 17:54:07 +00:00
|
|
|
|
2015-06-07 15:57:34 +00:00
|
|
|
Isolate* Isolate::Init(const char* name_prefix,
|
|
|
|
const Dart_IsolateFlags& api_flags,
|
|
|
|
bool is_vm_isolate) {
|
|
|
|
Isolate* result = new Isolate(api_flags);
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(result != NULL);
|
|
|
|
|
2014-08-15 17:35:00 +00:00
|
|
|
// Initialize metrics.
|
|
|
|
#define ISOLATE_METRIC_INIT(type, variable, name, unit) \
|
|
|
|
result->metric_##variable##_.Init(result, name, NULL, Metric::unit);
|
|
|
|
ISOLATE_METRIC_LIST(ISOLATE_METRIC_INIT);
|
|
|
|
#undef ISOLATE_METRIC_INIT
|
|
|
|
|
2015-06-16 17:10:14 +00:00
|
|
|
// Initialize Timeline streams.
|
|
|
|
#define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default) \
|
2015-08-18 22:18:02 +00:00
|
|
|
result->stream_##name##_.Init(#name, \
|
2015-09-21 21:23:59 +00:00
|
|
|
enabled_by_default, \
|
|
|
|
Timeline::Stream##name##EnabledFlag());
|
2015-06-16 17:10:14 +00:00
|
|
|
ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT);
|
|
|
|
#undef ISOLATE_TIMELINE_STREAM_INIT
|
|
|
|
|
2015-08-03 14:26:23 +00:00
|
|
|
Heap::Init(result,
|
|
|
|
is_vm_isolate
|
|
|
|
? 0 // New gen size 0; VM isolate should only allocate in old.
|
|
|
|
: FLAG_new_gen_semi_max_size * MBInWords,
|
|
|
|
FLAG_old_gen_heap_size * MBInWords,
|
|
|
|
FLAG_external_max_size * MBInWords);
|
2015-06-16 17:10:14 +00:00
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// TODO(5411455): For now just set the recently created isolate as
|
|
|
|
// the current isolate.
|
2015-04-01 17:48:11 +00:00
|
|
|
Thread::EnterIsolate(result);
|
2011-10-05 05:20:07 +00:00
|
|
|
|
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);
|
|
|
|
|
2012-02-01 18:53:40 +00:00
|
|
|
result->set_main_port(PortMap::CreatePort(result->message_handler()));
|
2015-01-12 23:14:30 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// Verify that we are never reusing a live origin id.
|
|
|
|
VerifyOriginId id_verifier(result->main_port());
|
|
|
|
Isolate::VisitIsolates(&id_verifier);
|
|
|
|
#endif
|
|
|
|
result->set_origin_id(result->main_port());
|
2014-07-03 12:56:02 +00:00
|
|
|
result->set_pause_capability(result->random()->NextUInt64());
|
|
|
|
result->set_terminate_capability(result->random()->NextUInt64());
|
|
|
|
|
2012-01-18 21:46:27 +00:00
|
|
|
result->BuildName(name_prefix);
|
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());
|
|
|
|
}
|
|
|
|
}
|
2015-09-16 18:18:31 +00:00
|
|
|
|
|
|
|
result->compiler_stats_ = new CompilerStats(result);
|
|
|
|
if (FLAG_compiler_benchmark) {
|
|
|
|
result->compiler_stats_->EnableBenchmark();
|
2015-05-12 23:03:48 +00:00
|
|
|
}
|
2015-09-16 18:18:31 +00:00
|
|
|
|
2015-05-12 23:48:01 +00:00
|
|
|
ObjectIdRing::Init(result);
|
2015-09-15 19:49:52 +00:00
|
|
|
|
|
|
|
// Add to isolate list. Shutdown and delete the isolate on failure.
|
|
|
|
if (!AddIsolateToList(result)) {
|
|
|
|
result->LowLevelShutdown();
|
|
|
|
Thread::ExitIsolate();
|
|
|
|
delete result;
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-02-11 23:39:43 +00:00
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-19 04:58:08 +00:00
|
|
|
/* static */
|
|
|
|
uword Isolate::GetCurrentStackPointer() {
|
|
|
|
// Since AddressSanitizer's detect_stack_use_after_return instruments the
|
|
|
|
// C++ code to give out fake stack addresses, we call a stub in that case.
|
2015-08-05 08:18:35 +00:00
|
|
|
uword (*func)() = reinterpret_cast<uword (*)()>(
|
|
|
|
StubCode::GetStackPointer_entry()->EntryPoint());
|
2015-02-19 04:58:08 +00:00
|
|
|
// But for performance (and to support simulators), we normally use a local.
|
|
|
|
#if defined(__has_feature)
|
|
|
|
#if __has_feature(address_sanitizer)
|
|
|
|
uword current_sp = func();
|
|
|
|
return current_sp;
|
|
|
|
#else
|
2015-02-19 13:25:07 +00:00
|
|
|
uword stack_allocated_local_address = reinterpret_cast<uword>(&func);
|
2015-02-19 04:58:08 +00:00
|
|
|
return stack_allocated_local_address;
|
|
|
|
#endif
|
|
|
|
#else
|
2015-02-19 13:25:07 +00:00
|
|
|
uword stack_allocated_local_address = reinterpret_cast<uword>(&func);
|
2015-02-19 04:58:08 +00:00
|
|
|
return stack_allocated_local_address;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-16 18:22:57 +00:00
|
|
|
void Isolate::SetupInstructionsSnapshotPage(
|
|
|
|
const uint8_t* instructions_snapshot_buffer) {
|
|
|
|
InstructionsSnapshot snapshot(instructions_snapshot_buffer);
|
|
|
|
#if defined(DEBUG)
|
2015-09-24 09:36:46 +00:00
|
|
|
if (FLAG_trace_isolates) {
|
|
|
|
OS::Print("Precompiled instructions are at [0x%" Px ", 0x%" Px ")\n",
|
|
|
|
reinterpret_cast<uword>(snapshot.instructions_start()),
|
|
|
|
reinterpret_cast<uword>(snapshot.instructions_start()) +
|
|
|
|
snapshot.instructions_size());
|
|
|
|
}
|
2015-09-16 18:22:57 +00:00
|
|
|
#endif
|
|
|
|
heap_->SetupInstructionsSnapshotPage(snapshot.instructions_start(),
|
|
|
|
snapshot.instructions_size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 19:06:18 +00:00
|
|
|
void Isolate::set_debugger_name(const char* name) {
|
|
|
|
free(debugger_name_);
|
|
|
|
debugger_name_ = strdup(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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";
|
|
|
|
}
|
2015-03-26 19:06:18 +00:00
|
|
|
set_debugger_name(name_prefix);
|
2015-02-12 19:10:55 +00:00
|
|
|
if (ServiceIsolate::NameEquals(name_prefix)) {
|
2015-01-29 18:31:27 +00:00
|
|
|
name_ = strdup(name_prefix);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-11 07:18:14 +00:00
|
|
|
name_ = OS::SCreate(NULL, "%s-%" Pd64 "", name_prefix, main_port());
|
2012-01-18 21:46:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-27 18:28:47 +00:00
|
|
|
void Isolate::SetStackLimitFromStackBase(uword stack_base) {
|
2014-11-14 23:15:00 +00:00
|
|
|
// Set stack limit.
|
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.
|
2014-08-27 18:28:47 +00:00
|
|
|
stack_base = sim->StackTop();
|
2013-02-27 17:13:51 +00:00
|
|
|
// The overflow area is accounted for by the simulator.
|
|
|
|
#endif
|
2015-11-19 21:45:10 +00:00
|
|
|
SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::SetStackLimit(uword limit) {
|
2014-08-20 03:54:14 +00:00
|
|
|
// The isolate setting the stack limit is not necessarily the isolate which
|
|
|
|
// the stack limit is being set on.
|
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-08-27 18:28:47 +00:00
|
|
|
void Isolate::ClearStackLimit() {
|
|
|
|
SetStackLimit(~static_cast<uword>(0));
|
2013-11-19 18:26:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-16 18:41:20 +00:00
|
|
|
void Isolate::ScheduleInterrupts(uword interrupt_bits) {
|
2014-08-20 03:54:14 +00:00
|
|
|
MutexLocker ml(mutex_);
|
2011-12-16 18:41:20 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-30 17:11:09 +00:00
|
|
|
void Isolate::DoneLoading() {
|
2015-10-12 22:51:06 +00:00
|
|
|
GrowableObjectArray& libs = GrowableObjectArray::Handle(current_zone(),
|
|
|
|
object_store()->libraries());
|
|
|
|
Library& lib = Library::Handle(current_zone());
|
2014-06-30 17:11:09 +00:00
|
|
|
intptr_t num_libs = libs.Length();
|
|
|
|
for (intptr_t i = 0; i < num_libs; i++) {
|
|
|
|
lib ^= libs.At(i);
|
|
|
|
// If this library was loaded with Dart_LoadLibrary, it was marked
|
|
|
|
// as 'load in progres'. Set the status to 'loaded'.
|
|
|
|
if (lib.LoadInProgress()) {
|
|
|
|
lib.SetLoaded();
|
|
|
|
}
|
|
|
|
}
|
2015-10-28 23:02:58 +00:00
|
|
|
TokenStream::CloseSharedTokenList(this);
|
2014-06-30 17:11:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-09 17:51:24 +00:00
|
|
|
bool Isolate::MakeRunnable() {
|
|
|
|
ASSERT(Isolate::Current() == NULL);
|
2015-03-26 19:06:18 +00:00
|
|
|
|
2014-08-20 03:54:14 +00:00
|
|
|
MutexLocker ml(mutex_);
|
2013-04-09 17:51:24 +00:00
|
|
|
// Check if we are in a valid state to make the isolate runnable.
|
2015-05-11 18:23:20 +00:00
|
|
|
if (is_runnable() == true) {
|
2013-04-09 17:51:24 +00:00
|
|
|
return false; // Already runnable.
|
|
|
|
}
|
|
|
|
// Set the isolate as runnable and if we are being spawned schedule
|
|
|
|
// isolate on thread pool for execution.
|
2015-04-17 00:44:47 +00:00
|
|
|
ASSERT(object_store()->root_library() != Library::null());
|
2015-05-11 18:23:20 +00:00
|
|
|
set_is_runnable(true);
|
2015-02-12 19:10:55 +00:00
|
|
|
if (!ServiceIsolate::IsServiceIsolate(this)) {
|
2014-05-26 06:09:28 +00:00
|
|
|
message_handler()->set_pause_on_start(FLAG_pause_isolates_on_start);
|
|
|
|
message_handler()->set_pause_on_exit(FLAG_pause_isolates_on_exit);
|
|
|
|
}
|
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();
|
|
|
|
}
|
2015-06-16 17:10:14 +00:00
|
|
|
TimelineStream* stream = GetIsolateStream();
|
|
|
|
ASSERT(stream != NULL);
|
2015-06-16 17:52:48 +00:00
|
|
|
TimelineEvent* event = stream->StartEvent();
|
2015-06-16 17:10:14 +00:00
|
|
|
if (event != NULL) {
|
2015-06-16 17:52:48 +00:00
|
|
|
event->Instant("Runnable");
|
|
|
|
event->Complete();
|
2015-06-16 17:10:14 +00:00
|
|
|
}
|
2015-08-21 17:25:38 +00:00
|
|
|
if (Service::isolate_stream.enabled()) {
|
|
|
|
ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
|
|
|
|
Service::HandleEvent(&runnableEvent);
|
|
|
|
}
|
2013-04-09 17:51:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-13 00:39:16 +00:00
|
|
|
bool Isolate::VerifyPauseCapability(const Object& capability) const {
|
|
|
|
return !capability.IsNull() &&
|
|
|
|
capability.IsCapability() &&
|
|
|
|
(pause_capability() == Capability::Cast(capability).Id());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Isolate::VerifyTerminateCapability(const Object& capability) const {
|
|
|
|
return !capability.IsNull() &&
|
|
|
|
capability.IsCapability() &&
|
|
|
|
(terminate_capability() == Capability::Cast(capability).Id());
|
2014-07-03 12:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Isolate::AddResumeCapability(const Capability& capability) {
|
|
|
|
// Ensure a limit for the number of resume capabilities remembered.
|
2015-03-07 01:04:19 +00:00
|
|
|
static const intptr_t kMaxResumeCapabilities = kSmiMax / (6 * kWordSize);
|
2014-07-03 12:56:02 +00:00
|
|
|
|
|
|
|
const GrowableObjectArray& caps = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->resume_capabilities());
|
|
|
|
Capability& current = Capability::Handle(current_zone());
|
2014-07-03 12:56:02 +00:00
|
|
|
intptr_t insertion_index = -1;
|
|
|
|
for (intptr_t i = 0; i < caps.Length(); i++) {
|
|
|
|
current ^= caps.At(i);
|
|
|
|
if (current.IsNull()) {
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
insertion_index = i;
|
|
|
|
}
|
|
|
|
} else if (current.Id() == capability.Id()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
if (caps.Length() >= kMaxResumeCapabilities) {
|
|
|
|
// Cannot grow the array of resume capabilities beyond its max. Additional
|
|
|
|
// pause requests are ignored. In practice will never happen as we will
|
|
|
|
// run out of memory beforehand.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
caps.Add(capability);
|
|
|
|
} else {
|
|
|
|
caps.SetAt(insertion_index, capability);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Isolate::RemoveResumeCapability(const Capability& capability) {
|
|
|
|
const GrowableObjectArray& caps = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->resume_capabilities());
|
|
|
|
Capability& current = Capability::Handle(current_zone());
|
2014-07-03 12:56:02 +00:00
|
|
|
for (intptr_t i = 0; i < caps.Length(); i++) {
|
|
|
|
current ^= caps.At(i);
|
|
|
|
if (!current.IsNull() && (current.Id() == capability.Id())) {
|
|
|
|
// Remove the matching capability from the list.
|
|
|
|
current = Capability::null();
|
|
|
|
caps.SetAt(i, current);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-07 01:04:19 +00:00
|
|
|
// TODO(iposva): Remove duplicated code and start using some hash based
|
|
|
|
// structure instead of these linear lookups.
|
2015-04-13 10:29:54 +00:00
|
|
|
void Isolate::AddExitListener(const SendPort& listener,
|
|
|
|
const Instance& response) {
|
2015-03-07 01:04:19 +00:00
|
|
|
// Ensure a limit for the number of listeners remembered.
|
2015-04-13 10:29:54 +00:00
|
|
|
static const intptr_t kMaxListeners = kSmiMax / (12 * kWordSize);
|
2015-03-07 01:04:19 +00:00
|
|
|
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->exit_listeners());
|
|
|
|
SendPort& current = SendPort::Handle(current_zone());
|
2015-03-07 01:04:19 +00:00
|
|
|
intptr_t insertion_index = -1;
|
2015-04-13 10:29:54 +00:00
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
2015-03-07 01:04:19 +00:00
|
|
|
current ^= listeners.At(i);
|
|
|
|
if (current.IsNull()) {
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
insertion_index = i;
|
|
|
|
}
|
|
|
|
} else if (current.Id() == listener.Id()) {
|
2015-04-13 10:29:54 +00:00
|
|
|
listeners.SetAt(i + 1, response);
|
2015-03-07 01:04:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
if (listeners.Length() >= kMaxListeners) {
|
|
|
|
// Cannot grow the array of listeners beyond its max. Additional
|
|
|
|
// listeners are ignored. In practice will never happen as we will
|
|
|
|
// run out of memory beforehand.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
listeners.Add(listener);
|
2015-04-13 10:29:54 +00:00
|
|
|
listeners.Add(response);
|
2015-03-07 01:04:19 +00:00
|
|
|
} else {
|
|
|
|
listeners.SetAt(insertion_index, listener);
|
2015-04-13 10:29:54 +00:00
|
|
|
listeners.SetAt(insertion_index + 1, response);
|
2015-03-07 01:04:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::RemoveExitListener(const SendPort& listener) {
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->exit_listeners());
|
|
|
|
SendPort& current = SendPort::Handle(current_zone());
|
2015-04-13 10:29:54 +00:00
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
2015-03-07 01:04:19 +00:00
|
|
|
current ^= listeners.At(i);
|
|
|
|
if (!current.IsNull() && (current.Id() == listener.Id())) {
|
|
|
|
// Remove the matching listener from the list.
|
|
|
|
current = SendPort::null();
|
|
|
|
listeners.SetAt(i, current);
|
2015-04-13 10:29:54 +00:00
|
|
|
listeners.SetAt(i + 1, Object::null_instance());
|
2015-03-07 01:04:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::NotifyExitListeners() {
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), this->object_store()->exit_listeners());
|
2015-03-07 01:04:19 +00:00
|
|
|
if (listeners.IsNull()) return;
|
|
|
|
|
2015-10-12 22:51:06 +00:00
|
|
|
SendPort& listener = SendPort::Handle(current_zone());
|
|
|
|
Instance& response = Instance::Handle(current_zone());
|
2015-04-13 10:29:54 +00:00
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
2015-03-07 01:04:19 +00:00
|
|
|
listener ^= listeners.At(i);
|
|
|
|
if (!listener.IsNull()) {
|
|
|
|
Dart_Port port_id = listener.Id();
|
2015-04-13 10:29:54 +00:00
|
|
|
response ^= listeners.At(i + 1);
|
2015-12-12 00:07:16 +00:00
|
|
|
PortMap::PostMessage(SerializeMessage(port_id, response));
|
2015-03-07 01:04:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::AddErrorListener(const SendPort& listener) {
|
|
|
|
// Ensure a limit for the number of listeners remembered.
|
|
|
|
static const intptr_t kMaxListeners = kSmiMax / (6 * kWordSize);
|
|
|
|
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->error_listeners());
|
|
|
|
SendPort& current = SendPort::Handle(current_zone());
|
2015-03-07 01:04:19 +00:00
|
|
|
intptr_t insertion_index = -1;
|
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
|
|
|
current ^= listeners.At(i);
|
|
|
|
if (current.IsNull()) {
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
insertion_index = i;
|
|
|
|
}
|
|
|
|
} else if (current.Id() == listener.Id()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (insertion_index < 0) {
|
|
|
|
if (listeners.Length() >= kMaxListeners) {
|
|
|
|
// Cannot grow the array of listeners beyond its max. Additional
|
|
|
|
// listeners are ignored. In practice will never happen as we will
|
|
|
|
// run out of memory beforehand.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
listeners.Add(listener);
|
|
|
|
} else {
|
|
|
|
listeners.SetAt(insertion_index, listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::RemoveErrorListener(const SendPort& listener) {
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), object_store()->error_listeners());
|
|
|
|
SendPort& current = SendPort::Handle(current_zone());
|
2015-03-07 01:04:19 +00:00
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
|
|
|
current ^= listeners.At(i);
|
|
|
|
if (!current.IsNull() && (current.Id() == listener.Id())) {
|
|
|
|
// Remove the matching listener from the list.
|
|
|
|
current = SendPort::null();
|
|
|
|
listeners.SetAt(i, current);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-14 10:48:01 +00:00
|
|
|
bool Isolate::NotifyErrorListeners(const String& msg,
|
2015-03-07 01:04:19 +00:00
|
|
|
const String& stacktrace) {
|
|
|
|
const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
|
2015-10-12 22:51:06 +00:00
|
|
|
current_zone(), this->object_store()->error_listeners());
|
2015-08-14 10:48:01 +00:00
|
|
|
if (listeners.IsNull()) return false;
|
2015-03-07 01:04:19 +00:00
|
|
|
|
2015-10-12 22:51:06 +00:00
|
|
|
const Array& arr = Array::Handle(current_zone(), Array::New(2));
|
2015-03-07 01:04:19 +00:00
|
|
|
arr.SetAt(0, msg);
|
|
|
|
arr.SetAt(1, stacktrace);
|
2015-10-12 22:51:06 +00:00
|
|
|
SendPort& listener = SendPort::Handle(current_zone());
|
2015-03-07 01:04:19 +00:00
|
|
|
for (intptr_t i = 0; i < listeners.Length(); i++) {
|
|
|
|
listener ^= listeners.At(i);
|
|
|
|
if (!listener.IsNull()) {
|
|
|
|
Dart_Port port_id = listener.Id();
|
2015-12-12 00:07:16 +00:00
|
|
|
PortMap::PostMessage(SerializeMessage(port_id, arr));
|
2015-03-07 01:04:19 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-14 10:48:01 +00:00
|
|
|
return listeners.Length() > 0;
|
2015-03-07 01:04:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
static MessageHandler::MessageStatus RunIsolate(uword parameter) {
|
2013-04-09 17:51:24 +00:00
|
|
|
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);
|
2015-11-19 21:45:10 +00:00
|
|
|
Thread* thread = Thread::Current();
|
2015-09-02 00:18:55 +00:00
|
|
|
ASSERT(thread->isolate() == isolate);
|
2015-09-02 23:07:48 +00:00
|
|
|
StackZone zone(thread);
|
2015-09-02 00:18:55 +00:00
|
|
|
HandleScope handle_scope(thread);
|
2015-07-20 14:46:54 +00:00
|
|
|
|
|
|
|
// If particular values were requested for this newly spawned isolate, then
|
|
|
|
// they are set here before the isolate starts executing user code.
|
|
|
|
isolate->SetErrorsFatal(state->errors_are_fatal());
|
|
|
|
if (state->on_exit_port() != ILLEGAL_PORT) {
|
|
|
|
const SendPort& listener =
|
|
|
|
SendPort::Handle(SendPort::New(state->on_exit_port()));
|
|
|
|
isolate->AddExitListener(listener, Instance::null_instance());
|
|
|
|
}
|
|
|
|
if (state->on_error_port() != ILLEGAL_PORT) {
|
|
|
|
const SendPort& listener =
|
|
|
|
SendPort::Handle(SendPort::New(state->on_error_port()));
|
|
|
|
isolate->AddErrorListener(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Switch back to spawning 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.
|
2015-10-06 18:27:26 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
const Error& error =
|
|
|
|
Error::Handle(isolate->object_store()->sticky_error());
|
|
|
|
ASSERT(!error.IsUnwindError());
|
|
|
|
#endif
|
|
|
|
return MessageHandler::kError;
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
return StoreError(isolate, Error::Cast(result));
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
2014-06-04 09:40:29 +00:00
|
|
|
ASSERT(result.IsFunction());
|
2015-10-12 22:51:06 +00:00
|
|
|
Function& func = Function::Handle(thread->zone());
|
2014-06-04 09:40:29 +00:00
|
|
|
func ^= result.raw();
|
2013-10-25 19:23:00 +00:00
|
|
|
|
2014-09-04 16:53:44 +00:00
|
|
|
// TODO(turnidge): Currently we need a way to force a one-time
|
|
|
|
// breakpoint for all spawned isolates to support isolate
|
|
|
|
// debugging. Remove this once the vmservice becomes the standard
|
2015-03-26 17:19:09 +00:00
|
|
|
// way to debug. Set the breakpoint on the static function instead
|
|
|
|
// of its implicit closure function because that latter is merely
|
|
|
|
// a dispatcher that is marked as undebuggable.
|
2014-09-04 16:53:44 +00:00
|
|
|
if (FLAG_break_at_isolate_spawn) {
|
|
|
|
isolate->debugger()->OneTimeBreakAtEntry(func);
|
|
|
|
}
|
|
|
|
|
2015-03-26 17:19:09 +00:00
|
|
|
func = func.ImplicitClosureFunction();
|
|
|
|
|
2014-08-20 19:57:09 +00:00
|
|
|
const Array& capabilities = Array::Handle(Array::New(2));
|
|
|
|
Capability& capability = Capability::Handle();
|
|
|
|
capability = Capability::New(isolate->pause_capability());
|
|
|
|
capabilities.SetAt(0, capability);
|
2014-12-30 23:52:37 +00:00
|
|
|
// Check whether this isolate should be started in paused state.
|
|
|
|
if (state->paused()) {
|
|
|
|
bool added = isolate->AddResumeCapability(capability);
|
|
|
|
ASSERT(added); // There should be no pending resume capabilities.
|
|
|
|
isolate->message_handler()->increment_paused();
|
|
|
|
}
|
2014-08-20 19:57:09 +00:00
|
|
|
capability = Capability::New(isolate->terminate_capability());
|
|
|
|
capabilities.SetAt(1, capability);
|
|
|
|
|
2013-10-25 19:23:00 +00:00
|
|
|
// Instead of directly invoking the entry point we call '_startIsolate' with
|
2014-08-20 19:57:09 +00:00
|
|
|
// the entry point as argument.
|
2013-10-25 19:23:00 +00:00
|
|
|
// 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.
|
2014-08-20 19:57:09 +00:00
|
|
|
const Array& args = Array::Handle(Array::New(7));
|
|
|
|
args.SetAt(0, SendPort::Handle(SendPort::New(state->parent_port())));
|
|
|
|
args.SetAt(1, Instance::Handle(func.ImplicitStaticClosure()));
|
2015-09-02 00:18:55 +00:00
|
|
|
args.SetAt(2, Instance::Handle(state->BuildArgs(thread)));
|
|
|
|
args.SetAt(3, Instance::Handle(state->BuildMessage(thread)));
|
2014-08-20 19:57:09 +00:00
|
|
|
args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False());
|
|
|
|
args.SetAt(5, ReceivePort::Handle(
|
|
|
|
ReceivePort::New(isolate->main_port(), true /* control port */)));
|
|
|
|
args.SetAt(6, capabilities);
|
2013-10-25 19:23:00 +00:00
|
|
|
|
|
|
|
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()) {
|
2015-10-06 18:27:26 +00:00
|
|
|
return StoreError(isolate, Error::Cast(result));
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-06 18:27:26 +00:00
|
|
|
return MessageHandler::kOK;
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2015-11-19 21:45:10 +00:00
|
|
|
Thread* thread = Thread::Current();
|
2015-09-02 00:18:55 +00:00
|
|
|
ASSERT(thread->isolate() == isolate);
|
2015-09-02 23:07:48 +00:00
|
|
|
StackZone zone(thread);
|
2015-09-02 00:18:55 +00:00
|
|
|
HandleScope handle_scope(thread);
|
2015-09-24 17:22:05 +00:00
|
|
|
const Error& error = Error::Handle(isolate->object_store()->sticky_error());
|
2014-12-13 00:39:16 +00:00
|
|
|
if (!error.IsNull() && !error.IsUnwindError()) {
|
2013-04-09 17:51:24 +00:00
|
|
|
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
|
|
|
}
|
2015-11-02 22:29:16 +00:00
|
|
|
// Shut the isolate down.
|
|
|
|
Dart::ShutdownIsolate(isolate);
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-23 19:13:25 +00:00
|
|
|
RawError* Isolate::HandleInterrupts() {
|
|
|
|
uword interrupt_bits = GetAndClearInterrupts();
|
|
|
|
if ((interrupt_bits & kVMInterrupt) != 0) {
|
|
|
|
thread_registry()->CheckSafepoint();
|
|
|
|
if (store_buffer()->Overflowed()) {
|
|
|
|
if (FLAG_verbose_gc) {
|
|
|
|
OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
|
|
|
|
}
|
|
|
|
heap()->CollectGarbage(Heap::kNew);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((interrupt_bits & kMessageInterrupt) != 0) {
|
2015-10-06 18:27:26 +00:00
|
|
|
MessageHandler::MessageStatus status =
|
|
|
|
message_handler()->HandleOOBMessages();
|
|
|
|
if (status != MessageHandler::kOK) {
|
2015-09-23 19:13:25 +00:00
|
|
|
// False result from HandleOOBMessages signals that the isolate should
|
|
|
|
// be terminating.
|
|
|
|
if (FLAG_trace_isolates) {
|
|
|
|
OS::Print("[!] Terminating isolate due to OOB message:\n"
|
|
|
|
"\tisolate: %s\n", name());
|
|
|
|
}
|
2015-09-24 17:22:05 +00:00
|
|
|
const Error& error = Error::Handle(object_store()->sticky_error());
|
2015-10-06 18:27:26 +00:00
|
|
|
ASSERT(!error.IsNull() && error.IsUnwindError());
|
2015-09-24 17:22:05 +00:00
|
|
|
object_store()->clear_sticky_error();
|
|
|
|
return error.raw();
|
2015-09-23 19:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Error::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-17 23:40:27 +00:00
|
|
|
void Isolate::AddClosureFunction(const Function& function) const {
|
|
|
|
GrowableObjectArray& closures =
|
|
|
|
GrowableObjectArray::Handle(object_store()->closure_functions());
|
|
|
|
ASSERT(!closures.IsNull());
|
|
|
|
ASSERT(function.IsNonImplicitClosureFunction());
|
|
|
|
closures.Add(function, Heap::kOld);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the linear lookup turns out to be too expensive, the list
|
|
|
|
// of closures could be maintained in a hash map, with the key
|
|
|
|
// being the token position of the closure. There are almost no
|
|
|
|
// collisions with this simple hash value. However, iterating over
|
|
|
|
// all closure functions becomes more difficult, especially when
|
|
|
|
// the list/map changes while iterating over it.
|
|
|
|
RawFunction* Isolate::LookupClosureFunction(const Function& parent,
|
|
|
|
intptr_t token_pos) const {
|
|
|
|
const GrowableObjectArray& closures =
|
|
|
|
GrowableObjectArray::Handle(object_store()->closure_functions());
|
|
|
|
ASSERT(!closures.IsNull());
|
|
|
|
Function& closure = Function::Handle();
|
|
|
|
intptr_t num_closures = closures.Length();
|
|
|
|
for (intptr_t i = 0; i < num_closures; i++) {
|
|
|
|
closure ^= closures.At(i);
|
|
|
|
if ((closure.token_pos() == token_pos) &&
|
|
|
|
(closure.parent_function() == parent.raw())) {
|
|
|
|
return closure.raw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Function::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
intptr_t Isolate::FindClosureIndex(const Function& needle) const {
|
|
|
|
const GrowableObjectArray& closures_array =
|
|
|
|
GrowableObjectArray::Handle(object_store()->closure_functions());
|
|
|
|
intptr_t num_closures = closures_array.Length();
|
|
|
|
for (intptr_t i = 0; i < num_closures; i++) {
|
|
|
|
if (closures_array.At(i) == needle.raw()) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawFunction* Isolate::ClosureFunctionFromIndex(intptr_t idx) const {
|
|
|
|
const GrowableObjectArray& closures_array =
|
|
|
|
GrowableObjectArray::Handle(object_store()->closure_functions());
|
|
|
|
if ((idx < 0) || (idx >= closures_array.Length())) {
|
|
|
|
return Function::null();
|
|
|
|
}
|
|
|
|
return Function::RawCast(closures_array.At(idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-07 22:17:56 +00:00
|
|
|
class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
|
|
|
|
public:
|
2015-10-09 17:10:34 +00:00
|
|
|
FinalizeWeakPersistentHandlesVisitor() : HandleVisitor(Thread::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);
|
2015-10-09 17:10:34 +00:00
|
|
|
handle->UpdateUnreachable(thread()->isolate());
|
2012-09-07 22:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(FinalizeWeakPersistentHandlesVisitor);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-09-15 19:49:52 +00:00
|
|
|
void Isolate::LowLevelShutdown() {
|
|
|
|
// Ensure we have a zone and handle scope so that we can call VM functions,
|
|
|
|
// but we no longer allocate new heap objects.
|
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
StackZone stack_zone(thread);
|
|
|
|
HandleScope handle_scope(thread);
|
|
|
|
NoSafepointScope no_safepoint_scope;
|
|
|
|
|
|
|
|
// Notify exit listeners that this isolate is shutting down.
|
|
|
|
if (object_store() != NULL) {
|
2015-09-24 17:22:05 +00:00
|
|
|
const Error& error = Error::Handle(object_store()->sticky_error());
|
|
|
|
if (error.IsNull() ||
|
|
|
|
!error.IsUnwindError() ||
|
|
|
|
UnwindError::Cast(error).is_user_initiated()) {
|
|
|
|
NotifyExitListeners();
|
|
|
|
}
|
2015-09-15 19:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2015-09-24 18:32:21 +00:00
|
|
|
// Before analyzing the isolate's timeline blocks- reclaim all cached blocks.
|
2015-10-16 20:36:58 +00:00
|
|
|
Timeline::ReclaimCachedBlocksFromThreads();
|
2015-09-15 19:49:52 +00:00
|
|
|
|
|
|
|
// Dump all timing data for the isolate.
|
|
|
|
if (FLAG_timing) {
|
|
|
|
TimelinePauseTrace tpt;
|
|
|
|
tpt.Print();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finalize any weak persistent handles with a non-null referent.
|
|
|
|
FinalizeWeakPersistentHandlesVisitor visitor;
|
|
|
|
api_state()->weak_persistent_handles().VisitHandles(&visitor);
|
|
|
|
|
|
|
|
if (FLAG_trace_isolates) {
|
|
|
|
heap()->PrintSizes();
|
|
|
|
MegamorphicCacheTable::PrintSizes(this);
|
|
|
|
Symbols::DumpStats();
|
|
|
|
OS::Print("[-] Stopping isolate:\n"
|
|
|
|
"\tisolate: %s\n", name());
|
|
|
|
}
|
|
|
|
if (FLAG_print_metrics) {
|
|
|
|
LogBlock lb;
|
|
|
|
THR_Print("Printing metrics for %s\n", name());
|
|
|
|
#define ISOLATE_METRIC_PRINT(type, variable, name, unit) \
|
|
|
|
THR_Print("%s\n", metric_##variable##_.ToString());
|
|
|
|
|
|
|
|
ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT);
|
|
|
|
#undef ISOLATE_METRIC_PRINT
|
|
|
|
THR_Print("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
void Isolate::Shutdown() {
|
|
|
|
ASSERT(this == Isolate::Current());
|
2015-11-03 00:39:22 +00:00
|
|
|
// Wait until all background compilation has finished.
|
2015-11-19 09:13:16 +00:00
|
|
|
if (background_compiler_ != NULL) {
|
|
|
|
BackgroundCompiler::Stop(background_compiler_);
|
|
|
|
}
|
2015-11-03 00:39:22 +00:00
|
|
|
|
2014-10-06 23:20:23 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
if (heap_ != NULL) {
|
2015-01-21 20:30:09 +00:00
|
|
|
// The VM isolate keeps all objects marked.
|
|
|
|
heap_->Verify(this == Dart::vm_isolate() ? kRequireMarked : kForbidMarked);
|
2014-10-06 23:20:23 +00:00
|
|
|
}
|
|
|
|
#endif // DEBUG
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2015-09-02 00:18:55 +00:00
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
|
2015-11-02 22:29:16 +00:00
|
|
|
// Don't allow anymore dart code to execution on this isolate.
|
|
|
|
ClearStackLimit();
|
|
|
|
|
2015-07-17 20:06:21 +00:00
|
|
|
// First, perform higher-level cleanup that may need to allocate.
|
|
|
|
{
|
|
|
|
// Ensure we have a zone and handle scope so that we can call VM functions.
|
2015-09-02 23:07:48 +00:00
|
|
|
StackZone stack_zone(thread);
|
2015-09-02 00:18:55 +00:00
|
|
|
HandleScope handle_scope(thread);
|
2015-07-17 20:06:21 +00:00
|
|
|
|
|
|
|
// Write out the coverage data if collection has been enabled.
|
2015-09-15 19:49:52 +00:00
|
|
|
if ((this != Dart::vm_isolate()) &&
|
|
|
|
!ServiceIsolate::IsServiceIsolateDescendant(this)) {
|
2015-10-12 22:51:06 +00:00
|
|
|
CodeCoverage::Write(thread);
|
2015-09-15 19:49:52 +00:00
|
|
|
}
|
2015-09-16 22:14:09 +00:00
|
|
|
|
|
|
|
// Write compiler stats data if enabled.
|
|
|
|
if (FLAG_compiler_stats
|
|
|
|
&& !ServiceIsolate::IsServiceIsolateDescendant(this)
|
|
|
|
&& (this != Dart::vm_isolate())) {
|
|
|
|
OS::Print("%s", compiler_stats()->PrintToZone());
|
|
|
|
}
|
2015-07-17 20:06:21 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 17:17:41 +00:00
|
|
|
// Remove this isolate from the list *before* we start tearing it down, to
|
|
|
|
// avoid exposing it in a state of decay.
|
|
|
|
RemoveIsolateFromList(this);
|
|
|
|
|
2015-07-14 00:49:49 +00:00
|
|
|
if (heap_ != NULL) {
|
|
|
|
// Wait for any concurrent GC tasks to finish before shutting down.
|
2015-07-17 20:06:21 +00:00
|
|
|
// TODO(koda): Support faster sweeper shutdown (e.g., after current page).
|
2015-07-14 00:49:49 +00:00
|
|
|
PageSpace* old_space = heap_->old_space();
|
|
|
|
MonitorLocker ml(old_space->tasks_lock());
|
|
|
|
while (old_space->tasks() > 0) {
|
|
|
|
ml.Wait();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 20:06:21 +00:00
|
|
|
// Then, proceed with low-level teardown.
|
2015-09-15 19:49:52 +00:00
|
|
|
LowLevelShutdown();
|
2015-06-16 17:10:14 +00:00
|
|
|
|
2015-07-17 20:06:21 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// No concurrent sweeper tasks should be running at this point.
|
|
|
|
if (heap_ != NULL) {
|
|
|
|
PageSpace* old_space = heap_->old_space();
|
|
|
|
MonitorLocker ml(old_space->tasks_lock());
|
|
|
|
ASSERT(old_space->tasks() == 0);
|
2012-01-18 21:46:27 +00:00
|
|
|
}
|
2015-07-17 20:06:21 +00:00
|
|
|
#endif
|
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.
|
2015-04-01 17:48:11 +00:00
|
|
|
Thread::ExitIsolate();
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-01 00:30:25 +00:00
|
|
|
Dart_IsolateCreateCallback Isolate::create_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;
|
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;
|
2015-09-15 19:49:52 +00:00
|
|
|
bool Isolate::creation_enabled_ = false;
|
2014-02-07 17:43:21 +00:00
|
|
|
|
2015-07-08 00:20:20 +00:00
|
|
|
void Isolate::IterateObjectPointers(ObjectPointerVisitor* visitor,
|
|
|
|
bool validate_frames) {
|
|
|
|
HeapIterationScope heap_iteration_scope;
|
2015-11-20 20:36:16 +00:00
|
|
|
VisitObjectPointers(visitor, validate_frames);
|
2015-07-08 00:20:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
|
|
|
|
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);
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// Visit objects in per isolate stubs.
|
|
|
|
StubCode::VisitObjectPointers(visitor);
|
|
|
|
|
|
|
|
// Visit the dart api state for all local and persistent handles.
|
|
|
|
if (api_state() != NULL) {
|
2015-11-20 20:36:16 +00:00
|
|
|
api_state()->VisitObjectPointers(visitor);
|
2011-10-05 05:20:07 +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_));
|
|
|
|
|
2014-09-19 18:00:13 +00:00
|
|
|
// Visit the default tag which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(reinterpret_cast<RawObject**>(&default_tag_));
|
|
|
|
|
2014-04-10 22:32:45 +00:00
|
|
|
// Visit the tag table which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(reinterpret_cast<RawObject**>(&tag_table_));
|
|
|
|
|
2015-10-30 20:32:21 +00:00
|
|
|
if (background_compiler() != NULL) {
|
|
|
|
background_compiler()->VisitPointers(visitor);
|
|
|
|
}
|
2015-10-05 19:29:22 +00:00
|
|
|
|
2015-02-26 18:48:55 +00:00
|
|
|
// Visit the deoptimized code array which is stored in the isolate.
|
|
|
|
visitor->VisitPointer(
|
|
|
|
reinterpret_cast<RawObject**>(&deoptimized_code_array_));
|
|
|
|
|
2015-08-27 18:23:39 +00:00
|
|
|
// Visit the pending service extension calls.
|
|
|
|
visitor->VisitPointer(
|
|
|
|
reinterpret_cast<RawObject**>(&pending_service_extension_calls_));
|
|
|
|
|
|
|
|
// Visit the registered service extension handlers.
|
|
|
|
visitor->VisitPointer(
|
|
|
|
reinterpret_cast<RawObject**>(®istered_service_extension_handlers_));
|
|
|
|
|
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);
|
|
|
|
}
|
2015-07-09 18:22:26 +00:00
|
|
|
|
2015-08-12 15:47:54 +00:00
|
|
|
// Visit objects in thread registry (e.g., Dart stack, handles in zones).
|
|
|
|
thread_registry()->VisitObjectPointers(visitor, validate_frames);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2011-12-20 01:44:53 +00:00
|
|
|
|
2015-11-20 20:36:16 +00:00
|
|
|
void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor) {
|
2011-12-20 01:44:53 +00:00
|
|
|
if (api_state() != NULL) {
|
2015-11-20 20:36:16 +00:00
|
|
|
api_state()->VisitWeakHandles(visitor);
|
2014-04-15 16:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-12 18:04:44 +00:00
|
|
|
static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) {
|
|
|
|
switch (pi) {
|
|
|
|
case kPauseOnAllExceptions:
|
|
|
|
return "All";
|
|
|
|
case kNoPauseOnExceptions:
|
|
|
|
return "None";
|
|
|
|
case kPauseOnUnhandledExceptions:
|
|
|
|
return "Unhandled";
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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"));
|
2015-10-20 16:47:35 +00:00
|
|
|
jsobj.AddFixedServiceId("isolates/%" Pd64 "",
|
|
|
|
static_cast<int64_t>(main_port()));
|
2014-03-20 21:00:10 +00:00
|
|
|
|
2015-03-26 19:06:18 +00:00
|
|
|
jsobj.AddProperty("name", debugger_name());
|
2015-10-20 16:47:35 +00:00
|
|
|
jsobj.AddPropertyF("number", "%" Pd64 "",
|
|
|
|
static_cast<int64_t>(main_port()));
|
2014-03-20 21:00:10 +00:00
|
|
|
if (ref) {
|
|
|
|
return;
|
|
|
|
}
|
2015-10-20 16:47:35 +00:00
|
|
|
jsobj.AddPropertyF("_originNumber", "%" Pd64 "",
|
|
|
|
static_cast<int64_t>(origin_id()));
|
2015-03-26 19:06:18 +00:00
|
|
|
int64_t start_time_millis = start_time() / kMicrosecondsPerMillisecond;
|
2015-08-26 17:57:59 +00:00
|
|
|
jsobj.AddPropertyTimeMillis("startTime", start_time_millis);
|
2014-01-29 18:40:12 +00:00
|
|
|
{
|
2015-05-26 21:05:50 +00:00
|
|
|
JSONObject jsheap(&jsobj, "_heaps");
|
2014-06-18 17:39:37 +00:00
|
|
|
heap()->PrintToJSONObject(Heap::kNew, &jsheap);
|
|
|
|
heap()->PrintToJSONObject(Heap::kOld, &jsheap);
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
|
|
|
|
2014-05-20 17:09:08 +00:00
|
|
|
jsobj.AddProperty("livePorts", message_handler()->live_ports());
|
|
|
|
jsobj.AddProperty("pauseOnExit", message_handler()->pause_on_exit());
|
|
|
|
|
|
|
|
if (message_handler()->paused_on_start()) {
|
|
|
|
ASSERT(debugger()->PauseEvent() == NULL);
|
2015-03-05 19:02:42 +00:00
|
|
|
ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
|
|
|
|
jsobj.AddProperty("pauseEvent", &pause_event);
|
2014-05-20 17:09:08 +00:00
|
|
|
} else if (message_handler()->paused_on_exit()) {
|
|
|
|
ASSERT(debugger()->PauseEvent() == NULL);
|
2015-03-05 19:02:42 +00:00
|
|
|
ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
|
|
|
|
jsobj.AddProperty("pauseEvent", &pause_event);
|
2015-08-24 20:38:33 +00:00
|
|
|
} else if (debugger()->PauseEvent() != NULL && !resume_request_) {
|
2015-03-05 19:02:42 +00:00
|
|
|
ServiceEvent pause_event(debugger()->PauseEvent());
|
|
|
|
jsobj.AddProperty("pauseEvent", &pause_event);
|
|
|
|
} else {
|
|
|
|
ServiceEvent pause_event(this, ServiceEvent::kResume);
|
|
|
|
|
|
|
|
// TODO(turnidge): Don't compute a full stack trace.
|
|
|
|
DebuggerStackTrace* stack = debugger()->StackTrace();
|
|
|
|
if (stack->Length() > 0) {
|
|
|
|
pause_event.set_top_frame(stack->FrameAt(0));
|
|
|
|
}
|
|
|
|
jsobj.AddProperty("pauseEvent", &pause_event);
|
2014-05-20 17:09:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-12 18:04:44 +00:00
|
|
|
jsobj.AddProperty("exceptionPauseMode",
|
|
|
|
ExceptionPauseInfoToServiceEnum(debugger()->GetExceptionPauseInfo()));
|
|
|
|
|
2014-01-29 18:40:12 +00:00
|
|
|
const Library& lib =
|
|
|
|
Library::Handle(object_store()->root_library());
|
2015-08-21 17:25:38 +00:00
|
|
|
if (!lib.IsNull()) {
|
|
|
|
jsobj.AddProperty("rootLib", lib);
|
|
|
|
}
|
2013-04-04 18:48:24 +00:00
|
|
|
|
2014-04-02 18:30:01 +00:00
|
|
|
{
|
2015-05-26 21:05:50 +00:00
|
|
|
JSONObject tagCounters(&jsobj, "_tagCounters");
|
2014-04-02 18:30:01 +00:00
|
|
|
vm_tag_counters()->PrintToJSONObject(&tagCounters);
|
|
|
|
}
|
2014-03-25 18:09:02 +00:00
|
|
|
if (object_store()->sticky_error() != Object::null()) {
|
2015-10-19 17:27:36 +00:00
|
|
|
Error& error = Error::Handle(object_store()->sticky_error());
|
2014-03-25 18:09:02 +00:00
|
|
|
ASSERT(!error.IsNull());
|
|
|
|
jsobj.AddProperty("error", error, false);
|
|
|
|
}
|
|
|
|
|
2014-05-05 16:54:59 +00:00
|
|
|
{
|
|
|
|
const GrowableObjectArray& libs =
|
|
|
|
GrowableObjectArray::Handle(object_store()->libraries());
|
|
|
|
intptr_t num_libs = libs.Length();
|
2014-05-23 10:09:54 +00:00
|
|
|
Library& lib = Library::Handle();
|
2014-05-05 16:54:59 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2015-03-05 19:02:42 +00:00
|
|
|
{
|
|
|
|
JSONArray breakpoints(&jsobj, "breakpoints");
|
|
|
|
debugger()->PrintBreakpointsToJSONArray(&breakpoints);
|
|
|
|
}
|
2015-06-15 19:05:23 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
JSONObject jssettings(&jsobj, "_debuggerSettings");
|
|
|
|
debugger()->PrintSettingsToJSONObject(&jssettings);
|
|
|
|
}
|
2013-04-04 18:48:24 +00:00
|
|
|
}
|
|
|
|
|
2013-04-09 17:51:24 +00:00
|
|
|
|
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) {
|
2014-09-19 18:00:13 +00:00
|
|
|
uword user_tag = tag.tag();
|
|
|
|
ASSERT(user_tag < kUwordMax);
|
|
|
|
set_user_tag(user_tag);
|
2014-04-10 22:32:45 +00:00
|
|
|
current_tag_ = tag.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-19 18:00:13 +00:00
|
|
|
void Isolate::set_default_tag(const UserTag& tag) {
|
|
|
|
default_tag_ = tag.raw();
|
|
|
|
}
|
|
|
|
|
2015-11-04 17:31:19 +00:00
|
|
|
void Isolate::set_ic_miss_code(const Code& code) {
|
|
|
|
ic_miss_code_ = code.raw();
|
|
|
|
}
|
|
|
|
|
2014-09-19 18:00:13 +00:00
|
|
|
|
2015-02-26 18:48:55 +00:00
|
|
|
void Isolate::set_deoptimized_code_array(const GrowableObjectArray& value) {
|
2015-11-03 00:39:22 +00:00
|
|
|
ASSERT(Thread::Current()->IsMutatorThread());
|
2015-02-26 18:48:55 +00:00
|
|
|
deoptimized_code_array_ = value.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::TrackDeoptimizedCode(const Code& code) {
|
|
|
|
ASSERT(!code.IsNull());
|
|
|
|
const GrowableObjectArray& deoptimized_code =
|
|
|
|
GrowableObjectArray::Handle(deoptimized_code_array());
|
|
|
|
if (deoptimized_code.IsNull()) {
|
|
|
|
// Not tracking deoptimized code.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// TODO(johnmccutchan): Scan this array and the isolate's profile before
|
|
|
|
// old space GC and remove the keep_code flag.
|
|
|
|
deoptimized_code.Add(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 18:23:39 +00:00
|
|
|
void Isolate::set_pending_service_extension_calls(
|
|
|
|
const GrowableObjectArray& value) {
|
|
|
|
pending_service_extension_calls_ = value.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::set_registered_service_extension_handlers(
|
|
|
|
const GrowableObjectArray& value) {
|
|
|
|
registered_service_extension_handlers_ = value.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawObject* Isolate::InvokePendingServiceExtensionCalls() {
|
|
|
|
GrowableObjectArray& calls =
|
|
|
|
GrowableObjectArray::Handle(GetAndClearPendingServiceExtensionCalls());
|
|
|
|
if (calls.IsNull()) {
|
|
|
|
return Object::null();
|
|
|
|
}
|
|
|
|
// Grab run function.
|
|
|
|
const Library& developer_lib = Library::Handle(Library::DeveloperLibrary());
|
|
|
|
ASSERT(!developer_lib.IsNull());
|
|
|
|
const Function& run_extension = Function::Handle(
|
|
|
|
developer_lib.LookupLocalFunction(Symbols::_runExtension()));
|
|
|
|
ASSERT(!run_extension.IsNull());
|
|
|
|
|
|
|
|
const Array& arguments =
|
|
|
|
Array::Handle(Array::New(kPendingEntrySize, Heap::kNew));
|
|
|
|
Object& result = Object::Handle();
|
|
|
|
String& method_name = String::Handle();
|
|
|
|
Instance& closure = Instance::Handle();
|
|
|
|
Array& parameter_keys = Array::Handle();
|
|
|
|
Array& parameter_values = Array::Handle();
|
|
|
|
Instance& reply_port = Instance::Handle();
|
|
|
|
Instance& id = Instance::Handle();
|
|
|
|
for (intptr_t i = 0; i < calls.Length(); i += kPendingEntrySize) {
|
|
|
|
// Grab arguments for call.
|
|
|
|
closure ^= calls.At(i + kPendingHandlerIndex);
|
|
|
|
ASSERT(!closure.IsNull());
|
|
|
|
arguments.SetAt(kPendingHandlerIndex, closure);
|
|
|
|
method_name ^= calls.At(i + kPendingMethodNameIndex);
|
|
|
|
ASSERT(!method_name.IsNull());
|
|
|
|
arguments.SetAt(kPendingMethodNameIndex, method_name);
|
|
|
|
parameter_keys ^= calls.At(i + kPendingKeysIndex);
|
|
|
|
ASSERT(!parameter_keys.IsNull());
|
|
|
|
arguments.SetAt(kPendingKeysIndex, parameter_keys);
|
|
|
|
parameter_values ^= calls.At(i + kPendingValuesIndex);
|
|
|
|
ASSERT(!parameter_values.IsNull());
|
|
|
|
arguments.SetAt(kPendingValuesIndex, parameter_values);
|
|
|
|
reply_port ^= calls.At(i + kPendingReplyPortIndex);
|
|
|
|
ASSERT(!reply_port.IsNull());
|
|
|
|
arguments.SetAt(kPendingReplyPortIndex, reply_port);
|
|
|
|
id ^= calls.At(i + kPendingIdIndex);
|
|
|
|
arguments.SetAt(kPendingIdIndex, id);
|
|
|
|
|
|
|
|
result = DartEntry::InvokeFunction(run_extension, arguments);
|
|
|
|
if (result.IsError()) {
|
|
|
|
if (result.IsUnwindError()) {
|
|
|
|
// Propagate the unwind error. Remaining service extension calls
|
|
|
|
// are dropped.
|
|
|
|
return result.raw();
|
|
|
|
} else {
|
|
|
|
// Send error back over the protocol.
|
|
|
|
Service::PostError(method_name,
|
|
|
|
parameter_keys,
|
|
|
|
parameter_values,
|
|
|
|
reply_port,
|
|
|
|
id,
|
|
|
|
Error::Cast(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = DartLibraryCalls::DrainMicrotaskQueue();
|
|
|
|
if (result.IsError()) {
|
|
|
|
return result.raw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Object::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawGrowableObjectArray* Isolate::GetAndClearPendingServiceExtensionCalls() {
|
|
|
|
RawGrowableObjectArray* r = pending_service_extension_calls_;
|
|
|
|
pending_service_extension_calls_ = GrowableObjectArray::null();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::AppendServiceExtensionCall(const Instance& closure,
|
|
|
|
const String& method_name,
|
|
|
|
const Array& parameter_keys,
|
|
|
|
const Array& parameter_values,
|
|
|
|
const Instance& reply_port,
|
|
|
|
const Instance& id) {
|
|
|
|
GrowableObjectArray& calls =
|
|
|
|
GrowableObjectArray::Handle(pending_service_extension_calls());
|
|
|
|
if (calls.IsNull()) {
|
|
|
|
calls ^= GrowableObjectArray::New();
|
|
|
|
ASSERT(!calls.IsNull());
|
|
|
|
set_pending_service_extension_calls(calls);
|
|
|
|
}
|
|
|
|
ASSERT(kPendingHandlerIndex == 0);
|
|
|
|
calls.Add(closure);
|
|
|
|
ASSERT(kPendingMethodNameIndex == 1);
|
|
|
|
calls.Add(method_name);
|
|
|
|
ASSERT(kPendingKeysIndex == 2);
|
|
|
|
calls.Add(parameter_keys);
|
|
|
|
ASSERT(kPendingValuesIndex == 3);
|
|
|
|
calls.Add(parameter_values);
|
|
|
|
ASSERT(kPendingReplyPortIndex == 4);
|
|
|
|
calls.Add(reply_port);
|
|
|
|
ASSERT(kPendingIdIndex == 5);
|
|
|
|
calls.Add(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This function is written in C++ and not Dart because we must do this
|
|
|
|
// operation atomically in the face of random OOB messages. Do not port
|
|
|
|
// to Dart code unless you can ensure that the operations will can be
|
|
|
|
// done atomically.
|
|
|
|
void Isolate::RegisterServiceExtensionHandler(const String& name,
|
|
|
|
const Instance& closure) {
|
|
|
|
GrowableObjectArray& handlers =
|
|
|
|
GrowableObjectArray::Handle(registered_service_extension_handlers());
|
|
|
|
if (handlers.IsNull()) {
|
|
|
|
handlers ^= GrowableObjectArray::New(Heap::kOld);
|
|
|
|
set_registered_service_extension_handlers(handlers);
|
|
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
|
|
{
|
|
|
|
// Sanity check.
|
|
|
|
const Instance& existing_handler =
|
|
|
|
Instance::Handle(LookupServiceExtensionHandler(name));
|
|
|
|
ASSERT(existing_handler.IsNull());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ASSERT(kRegisteredNameIndex == 0);
|
|
|
|
handlers.Add(name, Heap::kOld);
|
|
|
|
ASSERT(kRegisteredHandlerIndex == 1);
|
|
|
|
handlers.Add(closure, Heap::kOld);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This function is written in C++ and not Dart because we must do this
|
|
|
|
// operation atomically in the face of random OOB messages. Do not port
|
|
|
|
// to Dart code unless you can ensure that the operations will can be
|
|
|
|
// done atomically.
|
|
|
|
RawInstance* Isolate::LookupServiceExtensionHandler(const String& name) {
|
|
|
|
const GrowableObjectArray& handlers =
|
|
|
|
GrowableObjectArray::Handle(registered_service_extension_handlers());
|
|
|
|
if (handlers.IsNull()) {
|
|
|
|
return Instance::null();
|
|
|
|
}
|
|
|
|
String& handler_name = String::Handle();
|
|
|
|
for (intptr_t i = 0; i < handlers.Length(); i += kRegisteredEntrySize) {
|
|
|
|
handler_name ^= handlers.At(i + kRegisteredNameIndex);
|
|
|
|
ASSERT(!handler_name.IsNull());
|
|
|
|
if (handler_name.Equals(name)) {
|
|
|
|
return Instance::RawCast(handlers.At(i + kRegisteredHandlerIndex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Instance::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-01 17:56:35 +00:00
|
|
|
void Isolate::WakePauseEventHandler(Dart_Isolate isolate) {
|
2015-05-19 18:41:42 +00:00
|
|
|
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
|
2015-05-01 17:56:35 +00:00
|
|
|
MonitorLocker ml(iso->pause_loop_monitor_);
|
|
|
|
ml.Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::PauseEventHandler() {
|
|
|
|
// We are stealing a pause event (like a breakpoint) from the
|
|
|
|
// embedder. We don't know what kind of thread we are on -- it
|
|
|
|
// could be from our thread pool or it could be a thread from the
|
|
|
|
// embedder. Sit on the current thread handling service events
|
|
|
|
// until we are told to resume.
|
|
|
|
if (pause_loop_monitor_ == NULL) {
|
|
|
|
pause_loop_monitor_ = new Monitor();
|
|
|
|
}
|
|
|
|
Dart_EnterScope();
|
|
|
|
MonitorLocker ml(pause_loop_monitor_);
|
|
|
|
|
|
|
|
Dart_MessageNotifyCallback saved_notify_callback =
|
|
|
|
message_notify_callback();
|
|
|
|
set_message_notify_callback(Isolate::WakePauseEventHandler);
|
|
|
|
|
|
|
|
bool resume = false;
|
|
|
|
while (true) {
|
|
|
|
// Handle all available vm service messages, up to a resume
|
|
|
|
// request.
|
|
|
|
while (!resume && Dart_HasServiceMessages()) {
|
|
|
|
pause_loop_monitor_->Exit();
|
|
|
|
resume = Dart_HandleServiceMessages();
|
|
|
|
pause_loop_monitor_->Enter();
|
|
|
|
}
|
|
|
|
if (resume) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for more service messages.
|
|
|
|
Monitor::WaitResult res = ml.Wait();
|
|
|
|
ASSERT(res == Monitor::kNotified);
|
|
|
|
}
|
|
|
|
set_message_notify_callback(saved_notify_callback);
|
|
|
|
Dart_ExitScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-15 17:35:00 +00:00
|
|
|
intptr_t Isolate::IsolateListLength() {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
intptr_t count = 0;
|
|
|
|
Isolate* current = isolates_list_head_;
|
|
|
|
while (current != NULL) {
|
|
|
|
count++;
|
|
|
|
current = current->next_;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-15 19:49:52 +00:00
|
|
|
bool Isolate::AddIsolateToList(Isolate* isolate) {
|
2014-02-07 17:43:21 +00:00
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
2015-09-15 19:49:52 +00:00
|
|
|
if (!creation_enabled_) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-07 17:43:21 +00:00
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
ASSERT(isolate->next_ == NULL);
|
|
|
|
isolate->next_ = isolates_list_head_;
|
|
|
|
isolates_list_head_ = isolate;
|
2015-09-15 19:49:52 +00:00
|
|
|
return true;
|
2014-02-07 17:43:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::RemoveIsolateFromList(Isolate* isolate) {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
if (isolate == isolates_list_head_) {
|
|
|
|
isolates_list_head_ = isolate->next_;
|
2015-09-15 19:49:52 +00:00
|
|
|
if (!creation_enabled_) {
|
|
|
|
ml.Notify();
|
|
|
|
}
|
2014-02-07 17:43:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Isolate* previous = NULL;
|
|
|
|
Isolate* current = isolates_list_head_;
|
|
|
|
while (current) {
|
|
|
|
if (current == isolate) {
|
|
|
|
ASSERT(previous != NULL);
|
|
|
|
previous->next_ = current->next_;
|
2015-09-15 19:49:52 +00:00
|
|
|
if (!creation_enabled_) {
|
|
|
|
ml.Notify();
|
|
|
|
}
|
2014-02-07 17:43:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
previous = current;
|
|
|
|
current = current->next_;
|
|
|
|
}
|
2015-09-15 19:49:52 +00:00
|
|
|
// If we are shutting down the VM, the isolate may not be in the list.
|
|
|
|
ASSERT(!creation_enabled_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::DisableIsolateCreation() {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
creation_enabled_ = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Isolate::EnableIsolateCreation() {
|
|
|
|
MonitorLocker ml(isolates_list_monitor_);
|
|
|
|
creation_enabled_ = true;
|
2014-02-07 17:43:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
void Isolate::KillLocked(LibMsgId msg_id) {
|
2015-09-15 19:49:52 +00:00
|
|
|
Dart_CObject kill_msg;
|
|
|
|
Dart_CObject* list_values[4];
|
|
|
|
kill_msg.type = Dart_CObject_kArray;
|
|
|
|
kill_msg.value.as_array.length = 4;
|
|
|
|
kill_msg.value.as_array.values = list_values;
|
|
|
|
|
|
|
|
Dart_CObject oob;
|
|
|
|
oob.type = Dart_CObject_kInt32;
|
|
|
|
oob.value.as_int32 = Message::kIsolateLibOOBMsg;
|
|
|
|
list_values[0] = &oob;
|
|
|
|
|
2015-09-24 17:22:05 +00:00
|
|
|
Dart_CObject msg_type;
|
|
|
|
msg_type.type = Dart_CObject_kInt32;
|
2015-10-06 18:27:26 +00:00
|
|
|
msg_type.value.as_int32 = msg_id;
|
2015-09-24 17:22:05 +00:00
|
|
|
list_values[1] = &msg_type;
|
2015-09-15 19:49:52 +00:00
|
|
|
|
|
|
|
Dart_CObject cap;
|
|
|
|
cap.type = Dart_CObject_kCapability;
|
|
|
|
cap.value.as_capability.id = terminate_capability();
|
|
|
|
list_values[2] = ∩
|
|
|
|
|
|
|
|
Dart_CObject imm;
|
|
|
|
imm.type = Dart_CObject_kInt32;
|
2015-09-23 19:13:25 +00:00
|
|
|
imm.value.as_int32 = Isolate::kImmediateAction;
|
2015-09-15 19:49:52 +00:00
|
|
|
list_values[3] = &imm;
|
|
|
|
|
|
|
|
{
|
|
|
|
uint8_t* buffer = NULL;
|
|
|
|
ApiMessageWriter writer(&buffer, allocator);
|
|
|
|
bool success = writer.WriteCMessage(&kill_msg);
|
|
|
|
ASSERT(success);
|
|
|
|
|
|
|
|
// Post the message at the given port.
|
|
|
|
success = PortMap::PostMessage(new Message(main_port(),
|
|
|
|
buffer,
|
|
|
|
writer.BytesWritten(),
|
|
|
|
Message::kOOBPriority));
|
|
|
|
ASSERT(success);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class IsolateKillerVisitor : public IsolateVisitor {
|
|
|
|
public:
|
2015-10-06 18:27:26 +00:00
|
|
|
explicit IsolateKillerVisitor(Isolate::LibMsgId msg_id)
|
|
|
|
: target_(NULL), msg_id_(msg_id) {}
|
2015-09-15 19:49:52 +00:00
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
IsolateKillerVisitor(Isolate* isolate, Isolate::LibMsgId msg_id)
|
|
|
|
: target_(isolate), msg_id_(msg_id) {
|
2015-09-15 19:49:52 +00:00
|
|
|
ASSERT(isolate != Dart::vm_isolate());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~IsolateKillerVisitor() {}
|
|
|
|
|
|
|
|
void VisitIsolate(Isolate* isolate) {
|
|
|
|
ASSERT(isolate != NULL);
|
|
|
|
if (ShouldKill(isolate)) {
|
2015-10-06 18:27:26 +00:00
|
|
|
isolate->KillLocked(msg_id_);
|
2015-09-15 19:49:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool ShouldKill(Isolate* isolate) {
|
|
|
|
// If a target_ is specified, then only kill the target_.
|
|
|
|
// Otherwise, don't kill the service isolate or vm isolate.
|
|
|
|
return (((target_ != NULL) && (isolate == target_)) ||
|
|
|
|
((target_ == NULL) &&
|
|
|
|
!ServiceIsolate::IsServiceIsolateDescendant(isolate) &&
|
|
|
|
(isolate != Dart::vm_isolate())));
|
|
|
|
}
|
|
|
|
|
|
|
|
Isolate* target_;
|
2015-10-06 18:27:26 +00:00
|
|
|
Isolate::LibMsgId msg_id_;
|
2015-09-15 19:49:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
void Isolate::KillAllIsolates(LibMsgId msg_id) {
|
|
|
|
IsolateKillerVisitor visitor(msg_id);
|
2015-09-15 19:49:52 +00:00
|
|
|
VisitIsolates(&visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-06 18:27:26 +00:00
|
|
|
void Isolate::KillIfExists(Isolate* isolate, LibMsgId msg_id) {
|
|
|
|
IsolateKillerVisitor visitor(isolate, msg_id);
|
2015-09-15 19:49:52 +00:00
|
|
|
VisitIsolates(&visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-02 00:18:55 +00:00
|
|
|
static RawInstance* DeserializeObject(Thread* thread,
|
2014-08-20 19:57:09 +00:00
|
|
|
uint8_t* obj_data,
|
|
|
|
intptr_t obj_len) {
|
|
|
|
if (obj_data == NULL) {
|
|
|
|
return Instance::null();
|
|
|
|
}
|
2015-09-02 00:18:55 +00:00
|
|
|
MessageSnapshotReader reader(obj_data, obj_len, thread);
|
|
|
|
Zone* zone = thread->zone();
|
|
|
|
const Object& obj = Object::Handle(zone, reader.ReadObject());
|
2014-08-20 19:57:09 +00:00
|
|
|
ASSERT(!obj.IsError());
|
2015-09-02 00:18:55 +00:00
|
|
|
Instance& instance = Instance::Handle(zone);
|
2014-08-20 19:57:09 +00:00
|
|
|
instance ^= obj.raw(); // Can't use Instance::Cast because may be null.
|
|
|
|
return instance.raw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-12 16:05:37 +00:00
|
|
|
static const char* NewConstChar(const char* chars) {
|
|
|
|
size_t len = strlen(chars);
|
|
|
|
char* mem = new char[len + 1];
|
|
|
|
memmove(mem, chars, len + 1);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-20 19:57:09 +00:00
|
|
|
IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
|
2015-11-18 19:02:32 +00:00
|
|
|
Dart_Port origin_id,
|
|
|
|
void* init_data,
|
2014-08-20 19:57:09 +00:00
|
|
|
const Function& func,
|
2014-12-30 23:52:37 +00:00
|
|
|
const Instance& message,
|
2015-07-20 14:46:54 +00:00
|
|
|
bool paused,
|
|
|
|
bool errors_are_fatal,
|
|
|
|
Dart_Port on_exit_port,
|
|
|
|
Dart_Port on_error_port)
|
2013-04-09 17:51:24 +00:00
|
|
|
: isolate_(NULL),
|
2014-08-20 19:57:09 +00:00
|
|
|
parent_port_(parent_port),
|
2015-11-18 19:02:32 +00:00
|
|
|
origin_id_(origin_id),
|
|
|
|
init_data_(init_data),
|
2015-07-20 14:46:54 +00:00
|
|
|
on_exit_port_(on_exit_port),
|
|
|
|
on_error_port_(on_error_port),
|
2013-04-09 17:51:24 +00:00
|
|
|
script_url_(NULL),
|
2014-09-23 05:46:14 +00:00
|
|
|
package_root_(NULL),
|
2015-10-12 16:05:37 +00:00
|
|
|
package_map_(NULL),
|
2013-04-09 17:51:24 +00:00
|
|
|
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),
|
2014-08-20 19:57:09 +00:00
|
|
|
serialized_args_(NULL),
|
|
|
|
serialized_args_len_(0),
|
|
|
|
serialized_message_(NULL),
|
2014-12-30 23:52:37 +00:00
|
|
|
serialized_message_len_(0),
|
2015-06-07 15:57:34 +00:00
|
|
|
isolate_flags_(),
|
2015-07-20 14:46:54 +00:00
|
|
|
paused_(paused),
|
|
|
|
errors_are_fatal_(errors_are_fatal) {
|
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());
|
2015-10-12 16:05:37 +00:00
|
|
|
library_url_ = NewConstChar(lib_url.ToCString());
|
2013-04-09 17:51:24 +00:00
|
|
|
|
|
|
|
const String& func_name = String::Handle(func.name());
|
2015-10-12 16:05:37 +00:00
|
|
|
function_name_ = NewConstChar(func_name.ToCString());
|
2013-11-20 09:14:30 +00:00
|
|
|
if (!cls.IsTopLevel()) {
|
|
|
|
const String& class_name = String::Handle(cls.Name());
|
2015-10-12 16:05:37 +00:00
|
|
|
class_name_ = NewConstChar(class_name.ToCString());
|
2013-11-20 09:14:30 +00:00
|
|
|
}
|
2015-01-12 23:14:30 +00:00
|
|
|
bool can_send_any_object = true;
|
|
|
|
SerializeObject(message,
|
|
|
|
&serialized_message_,
|
|
|
|
&serialized_message_len_,
|
|
|
|
can_send_any_object);
|
2015-06-07 15:57:34 +00:00
|
|
|
// Inherit flags from spawning isolate.
|
|
|
|
isolate_flags()->CopyFrom(Isolate::Current()->flags());
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-20 19:57:09 +00:00
|
|
|
IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
|
2015-11-18 19:02:32 +00:00
|
|
|
void* init_data,
|
2014-08-20 19:57:09 +00:00
|
|
|
const char* script_url,
|
2014-09-23 05:46:14 +00:00
|
|
|
const char* package_root,
|
2015-10-12 16:05:37 +00:00
|
|
|
const char** package_map,
|
2014-08-20 19:57:09 +00:00
|
|
|
const Instance& args,
|
2014-12-30 23:52:37 +00:00
|
|
|
const Instance& message,
|
2015-07-20 14:46:54 +00:00
|
|
|
bool paused,
|
|
|
|
bool errors_are_fatal,
|
|
|
|
Dart_Port on_exit_port,
|
|
|
|
Dart_Port on_error_port)
|
2013-04-09 17:51:24 +00:00
|
|
|
: isolate_(NULL),
|
2014-08-20 19:57:09 +00:00
|
|
|
parent_port_(parent_port),
|
2015-11-18 19:02:32 +00:00
|
|
|
origin_id_(ILLEGAL_PORT),
|
|
|
|
init_data_(init_data),
|
2015-07-20 14:46:54 +00:00
|
|
|
on_exit_port_(on_exit_port),
|
|
|
|
on_error_port_(on_error_port),
|
2015-10-12 16:05:37 +00:00
|
|
|
script_url_(script_url),
|
|
|
|
package_root_(package_root),
|
|
|
|
package_map_(package_map),
|
2013-04-09 17:51:24 +00:00
|
|
|
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),
|
2014-08-20 19:57:09 +00:00
|
|
|
serialized_args_(NULL),
|
|
|
|
serialized_args_len_(0),
|
|
|
|
serialized_message_(NULL),
|
2014-12-30 23:52:37 +00:00
|
|
|
serialized_message_len_(0),
|
2015-06-07 15:57:34 +00:00
|
|
|
isolate_flags_(),
|
2015-07-20 14:46:54 +00:00
|
|
|
paused_(paused),
|
|
|
|
errors_are_fatal_(errors_are_fatal) {
|
2015-10-12 16:05:37 +00:00
|
|
|
function_name_ = NewConstChar("main");
|
2015-01-12 23:14:30 +00:00
|
|
|
bool can_send_any_object = false;
|
|
|
|
SerializeObject(args,
|
|
|
|
&serialized_args_,
|
|
|
|
&serialized_args_len_,
|
|
|
|
can_send_any_object);
|
|
|
|
SerializeObject(message,
|
|
|
|
&serialized_message_,
|
|
|
|
&serialized_message_len_,
|
|
|
|
can_send_any_object);
|
2015-06-07 15:57:34 +00:00
|
|
|
// By default inherit flags from spawning isolate. These can be overridden
|
|
|
|
// from the calling code.
|
|
|
|
isolate_flags()->CopyFrom(Isolate::Current()->flags());
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IsolateSpawnState::~IsolateSpawnState() {
|
2015-10-12 17:58:11 +00:00
|
|
|
delete[] script_url_;
|
|
|
|
delete[] package_root_;
|
2015-10-12 16:05:37 +00:00
|
|
|
for (int i = 0; package_map_ != NULL; i++) {
|
|
|
|
if (package_map_[i] != NULL) {
|
2015-10-12 17:58:11 +00:00
|
|
|
delete[] package_map_[i];
|
2015-10-12 16:05:37 +00:00
|
|
|
} else {
|
2015-10-12 17:58:11 +00:00
|
|
|
delete[] package_map_;
|
2015-10-12 16:05:37 +00:00
|
|
|
package_map_ = NULL;
|
|
|
|
}
|
|
|
|
}
|
2015-10-12 17:58:11 +00:00
|
|
|
delete[] library_url_;
|
|
|
|
delete[] class_name_;
|
|
|
|
delete[] function_name_;
|
2014-08-20 19:57:09 +00:00
|
|
|
free(serialized_args_);
|
|
|
|
free(serialized_message_);
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RawObject* IsolateSpawnState::ResolveFunction() {
|
2015-01-22 21:28:27 +00:00
|
|
|
const String& func_name = String::Handle(String::New(function_name()));
|
|
|
|
|
|
|
|
if (library_url() == NULL) {
|
|
|
|
// Handle spawnUri lookup rules.
|
|
|
|
// Check whether the root library defines a main function.
|
|
|
|
const Library& lib = Library::Handle(I->object_store()->root_library());
|
|
|
|
Function& func = Function::Handle(lib.LookupLocalFunction(func_name));
|
|
|
|
if (func.IsNull()) {
|
|
|
|
// Check whether main is reexported from the root library.
|
|
|
|
const Object& obj = Object::Handle(lib.LookupReExport(func_name));
|
|
|
|
if (obj.IsFunction()) {
|
|
|
|
func ^= obj.raw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (func.IsNull()) {
|
2013-04-09 17:51:24 +00:00
|
|
|
const String& msg = String::Handle(String::NewFormatted(
|
2015-01-22 21:28:27 +00:00
|
|
|
"Unable to resolve function '%s' in script '%s'.",
|
|
|
|
function_name(), script_url()));
|
2013-04-09 17:51:24 +00:00
|
|
|
return LanguageError::New(msg);
|
|
|
|
}
|
2015-01-22 21:28:27 +00:00
|
|
|
return func.raw();
|
2013-04-09 17:51:24 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 21:28:27 +00:00
|
|
|
ASSERT(script_url() == NULL);
|
|
|
|
// Resolve the library.
|
|
|
|
const String& lib_url = String::Handle(String::New(library_url()));
|
|
|
|
const Library& lib = Library::Handle(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);
|
|
|
|
}
|
2013-11-20 09:14:30 +00:00
|
|
|
|
2015-01-22 21:28:27 +00:00
|
|
|
// Resolve the function.
|
2013-11-20 09:14:30 +00:00
|
|
|
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'.",
|
2015-01-22 21:28:27 +00:00
|
|
|
function_name(), library_url()));
|
2013-11-20 09:14:30 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-02 00:18:55 +00:00
|
|
|
RawInstance* IsolateSpawnState::BuildArgs(Thread* thread) {
|
|
|
|
return DeserializeObject(thread, serialized_args_, serialized_args_len_);
|
2014-08-20 19:57:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-02 00:18:55 +00:00
|
|
|
RawInstance* IsolateSpawnState::BuildMessage(Thread* thread) {
|
|
|
|
return DeserializeObject(thread,
|
2014-08-20 19:57:09 +00:00
|
|
|
serialized_message_, serialized_message_len_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
} // namespace dart
|