modules.cc 9.81 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 9 10 11

namespace v8 {
namespace internal {

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


23 24 25
void ModuleDescriptor::AddStarImport(
    const AstRawString* local_name, const AstRawString* module_request,
    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
}

32 33
void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) {
  AddModuleRequest(module_request);
34
}
35 36


37 38 39
void ModuleDescriptor::AddExport(
    const AstRawString* local_name, const AstRawString* export_name,
    Scanner::Location loc, Zone* zone) {
40
  Entry* entry = new (zone) Entry(loc);
41 42
  entry->export_name = export_name;
  entry->local_name = local_name;
43
  AddRegularExport(entry);
44
}
45 46


47 48 49 50 51
void ModuleDescriptor::AddExport(
    const AstRawString* import_name, const AstRawString* export_name,
    const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
  DCHECK_NOT_NULL(import_name);
  DCHECK_NOT_NULL(export_name);
52
  Entry* entry = new (zone) Entry(loc);
53 54
  entry->export_name = export_name;
  entry->import_name = import_name;
55
  entry->module_request = AddModuleRequest(module_request);
56
  AddSpecialExport(entry, zone);
57 58 59
}


60 61
void ModuleDescriptor::AddStarExport(
    const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
62
  Entry* entry = new (zone) Entry(loc);
63
  entry->module_request = AddModuleRequest(module_request);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  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;
  return avfactory->GetString(Handle<String>::cast(object));
}

}  // namespace

84 85
Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
    Isolate* isolate) const {
86 87 88 89 90
  CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
  return ModuleInfoEntry::New(
      isolate, ToStringOrUndefined(isolate, export_name),
      ToStringOrUndefined(isolate, local_name),
      ToStringOrUndefined(isolate, import_name),
91 92
      Handle<Object>(Smi::FromInt(module_request), isolate), location.beg_pos,
      location.end_pos);
93 94 95
}

ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
96 97 98 99 100 101 102 103 104
    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));
105
  result->module_request = Smi::cast(entry->module_request())->value();
106
  return result;
107 108
}

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
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.)

  ZoneVector<Handle<Object>> data(zone);
  data.reserve(2 * regular_exports_.size());

  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    // Find out how many export names this local name has.
    auto next = it;
    int size = 0;
    do {
      ++next;
      ++size;
    } while (next != regular_exports_.end() && next->first == it->first);

    Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(size);
    data.push_back(it->second->local_name->string());
    data.push_back(export_names);

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

    // Continue with the next distinct key.
    DCHECK(it == next);
  }

  // We cannot create the FixedArray earlier because we only now know the
  // precise size (the number of unique keys in regular_exports).
  int size = static_cast<int>(data.size());
  Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
  for (int i = 0; i < size; ++i) {
    result->set(i, *data[i]);
  }
  return result;
}

void ModuleDescriptor::DeserializeRegularExports(Isolate* isolate,
                                                 AstValueFactory* avfactory,
                                                 Handle<FixedArray> data) {
  for (int i = 0, length_i = data->length(); i < length_i;) {
    Handle<String> local_name(String::cast(data->get(i++)), isolate);
    Handle<FixedArray> export_names(FixedArray::cast(data->get(i++)), isolate);

    for (int j = 0, length_j = export_names->length(); j < length_j; ++j) {
      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);

      AddRegularExport(entry);
    }
  }
}

172 173
void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
174
    Entry* entry = it->second;
175
    DCHECK_NOT_NULL(entry->local_name);
176 177 178 179 180
    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);
181
      DCHECK_LT(entry->module_request, 0);
182
      DCHECK_NOT_NULL(import->second->import_name);
183 184 185
      DCHECK_LE(0, import->second->module_request);
      DCHECK_LT(import->second->module_request,
                static_cast<int>(module_requests_.size()));
186 187
      entry->import_name = import->second->import_name;
      entry->module_request = import->second->module_request;
188 189 190 191 192 193 194
      // 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;
195
      entry->local_name = nullptr;
neis's avatar
neis committed
196
      AddSpecialExport(entry, zone);
197 198 199
      it = regular_exports_.erase(it);
    } else {
      it++;
200 201 202 203
    }
  }
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
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

225
const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
226
    Zone* zone) const {
227 228 229
  const ModuleDescriptor::Entry* duplicate = nullptr;
  ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
      zone);
230 231
  for (const auto& elem : regular_exports_) {
    duplicate = BetterDuplicate(elem.second, export_names, duplicate);
232 233 234
  }
  for (auto entry : special_exports_) {
    if (entry->export_name == nullptr) continue;  // Star export.
235
    duplicate = BetterDuplicate(entry, export_names, duplicate);
236
  }
237
  return duplicate;
238 239
}

240
bool ModuleDescriptor::Validate(ModuleScope* module_scope,
241
                                PendingCompilationErrorHandler* error_handler,
242
                                Zone* zone) {
243 244 245 246 247
  DCHECK_EQ(this, module_scope->module());
  DCHECK_NOT_NULL(error_handler);

  // Report error iff there are duplicate exports.
  {
248
    const Entry* entry = FindDuplicateExport(zone);
249 250 251 252 253
    if (entry != nullptr) {
      error_handler->ReportMessageAt(
          entry->location.beg_pos, entry->location.end_pos,
          MessageTemplate::kDuplicateExport, entry->export_name);
      return false;
254 255 256 257
    }
  }

  // Report error iff there are exports of non-existent local names.
258 259
  for (const auto& elem : regular_exports_) {
    const Entry* entry = elem.second;
260
    DCHECK_NOT_NULL(entry->local_name);
261 262 263 264 265 266 267 268
    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;
    }
  }

269
  MakeIndirectExportsExplicit(zone);
270
  return true;
271
}
272

273 274
}  // namespace internal
}  // namespace v8