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 "third_party/blink/renderer/core/script/module_record_resolver_impl.h"
6
7 #include "third_party/blink/renderer/bindings/core/v8/module_record.h"
8 #include "third_party/blink/renderer/core/script/modulator.h"
9 #include "third_party/blink/renderer/core/script/module_script.h"
10
11 namespace blink {
12
RegisterModuleScript(const ModuleScript * module_script)13 void ModuleRecordResolverImpl::RegisterModuleScript(
14 const ModuleScript* module_script) {
15 DCHECK(module_script);
16 v8::Local<v8::Module> module = module_script->V8Module();
17 if (module.IsEmpty())
18 return;
19
20 v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
21 BoxedV8Module* record = MakeGarbageCollected<BoxedV8Module>(isolate, module);
22 DVLOG(1) << "ModuleRecordResolverImpl::RegisterModuleScript(url="
23 << module_script->BaseURL().GetString()
24 << ", hash=" << BoxedV8ModuleHash::GetHash(record) << ")";
25
26 auto result = record_to_module_script_map_.Set(record, module_script);
27
28 DCHECK(result.is_new_entry);
29 }
30
UnregisterModuleScript(const ModuleScript * module_script)31 void ModuleRecordResolverImpl::UnregisterModuleScript(
32 const ModuleScript* module_script) {
33 DCHECK(module_script);
34 v8::Local<v8::Module> module = module_script->V8Module();
35 if (module.IsEmpty())
36 return;
37
38 v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
39 BoxedV8Module* record = MakeGarbageCollected<BoxedV8Module>(isolate, module);
40 DVLOG(1) << "ModuleRecordResolverImpl::UnregisterModuleScript(url="
41 << module_script->BaseURL().GetString()
42 << ", hash=" << BoxedV8ModuleHash::GetHash(record) << ")";
43
44 record_to_module_script_map_.erase(record);
45 }
46
GetModuleScriptFromModuleRecord(v8::Local<v8::Module> module) const47 const ModuleScript* ModuleRecordResolverImpl::GetModuleScriptFromModuleRecord(
48 v8::Local<v8::Module> module) const {
49 v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
50 const auto it = record_to_module_script_map_.find(
51 MakeGarbageCollected<BoxedV8Module>(isolate, module));
52 CHECK_NE(it, record_to_module_script_map_.end())
53 << "Failed to find ModuleScript corresponding to the "
54 "record.[[HostDefined]]";
55 CHECK(it->value);
56 return it->value;
57 }
58
59 // <specdef
60 // href="https://html.spec.whatwg.org/C/#hostresolveimportedmodule(referencingscriptormodule,-specifier)">
Resolve(const String & specifier,v8::Local<v8::Module> referrer,ExceptionState & exception_state)61 v8::Local<v8::Module> ModuleRecordResolverImpl::Resolve(
62 const String& specifier,
63 v8::Local<v8::Module> referrer,
64 ExceptionState& exception_state) {
65 v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
66 DVLOG(1) << "ModuleRecordResolverImpl::resolve(specifier=\"" << specifier
67 << ", referrer.hash="
68 << BoxedV8ModuleHash::GetHash(
69 MakeGarbageCollected<BoxedV8Module>(isolate, referrer))
70 << ")";
71
72 // <spec step="3">If referencingScriptOrModule is not null, then:</spec>
73 //
74 // Currently this function implements the spec before
75 // https://github.com/tc39/proposal-dynamic-import is applied, i.e. where
76 // |referencingScriptOrModule| was always a non-null module script.
77
78 // <spec step="3.2">Set settings object to referencing script's settings
79 // object.</spec>
80 //
81 // <spec step="4">Let moduleMap be settings object's module map.</spec>
82 //
83 // These are |modulator_| and |this|, respectively, because module script's
84 // settings object is always the current settings object in Blink.
85
86 // <spec step="3.1">Let referencing script be
87 // referencingScriptOrModule.[[HostDefined]].</spec>
88 const ModuleScript* referrer_module =
89 GetModuleScriptFromModuleRecord(referrer);
90
91 // <spec step="3.3">Set base URL to referencing script's base URL.</spec>
92 // <spec step="5">Let url be the result of resolving a module specifier given
93 // base URL and specifier.</spec>
94 KURL url = referrer_module->ResolveModuleSpecifier(specifier);
95
96 // <spec step="6">Assert: url is never failure, because resolving a module
97 // specifier must have been previously successful with these same two
98 // arguments ...</spec>
99 DCHECK(url.IsValid());
100
101 // <spec step="7">Let resolved module script be moduleMap[url]. (This entry
102 // must exist for us to have gotten to this point.)</spec>
103 ModuleScript* module_script = modulator_->GetFetchedModuleScript(url);
104
105 // <spec step="8">Assert: resolved module script is a module script (i.e., is
106 // not null or "fetching").</spec>
107 //
108 // <spec step="9">Assert: resolved module script's record is not null.</spec>
109 DCHECK(module_script);
110 v8::Local<v8::Module> record = module_script->V8Module();
111 CHECK(!record.IsEmpty());
112
113 // <spec step="10">Return resolved module script's record.</spec>
114 return record;
115 }
116
ContextDestroyed()117 void ModuleRecordResolverImpl::ContextDestroyed() {
118 // crbug.com/725816 : What we should really do is to make the map key
119 // weak reference to v8::Module.
120 record_to_module_script_map_.clear();
121 }
122
Trace(Visitor * visitor)123 void ModuleRecordResolverImpl::Trace(Visitor* visitor) {
124 ModuleRecordResolver::Trace(visitor);
125 ExecutionContextLifecycleObserver::Trace(visitor);
126 visitor->Trace(record_to_module_script_map_);
127 visitor->Trace(modulator_);
128 }
129
130 } // namespace blink
131