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

Side by Side Diff: third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp

Issue 2555653002: [WIP Prototype] ES6 https://html.spec.whatwg.org/#fetch-a-single-module-script implementation (Closed)
Patch Set: ModuleScriptLoaderTest Created 3 years, 11 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
OLDNEW
(Empty)
1 // Copyright 2017 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 "core/loader/modulescript/ModuleTreeLinker.h"
6
7 #include "bindings/core/v8/ModuleController.h"
8 #include "bindings/core/v8/ScriptModule.h"
9 #include "core/dom/ModuleScript.h"
10 #include "core/loader/modulescript/ModuleTreeLinkerRegistry.h"
11
12 namespace blink {
13
14 ModuleTreeLinker::ModuleTreeLinker(Modulator* modulator,
15 ModuleTreeLinkerRegistry* registry,
16 ModuleTreeClient* client)
17 : m_modulator(modulator), m_registry(registry), m_client(client) {
18 DCHECK(modulator);
19 DCHECK(registry);
20 DCHECK(client);
21 }
22
23 DEFINE_TRACE(ModuleTreeLinker) {
24 visitor->trace(m_modulator);
25 visitor->trace(m_registry);
26 visitor->trace(m_client);
27 visitor->trace(m_moduleScript);
28 visitor->trace(m_dependencyClients);
29 SingleModuleClient::trace(visitor);
30 }
31
32 void ModuleTreeLinker::advanceState(State newState) {
33 printf("mtf %p adv state: %d\n", this, newState);
34 switch (m_state) {
35 case State::Initial:
36 DCHECK_EQ(newState, State::FetchingSelf);
37 break;
38 case State::FetchingSelf:
39 DCHECK(newState == State::FetchingDependencies ||
40 newState == State::Finished);
41 break;
42 case State::FetchingDependencies:
43 DCHECK(newState == State::Instantiating || newState == State::Finished);
44 break;
45 case State::Instantiating:
46 DCHECK_EQ(newState, State::Finished);
47 break;
48 case State::Finished:
49 NOTREACHED();
50 break;
51 default:
52 NOTREACHED();
53 }
54
55 m_state = newState;
56
57 if (m_state == State::Finished) {
58 m_registry->releaseFinishedFetcher(this);
59 m_client->notifyFinishedModuleTree(m_moduleScript);
60 }
61 }
62
63 ModuleTreeLinker* ModuleTreeLinker::fetch(const KURL& url,
64 const KURL& baseURL,
65 Modulator* modulator,
66 ModuleTreeLinkerRegistry* registry,
67 ModuleTreeClient* client) {
68 ModuleTreeLinker* fetcher = new ModuleTreeLinker(modulator, registry, client);
69 fetcher->fetchSelf(url, baseURL);
70 return fetcher;
71 }
72
73 void ModuleTreeLinker::fetchSelf(const KURL& url, const KURL& baseURL) {
74 // https://html.spec.whatwg.org/multipage/webappapis.html#internal-module-scri pt-graph-fetching-procedure
75
76 // Step 1. Fetch a single module script given url, fetch client settings
77 // object, destination, cryptographic nonce, parser state, credentials mode,
78 // module map settings object, referrer, and the top-level module fetch flag.
79 // If the caller of this algorithm specified custom perform the fetch steps,
80 // pass those along while fetching a single module script.
81 // Step 2. Return from this algorithm, and run the following steps when
82 // fetching a single module script asynchronously completes with result.
83 advanceState(State::FetchingSelf);
84 m_modulator->fetchSingle(url, baseURL, this);
85 }
86
87 class ModuleTreeLinker::DependencyModuleClient
88 : public GarbageCollectedFinalized<
89 ModuleTreeLinker::DependencyModuleClient>,
90 public ModuleTreeClient {
91 USING_GARBAGE_COLLECTED_MIXIN(ModuleTreeLinker::DependencyModuleClient);
92
93 public:
94 static DependencyModuleClient* create(ModuleTreeLinker* moduleTreeLinkers) {
95 return new DependencyModuleClient(moduleTreeLinkers);
96 }
97 virtual ~DependencyModuleClient() = default;
98
99 DEFINE_INLINE_TRACE() {
100 visitor->trace(m_moduleTreeLinkers);
101 ModuleTreeClient::trace(visitor);
102 }
103
104 private:
105 DependencyModuleClient(ModuleTreeLinker* moduleTreeLinkers)
106 : m_moduleTreeLinkers(moduleTreeLinkers) {
107 DCHECK(moduleTreeLinkers);
108 }
109
110 // Implements ModuleTreeClient
111 void notifyFinishedModuleTree(ModuleScript*) override;
112
113 Member<ModuleTreeLinker> m_moduleTreeLinkers;
114 };
115
116 void ModuleTreeLinker::notifyFinishedSingleModule(ModuleScript* moduleScript) {
117 // https://html.spec.whatwg.org/multipage/webappapis.html#internal-module-scri pt-graph-fetching-procedure
118
119 // Step 3. If result is null, asynchronously complete this algorithm with null
120 // and abort these steps.
121 if (!moduleScript) {
122 advanceState(State::Finished);
123 return;
124 }
125
126 // Step 4. Otherwise, result is a module script. Fetch the descendants of
127 // result given destination and an ancestor list obtained by appending url to
128 // ancestor list. Wait for fetching the descendants of a module script to
129 // asynchronously complete with descendants result before proceeding to the
130 // next step.
131 m_moduleScript = moduleScript;
132 fetchDescendants();
133
134 // Note: Step 5- continues in instantiate() method, after
135 // "fetch the descendants of a module script" procedure completes.
136 }
137
138 void ModuleTreeLinker::fetchDescendants() {
139 DCHECK(m_moduleScript);
140 advanceState(State::FetchingDependencies);
141
142 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-the-descendant s-of-a-module-script
143
144 // Step 1. Let record be module script's module record.
145 ScriptModule record = m_moduleScript->record();
146
147 // Step 2. If record.[[RequestedModules]] is empty, asynchronously complete
148 // this algorithm with module script.
149 Vector<String> moduleRequests =
150 m_modulator->moduleController()->moduleRequestsFromScriptModule(record);
151 if (moduleRequests.isEmpty()) {
152 // Continue to instantiate() to process "internal module script graph
153 // fetching procedure" Step 5-.
154 instantiate();
155 return;
156 }
157
158 // Step 3. Let urls be a new empty list.
159 Vector<KURL> urls;
160
161 // Step 4. For each string requested of record.[[RequestedModules]],
162 for (const auto& moduleRequest : moduleRequests) {
163 // Step 4.1. Let url be the result of resolving a module specifier given
164 // module script and requested.
165 KURL url = m_modulator->resolveModuleSpecifier(moduleRequest,
166 m_moduleScript->baseURL());
167 printf("resolveModuleSpecifier \"%s\" -> \"%s\"\n",
168 moduleRequest.utf8().data(), url.getString().utf8().data());
169
170 // Step 4.2. If the result is error: ...
171 if (url.isNull()) {
172 // Let error be a new TypeError exception.
173 // Report the exception error for module script.
174 // Abort this algorithm, and asynchronously complete it with null.
175 m_moduleScript = nullptr;
176 advanceState(State::Finished);
177 }
178
179 // Step 4.3. Otherwise, if ancestor list does not contain url, append url to
yhirano 2017/01/06 07:27:01 Where is the ancestor list? Is it guaranteed that
kouhei (in TOK) 2017/01/11 01:41:58 Implemented "ancestor list" algorithm.
kouhei (in TOK) 2017/01/11 02:30:17 Sorry this was still incomplete. Fixing.
180 // urls.
181 DCHECK(url.isValid());
182 urls.push_back(url);
183 }
184
185 // Step 5. For each url in urls, perform the internal module script graph
186 // fetching procedure given url, module script's credentials mode, module
187 // script's cryptographic nonce, module script's parser state, destination,
188 // module script's settings object, module script's settings object, ancestor
189 // list, module script's base URL, and with the top-level module fetch flag
190 // unset. If the caller of this algorithm specified custom perform the fetch
191 // steps, pass those along while performing the internal module script graph
192 // fetching procedure.
193 DCHECK_EQ(m_numIncompleteDescendants, 0u);
194 m_numIncompleteDescendants = urls.size();
195 for (const KURL& url : urls) {
196 DependencyModuleClient* dependencyClient =
197 DependencyModuleClient::create(this);
198 m_dependencyClients.add(dependencyClient);
199 m_modulator->fetchTree(url, m_moduleScript->baseURL(), dependencyClient);
200 }
201
202 // Asynchronously continue processing after notifyOneDescendantFinished() is
203 // called m_numIncompleteDescendants times.
204 DCHECK(m_numIncompleteDescendants);
205 }
206
207 void ModuleTreeLinker::DependencyModuleClient::notifyFinishedModuleTree(
208 ModuleScript* moduleScript) {
209 bool wasSuccess = !!moduleScript;
210 m_moduleTreeLinkers->notifyOneDescendantFinished(wasSuccess);
211 }
212
213 void ModuleTreeLinker::notifyOneDescendantFinished(bool wasSuccess) {
214 if (m_state == State::Finished) {
215 // We may reach here if one of the descendant failed to load, and the other
216 // descendants fetches were in flight.
217 DCHECK(!m_moduleScript);
218 return;
219 }
220
221 DCHECK(m_state == State::FetchingDependencies);
222
223 DCHECK_GT(m_numIncompleteDescendants, 0u);
224 --m_numIncompleteDescendants;
225
226 if (!wasSuccess) {
227 m_moduleScript = nullptr;
228 advanceState(State::Finished);
229 return;
230 }
231
232 DCHECK(m_moduleScript);
233 printf("remaining desc %zu\n", m_numIncompleteDescendants);
234 if (!m_numIncompleteDescendants)
235 instantiate();
236 }
237
238 void ModuleTreeLinker::instantiate() {
239 DCHECK(m_moduleScript);
240 // https://html.spec.whatwg.org/multipage/webappapis.html#internal-module-scri pt-graph-fetching-procedure
241
242 // Step 5. Let record be result's module record.
243 ScriptModule record = m_moduleScript->record();
244
245 // Step 6. Let instantiationStatus be record.ModuleDeclarationInstantiation().
246 bool instantiateSuccess =
247 m_modulator->moduleController()->instantiateModule(record);
248 DCHECK(instantiateSuccess); // TODO(kouhei)
249 m_moduleScript->updateStateAfterInstantiation(ScriptValue());
250 InstantiationState instantiationStatus = m_moduleScript->instantiationState();
251
252 // Step 7. For each module script script in result's uninstantiated inclusive
253 // descendant module scripts, perform the following steps:
254 HeapHashSet<Member<ModuleScript>> uninstantiatedSet =
yhirano 2017/01/06 07:27:01 Is there an ordering issue? "set" in the spec look
kouhei (in TOK) 2017/01/11 01:41:58 No. Added a spec note.
255 uninstantiatedInclusiveDescendants();
256 for (const auto& descendant : uninstantiatedSet) {
257 if (instantiationStatus == InstantiationState::Errored) {
258 // Step 7.1. If instantiationStatus is an abrupt completion, then set
259 // script's
260 // instantiation state to "errored", its instantiation error to
261 // instantiationStatus.[[Value]], and its module record to null.
262 descendant->propagateUpstreamError(m_moduleScript->instantiationError());
263 } else {
264 // Step 7.2. Otherwise, set script's instantiation state to
265 // "instantiated".
266 descendant->propagateUpstreamSuccess();
267 }
268 }
269
270 // Step 8. Asynchronously complete this algorithm with descendants result.
271 advanceState(State::Finished);
272 }
273
274 HeapHashSet<Member<ModuleScript>>
275 ModuleTreeLinker::uninstantiatedInclusiveDescendants() {
276 // https://html.spec.whatwg.org/multipage/webappapis.html#uninstantiated-inclu sive-descendant-module-scripts
277 // Step 1. Let moduleMap be script's settings object's module map.
278 // Note: Modulator is our "settings object".
279 // Note: We won't reference the ModuleMap directly here to aid testing.
280
281 // Step 2. Let stack be the stack « script ».
282 HeapDeque<Member<ModuleScript>> stack;
283 stack.prepend(m_moduleScript);
284
285 // Step 3. Let inclusive descendants be an empty set.
286 HeapHashSet<Member<ModuleScript>> inclusiveDescendants;
287
288 // Step 4. While stack is not empty:
289 while (!stack.isEmpty()) {
290 // Step 4.1. Let current the result of popping from stack.
291 ModuleScript* current = stack.takeFirst();
292
293 // Step 4.2. If inclusive descendants and stack both do not contain current,
294 // then:
295 if (inclusiveDescendants.contains(current))
296 continue;
297 if (std::find(stack.begin(), stack.end(), current) == stack.end())
yhirano 2017/01/06 07:27:01 !=
kouhei (in TOK) 2017/01/11 01:41:58 Done.
298 continue;
299
300 // Step 4.2.1. Append current to inclusive descendants.
301 inclusiveDescendants.add(current);
302
303 // TODO(kouhei): This implementation is a direct transliteration of the
304 // spec. Omit intermediate vectors at the least.
305
306 // Step 4.2.2. Let child specifiers be the value of current's module
307 // record's [[RequestedModules]] internal slot.
308 Vector<String> childSpecifiers =
309 m_modulator->moduleController()->moduleRequestsFromScriptModule(
310 current->record());
311 // Step 4.2.3. Let child URLs be the list obtained by calling resolve a
312 // module specifier once for each item of child specifiers, given current
313 // and that item. Omit any failures.
314 Vector<KURL> childURLs;
315 for (const auto& childSpecifier : childSpecifiers) {
316 KURL childURL = m_modulator->resolveModuleSpecifier(childSpecifier,
317 current->baseURL());
318 if (childURL.isValid())
319 childURLs.push_back(childURL);
320 }
321 // Step 4.2.4. Let child modules be the list obtained by getting each value
322 // in moduleMap whose key is given by an item of child URLs.
323 HeapVector<Member<ModuleScript>> childModules;
324 for (const auto& childURL : childURLs) {
325 ModuleScript* moduleScript =
326 m_modulator->retrieveFetchedModuleScript(childURL);
327 childModules.push_back(moduleScript);
328 }
329 // Step 4.2.5. For each s in child modules that is not contained by
330 // inclusive descendants, push s onto stack.
331 for (const auto& s : childModules) {
332 if (!inclusiveDescendants.contains(s))
333 stack.prepend(s);
334 }
335 }
336
337 // Step 5. Return a set containing all items of inclusive descendants whose
338 // instantiation state is "uninstantiated".
339 HeapHashSet<Member<ModuleScript>> uninstantiatedSet;
340 for (const auto& script : inclusiveDescendants) {
341 if (script->instantiationState() == InstantiationState::Uninstantiated)
342 uninstantiatedSet.add(script);
343 }
344 return uninstantiatedSet;
345 }
346
347 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698