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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/dom/ModuleMap.cpp
diff --git a/third_party/WebKit/Source/core/dom/ModuleMap.cpp b/third_party/WebKit/Source/core/dom/ModuleMap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3773b82cbae66e02d72a7d36df7158f505252472
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/ModuleMap.cpp
@@ -0,0 +1,200 @@
+// Copyright 2016 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 "bindings/core/v8/V8PerIsolateData.h"
+#include "core/dom/ModuleMap.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/frame/LocalFrame.h"
+#include "wtf/AutoReset.h"
+#include <v8.h>
+
+namespace blink {
+
+LocalFrame* g_localFrame = nullptr;
+
+ModuleLoaderClient::~ModuleLoaderClient()
+{
+}
+
+void ModuleLoaderClient::catchUpToLatestStateIfNeeded(ModuleLoaderState latetstState)
+{
+ if (m_state == State::Fetched || m_state == State::Failed)
+ return;
+ if (latestState == State::Fetched || latestState == State::Failed) {
+ notifyFinished();
+ m_state = latestState;
+ }
+}
+
+ModuleLoader::ModuleLoader(const KURL& url)
+ : m_url(url), m_state(State::Initial) {}
+
+ModuleLoader::~ModuleLoader() {}
+
+void ModuleLoader::advanceState(ModuleLoader::State newState) {
+ switch (m_state) {
+ case State::Initial:
+ DCHECK_EQ(newState, State::Fetching);
+ break;
+ case State::Fetching:
+ DCHECK(newState == State::Fetched || newState == State::Failed);
+ break;
+
+ case State::Fetched:
+ case State::Failed:
+ default:
+ NOTREACHED();
+ }
+ m_state = newState;
+
+ notifyAndFlushPendingClients();
+}
+
+void ModuleLoader::fetch(ResourceFetcher* fetcher) {
+ // Step 4. Set moduleMap[url] to "fetching".
+ advanceState(State::Fetching);
+
+ // Step 5. Let request be a new request whose url is url, destination is
+ // destination, type is "script", mode is "cors", credentials mode is
+ // credentials mode, cryptographic nonce metadata is cryptographic nonce,
+ // parser metadata is parser state, referrer is referrer, and client is fetch
+ // client settings object.
+ FetchRequest request(ResourceRequest(m_url), "module");
+ // request.setDefer(FetchRequest::LazyLoad); //? always async -> defer?
+ Member<ScriptResource> resource = ScriptResource::fetch(request, fetcher);
+ setResource(resource);
+
+ // Step 6. If the caller specified custom steps to perform the fetch, perform
+ // them on request, setting the is top-level flag if the top-level module
+ // fetch flag is set. Return from this algorithm, and when the custom perform
+ // the fetch steps complete with response response, run the remaining steps.
+ // Otherwise, fetch request. Return from this algorithm, and run the remaining
+ // steps as part of the fetch's process response for the response response.
+ // Note: response is always CORS-same-origin.
+
+ // TODO(kouhei): I don't know what Step 6 means. ScriptLoader seems to ignore
+ // the step?
+}
+
+void ModuleLoader::notifyFinished(Resource*) {
+ printf("notifyFinished!\n");
+
+ // Step 7. If any of the following conditions are met, set moduleMap[url] to
+ // null, asynchronously complete this algorithm with null, and abort these
+ // steps:
+ // - response's type is "error"
+ // - response's status is not an ok status
+ // The result of extracting a MIME type from response's header list (ignoring
+ // parameters) is not a JavaScript MIME type
+ // Note: For historical reasons, fetching a classic script does not include
+ // MIME type checking. In contrast, module scripts will fail to load if they
+ // are not of a correct MIME type.
+ if (resource()->errorOccurred()) {
+ advanceState(State::Failed);
+ return;
+ }
+
+ // Step 8. Let source text be the result of UTF-8 decoding response's body.
+ String script = resource()->script();
+ printf("fetched script: %s\n", script.utf8().data());
+
+ // Step 9. Let module script be the result of creating a module script given
+ // source text, module map settings object, response's url, cryptographic
+ // nonce, parser state, and credentials mode.
+ v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
+ v8::HandleScope handleScope(isolate);
+
+ ScriptState* scriptState = ScriptState::forMainWorld(g_localFrame);
+ DCHECK(scriptState);
+
+ // ??? : I'm not sure why this requres scriptState to run compile step.
+ ScriptState::Scope scope(scriptState);
+ m_scriptModule = ScriptModule::compile(isolate, script, m_url.getString());
+
+ advanceState(State::Fetched);
+}
+
+void ModuleLoader::addClient(ModuleLoaderClient* newClient) {
+ DCHECK(!m_pendingClients.contains(newClient));
+ DCHECK(!m_clients.contains(newClient));
+ m_pendingClients.add(newClient);
+
+ notifyAndFlushPendingClients();
+}
+
+void ModuleLoader::notifyAndFlushPendingClients(FlushType flushType) {
+ if (m_insidePendingClientsLoop) {
+ // This notifyAndFlushPendingClients call was reentrant.
+ // Defer to first notifyAndFlushPendingClients to do the job.
+ return;
+ }
+
+ AutoReset<bool> forbidClientModificationScope(&m_insideAddPendingClientsLoop, true);
+
+ DCHECK(m_pendingClients.isEmpty());
+ if (flushType == FlushType::MayHaveAdvancedState)
+ m_pendingClients.swap(m_clients);
+
+ while (!m_pendingClients.isEmpty()) {
+ // Iterate on copy as m_pendingClients may be added in the notification loop.
+ HeapHashSet<Member<ModuleLoaderClient>> clientsToCatchUp;
+ clientsToCatchUp.swap(m_pendingClients);
+ for (const auto& client : clientsToCatchUp) {
+ client->catchUpToLatestStateIfNeeded(m_state);
+ }
+
+ // Caught up clients do not have any notifications to receive after the
+ // load is finished.
+ if (isFinished())
+ continue;
+
+ while (clientsToCatchUp.isEmpty())
+ m_clients.add(clientsToCatchUp.takeAny());
+ }
+}
+
+DEFINE_TRACE(ModuleLoader) {
+ visitor->trace(m_clients);
+ ResourceOwner<ScriptResource>::trace(visitor);
+}
+
+ModuleMap::ModuleMap(LocalFrame* frame, ResourceFetcher* fetcher)
+ : m_frame(frame), m_fetcher(fetcher) {
+ DCHECK(m_frame);
+ DCHECK(m_fetcher);
+}
+
+void ModuleMap::fetch(const KURL& url, ModuleLoaderClient* client) {
+ g_localFrame = m_frame; // TODO(kouhei): AAAAAAAArrrrrgghhh
+ printf("ModuleMap::fetch(%s)\n", url.getString().utf8().data());
+
+ MapImpl::AddResult result = m_map.set(url, nullptr);
+ Member<ModuleLoader>& loaderEntry = result.storedValue->value;
+ if (!result.isNewEntry) {
+ printf("not new entry\n");
+
+ // - If moduleMap[url] is "fetching", wait (in parallel) until that
+ // loaderEntry's value changes, then proceed to the next step.
+ // - If moduleMap[url] exists, asynchronously complete this algorithm
+ // with moduleMap[url], and abort these steps.
+ loaderEntry->addClient(client);
+ return;
+ }
+
+ ModuleLoader* loader = ModuleLoader::create(url);
+ loader->fetch(m_fetcher.get());
+
+ // Step 10. Set moduleMap[url] to module script, and asynchronously complete
+ // this algorithm with module script.
+ loaderEntry = loader;
+ loaderEntry->addClient(client);
+}
+
+DEFINE_TRACE(ModuleMap) {
+ visitor->trace(m_map);
+ visitor->trace(m_frame);
+ visitor->trace(m_fetcher);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698