modules.cc revision f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3
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 9namespace v8 { 10namespace internal { 11 12void ModuleDescriptor::AddImport( 13 const AstRawString* import_name, const AstRawString* local_name, 14 const AstRawString* module_request, Scanner::Location loc, Zone* zone) { 15 Entry* entry = new (zone) Entry(loc); 16 entry->local_name = local_name; 17 entry->import_name = import_name; 18 entry->module_request = AddModuleRequest(module_request); 19 AddRegularImport(entry); 20} 21 22 23void ModuleDescriptor::AddStarImport( 24 const AstRawString* local_name, const AstRawString* module_request, 25 Scanner::Location loc, Zone* zone) { 26 Entry* entry = new (zone) Entry(loc); 27 entry->local_name = local_name; 28 entry->module_request = AddModuleRequest(module_request); 29 AddNamespaceImport(entry, zone); 30} 31 32void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) { 33 AddModuleRequest(module_request); 34} 35 36 37void ModuleDescriptor::AddExport( 38 const AstRawString* local_name, const AstRawString* export_name, 39 Scanner::Location loc, Zone* zone) { 40 Entry* entry = new (zone) Entry(loc); 41 entry->export_name = export_name; 42 entry->local_name = local_name; 43 AddRegularExport(entry); 44} 45 46 47void ModuleDescriptor::AddExport( 48 const AstRawString* import_name, const AstRawString* export_name, 49 const AstRawString* module_request, Scanner::Location loc, Zone* zone) { 50 DCHECK_NOT_NULL(import_name); 51 DCHECK_NOT_NULL(export_name); 52 Entry* entry = new (zone) Entry(loc); 53 entry->export_name = export_name; 54 entry->import_name = import_name; 55 entry->module_request = AddModuleRequest(module_request); 56 AddSpecialExport(entry, zone); 57} 58 59 60void ModuleDescriptor::AddStarExport( 61 const AstRawString* module_request, Scanner::Location loc, Zone* zone) { 62 Entry* entry = new (zone) Entry(loc); 63 entry->module_request = AddModuleRequest(module_request); 64 AddSpecialExport(entry, zone); 65} 66 67namespace { 68 69Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) { 70 return (s == nullptr) 71 ? Handle<Object>::cast(isolate->factory()->undefined_value()) 72 : Handle<Object>::cast(s->string()); 73} 74 75const AstRawString* FromStringOrUndefined(Isolate* isolate, 76 AstValueFactory* avfactory, 77 Handle<Object> object) { 78 if (object->IsUndefined(isolate)) return nullptr; 79 return avfactory->GetString(Handle<String>::cast(object)); 80} 81 82} // namespace 83 84Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize( 85 Isolate* isolate) const { 86 CHECK(Smi::IsValid(module_request)); // TODO(neis): Check earlier? 87 return ModuleInfoEntry::New( 88 isolate, ToStringOrUndefined(isolate, export_name), 89 ToStringOrUndefined(isolate, local_name), 90 ToStringOrUndefined(isolate, import_name), 91 Handle<Object>(Smi::FromInt(module_request), isolate)); 92} 93 94ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize( 95 Isolate* isolate, AstValueFactory* avfactory, 96 Handle<ModuleInfoEntry> entry) { 97 Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid()); 98 result->export_name = FromStringOrUndefined( 99 isolate, avfactory, handle(entry->export_name(), isolate)); 100 result->local_name = FromStringOrUndefined( 101 isolate, avfactory, handle(entry->local_name(), isolate)); 102 result->import_name = FromStringOrUndefined( 103 isolate, avfactory, handle(entry->import_name(), isolate)); 104 result->module_request = Smi::cast(entry->module_request())->value(); 105 return result; 106} 107 108Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate, 109 Zone* zone) const { 110 // We serialize regular exports in a way that lets us later iterate over their 111 // local names and for each local name immediately access all its export 112 // names. (Regular exports have neither import name nor module request.) 113 114 ZoneVector<Handle<Object>> data(zone); 115 data.reserve(2 * regular_exports_.size()); 116 117 for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { 118 // Find out how many export names this local name has. 119 auto next = it; 120 int size = 0; 121 do { 122 ++next; 123 ++size; 124 } while (next != regular_exports_.end() && next->first == it->first); 125 126 Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(size); 127 data.push_back(it->second->local_name->string()); 128 data.push_back(export_names); 129 130 // Collect the export names. 131 int i = 0; 132 for (; it != next; ++it) { 133 export_names->set(i++, *it->second->export_name->string()); 134 } 135 DCHECK_EQ(i, size); 136 137 // Continue with the next distinct key. 138 DCHECK(it == next); 139 } 140 141 // We cannot create the FixedArray earlier because we only now know the 142 // precise size (the number of unique keys in regular_exports). 143 int size = static_cast<int>(data.size()); 144 Handle<FixedArray> result = isolate->factory()->NewFixedArray(size); 145 for (int i = 0; i < size; ++i) { 146 result->set(i, *data[i]); 147 } 148 return result; 149} 150 151void ModuleDescriptor::DeserializeRegularExports(Isolate* isolate, 152 AstValueFactory* avfactory, 153 Handle<FixedArray> data) { 154 for (int i = 0, length_i = data->length(); i < length_i;) { 155 Handle<String> local_name(String::cast(data->get(i++)), isolate); 156 Handle<FixedArray> export_names(FixedArray::cast(data->get(i++)), isolate); 157 158 for (int j = 0, length_j = export_names->length(); j < length_j; ++j) { 159 Handle<String> export_name(String::cast(export_names->get(j)), isolate); 160 161 Entry* entry = 162 new (avfactory->zone()) Entry(Scanner::Location::invalid()); 163 entry->local_name = avfactory->GetString(local_name); 164 entry->export_name = avfactory->GetString(export_name); 165 166 AddRegularExport(entry); 167 } 168 } 169} 170 171void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) { 172 for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { 173 Entry* entry = it->second; 174 DCHECK_NOT_NULL(entry->local_name); 175 auto import = regular_imports_.find(entry->local_name); 176 if (import != regular_imports_.end()) { 177 // Found an indirect export. Patch export entry and move it from regular 178 // to special. 179 DCHECK_NULL(entry->import_name); 180 DCHECK_LT(entry->module_request, 0); 181 DCHECK_NOT_NULL(import->second->import_name); 182 DCHECK_LE(0, import->second->module_request); 183 DCHECK_LT(import->second->module_request, 184 static_cast<int>(module_requests_.size())); 185 entry->import_name = import->second->import_name; 186 entry->module_request = import->second->module_request; 187 entry->local_name = nullptr; 188 AddSpecialExport(entry, zone); 189 it = regular_exports_.erase(it); 190 } else { 191 it++; 192 } 193 } 194} 195 196namespace { 197 198const ModuleDescriptor::Entry* BetterDuplicate( 199 const ModuleDescriptor::Entry* candidate, 200 ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names, 201 const ModuleDescriptor::Entry* current_duplicate) { 202 DCHECK_NOT_NULL(candidate->export_name); 203 DCHECK(candidate->location.IsValid()); 204 auto insert_result = 205 export_names.insert(std::make_pair(candidate->export_name, candidate)); 206 if (insert_result.second) return current_duplicate; 207 if (current_duplicate == nullptr) { 208 current_duplicate = insert_result.first->second; 209 } 210 return (candidate->location.beg_pos > current_duplicate->location.beg_pos) 211 ? candidate 212 : current_duplicate; 213} 214 215} // namespace 216 217const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport( 218 Zone* zone) const { 219 const ModuleDescriptor::Entry* duplicate = nullptr; 220 ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names( 221 zone); 222 for (const auto& elem : regular_exports_) { 223 duplicate = BetterDuplicate(elem.second, export_names, duplicate); 224 } 225 for (auto entry : special_exports_) { 226 if (entry->export_name == nullptr) continue; // Star export. 227 duplicate = BetterDuplicate(entry, export_names, duplicate); 228 } 229 return duplicate; 230} 231 232bool ModuleDescriptor::Validate(ModuleScope* module_scope, 233 PendingCompilationErrorHandler* error_handler, 234 Zone* zone) { 235 DCHECK_EQ(this, module_scope->module()); 236 DCHECK_NOT_NULL(error_handler); 237 238 // Report error iff there are duplicate exports. 239 { 240 const Entry* entry = FindDuplicateExport(zone); 241 if (entry != nullptr) { 242 error_handler->ReportMessageAt( 243 entry->location.beg_pos, entry->location.end_pos, 244 MessageTemplate::kDuplicateExport, entry->export_name); 245 return false; 246 } 247 } 248 249 // Report error iff there are exports of non-existent local names. 250 for (const auto& elem : regular_exports_) { 251 const Entry* entry = elem.second; 252 DCHECK_NOT_NULL(entry->local_name); 253 if (module_scope->LookupLocal(entry->local_name) == nullptr) { 254 error_handler->ReportMessageAt( 255 entry->location.beg_pos, entry->location.end_pos, 256 MessageTemplate::kModuleExportUndefined, entry->local_name); 257 return false; 258 } 259 } 260 261 MakeIndirectExportsExplicit(zone); 262 return true; 263} 264 265} // namespace internal 266} // namespace v8 267