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

Side by Side Diff: third_party/WebKit/Source/core/dom/ModuleMap.cpp

Issue 2555653002: [WIP Prototype] ES6 https://html.spec.whatwg.org/#fetch-a-single-module-script implementation (Closed)
Patch Set: WIP: ModuleLoaderClient && crafts to make it work even if notifyFinished adds another ModuleLoaderC… Created 4 years 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 2016 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 "bindings/core/v8/V8PerIsolateData.h"
6 #include "core/dom/ModuleMap.h"
7 #include "core/fetch/ResourceFetcher.h"
8 #include "core/frame/LocalFrame.h"
9 #include "wtf/AutoReset.h"
10 #include <v8.h>
11
12 namespace blink {
13
14 LocalFrame* g_localFrame = nullptr;
15
16 ModuleLoaderClient::~ModuleLoaderClient()
17 {
18 }
19
20 void ModuleLoaderClient::catchUpToLatestStateIfNeeded(ModuleLoaderState latetstS tate)
21 {
22 if (m_state == State::Fetched || m_state == State::Failed)
23 return;
24 if (latestState == State::Fetched || latestState == State::Failed) {
25 notifyFinished();
26 m_state = latestState;
27 }
28 }
29
30 ModuleLoader::ModuleLoader(const KURL& url)
31 : m_url(url), m_state(State::Initial) {}
32
33 ModuleLoader::~ModuleLoader() {}
34
35 void ModuleLoader::advanceState(ModuleLoader::State newState) {
36 switch (m_state) {
37 case State::Initial:
38 DCHECK_EQ(newState, State::Fetching);
39 break;
40 case State::Fetching:
41 DCHECK(newState == State::Fetched || newState == State::Failed);
42 break;
43
44 case State::Fetched:
45 case State::Failed:
46 default:
47 NOTREACHED();
48 }
49 m_state = newState;
50
51 notifyAndFlushPendingClients();
52 }
53
54 void ModuleLoader::fetch(ResourceFetcher* fetcher) {
55 // Step 4. Set moduleMap[url] to "fetching".
56 advanceState(State::Fetching);
57
58 // Step 5. Let request be a new request whose url is url, destination is
59 // destination, type is "script", mode is "cors", credentials mode is
60 // credentials mode, cryptographic nonce metadata is cryptographic nonce,
61 // parser metadata is parser state, referrer is referrer, and client is fetch
62 // client settings object.
63 FetchRequest request(ResourceRequest(m_url), "module");
64 // request.setDefer(FetchRequest::LazyLoad); //? always async -> defer?
65 Member<ScriptResource> resource = ScriptResource::fetch(request, fetcher);
66 setResource(resource);
67
68 // Step 6. If the caller specified custom steps to perform the fetch, perform
69 // them on request, setting the is top-level flag if the top-level module
70 // fetch flag is set. Return from this algorithm, and when the custom perform
71 // the fetch steps complete with response response, run the remaining steps.
72 // Otherwise, fetch request. Return from this algorithm, and run the remaining
73 // steps as part of the fetch's process response for the response response.
74 // Note: response is always CORS-same-origin.
75
76 // TODO(kouhei): I don't know what Step 6 means. ScriptLoader seems to ignore
77 // the step?
78 }
79
80 void ModuleLoader::notifyFinished(Resource*) {
81 printf("notifyFinished!\n");
82
83 // Step 7. If any of the following conditions are met, set moduleMap[url] to
84 // null, asynchronously complete this algorithm with null, and abort these
85 // steps:
86 // - response's type is "error"
87 // - response's status is not an ok status
88 // The result of extracting a MIME type from response's header list (ignoring
89 // parameters) is not a JavaScript MIME type
90 // Note: For historical reasons, fetching a classic script does not include
91 // MIME type checking. In contrast, module scripts will fail to load if they
92 // are not of a correct MIME type.
93 if (resource()->errorOccurred()) {
94 advanceState(State::Failed);
95 return;
96 }
97
98 // Step 8. Let source text be the result of UTF-8 decoding response's body.
99 String script = resource()->script();
100 printf("fetched script: %s\n", script.utf8().data());
101
102 // Step 9. Let module script be the result of creating a module script given
103 // source text, module map settings object, response's url, cryptographic
104 // nonce, parser state, and credentials mode.
105 v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
106 v8::HandleScope handleScope(isolate);
107
108 ScriptState* scriptState = ScriptState::forMainWorld(g_localFrame);
109 DCHECK(scriptState);
110
111 // ??? : I'm not sure why this requres scriptState to run compile step.
112 ScriptState::Scope scope(scriptState);
113 m_scriptModule = ScriptModule::compile(isolate, script, m_url.getString());
114
115 advanceState(State::Fetched);
116 }
117
118 void ModuleLoader::addClient(ModuleLoaderClient* newClient) {
119 DCHECK(!m_pendingClients.contains(newClient));
120 DCHECK(!m_clients.contains(newClient));
121 m_pendingClients.add(newClient);
122
123 notifyAndFlushPendingClients();
124 }
125
126 void ModuleLoader::notifyAndFlushPendingClients(FlushType flushType) {
127 if (m_insidePendingClientsLoop) {
128 // This notifyAndFlushPendingClients call was reentrant.
129 // Defer to first notifyAndFlushPendingClients to do the job.
130 return;
131 }
132
133 AutoReset<bool> forbidClientModificationScope(&m_insideAddPendingClientsLoop, true);
134
135 DCHECK(m_pendingClients.isEmpty());
136 if (flushType == FlushType::MayHaveAdvancedState)
137 m_pendingClients.swap(m_clients);
138
139 while (!m_pendingClients.isEmpty()) {
140 // Iterate on copy as m_pendingClients may be added in the notification loop .
141 HeapHashSet<Member<ModuleLoaderClient>> clientsToCatchUp;
142 clientsToCatchUp.swap(m_pendingClients);
143 for (const auto& client : clientsToCatchUp) {
144 client->catchUpToLatestStateIfNeeded(m_state);
145 }
146
147 // Caught up clients do not have any notifications to receive after the
148 // load is finished.
149 if (isFinished())
150 continue;
151
152 while (clientsToCatchUp.isEmpty())
153 m_clients.add(clientsToCatchUp.takeAny());
154 }
155 }
156
157 DEFINE_TRACE(ModuleLoader) {
158 visitor->trace(m_clients);
159 ResourceOwner<ScriptResource>::trace(visitor);
160 }
161
162 ModuleMap::ModuleMap(LocalFrame* frame, ResourceFetcher* fetcher)
163 : m_frame(frame), m_fetcher(fetcher) {
164 DCHECK(m_frame);
165 DCHECK(m_fetcher);
166 }
167
168 void ModuleMap::fetch(const KURL& url, ModuleLoaderClient* client) {
169 g_localFrame = m_frame; // TODO(kouhei): AAAAAAAArrrrrgghhh
170 printf("ModuleMap::fetch(%s)\n", url.getString().utf8().data());
171
172 MapImpl::AddResult result = m_map.set(url, nullptr);
173 Member<ModuleLoader>& loaderEntry = result.storedValue->value;
174 if (!result.isNewEntry) {
175 printf("not new entry\n");
176
177 // - If moduleMap[url] is "fetching", wait (in parallel) until that
178 // loaderEntry's value changes, then proceed to the next step.
179 // - If moduleMap[url] exists, asynchronously complete this algorithm
180 // with moduleMap[url], and abort these steps.
181 loaderEntry->addClient(client);
182 return;
183 }
184
185 ModuleLoader* loader = ModuleLoader::create(url);
186 loader->fetch(m_fetcher.get());
187
188 // Step 10. Set moduleMap[url] to module script, and asynchronously complete
189 // this algorithm with module script.
190 loaderEntry = loader;
191 loaderEntry->addClient(client);
192 }
193
194 DEFINE_TRACE(ModuleMap) {
195 visitor->trace(m_map);
196 visitor->trace(m_frame);
197 visitor->trace(m_fetcher);
198 }
199
200 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698