Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Unified Diff: tonic/dart_library_loader.cc

Issue 1244493002: Wholesale move sky/engine/tonic to tonic (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tonic/dart_library_loader.h ('k') | tonic/dart_library_provider.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tonic/dart_library_loader.cc
diff --git a/tonic/dart_library_loader.cc b/tonic/dart_library_loader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a6492ad8835ba97c85850bc94b0d58c6e51a0924
--- /dev/null
+++ b/tonic/dart_library_loader.cc
@@ -0,0 +1,305 @@
+// 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 "tonic/dart_library_loader.h"
+
+#include "base/callback.h"
+#include "base/trace_event/trace_event.h"
+#include "mojo/common/data_pipe_drainer.h"
+#include "tonic/dart_api_scope.h"
+#include "tonic/dart_converter.h"
+#include "tonic/dart_dependency_catcher.h"
+#include "tonic/dart_error.h"
+#include "tonic/dart_isolate_scope.h"
+#include "tonic/dart_library_provider.h"
+#include "tonic/dart_state.h"
+
+using mojo::common::DataPipeDrainer;
+
+namespace blink {
+
+namespace {
+
+// Helper to erase a T* from a container of std::unique_ptr<T>s.
+template<typename T, typename C>
+void EraseUniquePtr(C& container, T* item) {
+ std::unique_ptr<T> key = std::unique_ptr<T>(item);
+ container.erase(key);
+ key.release();
+}
+
+}
+
+// A DartLibraryLoader::Job represents a network load. It fetches data from the
+// network and buffers the data in std::vector. To cancel the job, delete this
+// object.
+class DartLibraryLoader::Job : public DartDependency,
+ public DataPipeDrainer::Client {
+ public:
+ Job(DartLibraryLoader* loader, const std::string& name)
+ : loader_(loader), name_(name), weak_factory_(this) {
+ loader->library_provider()->GetLibraryAsStream(
+ name, base::Bind(&Job::OnStreamAvailable, weak_factory_.GetWeakPtr()));
+ }
+
+ const std::string& name() const { return name_; }
+
+ protected:
+ DartLibraryLoader* loader_;
+ // TODO(abarth): Should we be using SharedBuffer to buffer the data?
+ std::vector<uint8_t> buffer_;
+
+ private:
+ void OnStreamAvailable(mojo::ScopedDataPipeConsumerHandle pipe) {
+ if (!pipe.is_valid()) {
+ loader_->DidFailJob(this);
+ return;
+ }
+ drainer_ = adoptPtr(new DataPipeDrainer(this, pipe.Pass()));
+ }
+
+ // DataPipeDrainer::Client
+ void OnDataAvailable(const void* data, size_t num_bytes) override {
+ const uint8_t* bytes = static_cast<const uint8_t*>(data);
+ buffer_.insert(buffer_.end(), bytes, bytes + num_bytes);
+ }
+ // Subclasses must implement OnDataComplete.
+
+ std::string name_;
+ OwnPtr<DataPipeDrainer> drainer_;
+
+ base::WeakPtrFactory<Job> weak_factory_;
+};
+
+class DartLibraryLoader::ImportJob : public Job {
+ public:
+ ImportJob(DartLibraryLoader* loader, const std::string& name) : Job(loader, name) {
+ TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLibraryLoader::ImportJob", this, "url",
+ name);
+ }
+
+ private:
+ // DataPipeDrainer::Client
+ void OnDataComplete() override {
+ TRACE_EVENT_ASYNC_END0("sky", "DartLibraryLoader::ImportJob", this);
+ loader_->DidCompleteImportJob(this, buffer_);
+ }
+};
+
+class DartLibraryLoader::SourceJob : public Job {
+ public:
+ SourceJob(DartLibraryLoader* loader, const std::string& name, Dart_Handle library)
+ : Job(loader, name), library_(loader->dart_state(), library) {
+ TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLibraryLoader::SourceJob", this, "url",
+ name);
+ }
+
+ Dart_PersistentHandle library() const { return library_.value(); }
+
+ private:
+ // DataPipeDrainer::Client
+ void OnDataComplete() override {
+ TRACE_EVENT_ASYNC_END0("sky", "DartLibraryLoader::SourceJob", this);
+ loader_->DidCompleteSourceJob(this, buffer_);
+ }
+
+ DartPersistentValue library_;
+};
+
+// A DependencyWatcher represents a request to watch for when a given set of
+// dependencies (either libraries or parts of libraries) have finished loading.
+// When the dependencies are satisfied (including transitive dependencies), then
+// the |callback| will be invoked.
+class DartLibraryLoader::DependencyWatcher {
+ public:
+ DependencyWatcher(const std::unordered_set<DartDependency*>& dependencies,
+ const base::Closure& callback)
+ : dependencies_(dependencies), callback_(callback) {
+ DCHECK(!dependencies_.empty());
+ }
+
+ bool DidResolveDependency(
+ DartDependency* resolved_dependency,
+ const std::unordered_set<DartDependency*>& new_dependencies) {
+ const auto& it = dependencies_.find(resolved_dependency);
+ if (it == dependencies_.end())
+ return false;
+ dependencies_.erase(it);
+ for (const auto& dependency : new_dependencies)
+ dependencies_.insert(dependency);
+ return dependencies_.empty();
+ }
+
+ const base::Closure& callback() const { return callback_; }
+
+ private:
+ std::unordered_set<DartDependency*> dependencies_;
+ base::Closure callback_;
+};
+
+// A WatcherSignaler is responsible for signaling DependencyWatchers when their
+// dependencies resolve and for calling the DependencyWatcher's callback. We use
+// a separate object of this task because we want to carefully manage when we
+// call the callbacks, which can call into us again reentrantly.
+//
+// WatcherSignaler is designed to be placed on the stack as a RAII. After its
+// destructor runs, we might have executed aribitrary script.
+class DartLibraryLoader::WatcherSignaler {
+ public:
+ WatcherSignaler(DartLibraryLoader& loader,
+ DartDependency* resolved_dependency)
+ : loader_(loader),
+ catcher_(adoptPtr(new DartDependencyCatcher(loader))),
+ resolved_dependency_(resolved_dependency) {}
+
+ ~WatcherSignaler() {
+ std::vector<DependencyWatcher*> completed_watchers;
+ for (const auto& watcher : loader_.dependency_watchers_) {
+ if (watcher->DidResolveDependency(resolved_dependency_,
+ catcher_->dependencies()))
+ completed_watchers.push_back(watcher.get());
+ }
+
+ // Notice that we remove the dependency catcher and extract all the
+ // callbacks before running any of them. We don't want to be re-entered
+ // below the callbacks and end up in an inconsistent state.
+ catcher_.clear();
+ std::vector<base::Closure> callbacks;
+ for (const auto& watcher : completed_watchers) {
+ callbacks.push_back(watcher->callback());
+ EraseUniquePtr(loader_.dependency_watchers_, watcher);
+ }
+
+ // Finally, run all the callbacks while touching only data on the stack.
+ for (const auto& callback : callbacks)
+ callback.Run();
+ }
+
+ private:
+ DartLibraryLoader& loader_;
+ OwnPtr<DartDependencyCatcher> catcher_;
+ DartDependency* resolved_dependency_;
+};
+
+DartLibraryLoader::DartLibraryLoader(DartState* dart_state)
+ : dart_state_(dart_state),
+ library_provider_(nullptr),
+ dependency_catcher_(nullptr) {
+}
+
+DartLibraryLoader::~DartLibraryLoader() {
+}
+
+Dart_Handle DartLibraryLoader::HandleLibraryTag(Dart_LibraryTag tag,
+ Dart_Handle library,
+ Dart_Handle url) {
+ DCHECK(Dart_IsLibrary(library));
+ DCHECK(Dart_IsString(url));
+ if (tag == Dart_kCanonicalizeUrl)
+ return DartState::Current()->library_loader().CanonicalizeURL(library, url);
+ if (tag == Dart_kImportTag) {
+ return DartState::Current()->library_loader().Import(library, url);
+ }
+ if (tag == Dart_kSourceTag) {
+ return DartState::Current()->library_loader().Source(library, url);
+ }
+ DCHECK(false);
+ return Dart_NewApiError("Unknown library tag.");
+}
+
+void DartLibraryLoader::WaitForDependencies(
+ const std::unordered_set<DartDependency*>& dependencies,
+ const base::Closure& callback) {
+ if (dependencies.empty())
+ return callback.Run();
+ dependency_watchers_.insert(
+ std::unique_ptr<DependencyWatcher>(
+ new DependencyWatcher(dependencies, callback)));
+}
+
+void DartLibraryLoader::LoadLibrary(const std::string& name) {
+ const auto& result = pending_libraries_.insert(std::make_pair(name, nullptr));
+ if (result.second) {
+ // New entry.
+ std::unique_ptr<Job> job = std::unique_ptr<Job>(new ImportJob(this, name));
+ result.first->second = job.get();
+ jobs_.insert(std::move(job));
+ }
+ if (dependency_catcher_)
+ dependency_catcher_->AddDependency(result.first->second);
+}
+
+Dart_Handle DartLibraryLoader::Import(Dart_Handle library, Dart_Handle url) {
+ LoadLibrary(StdStringFromDart(url));
+ return Dart_True();
+}
+
+Dart_Handle DartLibraryLoader::Source(Dart_Handle library, Dart_Handle url) {
+ std::unique_ptr<Job> job = std::unique_ptr<Job>(
+ new SourceJob(this, StdStringFromDart(url), library));
+ if (dependency_catcher_)
+ dependency_catcher_->AddDependency(job.get());
+ jobs_.insert(std::move(job));
+ return Dart_True();
+}
+
+Dart_Handle DartLibraryLoader::CanonicalizeURL(Dart_Handle library,
+ Dart_Handle url) {
+ return library_provider_->CanonicalizeURL(library, url);
+}
+
+void DartLibraryLoader::DidCompleteImportJob(
+ ImportJob* job,
+ const std::vector<uint8_t>& buffer) {
+ DartIsolateScope scope(dart_state_->isolate());
+ DartApiScope api_scope;
+
+ WatcherSignaler watcher_signaler(*this, job);
+
+ Dart_Handle result = Dart_LoadLibrary(
+ StdStringToDart(job->name()),
+ Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0);
+ if (Dart_IsError(result)) {
+ LOG(ERROR) << "Error Loading " << job->name() << " "
+ << Dart_GetError(result);
+ }
+
+ pending_libraries_.erase(job->name());
+ EraseUniquePtr<Job>(jobs_, job);
+}
+
+void DartLibraryLoader::DidCompleteSourceJob(
+ SourceJob* job,
+ const std::vector<uint8_t>& buffer) {
+ DartIsolateScope scope(dart_state_->isolate());
+ DartApiScope api_scope;
+
+ WatcherSignaler watcher_signaler(*this, job);
+
+ Dart_Handle result = Dart_LoadSource(
+ Dart_HandleFromPersistent(job->library()),
+ StdStringToDart(job->name()),
+ Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0);
+
+ if (Dart_IsError(result)) {
+ LOG(ERROR) << "Error Loading " << job->name() << " "
+ << Dart_GetError(result);
+ }
+
+ EraseUniquePtr<Job>(jobs_, job);
+}
+
+void DartLibraryLoader::DidFailJob(Job* job) {
+ DartIsolateScope scope(dart_state_->isolate());
+ DartApiScope api_scope;
+
+ WatcherSignaler watcher_signaler(*this, job);
+
+ LOG(ERROR) << "Library Load failed: " << job->name();
+ // TODO(eseidel): Call Dart_LibraryHandleError in the SourceJob case?
+
+ EraseUniquePtr<Job>(jobs_, job);
+}
+
+} // namespace blink
« no previous file with comments | « tonic/dart_library_loader.h ('k') | tonic/dart_library_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698