modules.cc 13.8 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
#include "src/ast/modules.h"
6

7
#include "src/ast/ast-value-factory.h"
8
#include "src/ast/scopes.h"
9
#include "src/common/globals.h"
10
#include "src/heap/local-factory-inl.h"
11
#include "src/objects/module-inl.h"
12
#include "src/objects/objects-inl.h"
13
#include "src/parsing/pending-compilation-error-handler.h"
14 15 16 17

namespace v8 {
namespace internal {

18
bool SourceTextModuleDescriptor::AstRawStringComparer::operator()(
19
    const AstRawString* lhs, const AstRawString* rhs) const {
20
  return AstRawString::Compare(lhs, rhs) < 0;
21 22 23 24
}

bool SourceTextModuleDescriptor::ModuleRequestComparer::operator()(
    const AstModuleRequest* lhs, const AstModuleRequest* rhs) const {
25 26
  if (int specifier_comparison =
          AstRawString::Compare(lhs->specifier(), rhs->specifier())) {
27
    return specifier_comparison < 0;
28
  }
29 30 31

  auto lhsIt = lhs->import_assertions()->cbegin();
  auto rhsIt = rhs->import_assertions()->cbegin();
32 33 34
  for (; lhsIt != lhs->import_assertions()->cend() &&
         rhsIt != rhs->import_assertions()->cend();
       ++lhsIt, ++rhsIt) {
35
    if (int assertion_key_comparison =
36
            AstRawString::Compare(lhsIt->first, rhsIt->first)) {
37
      return assertion_key_comparison < 0;
38
    }
39

40 41
    if (int assertion_value_comparison =
            AstRawString::Compare(lhsIt->second.first, rhsIt->second.first)) {
42
      return assertion_value_comparison < 0;
43 44 45 46 47 48
    }
  }

  if (lhs->import_assertions()->size() != rhs->import_assertions()->size()) {
    return (lhs->import_assertions()->size() <
            rhs->import_assertions()->size());
49
  }
50 51

  return false;
52 53
}

54 55
void SourceTextModuleDescriptor::AddImport(
    const AstRawString* import_name, const AstRawString* local_name,
56 57
    const AstRawString* module_request,
    const ImportAssertions* import_assertions, const Scanner::Location loc,
58
    const Scanner::Location specifier_loc, Zone* zone) {
59
  Entry* entry = zone->New<Entry>(loc);
60 61
  entry->local_name = local_name;
  entry->import_name = import_name;
62 63
  entry->module_request =
      AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
64
  AddRegularImport(entry);
65
}
66

67 68
void SourceTextModuleDescriptor::AddStarImport(
    const AstRawString* local_name, const AstRawString* module_request,
69 70
    const ImportAssertions* import_assertions, const Scanner::Location loc,
    const Scanner::Location specifier_loc, Zone* zone) {
71
  Entry* entry = zone->New<Entry>(loc);
72
  entry->local_name = local_name;
73 74
  entry->module_request =
      AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
75
  AddNamespaceImport(entry, zone);
76 77
}

78
void SourceTextModuleDescriptor::AddEmptyImport(
79 80
    const AstRawString* module_request,
    const ImportAssertions* import_assertions,
81 82
    const Scanner::Location specifier_loc, Zone* zone) {
  AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
83
}
84

85 86 87
void SourceTextModuleDescriptor::AddExport(const AstRawString* local_name,
                                           const AstRawString* export_name,
                                           Scanner::Location loc, Zone* zone) {
88
  Entry* entry = zone->New<Entry>(loc);
89 90
  entry->export_name = export_name;
  entry->local_name = local_name;
91
  AddRegularExport(entry);
92
}
93

94 95
void SourceTextModuleDescriptor::AddExport(
    const AstRawString* import_name, const AstRawString* export_name,
96 97
    const AstRawString* module_request,
    const ImportAssertions* import_assertions, const Scanner::Location loc,
98
    const Scanner::Location specifier_loc, Zone* zone) {
99 100
  DCHECK_NOT_NULL(import_name);
  DCHECK_NOT_NULL(export_name);
101
  Entry* entry = zone->New<Entry>(loc);
102 103
  entry->export_name = export_name;
  entry->import_name = import_name;
104 105
  entry->module_request =
      AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
106
  AddSpecialExport(entry, zone);
107 108
}

109
void SourceTextModuleDescriptor::AddStarExport(
110 111
    const AstRawString* module_request,
    const ImportAssertions* import_assertions, const Scanner::Location loc,
112
    const Scanner::Location specifier_loc, Zone* zone) {
113
  Entry* entry = zone->New<Entry>(loc);
114 115
  entry->module_request =
      AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
116 117 118 119
  AddSpecialExport(entry, zone);
}

namespace {
120 121
template <typename IsolateT>
Handle<PrimitiveHeapObject> ToStringOrUndefined(IsolateT* isolate,
122
                                                const AstRawString* s) {
123 124
  if (s == nullptr) return isolate->factory()->undefined_value();
  return s->string();
125 126 127
}
}  // namespace

128
template <typename IsolateT>
129
Handle<ModuleRequest> SourceTextModuleDescriptor::AstModuleRequest::Serialize(
130
    IsolateT* isolate) const {
131 132
  // The import assertions will be stored in this array in the form:
  // [key1, value1, location1, key2, value2, location2, ...]
133
  Handle<FixedArray> import_assertions_array =
134 135 136 137
      isolate->factory()->NewFixedArray(
          static_cast<int>(import_assertions()->size() *
                           ModuleRequest::kAssertionEntrySize),
          AllocationType::kOld);
138

139 140 141 142 143 144 145 146
  int i = 0;
  for (auto iter = import_assertions()->cbegin();
       iter != import_assertions()->cend();
       ++iter, i += ModuleRequest::kAssertionEntrySize) {
    import_assertions_array->set(i, *iter->first->string());
    import_assertions_array->set(i + 1, *iter->second.first->string());
    import_assertions_array->set(i + 2,
                                 Smi::FromInt(iter->second.second.beg_pos));
147
  }
148
  return v8::internal::ModuleRequest::New(isolate, specifier()->string(),
149
                                          import_assertions_array, position());
150 151 152 153 154 155 156
}
template Handle<ModuleRequest>
SourceTextModuleDescriptor::AstModuleRequest::Serialize(Isolate* isolate) const;
template Handle<ModuleRequest>
SourceTextModuleDescriptor::AstModuleRequest::Serialize(
    LocalIsolate* isolate) const;

157
template <typename IsolateT>
158
Handle<SourceTextModuleInfoEntry> SourceTextModuleDescriptor::Entry::Serialize(
159
    IsolateT* isolate) const {
160
  CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
161
  return SourceTextModuleInfoEntry::New(
162 163
      isolate, ToStringOrUndefined(isolate, export_name),
      ToStringOrUndefined(isolate, local_name),
164 165
      ToStringOrUndefined(isolate, import_name), module_request, cell_index,
      location.beg_pos, location.end_pos);
166
}
167 168
template Handle<SourceTextModuleInfoEntry>
SourceTextModuleDescriptor::Entry::Serialize(Isolate* isolate) const;
169
template Handle<SourceTextModuleInfoEntry>
170
SourceTextModuleDescriptor::Entry::Serialize(LocalIsolate* isolate) const;
171

172
template <typename IsolateT>
173
Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports(
174
    IsolateT* isolate, Zone* zone) const {
175 176 177 178
  // 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.)

179
  ZoneVector<Handle<Object>> data(
180 181
      SourceTextModuleInfo::kRegularExportLength * regular_exports_.size(),
      zone);
182
  int index = 0;
183 184 185 186

  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    // Find out how many export names this local name has.
    auto next = it;
187
    int count = 0;
188
    do {
189 190
      DCHECK_EQ(it->second->local_name, next->second->local_name);
      DCHECK_EQ(it->second->cell_index, next->second->cell_index);
191
      ++next;
192
      ++count;
193 194
    } while (next != regular_exports_.end() && next->first == it->first);

195 196
    Handle<FixedArray> export_names =
        isolate->factory()->NewFixedArray(count, AllocationType::kOld);
197
    data[index + SourceTextModuleInfo::kRegularExportLocalNameOffset] =
198
        it->second->local_name->string();
199
    data[index + SourceTextModuleInfo::kRegularExportCellIndexOffset] =
200
        handle(Smi::FromInt(it->second->cell_index), isolate);
201 202 203
    data[index + SourceTextModuleInfo::kRegularExportExportNamesOffset] =
        export_names;
    index += SourceTextModuleInfo::kRegularExportLength;
204 205 206 207

    // Collect the export names.
    int i = 0;
    for (; it != next; ++it) {
208
      export_names->set(i++, *it->second->export_name->string());
209
    }
210
    DCHECK_EQ(i, count);
211 212 213 214

    // Continue with the next distinct key.
    DCHECK(it == next);
  }
215 216
  DCHECK_LE(index, static_cast<int>(data.size()));
  data.resize(index);
217 218

  // We cannot create the FixedArray earlier because we only now know the
219
  // precise size.
220 221
  Handle<FixedArray> result =
      isolate->factory()->NewFixedArray(index, AllocationType::kOld);
222
  for (int i = 0; i < index; ++i) {
223 224 225 226
    result->set(i, *data[i]);
  }
  return result;
}
227 228
template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports(
    Isolate* isolate, Zone* zone) const;
229
template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports(
230
    LocalIsolate* isolate, Zone* zone) const;
231

232
void SourceTextModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
233
  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
234
    Entry* entry = it->second;
235
    DCHECK_NOT_NULL(entry->local_name);
236 237 238 239 240
    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);
241
      DCHECK_LT(entry->module_request, 0);
242
      DCHECK_NOT_NULL(import->second->import_name);
243 244 245
      DCHECK_LE(0, import->second->module_request);
      DCHECK_LT(import->second->module_request,
                static_cast<int>(module_requests_.size()));
246 247
      entry->import_name = import->second->import_name;
      entry->module_request = import->second->module_request;
248 249 250 251 252 253 254
      // 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;
255
      entry->local_name = nullptr;
neis's avatar
neis committed
256
      AddSpecialExport(entry, zone);
257 258 259
      it = regular_exports_.erase(it);
    } else {
      it++;
260 261 262 263
    }
  }
}

264 265
SourceTextModuleDescriptor::CellIndexKind
SourceTextModuleDescriptor::GetCellIndexKind(int cell_index) {
266 267 268 269 270
  if (cell_index > 0) return kExport;
  if (cell_index < 0) return kImport;
  return kInvalid;
}

271
void SourceTextModuleDescriptor::AssignCellIndices() {
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  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--;
  }
}

301 302
namespace {

303 304 305 306 307
const SourceTextModuleDescriptor::Entry* BetterDuplicate(
    const SourceTextModuleDescriptor::Entry* candidate,
    ZoneMap<const AstRawString*, const SourceTextModuleDescriptor::Entry*>&
        export_names,
    const SourceTextModuleDescriptor::Entry* current_duplicate) {
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
  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

323 324 325 326 327
const SourceTextModuleDescriptor::Entry*
SourceTextModuleDescriptor::FindDuplicateExport(Zone* zone) const {
  const SourceTextModuleDescriptor::Entry* duplicate = nullptr;
  ZoneMap<const AstRawString*, const SourceTextModuleDescriptor::Entry*>
      export_names(zone);
328 329
  for (const auto& elem : regular_exports_) {
    duplicate = BetterDuplicate(elem.second, export_names, duplicate);
330 331 332
  }
  for (auto entry : special_exports_) {
    if (entry->export_name == nullptr) continue;  // Star export.
333
    duplicate = BetterDuplicate(entry, export_names, duplicate);
334
  }
335
  return duplicate;
336 337
}

338 339 340
bool SourceTextModuleDescriptor::Validate(
    ModuleScope* module_scope, PendingCompilationErrorHandler* error_handler,
    Zone* zone) {
341 342 343 344 345
  DCHECK_EQ(this, module_scope->module());
  DCHECK_NOT_NULL(error_handler);

  // Report error iff there are duplicate exports.
  {
346
    const Entry* entry = FindDuplicateExport(zone);
347 348 349 350 351
    if (entry != nullptr) {
      error_handler->ReportMessageAt(
          entry->location.beg_pos, entry->location.end_pos,
          MessageTemplate::kDuplicateExport, entry->export_name);
      return false;
352 353 354 355
    }
  }

  // Report error iff there are exports of non-existent local names.
356 357
  for (const auto& elem : regular_exports_) {
    const Entry* entry = elem.second;
358
    DCHECK_NOT_NULL(entry->local_name);
359 360 361 362 363 364 365 366
    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;
    }
  }

367
  MakeIndirectExportsExplicit(zone);
368
  AssignCellIndices();
369
  return true;
370
}
371

372 373
}  // namespace internal
}  // namespace v8