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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « tonic/dart_library_loader.h ('k') | tonic/dart_library_provider.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "tonic/dart_library_loader.h"
6
7 #include "base/callback.h"
8 #include "base/trace_event/trace_event.h"
9 #include "mojo/common/data_pipe_drainer.h"
10 #include "tonic/dart_api_scope.h"
11 #include "tonic/dart_converter.h"
12 #include "tonic/dart_dependency_catcher.h"
13 #include "tonic/dart_error.h"
14 #include "tonic/dart_isolate_scope.h"
15 #include "tonic/dart_library_provider.h"
16 #include "tonic/dart_state.h"
17
18 using mojo::common::DataPipeDrainer;
19
20 namespace blink {
21
22 namespace {
23
24 // Helper to erase a T* from a container of std::unique_ptr<T>s.
25 template<typename T, typename C>
26 void EraseUniquePtr(C& container, T* item) {
27 std::unique_ptr<T> key = std::unique_ptr<T>(item);
28 container.erase(key);
29 key.release();
30 }
31
32 }
33
34 // A DartLibraryLoader::Job represents a network load. It fetches data from the
35 // network and buffers the data in std::vector. To cancel the job, delete this
36 // object.
37 class DartLibraryLoader::Job : public DartDependency,
38 public DataPipeDrainer::Client {
39 public:
40 Job(DartLibraryLoader* loader, const std::string& name)
41 : loader_(loader), name_(name), weak_factory_(this) {
42 loader->library_provider()->GetLibraryAsStream(
43 name, base::Bind(&Job::OnStreamAvailable, weak_factory_.GetWeakPtr()));
44 }
45
46 const std::string& name() const { return name_; }
47
48 protected:
49 DartLibraryLoader* loader_;
50 // TODO(abarth): Should we be using SharedBuffer to buffer the data?
51 std::vector<uint8_t> buffer_;
52
53 private:
54 void OnStreamAvailable(mojo::ScopedDataPipeConsumerHandle pipe) {
55 if (!pipe.is_valid()) {
56 loader_->DidFailJob(this);
57 return;
58 }
59 drainer_ = adoptPtr(new DataPipeDrainer(this, pipe.Pass()));
60 }
61
62 // DataPipeDrainer::Client
63 void OnDataAvailable(const void* data, size_t num_bytes) override {
64 const uint8_t* bytes = static_cast<const uint8_t*>(data);
65 buffer_.insert(buffer_.end(), bytes, bytes + num_bytes);
66 }
67 // Subclasses must implement OnDataComplete.
68
69 std::string name_;
70 OwnPtr<DataPipeDrainer> drainer_;
71
72 base::WeakPtrFactory<Job> weak_factory_;
73 };
74
75 class DartLibraryLoader::ImportJob : public Job {
76 public:
77 ImportJob(DartLibraryLoader* loader, const std::string& name) : Job(loader, na me) {
78 TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLibraryLoader::ImportJob", this, "url",
79 name);
80 }
81
82 private:
83 // DataPipeDrainer::Client
84 void OnDataComplete() override {
85 TRACE_EVENT_ASYNC_END0("sky", "DartLibraryLoader::ImportJob", this);
86 loader_->DidCompleteImportJob(this, buffer_);
87 }
88 };
89
90 class DartLibraryLoader::SourceJob : public Job {
91 public:
92 SourceJob(DartLibraryLoader* loader, const std::string& name, Dart_Handle libr ary)
93 : Job(loader, name), library_(loader->dart_state(), library) {
94 TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLibraryLoader::SourceJob", this, "url",
95 name);
96 }
97
98 Dart_PersistentHandle library() const { return library_.value(); }
99
100 private:
101 // DataPipeDrainer::Client
102 void OnDataComplete() override {
103 TRACE_EVENT_ASYNC_END0("sky", "DartLibraryLoader::SourceJob", this);
104 loader_->DidCompleteSourceJob(this, buffer_);
105 }
106
107 DartPersistentValue library_;
108 };
109
110 // A DependencyWatcher represents a request to watch for when a given set of
111 // dependencies (either libraries or parts of libraries) have finished loading.
112 // When the dependencies are satisfied (including transitive dependencies), then
113 // the |callback| will be invoked.
114 class DartLibraryLoader::DependencyWatcher {
115 public:
116 DependencyWatcher(const std::unordered_set<DartDependency*>& dependencies,
117 const base::Closure& callback)
118 : dependencies_(dependencies), callback_(callback) {
119 DCHECK(!dependencies_.empty());
120 }
121
122 bool DidResolveDependency(
123 DartDependency* resolved_dependency,
124 const std::unordered_set<DartDependency*>& new_dependencies) {
125 const auto& it = dependencies_.find(resolved_dependency);
126 if (it == dependencies_.end())
127 return false;
128 dependencies_.erase(it);
129 for (const auto& dependency : new_dependencies)
130 dependencies_.insert(dependency);
131 return dependencies_.empty();
132 }
133
134 const base::Closure& callback() const { return callback_; }
135
136 private:
137 std::unordered_set<DartDependency*> dependencies_;
138 base::Closure callback_;
139 };
140
141 // A WatcherSignaler is responsible for signaling DependencyWatchers when their
142 // dependencies resolve and for calling the DependencyWatcher's callback. We use
143 // a separate object of this task because we want to carefully manage when we
144 // call the callbacks, which can call into us again reentrantly.
145 //
146 // WatcherSignaler is designed to be placed on the stack as a RAII. After its
147 // destructor runs, we might have executed aribitrary script.
148 class DartLibraryLoader::WatcherSignaler {
149 public:
150 WatcherSignaler(DartLibraryLoader& loader,
151 DartDependency* resolved_dependency)
152 : loader_(loader),
153 catcher_(adoptPtr(new DartDependencyCatcher(loader))),
154 resolved_dependency_(resolved_dependency) {}
155
156 ~WatcherSignaler() {
157 std::vector<DependencyWatcher*> completed_watchers;
158 for (const auto& watcher : loader_.dependency_watchers_) {
159 if (watcher->DidResolveDependency(resolved_dependency_,
160 catcher_->dependencies()))
161 completed_watchers.push_back(watcher.get());
162 }
163
164 // Notice that we remove the dependency catcher and extract all the
165 // callbacks before running any of them. We don't want to be re-entered
166 // below the callbacks and end up in an inconsistent state.
167 catcher_.clear();
168 std::vector<base::Closure> callbacks;
169 for (const auto& watcher : completed_watchers) {
170 callbacks.push_back(watcher->callback());
171 EraseUniquePtr(loader_.dependency_watchers_, watcher);
172 }
173
174 // Finally, run all the callbacks while touching only data on the stack.
175 for (const auto& callback : callbacks)
176 callback.Run();
177 }
178
179 private:
180 DartLibraryLoader& loader_;
181 OwnPtr<DartDependencyCatcher> catcher_;
182 DartDependency* resolved_dependency_;
183 };
184
185 DartLibraryLoader::DartLibraryLoader(DartState* dart_state)
186 : dart_state_(dart_state),
187 library_provider_(nullptr),
188 dependency_catcher_(nullptr) {
189 }
190
191 DartLibraryLoader::~DartLibraryLoader() {
192 }
193
194 Dart_Handle DartLibraryLoader::HandleLibraryTag(Dart_LibraryTag tag,
195 Dart_Handle library,
196 Dart_Handle url) {
197 DCHECK(Dart_IsLibrary(library));
198 DCHECK(Dart_IsString(url));
199 if (tag == Dart_kCanonicalizeUrl)
200 return DartState::Current()->library_loader().CanonicalizeURL(library, url);
201 if (tag == Dart_kImportTag) {
202 return DartState::Current()->library_loader().Import(library, url);
203 }
204 if (tag == Dart_kSourceTag) {
205 return DartState::Current()->library_loader().Source(library, url);
206 }
207 DCHECK(false);
208 return Dart_NewApiError("Unknown library tag.");
209 }
210
211 void DartLibraryLoader::WaitForDependencies(
212 const std::unordered_set<DartDependency*>& dependencies,
213 const base::Closure& callback) {
214 if (dependencies.empty())
215 return callback.Run();
216 dependency_watchers_.insert(
217 std::unique_ptr<DependencyWatcher>(
218 new DependencyWatcher(dependencies, callback)));
219 }
220
221 void DartLibraryLoader::LoadLibrary(const std::string& name) {
222 const auto& result = pending_libraries_.insert(std::make_pair(name, nullptr));
223 if (result.second) {
224 // New entry.
225 std::unique_ptr<Job> job = std::unique_ptr<Job>(new ImportJob(this, name));
226 result.first->second = job.get();
227 jobs_.insert(std::move(job));
228 }
229 if (dependency_catcher_)
230 dependency_catcher_->AddDependency(result.first->second);
231 }
232
233 Dart_Handle DartLibraryLoader::Import(Dart_Handle library, Dart_Handle url) {
234 LoadLibrary(StdStringFromDart(url));
235 return Dart_True();
236 }
237
238 Dart_Handle DartLibraryLoader::Source(Dart_Handle library, Dart_Handle url) {
239 std::unique_ptr<Job> job = std::unique_ptr<Job>(
240 new SourceJob(this, StdStringFromDart(url), library));
241 if (dependency_catcher_)
242 dependency_catcher_->AddDependency(job.get());
243 jobs_.insert(std::move(job));
244 return Dart_True();
245 }
246
247 Dart_Handle DartLibraryLoader::CanonicalizeURL(Dart_Handle library,
248 Dart_Handle url) {
249 return library_provider_->CanonicalizeURL(library, url);
250 }
251
252 void DartLibraryLoader::DidCompleteImportJob(
253 ImportJob* job,
254 const std::vector<uint8_t>& buffer) {
255 DartIsolateScope scope(dart_state_->isolate());
256 DartApiScope api_scope;
257
258 WatcherSignaler watcher_signaler(*this, job);
259
260 Dart_Handle result = Dart_LoadLibrary(
261 StdStringToDart(job->name()),
262 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0);
263 if (Dart_IsError(result)) {
264 LOG(ERROR) << "Error Loading " << job->name() << " "
265 << Dart_GetError(result);
266 }
267
268 pending_libraries_.erase(job->name());
269 EraseUniquePtr<Job>(jobs_, job);
270 }
271
272 void DartLibraryLoader::DidCompleteSourceJob(
273 SourceJob* job,
274 const std::vector<uint8_t>& buffer) {
275 DartIsolateScope scope(dart_state_->isolate());
276 DartApiScope api_scope;
277
278 WatcherSignaler watcher_signaler(*this, job);
279
280 Dart_Handle result = Dart_LoadSource(
281 Dart_HandleFromPersistent(job->library()),
282 StdStringToDart(job->name()),
283 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0);
284
285 if (Dart_IsError(result)) {
286 LOG(ERROR) << "Error Loading " << job->name() << " "
287 << Dart_GetError(result);
288 }
289
290 EraseUniquePtr<Job>(jobs_, job);
291 }
292
293 void DartLibraryLoader::DidFailJob(Job* job) {
294 DartIsolateScope scope(dart_state_->isolate());
295 DartApiScope api_scope;
296
297 WatcherSignaler watcher_signaler(*this, job);
298
299 LOG(ERROR) << "Library Load failed: " << job->name();
300 // TODO(eseidel): Call Dart_LibraryHandleError in the SourceJob case?
301
302 EraseUniquePtr<Job>(jobs_, job);
303 }
304
305 } // namespace blink
OLDNEW
« 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