Add Observatory to sky dart_controller
- Bump Dart and Observatory DEPS to 45576 and 45565 respectively.
- Include 'dart:io' in snapshot
- Add 'dart:io' native bindings to sky bindings.
- Initialize 'dart:io' in sky dart_controller.
- Include Observatory and service isolate resources in build.
- Bring up service isolate.
- Start handle watcher isolate from service isolate (hides handle watcher isolate from debugger and Observatory).
- Hook up debugger.
R=eseidel@chromium.org
Review URL: https://codereview.chromium.org/1107803002
diff --git a/DEPS b/DEPS
index b16c545..a11b056 100644
--- a/DEPS
+++ b/DEPS
@@ -25,8 +25,8 @@
'v8_revision': '230d131d173ab2d60291d303177bc04ec3f6e519',
'angle_revision': 'bdd419f9f5b006e913606e7363125942c8ae06bc',
'buildtools_revision': '15308f469a704c45d15567fa69cd94ce07ad0e1b',
- 'dart_revision': '45304',
- 'dart_observatory_packages_revision': '43830',
+ 'dart_revision': '45576',
+ 'dart_observatory_packages_revision': '45565',
'pdfium_revision': 'b0115665b0f33971f1b7077740d51e155583cec0',
'boringssl_revision': '642f1498d056dbba3e50ed5a232ab2f482626dec',
'lss_revision': 'e079768b7e3a94dcbe7d338496c0c3bde7151b6e',
diff --git a/mojo/dart/embedder/BUILD.gn b/mojo/dart/embedder/BUILD.gn
index 95fcc46..26a8bdd 100644
--- a/mojo/dart/embedder/BUILD.gn
+++ b/mojo/dart/embedder/BUILD.gn
@@ -69,6 +69,7 @@
"//mojo/dart/embedder/io/socket_patch.dart",
"//mojo/dart/embedder/io/server_socket_patch.dart",
]
+ root_prefix = "//mojo/dart/embedder/"
output = "$target_gen_dir/dart_embedder_patch_resources.cc"
table_name = "dart_embedder_patch"
}
@@ -143,6 +144,7 @@
"//mojo/dart/embedder/vmservice/resources.dart",
"//mojo/dart/embedder/vmservice/server.dart",
]
+ root_prefix = "//mojo/dart/embedder/"
input_directory = "$root_out_dir/observatory/deployed/web/"
output = "$target_gen_dir/dart_embedder_service_isolate_resources.cc"
table_name = "dart_embedder_service_isolate"
@@ -252,7 +254,7 @@
outputs = [
"$root_out_dir/observatory/build/web/index.html",
- "$root_out_dir/observatory/build/web/index.html_bootstrap.dart.js",
+ "$root_out_dir/observatory/build/web/index.html.polymer.bootstrap.dart.js",
]
}
@@ -266,7 +268,7 @@
inputs = [
script,
"$root_out_dir/observatory/build/web/index.html",
- "$root_out_dir/observatory/build/web/index.html_bootstrap.dart.js",
+ "$root_out_dir/observatory/build/web/index.html.polymer.bootstrap.dart.js",
]
args = [
@@ -281,7 +283,7 @@
outputs = [
"$root_out_dir/observatory/deployed/web/index.html",
- "$root_out_dir/observatory/deployed/web/index.html_bootstrap.dart.js",
+ "$root_out_dir/observatory/deployed/web/index.html.polymer.bootstrap.dart.js",
]
}
diff --git a/mojo/dart/embedder/dart_debugger.cc b/mojo/dart/embedder/dart_debugger.cc
index 31e9ee4..684acc5 100644
--- a/mojo/dart/embedder/dart_debugger.cc
+++ b/mojo/dart/embedder/dart_debugger.cc
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <vector>
-
+#include "mojo/dart/embedder/dart_debugger.h"
#include "dart/runtime/include/dart_api.h"
#include "dart/runtime/include/dart_debugger_api.h"
#include "dart/runtime/include/dart_native_api.h"
-#include "mojo/dart/embedder/dart_debugger.h"
+
namespace mojo {
namespace dart {
@@ -45,10 +44,9 @@
intptr_t bp_id,
const Dart_CodeLocation& loc) {
Dart_EnterScope();
- DartDebuggerIsolate* debugger_isolate =
- FindIsolateById(isolate_id);
- CHECK(debugger_isolate != nullptr);
- debugger_isolate->MessageLoop();
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
+ (*isolates_)[isolate_index]->MessageLoop();
Dart_ExitScope();
}
@@ -56,10 +54,9 @@
Dart_Handle exception,
Dart_StackTrace stack_trace) {
Dart_EnterScope();
- DartDebuggerIsolate* debugger_isolate =
- FindIsolateById(isolate_id);
- CHECK(debugger_isolate != nullptr);
- debugger_isolate->MessageLoop();
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
+ (*isolates_)[isolate_index]->MessageLoop();
Dart_ExitScope();
}
@@ -69,11 +66,10 @@
if (kind == Dart_IsolateEvent::kCreated) {
AddIsolate(isolate_id);
} else {
- DartDebuggerIsolate* debugger_isolate =
- FindIsolateById(isolate_id);
- CHECK(debugger_isolate != nullptr);
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
if (kind == Dart_IsolateEvent::kInterrupted) {
- debugger_isolate->MessageLoop();
+ (*isolates_)[isolate_index]->MessageLoop();
} else {
CHECK(kind == Dart_IsolateEvent::kShutdown);
RemoveIsolate(isolate_id);
@@ -85,10 +81,9 @@
void DartDebugger::NotifyIsolate(Dart_Isolate isolate) {
base::AutoLock al(*lock_);
Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
- DartDebuggerIsolate* debugger_isolate =
- FindIsolateByIdLocked(isolate_id);
- if (debugger_isolate != nullptr) {
- debugger_isolate->Notify();
+ intptr_t isolate_index = FindIsolateIndexByIdLocked(isolate_id);
+ if (isolate_index >= 0) {
+ (*isolates_)[isolate_index]->Notify();
}
}
@@ -98,40 +93,38 @@
Dart_SetBreakpointResolvedHandler(BptResolvedHandler);
Dart_SetExceptionThrownHandler(ExceptionThrownHandler);
lock_ = new base::Lock();
+ isolates_ = new std::vector<std::unique_ptr<DartDebuggerIsolate>>();
}
-DartDebuggerIsolate* DartDebugger::FindIsolateById(Dart_IsolateId id) {
+intptr_t DartDebugger::FindIsolateIndexById(Dart_IsolateId id) {
base::AutoLock al(*lock_);
- return FindIsolateByIdLocked(id);
+ return FindIsolateIndexByIdLocked(id);
}
-DartDebuggerIsolate* DartDebugger::FindIsolateByIdLocked(
+intptr_t DartDebugger::FindIsolateIndexByIdLocked(
Dart_IsolateId id) {
lock_->AssertAcquired();
- for (size_t i = 0; i < isolates_.size(); i++) {
- DartDebuggerIsolate* isolate = isolates_[i];
- if (id == isolate->id()) {
- return isolate;
+ for (size_t i = 0; i < isolates_->size(); i++) {
+ if ((*isolates_)[i]->id() == id) {
+ return i;
}
}
- return nullptr;
+ return -1;
}
-DartDebuggerIsolate* DartDebugger::AddIsolate(Dart_IsolateId id) {
+void DartDebugger::AddIsolate(Dart_IsolateId id) {
base::AutoLock al(*lock_);
- CHECK(FindIsolateByIdLocked(id) == nullptr);
- DartDebuggerIsolate* debugger_isolate =
- new DartDebuggerIsolate(id);
- isolates_.push_back(debugger_isolate);
- return debugger_isolate;
+ CHECK(FindIsolateIndexByIdLocked(id) == -1);
+ std::unique_ptr<DartDebuggerIsolate> debugger_isolate =
+ std::unique_ptr<DartDebuggerIsolate>(new DartDebuggerIsolate(id));
+ isolates_->push_back(std::move(debugger_isolate));
}
void DartDebugger::RemoveIsolate(Dart_IsolateId id) {
base::AutoLock al(*lock_);
- for (size_t i = 0; i < isolates_.size(); i++) {
- DartDebuggerIsolate* isolate = isolates_[i];
- if (id == isolate->id()) {
- isolates_.erase(isolates_.begin() + i);
+ for (size_t i = 0; i < isolates_->size(); i++) {
+ if (id == (*isolates_)[i]->id()) {
+ isolates_->erase(isolates_->begin() + i);
return;
}
}
@@ -139,7 +132,8 @@
}
base::Lock* DartDebugger::lock_ = nullptr;
-std::vector<DartDebuggerIsolate*> DartDebugger::isolates_;
+std::vector<std::unique_ptr<DartDebuggerIsolate>>* DartDebugger::isolates_ =
+ nullptr;
-} // namespace apps
+} // namespace dart
} // namespace mojo
diff --git a/mojo/dart/embedder/dart_debugger.h b/mojo/dart/embedder/dart_debugger.h
index fe7ef2d..7db7986 100644
--- a/mojo/dart/embedder/dart_debugger.h
+++ b/mojo/dart/embedder/dart_debugger.h
@@ -5,6 +5,9 @@
#ifndef MOJO_DART_EMBEDDER_DART_DEBUGGER_H_
#define MOJO_DART_EMBEDDER_DART_DEBUGGER_H_
+#include <memory>
+#include <vector>
+
#include "dart/runtime/include/dart_api.h"
#include "dart/runtime/include/dart_debugger_api.h"
#include "dart/runtime/include/dart_native_api.h"
@@ -60,16 +63,16 @@
static void NotifyIsolate(Dart_Isolate isolate);
- static DartDebuggerIsolate* FindIsolateById(Dart_IsolateId id);
+ static intptr_t FindIsolateIndexById(Dart_IsolateId id);
- static DartDebuggerIsolate* FindIsolateByIdLocked(Dart_IsolateId id);
+ static intptr_t FindIsolateIndexByIdLocked(Dart_IsolateId id);
- static DartDebuggerIsolate* AddIsolate(Dart_IsolateId id);
+ static void AddIsolate(Dart_IsolateId id);
static void RemoveIsolate(Dart_IsolateId id);
static base::Lock* lock_;
- static std::vector<DartDebuggerIsolate*> isolates_;
+ static std::vector<std::unique_ptr<DartDebuggerIsolate>>* isolates_;
friend class DartDebuggerIsolate;
};
diff --git a/mojo/dart/embedder/embedder.gni b/mojo/dart/embedder/embedder.gni
index b5d3de3..dd9dcdf 100644
--- a/mojo/dart/embedder/embedder.gni
+++ b/mojo/dart/embedder/embedder.gni
@@ -48,6 +48,7 @@
# String output (name of output file)
# List inputs (list of input files to be included)
# String table_name (name of symbol for resource table)
+# String root_prefix (base directory of resources)
# Optional invoker inputs:
# String input_directory (directory of resources that are recursively added)
# List deps
@@ -71,6 +72,8 @@
inputs = [ script ] + invoker.inputs
+ root_prefix = rebase_path(invoker.root_prefix)
+
args = [
"--output",
rebase_path(output),
@@ -81,7 +84,7 @@
"--table_name",
invoker.table_name,
"--root_prefix",
- rebase_path("//mojo/dart/embedder/"),
+ root_prefix,
]
if (defined(invoker.input_directory)) {
args += [
diff --git a/mojo/dart/embedder/vmservice/server.dart b/mojo/dart/embedder/vmservice/server.dart
index 188b532..4e069f9 100644
--- a/mojo/dart/embedder/vmservice/server.dart
+++ b/mojo/dart/embedder/vmservice/server.dart
@@ -35,17 +35,9 @@
}
}
- post(var serial, dynamic result) {
+ post(dynamic result) {
try {
- if (serial == null && result is! String) {
- socket.add(result);
- } else {
- Map map = {
- 'id': serial,
- 'result': result
- };
- socket.add(JSON.encode(map));
- }
+ socket.add(result);
} catch (_) {
print("Ignoring error posting over WebSocket.");
}
@@ -67,7 +59,7 @@
HttpRequestClient(this.request, VMService service) : super(service);
- post(var serial, String result) {
+ post(String result) {
request.response..headers.contentType = jsonContentType
..write(result)
..close();
diff --git a/sky/engine/bindings/BUILD.gn b/sky/engine/bindings/BUILD.gn
index b7dbafe..fd6a30c 100644
--- a/sky/engine/bindings/BUILD.gn
+++ b/sky/engine/bindings/BUILD.gn
@@ -30,6 +30,9 @@
"scheduled_action.cc",
"scheduled_action.h",
]
+
+ defines = [ "DART_IO_SECURE_SOCKET_DISABLED" ]
+
deps = [
"//base",
"//dart/runtime/bin:libdart_withcore",
@@ -38,12 +41,14 @@
"//sky/engine/platform:platform",
"//sky/engine/tonic",
"//sky/engine/wtf",
+ "//dart/runtime/bin:embedded_dart_io",
":generated_bindings",
":snapshot_cc",
]
include_dirs = [
"..",
"$root_build_dir",
+ rebase_path("//dart/runtime"),
]
}
diff --git a/sky/engine/bindings/builtin.cc b/sky/engine/bindings/builtin.cc
index 81fd9d3..3fa5c39 100644
--- a/sky/engine/bindings/builtin.cc
+++ b/sky/engine/bindings/builtin.cc
@@ -6,6 +6,7 @@
#include "sky/engine/bindings/builtin.h"
#include "base/logging.h"
+#include "bin/io_natives.h"
#include "dart/runtime/include/dart_api.h"
#include "gen/sky/bindings/DartGlobal.h"
#include "sky/engine/bindings/builtin_natives.h"
@@ -31,6 +32,7 @@
BuiltinNatives::NativeLookup},
{"dart:sky", true, skySnapshotSymbolizer, skySnapshotResolver},
{"dart:mojo.internal", true, MojoNativeSymbol, MojoNativeLookup},
+ {"dart:io", true, dart::bin::IONativeSymbol, dart::bin::IONativeLookup },
};
} // namespace
diff --git a/sky/engine/bindings/builtin.h b/sky/engine/bindings/builtin.h
index 8c3bb05..93f67a2 100644
--- a/sky/engine/bindings/builtin.h
+++ b/sky/engine/bindings/builtin.h
@@ -18,6 +18,7 @@
kBuiltinLibrary,
kSkyLibrary,
kMojoInternalLibrary,
+ kIOLibrary,
kInvalidLibrary,
};
diff --git a/sky/engine/bindings/builtin_natives.cc b/sky/engine/bindings/builtin_natives.cc
index 55584a3..90bec2e 100644
--- a/sky/engine/bindings/builtin_natives.cc
+++ b/sky/engine/bindings/builtin_natives.cc
@@ -87,7 +87,8 @@
return closure;
}
-static void InitDartInternal(Dart_Handle builtin_library) {
+static void InitDartInternal(Dart_Handle builtin_library,
+ BuiltinNatives::IsolateType isolate_type) {
Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure");
Dart_Handle timer = GetClosure(builtin_library, "_getCreateTimerClosure");
@@ -96,35 +97,55 @@
DART_CHECK_VALID(Dart_SetField(
internal_library, ToDart("_printClosure"), print));
- Dart_Handle vm_hooks_name = ToDart("VMLibraryHooks");
- Dart_Handle vm_hooks = Dart_GetClass(internal_library, vm_hooks_name);
- DART_CHECK_VALID(vm_hooks);
- Dart_Handle timer_name = ToDart("timerFactory");
- DART_CHECK_VALID(Dart_SetField(vm_hooks, timer_name, timer));
+ if (isolate_type == BuiltinNatives::MainIsolate) {
+ Dart_Handle vm_hooks_name = ToDart("VMLibraryHooks");
+ Dart_Handle vm_hooks = Dart_GetClass(internal_library, vm_hooks_name);
+ DART_CHECK_VALID(vm_hooks);
+ Dart_Handle timer_name = ToDart("timerFactory");
+ DART_CHECK_VALID(Dart_SetField(vm_hooks, timer_name, timer));
+ } else {
+ CHECK(isolate_type == BuiltinNatives::DartIOIsolate);
+ Dart_Handle io_lib = DartBuiltin::LookupLibrary("dart:io");
+ Dart_Handle setup_hooks = Dart_NewStringFromCString("_setupHooks");
+ DART_CHECK_VALID(Dart_Invoke(io_lib, setup_hooks, 0, NULL));
+ Dart_Handle isolate_lib = DartBuiltin::LookupLibrary("dart:isolate");
+ DART_CHECK_VALID(Dart_Invoke(isolate_lib, setup_hooks, 0, NULL));
+ }
}
-static void InitDartCore(Dart_Handle builtin) {
+static void InitDartCore(Dart_Handle builtin,
+ BuiltinNatives::IsolateType isolate_type) {
Dart_Handle get_base_url = GetClosure(builtin, "_getGetBaseURLClosure");
Dart_Handle core_library = DartBuiltin::LookupLibrary("dart:core");
DART_CHECK_VALID(Dart_SetField(core_library,
ToDart("_uriBaseClosure"), get_base_url));
}
-static void InitDartAsync(Dart_Handle builtin_library) {
- Dart_Handle schedule_microtask =
- GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
+static void InitDartAsync(Dart_Handle builtin_library,
+ BuiltinNatives::IsolateType isolate_type) {
+ Dart_Handle schedule_microtask;
+ if (isolate_type == BuiltinNatives::MainIsolate) {
+ schedule_microtask =
+ GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
+ } else {
+ CHECK(isolate_type == BuiltinNatives::DartIOIsolate);
+ Dart_Handle isolate_lib = DartBuiltin::LookupLibrary("dart:isolate");
+ Dart_Handle method_name =
+ Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure");
+ schedule_microtask = Dart_Invoke(isolate_lib, method_name, 0, NULL);
+ }
Dart_Handle async_library = DartBuiltin::LookupLibrary("dart:async");
Dart_Handle set_schedule_microtask = ToDart("_setScheduleImmediateClosure");
DART_CHECK_VALID(Dart_Invoke(async_library, set_schedule_microtask, 1,
&schedule_microtask));
}
-void BuiltinNatives::Init() {
+void BuiltinNatives::Init(IsolateType isolate_type) {
Dart_Handle builtin = Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
DART_CHECK_VALID(builtin);
- InitDartInternal(builtin);
- InitDartCore(builtin);
- InitDartAsync(builtin);
+ InitDartInternal(builtin, isolate_type);
+ InitDartCore(builtin, isolate_type);
+ InitDartAsync(builtin, isolate_type);
}
// Implementation of native functions which are used for some
@@ -163,6 +184,7 @@
if (LogIfError(closure) || !Dart_IsClosure(closure))
return;
DartState* dart_state = DartState::Current();
+ CHECK(dart_state);
Microtask::enqueueMicrotask(base::Bind(&ExecuteMicrotask,
dart_state->GetWeakPtr(), DartValue::Create(dart_state, closure)));
}
@@ -182,6 +204,7 @@
DART_CHECK_VALID(Dart_GetNativeBooleanArgument(args, 2, &repeating));
DOMDartState* state = DOMDartState::Current();
+ CHECK(state);
int timer_id = DOMTimer::install(state->document(),
ScheduledAction::Create(state, closure),
milliseconds,
@@ -194,6 +217,7 @@
DART_CHECK_VALID(Dart_GetNativeIntegerArgument(args, 0, &timer_id));
DOMDartState* state = DOMDartState::Current();
+ CHECK(state);
DOMTimer::removeByID(state->document(), timer_id);
}
diff --git a/sky/engine/bindings/builtin_natives.h b/sky/engine/bindings/builtin_natives.h
index a08fc19..3f525bc 100644
--- a/sky/engine/bindings/builtin_natives.h
+++ b/sky/engine/bindings/builtin_natives.h
@@ -12,12 +12,17 @@
class BuiltinNatives {
public:
+ enum IsolateType {
+ MainIsolate,
+ DartIOIsolate,
+ };
+
static Dart_NativeFunction NativeLookup(Dart_Handle name,
int argument_count,
bool* auto_setup_scope);
static const uint8_t* NativeSymbol(Dart_NativeFunction native_function);
- static void Init();
+ static void Init(IsolateType isolate_type);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BuiltinNatives);
diff --git a/sky/engine/bindings/snapshot.dart b/sky/engine/bindings/snapshot.dart
index 51fd6f4..d620521 100644
--- a/sky/engine/bindings/snapshot.dart
+++ b/sky/engine/bindings/snapshot.dart
@@ -6,6 +6,7 @@
import 'dart:collection';
import 'dart:convert';
import 'dart:core';
+import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'dart:mojo.internal';
diff --git a/sky/engine/core/BUILD.gn b/sky/engine/core/BUILD.gn
index d01e064..661835c 100644
--- a/sky/engine/core/BUILD.gn
+++ b/sky/engine/core/BUILD.gn
@@ -4,6 +4,7 @@
import("//sky/engine/build/scripts/scripts.gni")
import("//sky/engine/core/core.gni")
+import("//mojo/dart/embedder/embedder.gni")
visibility = [ "//sky/engine/*" ]
@@ -52,20 +53,40 @@
]
}
+dart_embedder_resources("generate_sky_embedder_service_isolate_resources_cc") {
+ deps = [
+ "//mojo/dart/embedder:deploy_observatory",
+ ]
+ inputs = [
+ "//sky/engine/core/script/dart_service_isolate/loader.dart",
+ "//sky/engine/core/script/dart_service_isolate/main.dart",
+ "//sky/engine/core/script/dart_service_isolate/resources.dart",
+ "//sky/engine/core/script/dart_service_isolate/server.dart",
+ ]
+ root_prefix = "//sky/engine/core/script/"
+ input_directory = "$root_out_dir/observatory/deployed/web/"
+ output = "$target_gen_dir/sky_embedder_service_isolate_resources.cc"
+ table_name = "sky_embedder_service_isolate"
+}
+
static_library("core") {
output_name = "sky_core"
deps = [
":core_generated",
+ ":generate_sky_embedder_service_isolate_resources_cc",
":libraries",
":prerequisites",
"//sky/engine/platform",
"//sky/engine/bindings",
+ "//dart/runtime/bin:embedded_dart_io",
"//dart/runtime/bin:libdart_withcore",
]
sources = sky_core_files
+ sources += [ "$target_gen_dir/sky_embedder_service_isolate_resources.cc" ]
+
include_dirs = [
# Needed for dart_mirrors_api.h in dart_controller.cc
rebase_path("//dart/runtime"),
diff --git a/sky/engine/core/core.gni b/sky/engine/core/core.gni
index 5ecbe0a..2a78c74 100644
--- a/sky/engine/core/core.gni
+++ b/sky/engine/core/core.gni
@@ -1009,12 +1009,17 @@
"rendering/VerticalPositionCache.h",
"script/dart_controller.cc",
"script/dart_controller.h",
+ "script/dart_debugger.cc",
+ "script/dart_debugger.h",
"script/dart_dependency_catcher.cc",
"script/dart_dependency_catcher.h",
"script/dart_loader.cc",
"script/dart_loader.h",
+ "script/dart_service_isolate.cc",
+ "script/dart_service_isolate.h",
"script/dom_dart_state.cc",
"script/dom_dart_state.h",
+ "script/monitor.h",
]
core_idl_files = get_path_info([
diff --git a/sky/engine/core/script/dart_controller.cc b/sky/engine/core/script/dart_controller.cc
index dc7ce4c..e03cb34 100644
--- a/sky/engine/core/script/dart_controller.cc
+++ b/sky/engine/core/script/dart_controller.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
+#include "dart/runtime/bin/embedded_dart_io.h"
#include "dart/runtime/include/dart_mirrors_api.h"
#include "sky/engine/bindings/builtin.h"
#include "sky/engine/bindings/builtin_natives.h"
@@ -21,8 +22,10 @@
#include "sky/engine/core/html/imports/HTMLImport.h"
#include "sky/engine/core/html/imports/HTMLImportChild.h"
#include "sky/engine/core/loader/FrameLoaderClient.h"
+#include "sky/engine/core/script/dart_debugger.h"
#include "sky/engine/core/script/dart_dependency_catcher.h"
#include "sky/engine/core/script/dart_loader.h"
+#include "sky/engine/core/script/dart_service_isolate.h"
#include "sky/engine/core/script/dom_dart_state.h"
#include "sky/engine/public/platform/Platform.h"
#include "sky/engine/tonic/dart_api_scope.h"
@@ -176,9 +179,36 @@
String(url_name) == DART_VM_SERVICE_ISOLATE_NAME;
}
+static void EnsureHandleWatcherStarted() {
+ static bool handle_watcher_started = false;
+ if (handle_watcher_started)
+ return;
+
+ // TODO(dart): Call Dart_Cleanup (ensure the handle watcher isolate is closed)
+ // during shutdown.
+ Dart_Handle mojo_core_lib =
+ Builtin::LoadAndCheckLibrary(Builtin::kMojoInternalLibrary);
+ CHECK(!LogIfError((mojo_core_lib)));
+ Dart_Handle handle_watcher_type = Dart_GetType(
+ mojo_core_lib,
+ Dart_NewStringFromCString("MojoHandleWatcher"),
+ 0,
+ nullptr);
+ CHECK(!LogIfError(handle_watcher_type));
+ CHECK(!LogIfError(Dart_Invoke(
+ handle_watcher_type,
+ Dart_NewStringFromCString("_start"),
+ 0,
+ nullptr)));
+
+ // RunLoop until the handle watcher isolate is spun-up.
+ CHECK(!LogIfError(Dart_RunLoop()));
+ handle_watcher_started = true;
+}
+
// TODO(rafaelw): Right now this only supports the creation of the handle
-// watcher isolate. Presumably, we'll want application isolates to spawn their
-// own isolates.
+// watcher isolate and the service isolate. Presumably, we'll want application
+// isolates to spawn their own isolates.
static Dart_Isolate IsolateCreateCallback(const char* script_uri,
const char* main,
const char* package_root,
@@ -186,8 +216,34 @@
char** error) {
if (IsServiceIsolateURL(script_uri)) {
- return Dart_CreateIsolate(script_uri, "main", kDartIsolateSnapshotBuffer,
- nullptr, error);
+ CHECK(kDartIsolateSnapshotBuffer);
+ DartState* dart_state = new DartState();
+ Dart_Isolate isolate = Dart_CreateIsolate(script_uri,
+ "main",
+ kDartIsolateSnapshotBuffer,
+ nullptr,
+ error);
+ CHECK(isolate) << error;
+ dart_state->set_isolate(isolate);
+ CHECK(Dart_IsServiceIsolate(isolate));
+ CHECK(!LogIfError(Dart_SetLibraryTagHandler(LibraryTagHandler)));
+ {
+ DartApiScope apiScope;
+ Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
+ Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
+ Builtin::SetNativeResolver(Builtin::kIOLibrary);
+ BuiltinNatives::Init(BuiltinNatives::DartIOIsolate);
+ // Start the handle watcher from the service isolate so it isn't available
+ // for debugging or general Observatory interaction.
+ EnsureHandleWatcherStarted();
+ std::string ip = "127.0.0.1";
+ const intptr_t port = 0; // Automatic port assignment.
+ const bool service_isolate_booted =
+ DartServiceIsolate::Startup(ip, port, LibraryTagHandler, error);
+ CHECK(service_isolate_booted) << error;
+ }
+ Dart_ExitIsolate();
+ return isolate;
}
// Create & start the handle watcher isolate
@@ -204,6 +260,7 @@
DartApiScope apiScope;
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
+ Builtin::SetNativeResolver(Builtin::kIOLibrary);
// Ensure the isolate has a root library.
Dart_LoadScript(Dart_NewStringFromCString("dart:empty"),
@@ -233,33 +290,6 @@
base::Bind(&CallHandleMessage, DartState::From(dest_isolate)->GetWeakPtr()));
}
-static void EnsureHandleWatcherStarted() {
- static bool handle_watcher_started = false;
- if (handle_watcher_started)
- return;
-
- // TODO(dart): Call Dart_Cleanup (ensure the handle watcher isolate is closed)
- // during shutdown.
- Dart_Handle mojo_core_lib =
- Builtin::LoadAndCheckLibrary(Builtin::kMojoInternalLibrary);
- CHECK(!LogIfError((mojo_core_lib)));
- Dart_Handle handle_watcher_type = Dart_GetType(
- mojo_core_lib,
- Dart_NewStringFromCString("MojoHandleWatcher"),
- 0,
- nullptr);
- CHECK(!LogIfError(handle_watcher_type));
- CHECK(!LogIfError(Dart_Invoke(
- handle_watcher_type,
- Dart_NewStringFromCString("_start"),
- 0,
- nullptr)));
-
- // RunLoop until the handle watcher isolate is spun-up.
- CHECK(!LogIfError(Dart_RunLoop()));
- handle_watcher_started = true;
-}
-
void DartController::CreateIsolateFor(Document* document) {
DCHECK(document);
CHECK(kDartIsolateSnapshotBuffer);
@@ -283,7 +313,8 @@
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
- BuiltinNatives::Init();
+ Builtin::SetNativeResolver(Builtin::kIOLibrary);
+ BuiltinNatives::Init(BuiltinNatives::MainIsolate);
builtin_sky_ = adoptPtr(new BuiltinSky(dart_state()));
dart_state()->class_library().set_provider(builtin_sky_.get());
@@ -312,13 +343,20 @@
argv = kCheckedModeArgs;
#endif
+ dart::bin::BootstrapDartIo();
+
CHECK(Dart_SetVMFlags(argc, argv));
+ // This should be called before calling Dart_Initialize.
+ DartDebugger::InitDebugger();
CHECK(Dart_Initialize(kDartVmIsolateSnapshotBuffer,
IsolateCreateCallback,
nullptr, // Isolate interrupt callback.
UnhandledExceptionCallback, IsolateShutdownCallback,
// File IO callbacks.
nullptr, nullptr, nullptr, nullptr, nullptr));
+ // Wait for load port- ensures handle watcher and service isolates are
+ // running.
+ Dart_ServiceWaitForLoadPort();
}
} // namespace blink
diff --git a/sky/engine/core/script/dart_debugger.cc b/sky/engine/core/script/dart_debugger.cc
new file mode 100644
index 0000000..f7c1c49
--- /dev/null
+++ b/sky/engine/core/script/dart_debugger.cc
@@ -0,0 +1,138 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sky/engine/core/script/dart_debugger.h"
+
+#include "dart/runtime/include/dart_api.h"
+#include "dart/runtime/include/dart_debugger_api.h"
+#include "dart/runtime/include/dart_native_api.h"
+
+
+namespace blink {
+
+void DartDebuggerIsolate::MessageLoop() {
+ MonitorLocker ml(&monitor_);
+ // Request notification on isolate messages. This allows us to
+ // respond to vm service messages while at breakpoint.
+ Dart_SetMessageNotifyCallback(DartDebugger::NotifyIsolate);
+ while (true) {
+ // Handle all available vm service messages, up to a resume
+ // request.
+ bool resume = false;
+ while (!resume && Dart_HasServiceMessages()) {
+ monitor_.Exit();
+ resume = Dart_HandleServiceMessages();
+ monitor_.Enter();
+ }
+ if (resume) {
+ break;
+ }
+ ml.Wait();
+ }
+ Dart_SetMessageNotifyCallback(nullptr);
+}
+
+void DartDebugger::BptResolvedHandler(Dart_IsolateId isolate_id,
+ intptr_t bp_id,
+ const Dart_CodeLocation& location) {
+ // Nothing to do here. Service event is dispatched to let Observatory know
+ // that a breakpoint was resolved.
+}
+
+void DartDebugger::PausedEventHandler(Dart_IsolateId isolate_id,
+ intptr_t bp_id,
+ const Dart_CodeLocation& loc) {
+ Dart_EnterScope();
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
+ (*isolates_)[isolate_index]->MessageLoop();
+ Dart_ExitScope();
+}
+
+void DartDebugger::ExceptionThrownHandler(Dart_IsolateId isolate_id,
+ Dart_Handle exception,
+ Dart_StackTrace stack_trace) {
+ Dart_EnterScope();
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
+ (*isolates_)[isolate_index]->MessageLoop();
+ Dart_ExitScope();
+}
+
+void DartDebugger::IsolateEventHandler(Dart_IsolateId isolate_id,
+ Dart_IsolateEvent kind) {
+ Dart_EnterScope();
+ if (kind == Dart_IsolateEvent::kCreated) {
+ AddIsolate(isolate_id);
+ } else {
+ intptr_t isolate_index = FindIsolateIndexById(isolate_id);
+ CHECK(isolate_index != -1);
+ if (kind == Dart_IsolateEvent::kInterrupted) {
+ (*isolates_)[isolate_index]->MessageLoop();
+ } else {
+ CHECK(kind == Dart_IsolateEvent::kShutdown);
+ RemoveIsolate(isolate_id);
+ }
+ }
+ Dart_ExitScope();
+}
+
+void DartDebugger::NotifyIsolate(Dart_Isolate isolate) {
+ base::AutoLock al(*lock_);
+ Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
+ intptr_t isolate_index = FindIsolateIndexByIdLocked(isolate_id);
+ if (isolate_index >= 0) {
+ (*isolates_)[isolate_index]->Notify();
+ }
+}
+
+void DartDebugger::InitDebugger() {
+ Dart_SetIsolateEventHandler(IsolateEventHandler);
+ Dart_SetPausedEventHandler(PausedEventHandler);
+ Dart_SetBreakpointResolvedHandler(BptResolvedHandler);
+ Dart_SetExceptionThrownHandler(ExceptionThrownHandler);
+ lock_ = new base::Lock();
+ isolates_ = new std::vector<std::unique_ptr<DartDebuggerIsolate>>();
+}
+
+intptr_t DartDebugger::FindIsolateIndexById(Dart_IsolateId id) {
+ base::AutoLock al(*lock_);
+ return FindIsolateIndexByIdLocked(id);
+}
+
+intptr_t DartDebugger::FindIsolateIndexByIdLocked(
+ Dart_IsolateId id) {
+ lock_->AssertAcquired();
+ for (size_t i = 0; i < isolates_->size(); i++) {
+ if ((*isolates_)[i]->id() == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void DartDebugger::AddIsolate(Dart_IsolateId id) {
+ base::AutoLock al(*lock_);
+ CHECK(FindIsolateIndexByIdLocked(id) == -1);
+ std::unique_ptr<DartDebuggerIsolate> debugger_isolate =
+ std::unique_ptr<DartDebuggerIsolate>(new DartDebuggerIsolate(id));
+ isolates_->push_back(std::move(debugger_isolate));
+}
+
+void DartDebugger::RemoveIsolate(Dart_IsolateId id) {
+ base::AutoLock al(*lock_);
+ for (size_t i = 0; i < isolates_->size(); i++) {
+ if (id == (*isolates_)[i]->id()) {
+ isolates_->erase(isolates_->begin() + i);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+base::Lock* DartDebugger::lock_ = nullptr;
+std::vector<std::unique_ptr<DartDebuggerIsolate>>* DartDebugger::isolates_ =
+ nullptr;
+
+} // namespace blink
diff --git a/sky/engine/core/script/dart_debugger.h b/sky/engine/core/script/dart_debugger.h
new file mode 100644
index 0000000..8c93b6c
--- /dev/null
+++ b/sky/engine/core/script/dart_debugger.h
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
+#define SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "dart/runtime/include/dart_api.h"
+#include "dart/runtime/include/dart_debugger_api.h"
+#include "dart/runtime/include/dart_native_api.h"
+#include "sky/engine/core/script/monitor.h"
+
+namespace base {
+ class Lock;
+}
+
+namespace blink {
+
+class DartDebuggerIsolate {
+ public:
+ DartDebuggerIsolate(Dart_IsolateId id)
+ : id_(id) {
+ }
+
+ Dart_IsolateId id() const {
+ return id_;
+ }
+
+ void Notify() {
+ monitor_.Notify();
+ }
+
+ void MessageLoop();
+
+ private:
+ const Dart_IsolateId id_;
+ Monitor monitor_;
+};
+
+class DartDebugger {
+ public:
+ static void InitDebugger();
+
+ private:
+ static void BptResolvedHandler(Dart_IsolateId isolate_id,
+ intptr_t bp_id,
+ const Dart_CodeLocation& location);
+
+ static void PausedEventHandler(Dart_IsolateId isolate_id,
+ intptr_t bp_id,
+ const Dart_CodeLocation& loc);
+
+ static void ExceptionThrownHandler(Dart_IsolateId isolate_id,
+ Dart_Handle exception,
+ Dart_StackTrace stack_trace);
+
+ static void IsolateEventHandler(Dart_IsolateId isolate_id,
+ Dart_IsolateEvent kind);
+
+ static void NotifyIsolate(Dart_Isolate isolate);
+
+ static intptr_t FindIsolateIndexById(Dart_IsolateId id);
+
+ static intptr_t FindIsolateIndexByIdLocked(Dart_IsolateId id);
+
+ static void AddIsolate(Dart_IsolateId id);
+
+ static void RemoveIsolate(Dart_IsolateId id);
+
+ static base::Lock* lock_;
+ static std::vector<std::unique_ptr<DartDebuggerIsolate>>* isolates_;
+
+ friend class DartDebuggerIsolate;
+};
+
+} // namespace blink
+
+#endif // SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
\ No newline at end of file
diff --git a/sky/engine/core/script/dart_service_isolate.cc b/sky/engine/core/script/dart_service_isolate.cc
new file mode 100644
index 0000000..d1bf545
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate.cc
@@ -0,0 +1,304 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dart_service_isolate.h"
+
+#include "base/logging.h"
+#include "dart/runtime/include/dart_api.h"
+#include "sky/engine/tonic/dart_error.h"
+#include "sky/engine/tonic/dart_string.h"
+
+#define RETURN_ERROR_HANDLE(handle) \
+ if (Dart_IsError(handle)) { \
+ return handle; \
+ }
+
+#define SHUTDOWN_ON_ERROR(handle) \
+ if (Dart_IsError(handle)) { \
+ *error = strdup(Dart_GetError(handle)); \
+ Dart_ExitScope(); \
+ Dart_ShutdownIsolate(); \
+ return false; \
+ }
+
+#define kLibrarySourceNamePrefix "/dart_service_isolate"
+static const char* kServiceIsolateScript = "main.dart";
+
+struct ResourcesEntry {
+ const char* path_;
+ const char* resource_;
+ int length_;
+};
+
+namespace mojo {
+ namespace dart {
+ extern ResourcesEntry __sky_embedder_service_isolate_resources_[];
+ }
+}
+
+namespace blink {
+
+class Resources {
+ public:
+ static const int kNoSuchInstance = -1;
+ static int ResourceLookup(const char* path, const char** resource) {
+ ResourcesEntry* table = ResourcesTable();
+ for (int i = 0; table[i].path_ != NULL; i++) {
+ const ResourcesEntry& entry = table[i];
+ if (strcmp(path, entry.path_) == 0) {
+ *resource = entry.resource_;
+ DCHECK(entry.length_ > 0);
+ return entry.length_;
+ }
+ }
+ return kNoSuchInstance;
+ }
+
+ static const char* Path(int idx) {
+ DCHECK(idx >= 0);
+ ResourcesEntry* entry = At(idx);
+ if (entry == NULL) {
+ return NULL;
+ }
+ DCHECK(entry->path_ != NULL);
+ return entry->path_;
+ }
+
+ private:
+ static ResourcesEntry* At(int idx) {
+ DCHECK(idx >= 0);
+ ResourcesEntry* table = ResourcesTable();
+ for (int i = 0; table[i].path_ != NULL; i++) {
+ if (idx == i) {
+ return &table[i];
+ }
+ }
+ return NULL;
+ }
+ static ResourcesEntry* ResourcesTable() {
+ return &mojo::dart::__sky_embedder_service_isolate_resources_[0];
+ }
+};
+
+void DartServiceIsolate::TriggerResourceLoad(Dart_NativeArguments args) {
+ Dart_Handle library = Dart_RootLibrary();
+ DCHECK(!Dart_IsError(library));
+ Dart_Handle result = LoadResources(library);
+ DCHECK(!Dart_IsError(result));
+}
+
+void DartServiceIsolate::NotifyServerState(Dart_NativeArguments args) {
+ // NO-OP.
+}
+
+void DartServiceIsolate::Shutdown(Dart_NativeArguments args) {
+ // NO-OP.
+}
+
+DartBuiltin::Natives DartServiceIsolate::native_entries_[] = {
+ {"ServiceIsolate_TriggerResourceLoad", TriggerResourceLoad, 0 },
+ {"ServiceIsolate_NotifyServerState", NotifyServerState, 2 },
+ {"ServiceIsolate_Shutdown", Shutdown, 0 },
+};
+
+Dart_NativeFunction DartServiceIsolate::NativeResolver(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ CHECK(builtins_);
+ return builtins_->Resolver(name, argument_count, auto_setup_scope);
+}
+
+const uint8_t* DartServiceIsolate::NativeSymbolizer(
+ Dart_NativeFunction native_function) {
+ CHECK(builtins_);
+ return builtins_->Symbolizer(native_function);
+}
+
+Dart_LibraryTagHandler DartServiceIsolate::embedder_tag_handler_ = nullptr;
+DartBuiltin* DartServiceIsolate::builtins_ = nullptr;
+
+bool DartServiceIsolate::Startup(std::string server_ip,
+ intptr_t server_port,
+ Dart_LibraryTagHandler embedder_tag_handler,
+ char** error) {
+ Dart_Isolate isolate = Dart_CurrentIsolate();
+ CHECK(isolate);
+
+ // Remember the embedder's library tag handler.
+ embedder_tag_handler_ = embedder_tag_handler;
+ CHECK(embedder_tag_handler_);
+
+ // Setup native entries.
+ builtins_ =
+ new DartBuiltin(&DartServiceIsolate::native_entries_[0],
+ arraysize(native_entries_));
+
+ Dart_Handle result;
+
+ // Use our own library tag handler when loading service isolate sources.
+ Dart_SetLibraryTagHandler(DartServiceIsolate::LibraryTagHandler);
+ // Load main script.
+ Dart_Handle library = LoadScript(kServiceIsolateScript);
+ DCHECK(library != Dart_Null());
+ SHUTDOWN_ON_ERROR(library);
+ // Setup native entry resolution.
+ result = Dart_SetNativeResolver(library, NativeResolver, NativeSymbolizer);
+
+ SHUTDOWN_ON_ERROR(result);
+ // Finalize loading.
+ result = Dart_FinalizeLoading(false);
+ SHUTDOWN_ON_ERROR(result);
+
+ // Make runnable.
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+ bool retval = Dart_IsolateMakeRunnable(isolate);
+ if (!retval) {
+ Dart_EnterIsolate(isolate);
+ Dart_ShutdownIsolate();
+ *error = strdup("Invalid isolate state - Unable to make it runnable.");
+ return false;
+ }
+ Dart_EnterIsolate(isolate);
+ Dart_EnterScope();
+
+ library = Dart_RootLibrary();
+ SHUTDOWN_ON_ERROR(library);
+
+ // Set the HTTP server's ip.
+ result = Dart_SetField(library,
+ Dart_NewStringFromCString("_ip"),
+ Dart_NewStringFromCString(server_ip.c_str()));
+ SHUTDOWN_ON_ERROR(result);
+ // If we have a port specified, start the server immediately.
+ bool auto_start = server_port >= 0;
+ if (server_port < 0) {
+ // Adjust server_port to port 0 which will result in the first available
+ // port when the HTTP server is started.
+ server_port = 0;
+ }
+ // Set the HTTP's servers port.
+ result = Dart_SetField(library,
+ Dart_NewStringFromCString("_port"),
+ Dart_NewInteger(server_port));
+ SHUTDOWN_ON_ERROR(result);
+ result = Dart_SetField(library,
+ Dart_NewStringFromCString("_autoStart"),
+ Dart_NewBoolean(auto_start));
+ SHUTDOWN_ON_ERROR(result);
+ return true;
+}
+
+Dart_Handle DartServiceIsolate::GetSource(const char* name) {
+ const intptr_t kBufferSize = 512;
+ char buffer[kBufferSize];
+ snprintf(&buffer[0], kBufferSize-1, "%s/%s", kLibrarySourceNamePrefix, name);
+ const char* vmservice_source = NULL;
+ int r = Resources::ResourceLookup(buffer, &vmservice_source);
+ DCHECK(r != Resources::kNoSuchInstance);
+ return Dart_NewStringFromCString(vmservice_source);
+}
+
+Dart_Handle DartServiceIsolate::LoadScript(const char* name) {
+ Dart_Handle url = Dart_NewStringFromCString("dart:vmservice_sky");
+ Dart_Handle source = GetSource(name);
+ return Dart_LoadScript(url, source, 0, 0);
+}
+
+Dart_Handle DartServiceIsolate::LoadSource(Dart_Handle library, const char* name) {
+ Dart_Handle url = Dart_NewStringFromCString(name);
+ Dart_Handle source = GetSource(name);
+ return Dart_LoadSource(library, url, source, 0, 0);
+}
+
+Dart_Handle DartServiceIsolate::LoadResource(Dart_Handle library,
+ const char* resource_name) {
+ // Prepare for invoke call.
+ Dart_Handle name = Dart_NewStringFromCString(resource_name);
+ RETURN_ERROR_HANDLE(name);
+ const char* data_buffer = NULL;
+ int data_buffer_length = Resources::ResourceLookup(resource_name,
+ &data_buffer);
+ DCHECK(data_buffer_length != Resources::kNoSuchInstance);
+ Dart_Handle data_list = Dart_NewTypedData(Dart_TypedData_kUint8,
+ data_buffer_length);
+ RETURN_ERROR_HANDLE(data_list);
+ Dart_TypedData_Type type = Dart_TypedData_kInvalid;
+ void* data_list_buffer = NULL;
+ intptr_t data_list_buffer_length = 0;
+ Dart_Handle result = Dart_TypedDataAcquireData(data_list, &type,
+ &data_list_buffer,
+ &data_list_buffer_length);
+ RETURN_ERROR_HANDLE(result);
+ DCHECK(data_buffer_length == data_list_buffer_length);
+ DCHECK(data_list_buffer != NULL);
+ DCHECK(type = Dart_TypedData_kUint8);
+ memmove(data_list_buffer, &data_buffer[0], data_buffer_length);
+ result = Dart_TypedDataReleaseData(data_list);
+ RETURN_ERROR_HANDLE(result);
+
+ // Make invoke call.
+ const intptr_t kNumArgs = 2;
+ Dart_Handle args[kNumArgs] = { name, data_list };
+ result = Dart_Invoke(library, Dart_NewStringFromCString("_addResource"),
+ kNumArgs, args);
+ return result;
+}
+
+Dart_Handle DartServiceIsolate::LoadResources(Dart_Handle library) {
+ Dart_Handle result = Dart_Null();
+ intptr_t prefixLen = strlen(kLibrarySourceNamePrefix);
+ for (intptr_t i = 0; Resources::Path(i) != NULL; i++) {
+ const char* path = Resources::Path(i);
+ // If it doesn't begin with kLibrarySourceNamePrefix it is a frontend
+ // resource.
+ if (strncmp(path, kLibrarySourceNamePrefix, prefixLen) != 0) {
+ result = LoadResource(library, path);
+ if (Dart_IsError(result)) {
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+Dart_Handle DartServiceIsolate::LibraryTagHandler(Dart_LibraryTag tag,
+ Dart_Handle library,
+ Dart_Handle url) {
+ if (!Dart_IsLibrary(library)) {
+ return Dart_NewApiError("not a library");
+ }
+ if (!Dart_IsString(url)) {
+ return Dart_NewApiError("url is not a string");
+ }
+ const char* url_string = NULL;
+ Dart_Handle result = Dart_StringToCString(url, &url_string);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ Dart_Handle library_url = Dart_LibraryUrl(library);
+ const char* library_url_string = NULL;
+ result = Dart_StringToCString(library_url, &library_url_string);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ if (tag == Dart_kImportTag) {
+ // Embedder handles all requests for external libraries.
+ return embedder_tag_handler_(tag, library, url);
+ }
+ DCHECK((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl));
+ if (tag == Dart_kCanonicalizeUrl) {
+ // url is already canonicalized.
+ return url;
+ }
+ // Get source from builtin resources.
+ Dart_Handle source = GetSource(url_string);
+ if (Dart_IsError(source)) {
+ return source;
+ }
+ return Dart_LoadSource(library, url, source, 0, 0);
+}
+
+
+} // namespace blink
diff --git a/sky/engine/core/script/dart_service_isolate.h b/sky/engine/core/script/dart_service_isolate.h
new file mode 100644
index 0000000..450ad16
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate.h
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
+#define SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
+
+#include <string>
+
+#include "include/dart_api.h"
+#include "sky/engine/config.h"
+#include "sky/engine/tonic/dart_builtin.h"
+
+namespace blink {
+
+class DartServiceIsolate {
+ public:
+ static bool Bootstrap();
+
+ static bool Startup(std::string server_ip,
+ intptr_t server_port,
+ Dart_LibraryTagHandler embedder_tag_handler,
+ char** error);
+
+ private:
+ // Native entries.
+ static void TriggerResourceLoad(Dart_NativeArguments args);
+ static void NotifyServerState(Dart_NativeArguments args);
+ static void Shutdown(Dart_NativeArguments args);
+ // Native entry resolution.
+ static Dart_NativeFunction NativeResolver(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope);
+ static const uint8_t* NativeSymbolizer(Dart_NativeFunction native_function);
+ static DartBuiltin::Natives native_entries_[];
+ static DartBuiltin* builtins_;
+
+ // Script loading.
+ static Dart_Handle GetSource(const char* name);
+ static Dart_Handle LoadScript(const char* name);
+ static Dart_Handle LoadSource(Dart_Handle library, const char* name);
+ static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library,
+ Dart_Handle url);
+
+ // Observatory resource loading.
+ static Dart_Handle LoadResources(Dart_Handle library);
+ static Dart_Handle LoadResource(Dart_Handle library, const char* name);
+
+ static Dart_LibraryTagHandler embedder_tag_handler_;
+};
+
+
+} // namespace blink
+
+#endif // SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
diff --git a/sky/engine/core/script/dart_service_isolate/loader.dart b/sky/engine/core/script/dart_service_isolate/loader.dart
new file mode 100644
index 0000000..a8d0d94
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate/loader.dart
@@ -0,0 +1,11 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of dart_controller_service_isolate;
+
+_processLoadRequest(request) {
+ var sp = request[0];
+ var uri = Uri.parse(request[1]);
+ sp.send('Service isolate loading not supported by embedder (uri = $uri).');
+}
\ No newline at end of file
diff --git a/sky/engine/core/script/dart_service_isolate/main.dart b/sky/engine/core/script/dart_service_isolate/main.dart
new file mode 100644
index 0000000..1eb027d
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate/main.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2013, 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.
+
+library sky_shell_dart_controller_service_isolate;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:vmservice';
+
+part 'loader.dart';
+part 'resources.dart';
+part 'server.dart';
+
+// The TCP ip/port that the HTTP server listens on.
+int _port;
+String _ip;
+// Should the HTTP server auto start?
+bool _autoStart;
+
+// HTTP server.
+Server server;
+
+_onShutdown() {
+ if (server != null) {
+ server.close(true).catchError((e, st) {
+ print(e);
+ }).whenComplete(_shutdown);
+ } else {
+ _shutdown();
+ }
+}
+
+void _bootServer() {
+ // Load resources.
+ _triggerResourceLoad();
+ // Lazily create service.
+ var service = new VMService();
+ service.onShutdown = _onShutdown;
+ // Lazily create server.
+ server = new Server(service, _ip, _port);
+}
+
+main() {
+ if (_autoStart) {
+ _bootServer();
+ if (server != null) {
+ server.startup();
+ }
+ }
+ scriptLoadPort.handler = _processLoadRequest;
+ // It's just here to push an event on the event loop so that we invoke the
+ // scheduled microtasks.
+ Timer.run(() {});
+ return scriptLoadPort;
+}
+
+_shutdown() native "ServiceIsolate_Shutdown";
diff --git a/sky/engine/core/script/dart_service_isolate/resources.dart b/sky/engine/core/script/dart_service_isolate/resources.dart
new file mode 100644
index 0000000..11e347e
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate/resources.dart
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of dart_controller_service_isolate;
+
+String detectMimeType(String name) {
+ var extensionStart = name.lastIndexOf('.');
+ var extension = name.substring(extensionStart+1);
+ switch (extension) {
+ case 'html':
+ return 'text/html; charset=UTF-8';
+ case 'dart':
+ return 'application/dart; charset=UTF-8';
+ case 'js':
+ return 'application/javascript; charset=UTF-8';
+ case 'css':
+ return 'text/css; charset=UTF-8';
+ case 'gif':
+ return 'image/gif';
+ case 'png':
+ return 'image/png';
+ case 'jpg':
+ return 'image/jpeg';
+ case 'jpeg':
+ return 'image/jpeg';
+ case 'svg':
+ return 'image/svg+xml';
+ default:
+ return 'text/plain';
+ }
+}
+
+
+class Resource {
+ final String name;
+ final String mimeType;
+ final List<int> data;
+ Resource(this.name, this.mimeType, this.data);
+ static final Map<String, Resource> resources = new Map<String, Resource>();
+}
+
+
+_addResource(String name, List<int> data) {
+ var mimeType = detectMimeType(name);
+ Resource resource = new Resource(name, mimeType, data);
+ Resource.resources[name] = resource;
+}
+
+_triggerResourceLoad() native "ServiceIsolate_TriggerResourceLoad";
diff --git a/sky/engine/core/script/dart_service_isolate/server.dart b/sky/engine/core/script/dart_service_isolate/server.dart
new file mode 100644
index 0000000..4e069f9
--- /dev/null
+++ b/sky/engine/core/script/dart_service_isolate/server.dart
@@ -0,0 +1,225 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of dart_controller_service_isolate;
+
+class WebSocketClient extends Client {
+ static const int PARSE_ERROR_CODE = 4000;
+ static const int BINARY_MESSAGE_ERROR_CODE = 4001;
+ static const int NOT_MAP_ERROR_CODE = 4002;
+ final WebSocket socket;
+
+ WebSocketClient(this.socket, VMService service) : super(service) {
+ socket.listen((message) => onWebSocketMessage(message));
+ socket.done.then((_) => close());
+ }
+
+ onWebSocketMessage(message) {
+ if (message is String) {
+ var map;
+ try {
+ map = JSON.decode(message);
+ } catch (e) {
+ socket.close(PARSE_ERROR_CODE, 'Message parse error: $e');
+ return;
+ }
+ if (map is! Map) {
+ socket.close(NOT_MAP_ERROR_CODE, 'Message must be a JSON map.');
+ return;
+ }
+ var serial = map['id'];
+ onMessage(serial, new Message.fromJsonRpc(map));
+ } else {
+ socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
+ }
+ }
+
+ post(dynamic result) {
+ try {
+ socket.add(result);
+ } catch (_) {
+ print("Ignoring error posting over WebSocket.");
+ }
+ }
+
+ dynamic toJson() {
+ Map map = super.toJson();
+ map['type'] = 'WebSocketClient';
+ map['socket'] = '$socket';
+ return map;
+ }
+}
+
+
+class HttpRequestClient extends Client {
+ static ContentType jsonContentType =
+ new ContentType("application", "json", charset: "utf-8");
+ final HttpRequest request;
+
+ HttpRequestClient(this.request, VMService service) : super(service);
+
+ post(String result) {
+ request.response..headers.contentType = jsonContentType
+ ..write(result)
+ ..close();
+ close();
+ }
+
+ dynamic toJson() {
+ Map map = super.toJson();
+ map['type'] = 'HttpRequestClient';
+ map['request'] = '$request';
+ return map;
+ }
+}
+
+class Server {
+ static const WEBSOCKET_PATH = '/ws';
+ static const ROOT_REDIRECT_PATH = '/index.html';
+
+ final VMService _service;
+ final String _ip;
+ final int _port;
+
+ HttpServer _server;
+ bool get running => _server != null;
+ bool _displayMessages = false;
+
+ Server(this._service, this._ip, this._port) {
+ _displayMessages = (_ip != '127.0.0.1' || _port != 8181);
+ }
+
+ bool _shouldServeObservatory(HttpRequest request) {
+ if (request.headers['Observatory-Version'] != null) {
+ // Request is already coming from Observatory.
+ return false;
+ }
+ // TODO(johnmccutchan): Test with obscure browsers.
+ if (request.headers.value(HttpHeaders.USER_AGENT).contains('Mozilla')) {
+ // Request is coming from a browser but not Observatory application.
+ // Serve Observatory and let the Observatory make the real request.
+ return true;
+ }
+ // All other user agents are assumed to be textual.
+ return false;
+ }
+
+ _onServerShutdown() {
+ }
+
+ _serverError(error, stackTrace) {
+ _onServerShutdown();
+ }
+
+ _serverDone() {
+ _onServerShutdown();
+ }
+
+ _requestHandler(HttpRequest request) {
+ // Allow cross origin requests with 'observatory' header.
+ request.response.headers.add('Access-Control-Allow-Origin', '*');
+ request.response.headers.add('Access-Control-Allow-Headers',
+ 'Observatory-Version');
+
+ if (request.method != 'GET') {
+ // Not a GET request. Do nothing.
+ request.response.close();
+ return;
+ }
+
+ final String path =
+ request.uri.path == '/' ? ROOT_REDIRECT_PATH : request.uri.path;
+
+ if (path == WEBSOCKET_PATH) {
+ WebSocketTransformer.upgrade(request).then((WebSocket webSocket) {
+ new WebSocketClient(webSocket, _service);
+ });
+ return;
+ }
+
+ var resource = Resource.resources[path];
+ if (resource == null && _shouldServeObservatory(request)) {
+ resource = Resource.resources[ROOT_REDIRECT_PATH];
+ assert(resource != null);
+ }
+ if (resource != null) {
+ // Serving up a static resource (e.g. .css, .html, .png).
+ request.response.headers.contentType =
+ ContentType.parse(resource.mimeType);
+ request.response.add(resource.data);
+ request.response.close();
+ return;
+ }
+ var message = new Message.fromUri(request.uri);
+ var client = new HttpRequestClient(request, _service);
+ client.onMessage(null, message);
+ }
+
+ Future startup() {
+ if (_server != null) {
+ // Already running.
+ return new Future.value(this);
+ }
+
+ // Startup HTTP server.
+ var address = new InternetAddress('127.0.0.1');
+ return HttpServer.bind(address, _port).then((s) {
+ _server = s;
+ _server.listen(_requestHandler,
+ onError: _serverError,
+ onDone: _serverDone,
+ cancelOnError: true);
+ var ip = _server.address.address.toString();
+ if (_displayMessages) {
+ var port = _server.port.toString();
+ print('Observatory listening on http://$ip:$port');
+ }
+ // Server is up and running.
+ _notifyServerState(ip, _server.port);
+ return this;
+ }).catchError((e, st) {
+ print('Could not start Observatory HTTP server:\n$e\n$st\n');
+ _notifyServerState("", 0);
+ return this;
+ });
+ }
+
+ close(bool force) {
+ if (_server == null) {
+ return new Future.value(null);
+ }
+ return _server.close(force: force);
+ }
+
+ Future shutdown(bool forced) {
+ if (_server == null) {
+ // Not started.
+ return new Future.value(this);
+ }
+
+ // Force displaying of status messages if we are forcibly shutdown.
+ _displayMessages = _displayMessages || forced;
+
+ // Shutdown HTTP server and subscription.
+ var ip = _server.address.address.toString();
+ var port = _server.port.toString();
+ return close(forced).then((_) {
+ if (_displayMessages) {
+ print('Observatory no longer listening on http://$ip:$port');
+ }
+ _server = null;
+ _notifyServerState("", 0);
+ return this;
+ }).catchError((e, st) {
+ _server = null;
+ print('Could not shutdown Observatory HTTP server:\n$e\n$st\n');
+ _notifyServerState("", 0);
+ return this;
+ });
+ }
+
+}
+
+_notifyServerState(String ip, int port)
+ native "ServiceIsolate_NotifyServerState";
diff --git a/sky/engine/core/script/monitor.h b/sky/engine/core/script/monitor.h
new file mode 100644
index 0000000..af784ec
--- /dev/null
+++ b/sky/engine/core/script/monitor.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
+#define SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
+
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+
+namespace blink {
+
+class Monitor {
+ public:
+ Monitor() {
+ lock_ = new base::Lock();
+ condition_variable_ = new base::ConditionVariable(lock_);
+ }
+
+ ~Monitor() {
+ delete condition_variable_;
+ delete lock_;
+ }
+
+ void Enter() {
+ lock_->Acquire();
+ }
+
+ void Exit() {
+ lock_->Release();
+ }
+
+ void Notify() {
+ condition_variable_->Signal();
+ }
+
+ void Wait() {
+ condition_variable_->Wait();
+ }
+
+ private:
+ base::Lock* lock_;
+ base::ConditionVariable* condition_variable_;
+ DISALLOW_COPY_AND_ASSIGN(Monitor);
+};
+
+class MonitorLocker {
+ public:
+ explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) {
+ CHECK(monitor_);
+ monitor_->Enter();
+ }
+
+ virtual ~MonitorLocker() {
+ monitor_->Exit();
+ }
+
+ void Wait() {
+ return monitor_->Wait();
+ }
+
+ void Notify() {
+ monitor_->Notify();
+ }
+
+ private:
+ Monitor* const monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
+};
+
+} // namespace blink
+
+
+#endif // SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
\ No newline at end of file
diff --git a/sky/tools/webkitpy/layout_tests/controllers/single_test_runner.py b/sky/tools/webkitpy/layout_tests/controllers/single_test_runner.py
index 31d4d8c..56af871 100644
--- a/sky/tools/webkitpy/layout_tests/controllers/single_test_runner.py
+++ b/sky/tools/webkitpy/layout_tests/controllers/single_test_runner.py
@@ -307,6 +307,10 @@
failures.append(test_failures.FailureMissingAudio())
return failures
+ # FIXME: This won't be needed once we have flags for Sky that suppress the
+ # Observatory messages.
+ _filter_observatory_messages = re.compile(r"^CONSOLE: Observatory listening on.*\n", re.MULTILINE)
+
def _get_normalized_output_text(self, output):
"""Returns the normalized text output, i.e. the output in which
the end-of-line characters are normalized to "\n"."""
@@ -314,7 +318,9 @@
# changed to "\r\n" by our system (Python/Cygwin), resulting in
# "\r\r\n", when, in fact, we wanted to compare the text output with
# the normalized text expectation files.
- return output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
+ normalized_lines = output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
+ normalized_lines = re.sub(self._filter_observatory_messages, r"", normalized_lines)
+ return normalized_lines
# FIXME: This function also creates the image diff. Maybe that work should
# be handled elsewhere?