Files
sdk/runtime/vm/kernel_isolate.cc
T
Jens Johansen 137b85c114 Hide kernel isolate from isolate list; do not register it either
This is basically a copy of https://codereview.chromium.org/2689563010/
and https://codereview.chromium.org/2695013002/ - just hiding the kernel
isolate too.
That way, we won't see it and be confused when debugging via observatory.
Also, service tests could probably start working with the kernel isolate
too.

Still show isolate if passing "--show_kernel_isolate" though.

R=hausner@google.com

Review-Url: https://codereview.chromium.org/2690323003 .
2017-03-07 08:27:14 +01:00

457 lines
14 KiB
C++

// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/kernel_isolate.h"
#include "vm/compiler.h"
#include "include/dart_native_api.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/isolate.h"
#include "vm/lockers.h"
#include "vm/message.h"
#include "vm/message_handler.h"
#include "vm/native_entry.h"
#include "vm/native_arguments.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/port.h"
#include "vm/service.h"
#include "vm/symbols.h"
#include "vm/thread_pool.h"
#include "vm/timeline.h"
namespace dart {
#if !defined(DART_PRECOMPILED_RUNTIME)
#define Z (T->zone())
DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests.");
DEFINE_FLAG(bool,
use_dart_frontend,
false,
"Parse scripts with Dart-to-Kernel parser");
DEFINE_FLAG(bool,
show_kernel_isolate,
false,
"Show Kernel service isolate as normal isolate.");
const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME;
Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL;
Monitor* KernelIsolate::monitor_ = new Monitor();
Isolate* KernelIsolate::isolate_ = NULL;
bool KernelIsolate::initializing_ = true;
Dart_Port KernelIsolate::kernel_port_ = ILLEGAL_PORT;
class RunKernelTask : public ThreadPool::Task {
public:
virtual void Run() {
ASSERT(Isolate::Current() == NULL);
if (!FLAG_use_dart_frontend) {
ASSERT(FLAG_use_dart_frontend);
// In release builds, make this a no-op. In debug builds, the
// assert shows that this is not supposed to happen.
return;
}
#ifndef PRODUCT
TimelineDurationScope tds(Timeline::GetVMStream(), "KernelIsolateStartup");
#endif // !PRODUCT
char* error = NULL;
Isolate* isolate = NULL;
Dart_IsolateCreateCallback create_callback =
KernelIsolate::create_callback();
if (create_callback == NULL) {
KernelIsolate::FinishedInitializing();
return;
}
// Note: these flags must match those passed to the VM during
// the app-jit training run (see //utils/kernel-service/BUILD.gn).
Dart_IsolateFlags api_flags;
Isolate::FlagsInitialize(&api_flags);
api_flags.enable_type_checks = false;
api_flags.enable_asserts = false;
api_flags.enable_error_on_bad_type = false;
api_flags.enable_error_on_bad_override = false;
#if !defined(DART_PRECOMPILER)
api_flags.use_field_guards = true;
api_flags.use_osr = true;
#endif
isolate = reinterpret_cast<Isolate*>(create_callback(
KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error));
if (isolate == NULL) {
OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n",
error);
KernelIsolate::SetKernelIsolate(NULL);
KernelIsolate::FinishedInitializing();
return;
}
bool init_success = false;
{
ASSERT(Isolate::Current() == NULL);
StartIsolateScope start_scope(isolate);
init_success = RunMain(isolate);
}
KernelIsolate::FinishedInitializing();
if (!init_success) {
ShutdownIsolate(reinterpret_cast<uword>(isolate));
return;
}
// isolate_ was set as side effect of create callback.
ASSERT(KernelIsolate::IsKernelIsolate(isolate));
isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate,
reinterpret_cast<uword>(isolate));
}
protected:
static void ShutdownIsolate(uword parameter) {
if (FLAG_trace_kernel) {
OS::Print(DART_KERNEL_ISOLATE_NAME ": ShutdownIsolate\n");
}
Isolate* I = reinterpret_cast<Isolate*>(parameter);
ASSERT(KernelIsolate::IsKernelIsolate(I));
KernelIsolate::SetKernelIsolate(NULL);
KernelIsolate::SetLoadPort(ILLEGAL_PORT);
I->WaitForOutstandingSpawns();
{
// Print the error if there is one. This may execute dart code to
// print the exception object, so we need to use a StartIsolateScope.
ASSERT(Isolate::Current() == NULL);
StartIsolateScope start_scope(I);
Thread* T = Thread::Current();
ASSERT(I == T->isolate());
StackZone zone(T);
HandleScope handle_scope(T);
Error& error = Error::Handle(Z);
error = T->sticky_error();
if (!error.IsNull() && !error.IsUnwindError()) {
OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
error.ToErrorCString());
}
error = I->sticky_error();
if (!error.IsNull() && !error.IsUnwindError()) {
OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
error.ToErrorCString());
}
Dart::RunShutdownCallback();
}
// Shut the isolate down.
Dart::ShutdownIsolate(I);
if (FLAG_trace_kernel) {
OS::Print(DART_KERNEL_ISOLATE_NAME ": Shutdown.\n");
}
}
bool RunMain(Isolate* I) {
Thread* T = Thread::Current();
ASSERT(I == T->isolate());
StackZone zone(T);
HANDLESCOPE(T);
// Invoke main which will return the port to which load requests are sent.
const Library& root_library =
Library::Handle(Z, I->object_store()->root_library());
if (root_library.IsNull()) {
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not install a script.");
// Kernel isolate is not supported by embedder.
return false;
}
ASSERT(!root_library.IsNull());
const String& entry_name = String::Handle(Z, String::New("main"));
ASSERT(!entry_name.IsNull());
const Function& entry = Function::Handle(
Z, root_library.LookupFunctionAllowPrivate(entry_name));
if (entry.IsNull()) {
// Kernel isolate is not supported by embedder.
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not provide a main function.");
return false;
}
ASSERT(!entry.IsNull());
const Object& result = Object::Handle(
Z, DartEntry::InvokeFunction(entry, Object::empty_array()));
ASSERT(!result.IsNull());
if (result.IsError()) {
// Kernel isolate did not initialize properly.
const Error& error = Error::Cast(result);
OS::Print(DART_KERNEL_ISOLATE_NAME
": Calling main resulted in an error: %s",
error.ToErrorCString());
return false;
}
ASSERT(result.IsReceivePort());
const ReceivePort& rp = ReceivePort::Cast(result);
KernelIsolate::SetLoadPort(rp.Id());
return true;
}
};
void KernelIsolate::Run() {
if (!FLAG_use_dart_frontend) {
return;
}
// Grab the isolate create callback here to avoid race conditions with tests
// that change this after Dart_Initialize returns.
create_callback_ = Isolate::CreateCallback();
Dart::thread_pool()->Run(new RunKernelTask());
}
void KernelIsolate::InitCallback(Isolate* I) {
Thread* T = Thread::Current();
ASSERT(I == T->isolate());
ASSERT(I != NULL);
ASSERT(I->name() != NULL);
if (!FLAG_use_dart_frontend ||
(strstr(I->name(), DART_KERNEL_ISOLATE_NAME) == NULL)) {
// Not kernel isolate.
return;
}
ASSERT(!Exists());
if (FLAG_trace_kernel) {
OS::Print(DART_KERNEL_ISOLATE_NAME ": InitCallback for %s.\n", I->name());
}
SetKernelIsolate(I);
}
bool KernelIsolate::IsKernelIsolate(const Isolate* isolate) {
MonitorLocker ml(monitor_);
return isolate == isolate_;
}
bool KernelIsolate::IsRunning() {
MonitorLocker ml(monitor_);
return (kernel_port_ != ILLEGAL_PORT) && (isolate_ != NULL);
}
bool KernelIsolate::Exists() {
MonitorLocker ml(monitor_);
return isolate_ != NULL;
}
void KernelIsolate::SetKernelIsolate(Isolate* isolate) {
MonitorLocker ml(monitor_);
isolate_ = isolate;
}
void KernelIsolate::SetLoadPort(Dart_Port port) {
MonitorLocker ml(monitor_);
kernel_port_ = port;
}
void KernelIsolate::FinishedInitializing() {
MonitorLocker ml(monitor_);
initializing_ = false;
ml.NotifyAll();
}
Dart_Port KernelIsolate::WaitForKernelPort() {
if (!FLAG_use_dart_frontend) {
return ILLEGAL_PORT;
}
MonitorLocker ml(monitor_);
while (initializing_ && (kernel_port_ == ILLEGAL_PORT)) {
ml.Wait();
}
return kernel_port_;
}
class KernelCompilationRequest : public ValueObject {
public:
KernelCompilationRequest()
: monitor_(new Monitor()),
port_(Dart_NewNativePort("kernel-compilation-port",
&HandleResponse,
false)),
next_(NULL),
prev_(NULL) {
ASSERT(port_ != ILLEGAL_PORT);
RegisterRequest(this);
result_.status = Dart_KernelCompilationStatus_Unknown;
result_.error = NULL;
result_.kernel = NULL;
result_.kernel_size = 0;
}
~KernelCompilationRequest() {
UnregisterRequest(this);
Dart_CloseNativePort(port_);
delete monitor_;
}
Dart_KernelCompilationResult SendAndWaitForResponse(Dart_Port kernel_port,
const char* script_uri) {
// Build the [null, send_port, script_uri] message for the Kernel isolate:
// null tag tells it that request came from this code, instead of Loader
// so that it can given a more informative response.
Dart_CObject tag;
tag.type = Dart_CObject_kNull;
Dart_CObject send_port;
send_port.type = Dart_CObject_kSendPort;
send_port.value.as_send_port.id = port_;
send_port.value.as_send_port.origin_id = ILLEGAL_PORT;
Dart_CObject uri;
uri.type = Dart_CObject_kString;
uri.value.as_string = const_cast<char*>(script_uri);
static const intptr_t kMessageLen = 3;
Dart_CObject* message_arr[kMessageLen] = {&tag, &send_port, &uri};
Dart_CObject message;
message.type = Dart_CObject_kArray;
message.value.as_array.length = kMessageLen;
message.value.as_array.values = message_arr;
// Send the message.
Dart_PostCObject(kernel_port, &message);
// Wait for reply to arrive.
MonitorLocker ml(monitor_);
while (result_.status == Dart_KernelCompilationStatus_Unknown) {
ml.Wait();
}
return result_;
}
private:
// Possible responses from the Kernel isolate:
//
// [Ok, Uint8List KernelBinary]
// [Error, String error]
// [Crash, String error]
//
void HandleResponseImpl(Dart_CObject* message) {
ASSERT(message->type == Dart_CObject_kArray);
ASSERT(message->value.as_array.length >= 1);
Dart_CObject** response = message->value.as_array.values;
MonitorLocker ml(monitor_);
ASSERT(response[0]->type == Dart_CObject_kInt32);
result_.status = static_cast<Dart_KernelCompilationStatus>(
message->value.as_array.values[0]->value.as_int32);
if (result_.status == Dart_KernelCompilationStatus_Ok) {
ASSERT(response[1]->type == Dart_CObject_kTypedData);
ASSERT(response[1]->value.as_typed_data.type == Dart_TypedData_kUint8);
result_.kernel_size = response[1]->value.as_typed_data.length;
result_.kernel = static_cast<uint8_t*>(malloc(result_.kernel_size));
memmove(result_.kernel, response[1]->value.as_typed_data.values,
result_.kernel_size);
} else {
ASSERT(result_.status == Dart_KernelCompilationStatus_Crash ||
result_.status == Dart_KernelCompilationStatus_Error);
// This is an error.
ASSERT(response[1]->type == Dart_CObject_kString);
result_.error = strdup(response[1]->value.as_string);
}
ml.Notify();
}
static void HandleResponse(Dart_Port port, Dart_CObject* message) {
MonitorLocker locker(requests_monitor_);
KernelCompilationRequest* rq = FindRequestLocked(port);
if (rq == NULL) {
return;
}
rq->HandleResponseImpl(message);
}
static void RegisterRequest(KernelCompilationRequest* rq) {
MonitorLocker locker(requests_monitor_);
rq->next_ = requests_;
if (requests_ != NULL) {
requests_->prev_ = rq;
}
requests_ = rq;
}
static void UnregisterRequest(KernelCompilationRequest* rq) {
MonitorLocker locker(requests_monitor_);
if (rq->next_ != NULL) {
rq->next_->prev_ = rq->prev_;
}
if (rq->prev_ != NULL) {
rq->prev_->next_ = rq->next_;
} else {
requests_ = rq->next_;
}
}
// Note: Caller must hold requests_monitor_.
static KernelCompilationRequest* FindRequestLocked(Dart_Port port) {
for (KernelCompilationRequest* rq = requests_; rq != NULL; rq = rq->next_) {
if (rq->port_ == port) {
return rq;
}
}
return NULL;
}
// This monitor must be held whenever linked list of requests is accessed.
static Monitor* requests_monitor_;
// Linked list of all active requests. Used to find a request by port number.
// Guarded by requests_monitor_ lock.
static KernelCompilationRequest* requests_;
Monitor* monitor_;
Dart_Port port_;
// Linked list of active requests. Guarded by requests_monitor_ lock.
KernelCompilationRequest* next_;
KernelCompilationRequest* prev_;
Dart_KernelCompilationResult result_;
};
Monitor* KernelCompilationRequest::requests_monitor_ = new Monitor();
KernelCompilationRequest* KernelCompilationRequest::requests_ = NULL;
Dart_KernelCompilationResult KernelIsolate::CompileToKernel(
const char* script_uri) {
// This must be the main script to be loaded. Wait for Kernel isolate
// to finish initialization.
Dart_Port kernel_port = WaitForKernelPort();
if (kernel_port == ILLEGAL_PORT) {
Dart_KernelCompilationResult result;
result.status = Dart_KernelCompilationStatus_Unknown;
result.error = strdup("Error while initializing Kernel isolate");
return result;
}
KernelCompilationRequest request;
return request.SendAndWaitForResponse(kernel_port, script_uri);
}
#endif // DART_PRECOMPILED_RUNTIME
} // namespace dart