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

Side by Side Diff: sky/engine/core/script/dart_loader.cc

Issue 1202283004: Factor DartLibraryProvider out of DartLoader (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 6 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 | « sky/engine/core/script/dart_loader.h ('k') | sky/engine/core/script/dart_snapshot_loader.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 "sky/engine/core/script/dart_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 "sky/engine/core/script/dart_dependency_catcher.h"
11 #include "sky/engine/core/script/dom_dart_state.h"
12 #include "sky/engine/platform/fetcher/MojoFetcher.h"
13 #include "sky/engine/platform/weborigin/KURL.h"
14 #include "sky/engine/tonic/dart_api_scope.h"
15 #include "sky/engine/tonic/dart_converter.h"
16 #include "sky/engine/tonic/dart_error.h"
17 #include "sky/engine/tonic/dart_isolate_scope.h"
18 #include "sky/engine/wtf/MainThread.h"
19
20 using mojo::common::DataPipeDrainer;
21
22 namespace blink {
23 namespace {
24
25 Dart_Handle CanonicalizeURL(DartState* state,
26 Dart_Handle library,
27 Dart_Handle url) {
28 String string = StringFromDart(url);
29 if (string.startsWith("dart:"))
30 return url;
31 // TODO(dart): Figure out how 'package:' should work in sky.
32 if (string.startsWith("package:")) {
33 string.replace("package:", "/packages/");
34 }
35 String library_url_string = StringFromDart(Dart_LibraryUrl(library));
36 KURL library_url = KURL(ParsedURLString, library_url_string);
37 KURL resolved_url = KURL(library_url, string);
38 return StringToDart(state, resolved_url.string());
39 }
40
41 } // namespace
42
43 // A DartLoader::Job represents a network load. It fetches data from the network
44 // and buffers the data in Vector. To cancel the job, delete this object.
45 class DartLoader::Job : public DartDependency,
46 public MojoFetcher::Client,
47 public DataPipeDrainer::Client {
48 public:
49 Job(DartLoader* loader, const KURL& url, mojo::URLResponsePtr response)
50 : loader_(loader), url_(url)
51 {
52 if (!response) {
53 fetcher_ = adoptPtr(new MojoFetcher(this, url));
54 } else {
55 OnReceivedResponse(response.Pass());
56 }
57 }
58
59 const KURL& url() const { return url_; }
60
61 protected:
62 DartLoader* loader_;
63 // TODO(abarth): Should we be using SharedBuffer to buffer the data?
64 Vector<uint8_t> buffer_;
65
66 private:
67 // MojoFetcher::Client
68 void OnReceivedResponse(mojo::URLResponsePtr response) override {
69 if (response->status_code != 200) {
70 loader_->DidFailJob(this);
71 return;
72 }
73 drainer_ = adoptPtr(new DataPipeDrainer(this, response->body.Pass()));
74 }
75
76 // DataPipeDrainer::Client
77 void OnDataAvailable(const void* data, size_t num_bytes) override {
78 buffer_.append(static_cast<const uint8_t*>(data), num_bytes);
79 }
80 // Subclasses must implement OnDataComplete.
81
82 KURL url_;
83 OwnPtr<MojoFetcher> fetcher_;
84 OwnPtr<DataPipeDrainer> drainer_;
85 };
86
87 class DartLoader::ImportJob : public Job {
88 public:
89 ImportJob(DartLoader* loader, const KURL& url, mojo::URLResponsePtr response = nullptr)
90 : Job(loader, url, response.Pass()) {
91 TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLoader::ImportJob", this,
92 "url", url.string().ascii().toStdString());
93 }
94
95 private:
96 // DataPipeDrainer::Client
97 void OnDataComplete() override {
98 TRACE_EVENT_ASYNC_END0("sky", "DartLoader::ImportJob", this);
99 loader_->DidCompleteImportJob(this, buffer_);
100 }
101 };
102
103 class DartLoader::SourceJob : public Job {
104 public:
105 SourceJob(DartLoader* loader, const KURL& url, Dart_Handle library)
106 : Job(loader, url, nullptr), library_(loader->dart_state(), library) {
107 TRACE_EVENT_ASYNC_BEGIN1("sky", "DartLoader::SourceJob", this,
108 "url", url.string().ascii().toStdString());
109 }
110
111 Dart_PersistentHandle library() const { return library_.value(); }
112
113 private:
114 // DataPipeDrainer::Client
115 void OnDataComplete() override {
116 TRACE_EVENT_ASYNC_END0("sky", "DartLoader::SourceJob", this);
117 loader_->DidCompleteSourceJob(this, buffer_);
118 }
119
120 DartPersistentValue library_;
121 };
122
123 // A DependencyWatcher represents a request to watch for when a given set of
124 // dependencies (either libraries or parts of libraries) have finished loading.
125 // When the dependencies are satisfied (including transitive dependencies), then
126 // the |callback| will be invoked.
127 class DartLoader::DependencyWatcher {
128 public:
129 DependencyWatcher(const HashSet<DartDependency*>& dependencies,
130 const base::Closure& callback)
131 : dependencies_(dependencies), callback_(callback) {
132 DCHECK(!dependencies_.isEmpty());
133 }
134
135 bool DidResolveDependency(DartDependency* resolved_dependency,
136 const HashSet<DartDependency*>& new_dependencies) {
137 const auto& it = dependencies_.find(resolved_dependency);
138 if (it == dependencies_.end())
139 return false;
140 dependencies_.remove(it);
141 for (const auto& dependency : new_dependencies)
142 dependencies_.add(dependency);
143 return dependencies_.isEmpty();
144 }
145
146 const base::Closure& callback() const { return callback_; }
147
148 private:
149 HashSet<DartDependency*> dependencies_;
150 base::Closure callback_;
151 };
152
153 // A WatcherSignaler is responsible for signaling DependencyWatchers when their
154 // dependencies resolve and for calling the DependencyWatcher's callback. We use
155 // a separate object of this task because we want to carefully manage when we
156 // call the callbacks, which can call into us again reentrantly.
157 //
158 // WatcherSignaler is designed to be placed on the stack as a RAII. After its
159 // destructor runs, we might have executed aribitrary script.
160 class DartLoader::WatcherSignaler {
161 public:
162 WatcherSignaler(DartLoader& loader, DartDependency* resolved_dependency)
163 : loader_(loader),
164 catcher_(adoptPtr(new DartDependencyCatcher(loader))),
165 resolved_dependency_(resolved_dependency) {}
166
167 ~WatcherSignaler() {
168 Vector<DependencyWatcher*> completed_watchers;
169 for (const auto& watcher : loader_.dependency_watchers_) {
170 if (watcher->DidResolveDependency(resolved_dependency_,
171 catcher_->dependencies()))
172 completed_watchers.append(watcher.get());
173 }
174
175 // Notice that we remove the dependency catcher and extract all the
176 // callbacks before running any of them. We don't want to be re-entered
177 // below the callbacks and end up in an inconsistent state.
178 catcher_.clear();
179 Vector<base::Closure> callbacks;
180 for (const auto& watcher : completed_watchers) {
181 callbacks.append(watcher->callback());
182 loader_.dependency_watchers_.remove(watcher);
183 }
184
185 // Finally, run all the callbacks while touching only data on the stack.
186 for (const auto& callback : callbacks)
187 callback.Run();
188 }
189
190 private:
191 DartLoader& loader_;
192 OwnPtr<DartDependencyCatcher> catcher_;
193 DartDependency* resolved_dependency_;
194 };
195
196 DartLoader::DartLoader(DartState* dart_state)
197 : dart_state_(dart_state->GetWeakPtr()),
198 dependency_catcher_(nullptr) {
199 }
200
201 DartLoader::~DartLoader() {
202 }
203
204 Dart_Handle DartLoader::HandleLibraryTag(Dart_LibraryTag tag,
205 Dart_Handle library,
206 Dart_Handle url) {
207 DCHECK(Dart_IsLibrary(library));
208 DCHECK(Dart_IsString(url));
209 if (tag == Dart_kCanonicalizeUrl)
210 return CanonicalizeURL(DartState::Current(), library, url);
211 if (tag == Dart_kImportTag) {
212 CHECK(WTF::isMainThread());
213 return DOMDartState::Current()->loader().Import(library, url);
214 }
215 if (tag == Dart_kSourceTag) {
216 CHECK(WTF::isMainThread());
217 return DOMDartState::Current()->loader().Source(library, url);
218 }
219 DCHECK(false);
220 return Dart_NewApiError("Unknown library tag.");
221 }
222
223 void DartLoader::WaitForDependencies(
224 const HashSet<DartDependency*>& dependencies,
225 const base::Closure& callback) {
226 if (dependencies.isEmpty())
227 return callback.Run();
228 dependency_watchers_.add(
229 adoptPtr(new DependencyWatcher(dependencies, callback)));
230 }
231
232 void DartLoader::LoadLibrary(const KURL& url, mojo::URLResponsePtr response) {
233 if (response && response->status_code >= 400) {
234 LOG(ERROR) << url.string().utf8().data()
235 << " failed with " << response->status_code;
236 }
237
238 const auto& result = pending_libraries_.add(url.string(), nullptr);
239 if (result.isNewEntry) {
240 OwnPtr<Job> job = adoptPtr(new ImportJob(this, url));
241 result.storedValue->value = job.get();
242 jobs_.add(job.release());
243 }
244 if (dependency_catcher_)
245 dependency_catcher_->AddDependency(result.storedValue->value);
246 }
247
248 Dart_Handle DartLoader::Import(Dart_Handle library, Dart_Handle url) {
249 LoadLibrary(KURL(ParsedURLString, StringFromDart(url)));
250 return Dart_True();
251 }
252
253 Dart_Handle DartLoader::Source(Dart_Handle library, Dart_Handle url) {
254 KURL parsed_url(ParsedURLString, StringFromDart(url));
255 OwnPtr<Job> job = adoptPtr(new SourceJob(this, parsed_url, library));
256 if (dependency_catcher_)
257 dependency_catcher_->AddDependency(job.get());
258 jobs_.add(job.release());
259 return Dart_True();
260 }
261
262 void DartLoader::DidCompleteImportJob(ImportJob* job,
263 const Vector<uint8_t>& buffer) {
264 DCHECK(dart_state_);
265 DartIsolateScope scope(dart_state_->isolate());
266 DartApiScope api_scope;
267
268 WatcherSignaler watcher_signaler(*this, job);
269
270 String url_string = job->url().string();
271 LogIfError(Dart_LoadLibrary(
272 StringToDart(dart_state_.get(), url_string),
273 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0));
274
275 pending_libraries_.remove(url_string);
276 jobs_.remove(job);
277 }
278
279 void DartLoader::DidCompleteSourceJob(SourceJob* job,
280 const Vector<uint8_t>& buffer) {
281 DCHECK(dart_state_);
282 DartIsolateScope scope(dart_state_->isolate());
283 DartApiScope api_scope;
284
285 WatcherSignaler watcher_signaler(*this, job);
286
287 LogIfError(Dart_LoadSource(
288 Dart_HandleFromPersistent(job->library()),
289 StringToDart(dart_state_.get(), job->url().string()),
290 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0));
291
292 jobs_.remove(job);
293 }
294
295 void DartLoader::DidFailJob(Job* job) {
296 DCHECK(dart_state_);
297 DartIsolateScope scope(dart_state_->isolate());
298 DartApiScope api_scope;
299
300 WatcherSignaler watcher_signaler(*this, job);
301
302 LOG(ERROR) << "Library Load failed: " << job->url().string().utf8().data();
303 // TODO(eseidel): Call Dart_LibraryHandleError in the SourceJob case?
304
305 jobs_.remove(job);
306 }
307
308 } // namespace blink
OLDNEW
« no previous file with comments | « sky/engine/core/script/dart_loader.h ('k') | sky/engine/core/script/dart_snapshot_loader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698