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