Add support for snapshot loading to Sky

This CL adds the ability to load Dart snapshot files created by sky_packager in
Sky. Using a snapshot lets us transmit all the code for an app in a single blob
and should improve startup time. Later CLs will make this codepath easier to
use and evaluate performance.

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1197133004.
This commit is contained in:
Adam Barth 2015-06-23 18:40:01 -07:00
parent c89c751937
commit 1f258f383e
10 changed files with 175 additions and 25 deletions

View File

@ -1058,6 +1058,8 @@ sky_core_files = [
"script/dart_loader.h",
"script/dart_service_isolate.cc",
"script/dart_service_isolate.h",
"script/dart_snapshot_loader.cc",
"script/dart_snapshot_loader.h",
"script/dom_dart_state.cc",
"script/dom_dart_state.h",
"script/monitor.h",

View File

@ -27,6 +27,7 @@
#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/dart_snapshot_loader.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"
@ -40,6 +41,16 @@
#include "sky/engine/wtf/text/TextPosition.h"
namespace blink {
namespace {
void CreateEmptyRootLibraryIfNeeded() {
if (Dart_IsNull(Dart_RootLibrary())) {
Dart_LoadScript(Dart_NewStringFromCString("dart:empty"), Dart_EmptyString(),
0, 0);
}
}
} // namespace
#if ENABLE(DART_STRICT)
static const char* kCheckedModeArgs[] = {"--enable_asserts",
@ -126,6 +137,9 @@ void DartController::DidLoadMainLibrary(KURL url) {
}
void DartController::LoadMainLibrary(const KURL& url, mojo::URLResponsePtr response) {
DartState::Scope scope(dart_state());
CreateEmptyRootLibraryIfNeeded();
DartLoader& loader = dart_state()->loader();
DartDependencyCatcher dependency_catcher(loader);
loader.LoadLibrary(url, response.Pass());
@ -133,13 +147,33 @@ void DartController::LoadMainLibrary(const KURL& url, mojo::URLResponsePtr respo
base::Bind(&DartController::DidLoadMainLibrary, weak_factory_.GetWeakPtr(), url));
}
void DartController::DidLoadSnapshot() {
DCHECK(Dart_CurrentIsolate() == nullptr);
snapshot_loader_ = nullptr;
Dart_Isolate isolate = dart_state()->isolate();
DartIsolateScope isolate_scope(isolate);
DartApiScope dart_api_scope;
Dart_Handle library = Dart_RootLibrary();
if (LogIfError(library))
return;
DartInvokeAppField(library, ToDart("main"), 0, nullptr);
}
void DartController::LoadSnapshot(const KURL& url, mojo::URLResponsePtr response) {
snapshot_loader_ = adoptPtr(new DartSnapshotLoader(dart_state()));
snapshot_loader_->LoadSnapshot(url, response.Pass(),
base::Bind(&DartController::DidLoadSnapshot, weak_factory_.GetWeakPtr()));
}
void DartController::LoadScriptInModule(
AbstractModule* module,
const String& source,
const TextPosition& position,
const LoadFinishedCallback& finished_callback) {
DartIsolateScope isolate_scope(dart_state()->isolate());
DartApiScope dart_api_scope;
DartState::Scope scope(dart_state());
CreateEmptyRootLibraryIfNeeded();
DartDependencyCatcher dependency_catcher(dart_state()->loader());
Dart_Handle library_handle = CreateLibrary(module, source, position);
@ -274,6 +308,7 @@ static Dart_Isolate IsolateCreateCallback(const char* script_uri,
// Create & start the handle watcher isolate
CHECK(kDartIsolateSnapshotBuffer);
// TODO(abarth): Who deletes this DartState instance?
DartState* dart_state = new DartState();
Dart_Isolate isolate =
Dart_CreateIsolate("sky:handle_watcher", "", kDartIsolateSnapshotBuffer,
@ -289,9 +324,8 @@ static Dart_Isolate IsolateCreateCallback(const char* script_uri,
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
Builtin::SetNativeResolver(Builtin::kIOLibrary);
// Ensure the isolate has a root library.
Dart_LoadScript(Dart_NewStringFromCString("dart:empty"),
Dart_NewStringFromCString(""), 0, 0);
if (!script_uri)
CreateEmptyRootLibraryIfNeeded();
}
Dart_ExitIsolate();
@ -334,10 +368,6 @@ void DartController::CreateIsolateFor(PassOwnPtr<DOMDartState> state) {
{
DartApiScope apiScope;
// Ensure the isolate has a root library.
Dart_LoadScript(Dart_NewStringFromCString("dart:empty"),
Dart_NewStringFromCString(""), 0, 0);
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
Builtin::SetNativeResolver(Builtin::kIOLibrary);

View File

@ -18,6 +18,7 @@ namespace blink {
class AbstractModule;
class BuiltinSky;
class DOMDartState;
class DartSnapshotLoader;
class DartValue;
class HTMLScriptElement;
class KURL;
@ -35,6 +36,7 @@ class DartController {
// Can either issue the url load ourselves or take an existing response:
void LoadMainLibrary(const KURL& url, mojo::URLResponsePtr response = nullptr);
void LoadSnapshot(const KURL& url, mojo::URLResponsePtr response = nullptr);
void LoadScriptInModule(AbstractModule* module,
const String& source,
@ -57,9 +59,11 @@ class DartController {
const TextPosition& position);
void DidLoadMainLibrary(KURL url);
void DidLoadSnapshot();
OwnPtr<DOMDartState> dom_dart_state_;
OwnPtr<BuiltinSky> builtin_sky_;
OwnPtr<DartSnapshotLoader> snapshot_loader_;
base::WeakPtrFactory<DartController> weak_factory_;

View File

@ -0,0 +1,66 @@
// 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/config.h"
#include "sky/engine/core/script/dart_snapshot_loader.h"
#include "base/callback.h"
#include "base/trace_event/trace_event.h"
#include "sky/engine/platform/weborigin/KURL.h"
#include "sky/engine/tonic/dart_api_scope.h"
#include "sky/engine/tonic/dart_converter.h"
#include "sky/engine/tonic/dart_error.h"
#include "sky/engine/tonic/dart_isolate_scope.h"
#include "sky/engine/wtf/MainThread.h"
using mojo::common::DataPipeDrainer;
namespace blink {
DartSnapshotLoader::DartSnapshotLoader(DartState* dart_state)
: dart_state_(dart_state->GetWeakPtr()) {
}
DartSnapshotLoader::~DartSnapshotLoader() {
}
void DartSnapshotLoader::LoadSnapshot(const KURL& url,
mojo::URLResponsePtr response,
const base::Closure& callback) {
TRACE_EVENT_ASYNC_BEGIN0("sky", "DartSnapshotLoader::LoadSnapshot", this);
callback_ = callback;
if (!response) {
fetcher_ = adoptPtr(new MojoFetcher(this, url));
} else {
OnReceivedResponse(response.Pass());
}
}
void DartSnapshotLoader::OnReceivedResponse(mojo::URLResponsePtr response) {
if (response->status_code != 200) {
callback_.Run();
return;
}
drainer_ = adoptPtr(new DataPipeDrainer(this, response->body.Pass()));
}
void DartSnapshotLoader::OnDataAvailable(const void* data, size_t num_bytes) {
buffer_.append(static_cast<const uint8_t*>(data), num_bytes);
}
void DartSnapshotLoader::OnDataComplete() {
TRACE_EVENT_ASYNC_END0("sky", "DartSnapshotLoader::LoadSnapshot", this);
{
DartIsolateScope scope(dart_state_->isolate());
DartApiScope api_scope;
LogIfError(Dart_LoadScriptFromSnapshot(buffer_.data(), buffer_.size()));
}
callback_.Run();
}
} // namespace blink

View File

@ -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_SNAPSHOT_LOADER_H_
#define SKY_ENGINE_CORE_SCRIPT_DART_SNAPSHOT_LOADER_H_
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "dart/runtime/include/dart_api.h"
#include "mojo/common/data_pipe_drainer.h"
#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
#include "sky/engine/platform/fetcher/MojoFetcher.h"
#include "sky/engine/wtf/OwnPtr.h"
#include "sky/engine/wtf/Vector.h"
#include "sky/engine/wtf/text/WTFString.h"
namespace blink {
class DartState;
class KURL;
class DartSnapshotLoader : public MojoFetcher::Client,
public mojo::common::DataPipeDrainer::Client {
public:
explicit DartSnapshotLoader(DartState* dart_state);
~DartSnapshotLoader();
void LoadSnapshot(const KURL& url, mojo::URLResponsePtr response,
const base::Closure& callback);
DartState* dart_state() const { return dart_state_.get(); }
private:
// MojoFetcher::Client
void OnReceivedResponse(mojo::URLResponsePtr response) override;
// mojo::common::DataPipeDrainer::Client
void OnDataAvailable(const void* data, size_t num_bytes) override;
void OnDataComplete() override;
base::WeakPtr<DartState> dart_state_;
// TODO(abarth): Should we be using SharedBuffer to buffer the data?
Vector<uint8_t> buffer_;
OwnPtr<MojoFetcher> fetcher_;
OwnPtr<mojo::common::DataPipeDrainer> drainer_;
base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(DartSnapshotLoader);
};
} // namespace blink
#endif // SKY_ENGINE_CORE_SCRIPT_DART_SNAPSHOT_LOADER_H_

View File

@ -47,7 +47,9 @@ void SkyView::SetDisplayMetrics(const SkyDisplayMetrics& metrics) {
data_->view_->setDisplayMetrics(display_metrics_);
}
void SkyView::Load(const WebURL& url, mojo::URLResponsePtr response) {
void SkyView::Load(const WebURL& web_url, mojo::URLResponsePtr response) {
KURL url = web_url;
data_->view_ = View::create(base::Bind(
&SkyView::ScheduleFrame, weak_factory_.GetWeakPtr()));
data_->view_->setDisplayMetrics(display_metrics_);
@ -63,7 +65,10 @@ void SkyView::Load(const WebURL& url, mojo::URLResponsePtr response) {
client_->DidCreateIsolate(isolate);
}
dart_controller_->LoadMainLibrary(url, response.Pass());
if (url.path().endsWith(".snapshot"))
dart_controller_->LoadSnapshot(url, response.Pass());
else
dart_controller_->LoadMainLibrary(url, response.Pass());
}
void SkyView::BeginFrame(base::TimeTicks frame_time) {

View File

@ -104,7 +104,8 @@ bool WebView::shouldUseWebView(const GURL& url)
filename.resize(queryStart);
// For now .dart indicates we should use SkyView. Eventually we'll
// use SkyView for all urls regardless of file extension.
return !EndsWith(filename, ".dart", false);
return !EndsWith(filename, ".dart", false)
&& !EndsWith(filename, ".snapshot", false);
}
WebView* WebView::create(WebViewClient* client)

View File

@ -15,9 +15,6 @@
namespace {
static const char kSkyInternalsLibraryName[] = "dart:sky.internals";
static const char kSkyInternalsURL[] = "package:sky/internals.dart";
std::string Fetch(const std::string& url) {
base::FilePath path(url);
std::string source;
@ -122,14 +119,6 @@ Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
return Dart_NewApiError("Unknown library tag.");
}
void LoadSkyInternals() {
DartApiScope api_scope;
Dart_Handle library_name = StringToDart(kSkyInternalsLibraryName);
std::string url = GetLoader().CanonicalizePackageURL(kSkyInternalsURL);
LogIfError(Dart_LoadLibrary(library_name, StringToDart(Fetch(url)), 0, 0));
}
void LoadScript(const std::string& url) {
LogIfError(
Dart_LoadScript(StringToDart(url), StringToDart(Fetch(url)), 0, 0));

View File

@ -12,7 +12,6 @@
Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
void LoadSkyInternals();
void LoadScript(const std::string& url);
#endif // SKY_TOOLS_PACKAGER_LOADER_H_

View File

@ -32,7 +32,6 @@ Dart_Isolate CreateDartIsolate() {
CHECK(isolate) << error;
CHECK(!LogIfError(Dart_SetLibraryTagHandler(HandleLibraryTag)));
LoadSkyInternals();
Dart_ExitIsolate();
return isolate;