modules.cc 11.5 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
  CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
  return ModuleInfoEntry::New(
      isolate, ToStringOrUndefined(isolate, export_name),
      ToStringOrUndefined(isolate, local_name),
90 91
      ToStringOrUndefined(isolate, import_name), module_request, cell_index,
      location.beg_pos, location.end_pos);
92 93 94
}

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

109 110 111 112 113 114
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.)

115 116 117
  ZoneVector<Handle<Object>> data(
      ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
  int index = 0;
118 119 120 121

  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    // Find out how many export names this local name has.
    auto next = it;
122
    int count = 0;
123
    do {
124 125
      DCHECK_EQ(it->second->local_name, next->second->local_name);
      DCHECK_EQ(it->second->cell_index, next->second->cell_index);
126
      ++next;
127
      ++count;
128 129
    } while (next != regular_exports_.end() && next->first == it->first);

130 131 132 133 134 135 136
    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;
137 138 139 140 141 142

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

    // Continue with the next distinct key.
    DCHECK(it == next);
  }
148 149
  DCHECK_LE(index, static_cast<int>(data.size()));
  data.resize(index);
150 151

  // We cannot create the FixedArray earlier because we only now know the
152 153 154
  // precise size.
  Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
  for (int i = 0; i < index; ++i) {
155 156 157 158 159
    result->set(i, *data[i]);
  }
  return result;
}

160 161 162 163 164 165 166 167 168 169
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) {
170 171 172 173 174 175
      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);
176
      entry->cell_index = cell_index;
177 178 179 180 181 182

      AddRegularExport(entry);
    }
  }
}

183 184
void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
185
    Entry* entry = it->second;
186
    DCHECK_NOT_NULL(entry->local_name);
187 188 189 190 191
    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);
192
      DCHECK_LT(entry->module_request, 0);
193
      DCHECK_NOT_NULL(import->second->import_name);
194 195 196
      DCHECK_LE(0, import->second->module_request);
      DCHECK_LT(import->second->module_request,
                static_cast<int>(module_requests_.size()));
197 198
      entry->import_name = import->second->import_name;
      entry->module_request = import->second->module_request;
199 200 201 202 203 204 205
      // 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;
206
      entry->local_name = nullptr;
neis's avatar
neis committed
207
      AddSpecialExport(entry, zone);
208 209 210
      it = regular_exports_.erase(it);
    } else {
      it++;
211 212 213 214
    }
  }
}

215 216 217 218 219 220 221
ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
    int cell_index) {
  if (cell_index > 0) return kExport;
  if (cell_index < 0) return kImport;
  return kInvalid;
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
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--;
  }
}

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
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

273
const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
274
    Zone* zone) const {
275 276 277
  const ModuleDescriptor::Entry* duplicate = nullptr;
  ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
      zone);
278 279
  for (const auto& elem : regular_exports_) {
    duplicate = BetterDuplicate(elem.second, export_names, duplicate);
280 281 282
  }
  for (auto entry : special_exports_) {
    if (entry->export_name == nullptr) continue;  // Star export.
283
    duplicate = BetterDuplicate(entry, export_names, duplicate);
284
  }
285
  return duplicate;
286 287
}

288
bool ModuleDescriptor::Validate(ModuleScope* module_scope,
289
                                PendingCompilationErrorHandler* error_handler,
290
                                Zone* zone) {
291 292 293 294 295
  DCHECK_EQ(this, module_scope->module());
  DCHECK_NOT_NULL(error_handler);

  // Report error iff there are duplicate exports.
  {
296
    const Entry* entry = FindDuplicateExport(zone);
297 298 299 300 301
    if (entry != nullptr) {
      error_handler->ReportMessageAt(
          entry->location.beg_pos, entry->location.end_pos,
          MessageTemplate::kDuplicateExport, entry->export_name);
      return false;
302 303 304 305
    }
  }

  // Report error iff there are exports of non-existent local names.
306 307
  for (const auto& elem : regular_exports_) {
    const Entry* entry = elem.second;
308
    DCHECK_NOT_NULL(entry->local_name);
309 310 311 312 313 314 315 316
    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;
    }
  }

317
  MakeIndirectExportsExplicit(zone);
318
  AssignCellIndices();
319
  return true;
320
}
321

322 323
}  // namespace internal
}  // namespace v8