Line data Source code
1 : // Copyright 2012 the V8 project 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 "src/ast/modules.h"
6 : #include "src/ast/ast-value-factory.h"
7 : #include "src/ast/scopes.h"
8 : #include "src/objects-inl.h"
9 : #include "src/objects/module-inl.h"
10 : #include "src/pending-compilation-error-handler.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 290225 : bool ModuleDescriptor::AstRawStringComparer::operator()(
16 : const AstRawString* lhs, const AstRawString* rhs) const {
17 : // Fast path for equal pointers: a pointer is not strictly less than itself.
18 290225 : if (lhs == rhs) return false;
19 :
20 : // Order by contents (ordering by hash is unstable across runs).
21 288683 : if (lhs->is_one_byte() != rhs->is_one_byte()) {
22 : return lhs->is_one_byte();
23 : }
24 288683 : if (lhs->byte_length() != rhs->byte_length()) {
25 30944 : return lhs->byte_length() < rhs->byte_length();
26 : }
27 257739 : return memcmp(lhs->raw_data(), rhs->raw_data(), lhs->byte_length()) < 0;
28 : }
29 :
30 2154 : void ModuleDescriptor::AddImport(const AstRawString* import_name,
31 : const AstRawString* local_name,
32 : const AstRawString* module_request,
33 : const Scanner::Location loc,
34 : const Scanner::Location specifier_loc,
35 : Zone* zone) {
36 2154 : Entry* entry = new (zone) Entry(loc);
37 2154 : entry->local_name = local_name;
38 2154 : entry->import_name = import_name;
39 2154 : entry->module_request = AddModuleRequest(module_request, specifier_loc);
40 : AddRegularImport(entry);
41 2154 : }
42 :
43 260 : void ModuleDescriptor::AddStarImport(const AstRawString* local_name,
44 : const AstRawString* module_request,
45 : const Scanner::Location loc,
46 : const Scanner::Location specifier_loc,
47 : Zone* zone) {
48 260 : Entry* entry = new (zone) Entry(loc);
49 260 : entry->local_name = local_name;
50 260 : entry->module_request = AddModuleRequest(module_request, specifier_loc);
51 : AddNamespaceImport(entry, zone);
52 260 : }
53 :
54 145 : void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
55 : const Scanner::Location specifier_loc) {
56 : AddModuleRequest(module_request, specifier_loc);
57 145 : }
58 :
59 :
60 19154 : void ModuleDescriptor::AddExport(
61 : const AstRawString* local_name, const AstRawString* export_name,
62 : Scanner::Location loc, Zone* zone) {
63 19154 : Entry* entry = new (zone) Entry(loc);
64 19154 : entry->export_name = export_name;
65 19154 : entry->local_name = local_name;
66 : AddRegularExport(entry);
67 19154 : }
68 :
69 175 : void ModuleDescriptor::AddExport(const AstRawString* import_name,
70 : const AstRawString* export_name,
71 : const AstRawString* module_request,
72 : const Scanner::Location loc,
73 : const Scanner::Location specifier_loc,
74 : Zone* zone) {
75 : DCHECK_NOT_NULL(import_name);
76 : DCHECK_NOT_NULL(export_name);
77 175 : Entry* entry = new (zone) Entry(loc);
78 175 : entry->export_name = export_name;
79 175 : entry->import_name = import_name;
80 175 : entry->module_request = AddModuleRequest(module_request, specifier_loc);
81 : AddSpecialExport(entry, zone);
82 175 : }
83 :
84 150 : void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
85 : const Scanner::Location loc,
86 : const Scanner::Location specifier_loc,
87 : Zone* zone) {
88 150 : Entry* entry = new (zone) Entry(loc);
89 150 : entry->module_request = AddModuleRequest(module_request, specifier_loc);
90 : AddSpecialExport(entry, zone);
91 150 : }
92 :
93 : namespace {
94 : Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
95 : return (s == nullptr)
96 : ? Handle<Object>::cast(isolate->factory()->undefined_value())
97 2829 : : Handle<Object>::cast(s->string());
98 : }
99 : } // namespace
100 :
101 943 : Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
102 : Isolate* isolate) const {
103 943 : CHECK(Smi::IsValid(module_request)); // TODO(neis): Check earlier?
104 : return ModuleInfoEntry::New(
105 943 : isolate, ToStringOrUndefined(isolate, export_name),
106 943 : ToStringOrUndefined(isolate, local_name),
107 943 : ToStringOrUndefined(isolate, import_name), module_request, cell_index,
108 1886 : location.beg_pos, location.end_pos);
109 : }
110 :
111 1257 : Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
112 : Zone* zone) const {
113 : // We serialize regular exports in a way that lets us later iterate over their
114 : // local names and for each local name immediately access all its export
115 : // names. (Regular exports have neither import name nor module request.)
116 :
117 : ZoneVector<Handle<Object>> data(
118 1257 : ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
119 : int index = 0;
120 :
121 36541 : for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
122 : // Find out how many export names this local name has.
123 : auto next = it;
124 : int count = 0;
125 17727 : do {
126 : DCHECK_EQ(it->second->local_name, next->second->local_name);
127 : DCHECK_EQ(it->second->cell_index, next->second->cell_index);
128 : ++next;
129 17727 : ++count;
130 17727 : } while (next != regular_exports_.end() && next->first == it->first);
131 :
132 17642 : Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
133 17642 : data[index + ModuleInfo::kRegularExportLocalNameOffset] =
134 35284 : it->second->local_name->string();
135 17642 : data[index + ModuleInfo::kRegularExportCellIndexOffset] =
136 35284 : handle(Smi::FromInt(it->second->cell_index), isolate);
137 35284 : data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
138 17642 : index += ModuleInfo::kRegularExportLength;
139 :
140 : // Collect the export names.
141 : int i = 0;
142 35369 : for (; it != next; ++it) {
143 53181 : export_names->set(i++, *it->second->export_name->string());
144 : }
145 : DCHECK_EQ(i, count);
146 :
147 : // Continue with the next distinct key.
148 : DCHECK(it == next);
149 : }
150 : DCHECK_LE(index, static_cast<int>(data.size()));
151 1257 : data.resize(index);
152 :
153 : // We cannot create the FixedArray earlier because we only now know the
154 : // precise size.
155 1257 : Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
156 107109 : for (int i = 0; i < index; ++i) {
157 105852 : result->set(i, *data[i]);
158 : }
159 2514 : return result;
160 : }
161 :
162 15282 : void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
163 34030 : for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
164 18748 : Entry* entry = it->second;
165 : DCHECK_NOT_NULL(entry->local_name);
166 18748 : auto import = regular_imports_.find(entry->local_name);
167 18748 : if (import != regular_imports_.end()) {
168 : // Found an indirect export. Patch export entry and move it from regular
169 : // to special.
170 : DCHECK_NULL(entry->import_name);
171 : DCHECK_LT(entry->module_request, 0);
172 : DCHECK_NOT_NULL(import->second->import_name);
173 : DCHECK_LE(0, import->second->module_request);
174 : DCHECK_LT(import->second->module_request,
175 : static_cast<int>(module_requests_.size()));
176 55 : entry->import_name = import->second->import_name;
177 55 : entry->module_request = import->second->module_request;
178 : // Hack: When the indirect export cannot be resolved, we want the error
179 : // message to point at the import statement, not at the export statement.
180 : // Therefore we overwrite [entry]'s location here. Note that Validate()
181 : // has already checked for duplicate exports, so it's guaranteed that we
182 : // won't need to report any error pointing at the (now lost) export
183 : // location.
184 55 : entry->location = import->second->location;
185 55 : entry->local_name = nullptr;
186 : AddSpecialExport(entry, zone);
187 : it = regular_exports_.erase(it);
188 : } else {
189 : it++;
190 : }
191 : }
192 15282 : }
193 :
194 10045 : ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
195 : int cell_index) {
196 10045 : if (cell_index > 0) return kExport;
197 1398 : if (cell_index < 0) return kImport;
198 5 : return kInvalid;
199 : }
200 :
201 15282 : void ModuleDescriptor::AssignCellIndices() {
202 : int export_index = 1;
203 52478 : for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
204 18598 : auto current_key = it->first;
205 : // This local name may be exported under multiple export names. Assign the
206 : // same index to each such entry.
207 18693 : do {
208 18693 : Entry* entry = it->second;
209 : DCHECK_NOT_NULL(entry->local_name);
210 : DCHECK_NULL(entry->import_name);
211 : DCHECK_LT(entry->module_request, 0);
212 : DCHECK_EQ(entry->cell_index, 0);
213 18693 : entry->cell_index = export_index;
214 : it++;
215 18693 : } while (it != regular_exports_.end() && it->first == current_key);
216 18598 : export_index++;
217 : }
218 :
219 : int import_index = -1;
220 16446 : for (const auto& elem : regular_imports_) {
221 1164 : Entry* entry = elem.second;
222 : DCHECK_NOT_NULL(entry->local_name);
223 : DCHECK_NOT_NULL(entry->import_name);
224 : DCHECK_LE(0, entry->module_request);
225 : DCHECK_EQ(entry->cell_index, 0);
226 1164 : entry->cell_index = import_index;
227 1164 : import_index--;
228 : }
229 15282 : }
230 :
231 : namespace {
232 :
233 19118 : const ModuleDescriptor::Entry* BetterDuplicate(
234 : const ModuleDescriptor::Entry* candidate,
235 : ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names,
236 : const ModuleDescriptor::Entry* current_duplicate) {
237 : DCHECK_NOT_NULL(candidate->export_name);
238 : DCHECK(candidate->location.IsValid());
239 : auto insert_result =
240 38236 : export_names.insert(std::make_pair(candidate->export_name, candidate));
241 19118 : if (insert_result.second) return current_duplicate;
242 80 : if (current_duplicate == nullptr) {
243 65 : current_duplicate = insert_result.first->second;
244 : }
245 80 : return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
246 : ? candidate
247 80 : : current_duplicate;
248 : }
249 :
250 : } // namespace
251 :
252 15372 : const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
253 : Zone* zone) const {
254 : const ModuleDescriptor::Entry* duplicate = nullptr;
255 : ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
256 : zone);
257 34320 : for (const auto& elem : regular_exports_) {
258 18948 : duplicate = BetterDuplicate(elem.second, export_names, duplicate);
259 : }
260 15677 : for (auto entry : special_exports_) {
261 305 : if (entry->export_name == nullptr) continue; // Star export.
262 170 : duplicate = BetterDuplicate(entry, export_names, duplicate);
263 : }
264 15372 : return duplicate;
265 : }
266 :
267 15372 : bool ModuleDescriptor::Validate(ModuleScope* module_scope,
268 : PendingCompilationErrorHandler* error_handler,
269 : Zone* zone) {
270 : DCHECK_EQ(this, module_scope->module());
271 : DCHECK_NOT_NULL(error_handler);
272 :
273 : // Report error iff there are duplicate exports.
274 : {
275 15372 : const Entry* entry = FindDuplicateExport(zone);
276 15372 : if (entry != nullptr) {
277 : error_handler->ReportMessageAt(
278 65 : entry->location.beg_pos, entry->location.end_pos,
279 130 : MessageTemplate::kDuplicateExport, entry->export_name);
280 65 : return false;
281 : }
282 : }
283 :
284 : // Report error iff there are exports of non-existent local names.
285 34055 : for (const auto& elem : regular_exports_) {
286 18773 : const Entry* entry = elem.second;
287 : DCHECK_NOT_NULL(entry->local_name);
288 37546 : if (module_scope->LookupLocal(entry->local_name) == nullptr) {
289 : error_handler->ReportMessageAt(
290 25 : entry->location.beg_pos, entry->location.end_pos,
291 50 : MessageTemplate::kModuleExportUndefined, entry->local_name);
292 : return false;
293 : }
294 : }
295 :
296 15282 : MakeIndirectExportsExplicit(zone);
297 15282 : AssignCellIndices();
298 15282 : return true;
299 : }
300 :
301 : } // namespace internal
302 122036 : } // namespace v8
|