modules.cc 12.4 KB
Newer Older
1 2 3 4
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include "src/ast/modules.h"
#include "src/ast/ast-value-factory.h"
7
#include "src/ast/scopes.h"
8
#include "src/objects-inl.h"
9
#include "src/objects/module.h"
marja's avatar
marja committed
10
#include "src/pending-compilation-error-handler.h"
11 12 13 14

namespace v8 {
namespace internal {

15 16 17 18 19 20
void ModuleDescriptor::AddImport(const AstRawString* import_name,
                                 const AstRawString* local_name,
                                 const AstRawString* module_request,
                                 const Scanner::Location loc,
                                 const Scanner::Location specifier_loc,
                                 Zone* zone) {
21
  Entry* entry = new (zone) Entry(loc);
22 23
  entry->local_name = local_name;
  entry->import_name = import_name;
24
  entry->module_request = AddModuleRequest(module_request, specifier_loc);
25
  AddRegularImport(entry);
26
}
27

28 29 30 31 32
void ModuleDescriptor::AddStarImport(const AstRawString* local_name,
                                     const AstRawString* module_request,
                                     const Scanner::Location loc,
                                     const Scanner::Location specifier_loc,
                                     Zone* zone) {
33
  Entry* entry = new (zone) Entry(loc);
34
  entry->local_name = local_name;
35
  entry->module_request = AddModuleRequest(module_request, specifier_loc);
36
  AddNamespaceImport(entry, zone);
37 38
}

39 40 41
void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
                                      const Scanner::Location specifier_loc) {
  AddModuleRequest(module_request, specifier_loc);
42
}
43 44


45 46 47
void ModuleDescriptor::AddExport(
    const AstRawString* local_name, const AstRawString* export_name,
    Scanner::Location loc, Zone* zone) {
48
  Entry* entry = new (zone) Entry(loc);
49 50
  entry->export_name = export_name;
  entry->local_name = local_name;
51
  AddRegularExport(entry);
52
}
53

54 55 56 57 58 59
void ModuleDescriptor::AddExport(const AstRawString* import_name,
                                 const AstRawString* export_name,
                                 const AstRawString* module_request,
                                 const Scanner::Location loc,
                                 const Scanner::Location specifier_loc,
                                 Zone* zone) {
60 61
  DCHECK_NOT_NULL(import_name);
  DCHECK_NOT_NULL(export_name);
62
  Entry* entry = new (zone) Entry(loc);
63 64
  entry->export_name = export_name;
  entry->import_name = import_name;
65
  entry->module_request = AddModuleRequest(module_request, specifier_loc);
66
  AddSpecialExport(entry, zone);
67 68
}

69 70 71 72
void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
                                     const Scanner::Location loc,
                                     const Scanner::Location specifier_loc,
                                     Zone* zone) {
73
  Entry* entry = new (zone) Entry(loc);
74
  entry->module_request = AddModuleRequest(module_request, specifier_loc);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  AddSpecialExport(entry, zone);
}

namespace {

Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
  return (s == nullptr)
             ? Handle<Object>::cast(isolate->factory()->undefined_value())
             : Handle<Object>::cast(s->string());
}

const AstRawString* FromStringOrUndefined(Isolate* isolate,
                                          AstValueFactory* avfactory,
                                          Handle<Object> object) {
  if (object->IsUndefined(isolate)) return nullptr;
90
  return avfactory->GetString(Handle<String>::cast(object));
91 92 93 94
}

}  // namespace

95 96
Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
    Isolate* isolate) const {
97 98 99 100
  CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
  return ModuleInfoEntry::New(
      isolate, ToStringOrUndefined(isolate, export_name),
      ToStringOrUndefined(isolate, local_name),
101 102
      ToStringOrUndefined(isolate, import_name), module_request, cell_index,
      location.beg_pos, location.end_pos);
103 104 105
}

ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
106 107 108 109 110 111 112 113 114
    Isolate* isolate, AstValueFactory* avfactory,
    Handle<ModuleInfoEntry> entry) {
  Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
  result->export_name = FromStringOrUndefined(
      isolate, avfactory, handle(entry->export_name(), isolate));
  result->local_name = FromStringOrUndefined(
      isolate, avfactory, handle(entry->local_name(), isolate));
  result->import_name = FromStringOrUndefined(
      isolate, avfactory, handle(entry->import_name(), isolate));
115 116
  result->module_request = entry->module_request();
  result->cell_index = entry->cell_index();
117
  return result;
118 119
}

120 121 122 123 124 125
Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
                                                             Zone* zone) const {
  // We serialize regular exports in a way that lets us later iterate over their
  // local names and for each local name immediately access all its export
  // names.  (Regular exports have neither import name nor module request.)

126 127 128
  ZoneVector<Handle<Object>> data(
      ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
  int index = 0;
129 130 131 132

  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    // Find out how many export names this local name has.
    auto next = it;
133
    int count = 0;
134
    do {
135 136
      DCHECK_EQ(it->second->local_name, next->second->local_name);
      DCHECK_EQ(it->second->cell_index, next->second->cell_index);
137
      ++next;
138
      ++count;
139 140
    } while (next != regular_exports_.end() && next->first == it->first);

141 142 143 144 145 146 147
    Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
    data[index + ModuleInfo::kRegularExportLocalNameOffset] =
        it->second->local_name->string();
    data[index + ModuleInfo::kRegularExportCellIndexOffset] =
        handle(Smi::FromInt(it->second->cell_index), isolate);
    data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
    index += ModuleInfo::kRegularExportLength;
148 149 150 151 152 153

    // Collect the export names.
    int i = 0;
    for (; it != next; ++it) {
      export_names->set(i++, *it->second->export_name->string());
    }
154
    DCHECK_EQ(i, count);
155 156 157 158

    // Continue with the next distinct key.
    DCHECK(it == next);
  }
159 160
  DCHECK_LE(index, static_cast<int>(data.size()));
  data.resize(index);
161 162

  // We cannot create the FixedArray earlier because we only now know the
163 164 165
  // precise size.
  Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
  for (int i = 0; i < index; ++i) {
166 167 168 169 170
    result->set(i, *data[i]);
  }
  return result;
}

171 172 173 174 175 176 177 178 179 180
void ModuleDescriptor::DeserializeRegularExports(
    Isolate* isolate, AstValueFactory* avfactory,
    Handle<ModuleInfo> module_info) {
  for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
    Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
    int cell_index = module_info->RegularExportCellIndex(i);
    Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
                                    isolate);

    for (int j = 0, length = export_names->length(); j < length; ++j) {
181 182 183 184 185 186
      Handle<String> export_name(String::cast(export_names->get(j)), isolate);

      Entry* entry =
          new (avfactory->zone()) Entry(Scanner::Location::invalid());
      entry->local_name = avfactory->GetString(local_name);
      entry->export_name = avfactory->GetString(export_name);
187
      entry->cell_index = cell_index;
188 189 190 191 192 193

      AddRegularExport(entry);
    }
  }
}

194 195
void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
196
    Entry* entry = it->second;
197
    DCHECK_NOT_NULL(entry->local_name);
198 199 200 201 202
    auto import = regular_imports_.find(entry->local_name);
    if (import != regular_imports_.end()) {
      // Found an indirect export.  Patch export entry and move it from regular
      // to special.
      DCHECK_NULL(entry->import_name);
203
      DCHECK_LT(entry->module_request, 0);
204
      DCHECK_NOT_NULL(import->second->import_name);
205 206 207
      DCHECK_LE(0, import->second->module_request);
      DCHECK_LT(import->second->module_request,
                static_cast<int>(module_requests_.size()));
208 209
      entry->import_name = import->second->import_name;
      entry->module_request = import->second->module_request;
210 211 212 213 214 215 216
      // Hack: When the indirect export cannot be resolved, we want the error
      // message to point at the import statement, not at the export statement.
      // Therefore we overwrite [entry]'s location here.  Note that Validate()
      // has already checked for duplicate exports, so it's guaranteed that we
      // won't need to report any error pointing at the (now lost) export
      // location.
      entry->location = import->second->location;
217
      entry->local_name = nullptr;
neis's avatar
neis committed
218
      AddSpecialExport(entry, zone);
219 220 221
      it = regular_exports_.erase(it);
    } else {
      it++;
222 223 224 225
    }
  }
}

226 227 228 229 230 231 232
ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
    int cell_index) {
  if (cell_index > 0) return kExport;
  if (cell_index < 0) return kImport;
  return kInvalid;
}

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
void ModuleDescriptor::AssignCellIndices() {
  int export_index = 1;
  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    auto current_key = it->first;
    // This local name may be exported under multiple export names.  Assign the
    // same index to each such entry.
    do {
      Entry* entry = it->second;
      DCHECK_NOT_NULL(entry->local_name);
      DCHECK_NULL(entry->import_name);
      DCHECK_LT(entry->module_request, 0);
      DCHECK_EQ(entry->cell_index, 0);
      entry->cell_index = export_index;
      it++;
    } while (it != regular_exports_.end() && it->first == current_key);
    export_index++;
  }

  int import_index = -1;
  for (const auto& elem : regular_imports_) {
    Entry* entry = elem.second;
    DCHECK_NOT_NULL(entry->local_name);
    DCHECK_NOT_NULL(entry->import_name);
    DCHECK_LE(0, entry->module_request);
    DCHECK_EQ(entry->cell_index, 0);
    entry->cell_index = import_index;
    import_index--;
  }
}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
namespace {

const ModuleDescriptor::Entry* BetterDuplicate(
    const ModuleDescriptor::Entry* candidate,
    ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names,
    const ModuleDescriptor::Entry* current_duplicate) {
  DCHECK_NOT_NULL(candidate->export_name);
  DCHECK(candidate->location.IsValid());
  auto insert_result =
      export_names.insert(std::make_pair(candidate->export_name, candidate));
  if (insert_result.second) return current_duplicate;
  if (current_duplicate == nullptr) {
    current_duplicate = insert_result.first->second;
  }
  return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
             ? candidate
             : current_duplicate;
}

}  // namespace

284
const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
285
    Zone* zone) const {
286 287 288
  const ModuleDescriptor::Entry* duplicate = nullptr;
  ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
      zone);
289 290
  for (const auto& elem : regular_exports_) {
    duplicate = BetterDuplicate(elem.second, export_names, duplicate);
291 292 293
  }
  for (auto entry : special_exports_) {
    if (entry->export_name == nullptr) continue;  // Star export.
294
    duplicate = BetterDuplicate(entry, export_names, duplicate);
295
  }
296
  return duplicate;
297 298
}

299
bool ModuleDescriptor::Validate(ModuleScope* module_scope,
300
                                PendingCompilationErrorHandler* error_handler,
301
                                Zone* zone) {
302 303 304 305 306
  DCHECK_EQ(this, module_scope->module());
  DCHECK_NOT_NULL(error_handler);

  // Report error iff there are duplicate exports.
  {
307
    const Entry* entry = FindDuplicateExport(zone);
308 309 310 311 312
    if (entry != nullptr) {
      error_handler->ReportMessageAt(
          entry->location.beg_pos, entry->location.end_pos,
          MessageTemplate::kDuplicateExport, entry->export_name);
      return false;
313 314 315 316
    }
  }

  // Report error iff there are exports of non-existent local names.
317 318
  for (const auto& elem : regular_exports_) {
    const Entry* entry = elem.second;
319
    DCHECK_NOT_NULL(entry->local_name);
320 321 322 323 324 325 326 327
    if (module_scope->LookupLocal(entry->local_name) == nullptr) {
      error_handler->ReportMessageAt(
          entry->location.beg_pos, entry->location.end_pos,
          MessageTemplate::kModuleExportUndefined, entry->local_name);
      return false;
    }
  }

328
  MakeIndirectExportsExplicit(zone);
329
  AssignCellIndices();
330
  return true;
331
}
332

333 334
}  // namespace internal
}  // namespace v8