зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1614041 - Defer ModuleBuilder GC allocations r=arai
Introduce StencilModuleEntry type to replace {Import,Export}EntryObject during parsing. Also introduce StencilModuleMetadata to hold resulting import/export tables. Differential Revision: https://phabricator.services.mozilla.com/D83206
This commit is contained in:
Родитель
58ab7096a2
Коммит
5211daac48
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "vm/JSObject-inl.h"
|
#include "vm/JSObject-inl.h"
|
||||||
#include "vm/JSScript-inl.h"
|
#include "vm/JSScript-inl.h"
|
||||||
|
#include "vm/NativeObject-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
||||||
|
@ -1217,45 +1218,52 @@ ModuleBuilder::ModuleBuilder(JSContext* cx,
|
||||||
requestedModules_(cx, RequestedModuleVector(cx)),
|
requestedModules_(cx, RequestedModuleVector(cx)),
|
||||||
importEntries_(cx, ImportEntryMap(cx)),
|
importEntries_(cx, ImportEntryMap(cx)),
|
||||||
exportEntries_(cx, ExportEntryVector(cx)),
|
exportEntries_(cx, ExportEntryVector(cx)),
|
||||||
exportNames_(cx, AtomSet(cx)),
|
exportNames_(cx, AtomSet(cx)) {}
|
||||||
localExportEntries_(cx, ExportEntryVector(cx)),
|
|
||||||
indirectExportEntries_(cx, ExportEntryVector(cx)),
|
|
||||||
starExportEntries_(cx, ExportEntryVector(cx)) {}
|
|
||||||
|
|
||||||
bool ModuleBuilder::buildTables() {
|
bool ModuleBuilder::buildTables(frontend::StencilModuleMetadata& metadata) {
|
||||||
for (const auto& e : exportEntries_) {
|
// https://tc39.es/ecma262/#sec-parsemodule
|
||||||
RootedExportEntryObject exp(cx_, e);
|
// 15.2.1.17.1 ParseModule, Steps 4-11.
|
||||||
if (!exp->moduleRequest()) {
|
|
||||||
RootedImportEntryObject importEntry(cx_,
|
// Step 4.
|
||||||
importEntryFor(exp->localName()));
|
metadata.requestedModules = std::move(requestedModules_.get());
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
if (!metadata.importEntries.reserve(importEntries_.count())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto r = importEntries_.all(); !r.empty(); r.popFront()) {
|
||||||
|
frontend::StencilModuleEntry& entry = r.front().value();
|
||||||
|
metadata.importEntries.infallibleAppend(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 6-11.
|
||||||
|
for (const frontend::StencilModuleEntry& exp : exportEntries_) {
|
||||||
|
if (!exp.specifier) {
|
||||||
|
frontend::StencilModuleEntry* importEntry = importEntryFor(exp.localName);
|
||||||
if (!importEntry) {
|
if (!importEntry) {
|
||||||
if (!localExportEntries_.append(exp)) {
|
if (!metadata.localExportEntries.append(exp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (importEntry->importName() == cx_->names().star) {
|
if (importEntry->importName == cx_->names().star) {
|
||||||
if (!localExportEntries_.append(exp)) {
|
if (!metadata.localExportEntries.append(exp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RootedAtom exportName(cx_, exp->exportName());
|
auto entry = frontend::StencilModuleEntry::exportFromEntry(
|
||||||
RootedAtom moduleRequest(cx_, importEntry->moduleRequest());
|
importEntry->specifier, importEntry->importName, exp.exportName,
|
||||||
RootedAtom importName(cx_, importEntry->importName());
|
exp.lineno, exp.column);
|
||||||
RootedExportEntryObject exportEntry(cx_);
|
if (!metadata.indirectExportEntries.append(entry)) {
|
||||||
exportEntry = ExportEntryObject::create(
|
|
||||||
cx_, exportName, moduleRequest, importName, nullptr,
|
|
||||||
exp->lineNumber(), exp->columnNumber());
|
|
||||||
if (!exportEntry || !indirectExportEntries_.append(exportEntry)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (exp->importName() == cx_->names().star) {
|
} else if (exp.importName == cx_->names().star) {
|
||||||
if (!starExportEntries_.append(exp)) {
|
if (!metadata.starExportEntries.append(exp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!indirectExportEntries_.append(exp)) {
|
if (!metadata.indirectExportEntries.append(exp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1264,39 +1272,106 @@ bool ModuleBuilder::buildTables() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleBuilder::initModule(JS::Handle<ModuleObject*> module) {
|
enum class ModuleArrayType {
|
||||||
RootedArrayObject requestedModules(cx_,
|
ImportEntryObject,
|
||||||
js::CreateArray(cx_, requestedModules_));
|
ExportEntryObject,
|
||||||
if (!requestedModules) {
|
RequestedModuleObject,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ArrayObject* ModuleBuilderInitArray(
|
||||||
|
JSContext* cx, ModuleArrayType arrayType,
|
||||||
|
const frontend::StencilModuleMetadata::EntryVector& vector) {
|
||||||
|
RootedArrayObject resultArray(
|
||||||
|
cx, NewDenseFullyAllocatedArray(cx, vector.length()));
|
||||||
|
if (!resultArray) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultArray->ensureDenseInitializedLength(cx, 0, vector.length());
|
||||||
|
|
||||||
|
RootedAtom specifier(cx);
|
||||||
|
RootedAtom localName(cx);
|
||||||
|
RootedAtom importName(cx);
|
||||||
|
RootedAtom exportName(cx);
|
||||||
|
RootedObject req(cx);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < vector.length(); ++i) {
|
||||||
|
const frontend::StencilModuleEntry& entry = vector[i];
|
||||||
|
specifier = entry.specifier;
|
||||||
|
localName = entry.localName;
|
||||||
|
importName = entry.importName;
|
||||||
|
exportName = entry.exportName;
|
||||||
|
|
||||||
|
switch (arrayType) {
|
||||||
|
case ModuleArrayType::ImportEntryObject:
|
||||||
|
MOZ_ASSERT(localName && importName);
|
||||||
|
req = ImportEntryObject::create(cx, specifier, importName, localName,
|
||||||
|
entry.lineno, entry.column);
|
||||||
|
break;
|
||||||
|
case ModuleArrayType::ExportEntryObject:
|
||||||
|
MOZ_ASSERT(localName || importName || exportName);
|
||||||
|
req = ExportEntryObject::create(cx, exportName, specifier, importName,
|
||||||
|
localName, entry.lineno, entry.column);
|
||||||
|
break;
|
||||||
|
case ModuleArrayType::RequestedModuleObject:
|
||||||
|
req = RequestedModuleObject::create(cx, specifier, entry.lineno,
|
||||||
|
entry.column);
|
||||||
|
// TODO: Make this consistent with other object types.
|
||||||
|
if (req && !FreezeObject(cx, req)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!req) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
resultArray->initDenseElement(i, ObjectValue(*req));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use StencilModuleMetadata data to fill in ModuleObject
|
||||||
|
bool frontend::StencilModuleMetadata::initModule(
|
||||||
|
JSContext* cx, JS::Handle<ModuleObject*> module) {
|
||||||
|
RootedArrayObject requestedModulesObject(
|
||||||
|
cx, ModuleBuilderInitArray(cx, ModuleArrayType::RequestedModuleObject,
|
||||||
|
requestedModules));
|
||||||
|
if (!requestedModulesObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedArrayObject importEntries(cx_, createArrayFromHashMap(importEntries_));
|
RootedArrayObject importEntriesObject(
|
||||||
if (!importEntries) {
|
cx, ModuleBuilderInitArray(cx, ModuleArrayType::ImportEntryObject,
|
||||||
|
importEntries));
|
||||||
|
if (!importEntriesObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedArrayObject localExportEntries(
|
RootedArrayObject localExportEntriesObject(
|
||||||
cx_, js::CreateArray(cx_, localExportEntries_));
|
cx, ModuleBuilderInitArray(cx, ModuleArrayType::ExportEntryObject,
|
||||||
if (!localExportEntries) {
|
localExportEntries));
|
||||||
|
if (!localExportEntriesObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedArrayObject indirectExportEntries(
|
RootedArrayObject indirectExportEntriesObject(
|
||||||
cx_, js::CreateArray(cx_, indirectExportEntries_));
|
cx, ModuleBuilderInitArray(cx, ModuleArrayType::ExportEntryObject,
|
||||||
if (!indirectExportEntries) {
|
indirectExportEntries));
|
||||||
|
if (!indirectExportEntriesObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedArrayObject starExportEntries(cx_,
|
RootedArrayObject starExportEntriesObject(
|
||||||
js::CreateArray(cx_, starExportEntries_));
|
cx, ModuleBuilderInitArray(cx, ModuleArrayType::ExportEntryObject,
|
||||||
if (!starExportEntries) {
|
starExportEntries));
|
||||||
|
if (!starExportEntriesObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
module->initImportExportData(requestedModules, importEntries,
|
module->initImportExportData(
|
||||||
localExportEntries, indirectExportEntries,
|
requestedModulesObject, importEntriesObject, localExportEntriesObject,
|
||||||
starExportEntries);
|
indirectExportEntriesObject, starExportEntriesObject);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1335,10 +1410,9 @@ bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
|
||||||
eitherParser_.computeLineAndColumn(importNameNode->pn_pos.begin, &line,
|
eitherParser_.computeLineAndColumn(importNameNode->pn_pos.begin, &line,
|
||||||
&column);
|
&column);
|
||||||
|
|
||||||
RootedImportEntryObject importEntry(cx_);
|
auto entry = frontend::StencilModuleEntry::importEntry(
|
||||||
importEntry = ImportEntryObject::create(cx_, module, importName, localName,
|
module, localName, importName, line, column);
|
||||||
line, column);
|
if (!importEntries_.put(localName, entry)) {
|
||||||
if (!importEntry || !appendImportEntryObject(importEntry)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1346,12 +1420,6 @@ bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleBuilder::appendImportEntryObject(
|
|
||||||
HandleImportEntryObject importEntry) {
|
|
||||||
MOZ_ASSERT(importEntry->localName());
|
|
||||||
return importEntries_.put(importEntry->localName(), importEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModuleBuilder::processExport(frontend::ParseNode* exportNode) {
|
bool ModuleBuilder::processExport(frontend::ParseNode* exportNode) {
|
||||||
using namespace js::frontend;
|
using namespace js::frontend;
|
||||||
|
|
||||||
|
@ -1568,14 +1636,15 @@ bool ModuleBuilder::processExportFrom(frontend::BinaryNode* exportNode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportEntryObject* ModuleBuilder::importEntryFor(JSAtom* localName) const {
|
frontend::StencilModuleEntry* ModuleBuilder::importEntryFor(
|
||||||
|
JSAtom* localName) const {
|
||||||
MOZ_ASSERT(localName);
|
MOZ_ASSERT(localName);
|
||||||
auto ptr = importEntries_.lookup(localName);
|
auto ptr = importEntries_.lookup(localName);
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr->value();
|
return &ptr->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleBuilder::hasExportedName(JSAtom* name) const {
|
bool ModuleBuilder::hasExportedName(JSAtom* name) const {
|
||||||
|
@ -1592,10 +1661,19 @@ bool ModuleBuilder::appendExportEntry(HandleAtom exportName,
|
||||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
auto entry = frontend::StencilModuleEntry::exportAsEntry(
|
||||||
exportEntry = ExportEntryObject::create(cx_, exportName, nullptr, nullptr,
|
localName, exportName, line, column);
|
||||||
localName, line, column);
|
if (!exportEntries_.append(entry)) {
|
||||||
return exportEntry && appendExportEntryObject(exportEntry);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exportName) {
|
||||||
|
if (!exportNames_.put(exportName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleBuilder::appendExportFromEntry(HandleAtom exportName,
|
bool ModuleBuilder::appendExportFromEntry(HandleAtom exportName,
|
||||||
|
@ -1606,19 +1684,12 @@ bool ModuleBuilder::appendExportFromEntry(HandleAtom exportName,
|
||||||
uint32_t column;
|
uint32_t column;
|
||||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||||
|
|
||||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
auto entry = frontend::StencilModuleEntry::exportFromEntry(
|
||||||
exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest,
|
moduleRequest, importName, exportName, line, column);
|
||||||
importName, nullptr, line, column);
|
if (!exportEntries_.append(entry)) {
|
||||||
return exportEntry && appendExportEntryObject(exportEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModuleBuilder::appendExportEntryObject(
|
|
||||||
HandleExportEntryObject exportEntry) {
|
|
||||||
if (!exportEntries_.append(exportEntry)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAtom* exportName = exportEntry->exportName();
|
|
||||||
return !exportName || exportNames_.put(exportName);
|
return !exportName || exportNames_.put(exportName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1632,15 +1703,13 @@ bool ModuleBuilder::maybeAppendRequestedModule(HandleAtom specifier,
|
||||||
uint32_t column;
|
uint32_t column;
|
||||||
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
|
||||||
|
|
||||||
JSContext* cx = cx_;
|
auto entry =
|
||||||
RootedRequestedModuleObject req(
|
frontend::StencilModuleEntry::moduleRequest(specifier, line, column);
|
||||||
cx, RequestedModuleObject::create(cx, specifier, line, column));
|
if (!requestedModules_.append(entry)) {
|
||||||
if (!req) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FreezeObject(cx, req) && requestedModules_.append(req) &&
|
return requestedModuleSpecifiers_.put(specifier);
|
||||||
requestedModuleSpecifiers_.put(specifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -1660,25 +1729,6 @@ ArrayObject* js::CreateArray(JSContext* cx,
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
|
||||||
ArrayObject* ModuleBuilder::createArrayFromHashMap(
|
|
||||||
const JS::Rooted<GCHashMap<K, V>>& map) {
|
|
||||||
uint32_t length = map.count();
|
|
||||||
RootedArrayObject array(cx_, NewDenseFullyAllocatedArray(cx_, length));
|
|
||||||
if (!array) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
array->setDenseInitializedLength(length);
|
|
||||||
|
|
||||||
uint32_t i = 0;
|
|
||||||
for (auto r = map.all(); !r.empty(); r.popFront()) {
|
|
||||||
array->initDenseElement(i++, ObjectValue(*r.front().value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* js::GetOrCreateModuleMetaObject(JSContext* cx,
|
JSObject* js::GetOrCreateModuleMetaObject(JSContext* cx,
|
||||||
HandleObject moduleArg) {
|
HandleObject moduleArg) {
|
||||||
HandleModuleObject module = moduleArg.as<ModuleObject>();
|
HandleModuleObject module = moduleArg.as<ModuleObject>();
|
||||||
|
|
|
@ -551,7 +551,8 @@ ModuleObject* frontend::ModuleCompiler<Unit>::compile(
|
||||||
|
|
||||||
MOZ_ASSERT(compilationInfo.script);
|
MOZ_ASSERT(compilationInfo.script);
|
||||||
|
|
||||||
if (!builder.initModule(module)) {
|
StencilModuleMetadata& moduleMetadata = compilationInfo.moduleMetadata.get();
|
||||||
|
if (!moduleMetadata.initModule(cx, module)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,9 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||||
// an index (and CompilationInfo reference).
|
// an index (and CompilationInfo reference).
|
||||||
JS::RootedVector<ScopeCreationData> scopeCreationData;
|
JS::RootedVector<ScopeCreationData> scopeCreationData;
|
||||||
|
|
||||||
|
// Module metadata if this is a module compile.
|
||||||
|
JS::Rooted<StencilModuleMetadata> moduleMetadata;
|
||||||
|
|
||||||
// AsmJS modules generated by parsing.
|
// AsmJS modules generated by parsing.
|
||||||
HashMap<FunctionIndex, RefPtr<const JS::WasmModule>> asmJS;
|
HashMap<FunctionIndex, RefPtr<const JS::WasmModule>> asmJS;
|
||||||
|
|
||||||
|
@ -238,6 +241,7 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||||
enclosingScope(cx),
|
enclosingScope(cx),
|
||||||
topLevel(cx),
|
topLevel(cx),
|
||||||
scopeCreationData(cx),
|
scopeCreationData(cx),
|
||||||
|
moduleMetadata(cx),
|
||||||
asmJS(cx),
|
asmJS(cx),
|
||||||
sourceObject(cx) {}
|
sourceObject(cx) {}
|
||||||
|
|
||||||
|
|
|
@ -1622,13 +1622,17 @@ ModuleNode* Parser<FullParseHandler, Unit>::moduleBody(
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modulesc->builder.buildTables()) {
|
// Generate the Import/Export tables and store in CompilationInfo.
|
||||||
|
if (!modulesc->builder.buildTables(
|
||||||
|
this->compilationInfo_.moduleMetadata.get())) {
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check exported local bindings exist and mark them as closed over.
|
// Check exported local bindings exist and mark them as closed over.
|
||||||
for (auto entry : modulesc->builder.localExportEntries()) {
|
StencilModuleMetadata& moduleMetadata =
|
||||||
JSAtom* name = entry->localName();
|
this->compilationInfo_.moduleMetadata.get();
|
||||||
|
for (auto entry : moduleMetadata.localExportEntries) {
|
||||||
|
JSAtom* name = entry.localName;
|
||||||
MOZ_ASSERT(name);
|
MOZ_ASSERT(name);
|
||||||
|
|
||||||
DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
|
DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
|
||||||
|
|
|
@ -229,6 +229,29 @@ uint32_t ScopeCreationData::nextFrameSlot() const {
|
||||||
MOZ_CRASH("Not an enclosing intra-frame scope");
|
MOZ_CRASH("Not an enclosing intra-frame scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StencilModuleEntry::trace(JSTracer* trc) {
|
||||||
|
if (specifier) {
|
||||||
|
TraceManuallyBarrieredEdge(trc, &specifier, "module specifier");
|
||||||
|
}
|
||||||
|
if (localName) {
|
||||||
|
TraceManuallyBarrieredEdge(trc, &localName, "module local name");
|
||||||
|
}
|
||||||
|
if (importName) {
|
||||||
|
TraceManuallyBarrieredEdge(trc, &importName, "module import name");
|
||||||
|
}
|
||||||
|
if (exportName) {
|
||||||
|
TraceManuallyBarrieredEdge(trc, &exportName, "module export name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilModuleMetadata::trace(JSTracer* trc) {
|
||||||
|
requestedModules.trace(trc);
|
||||||
|
importEntries.trace(trc);
|
||||||
|
localExportEntries.trace(trc);
|
||||||
|
indirectExportEntries.trace(trc);
|
||||||
|
starExportEntries.trace(trc);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptStencil::trace(JSTracer* trc) {
|
void ScriptStencil::trace(JSTracer* trc) {
|
||||||
for (ScriptThingVariant& thing : gcThings) {
|
for (ScriptThingVariant& thing : gcThings) {
|
||||||
if (thing.is<ScriptAtom>()) {
|
if (thing.is<ScriptAtom>()) {
|
||||||
|
|
|
@ -330,6 +330,108 @@ class ScopeCreationData {
|
||||||
|
|
||||||
class EmptyGlobalScopeType {};
|
class EmptyGlobalScopeType {};
|
||||||
|
|
||||||
|
// Common type for ImportEntry / ExportEntry / ModuleRequest within frontend. We
|
||||||
|
// use a shared stencil class type to simplify serialization.
|
||||||
|
//
|
||||||
|
// https://tc39.es/ecma262/#importentry-record
|
||||||
|
// https://tc39.es/ecma262/#exportentry-record
|
||||||
|
//
|
||||||
|
// Note: We subdivide the spec's ExportEntry into ExportAs / ExportFrom forms
|
||||||
|
// for readability.
|
||||||
|
class StencilModuleEntry {
|
||||||
|
public:
|
||||||
|
// | ModuleRequest | ImportEntry | ExportAs | ExportFrom |
|
||||||
|
// |-----------------------------------------------------|
|
||||||
|
// specifier | required | required | nullptr | required |
|
||||||
|
// localName | null | required | required | nullptr |
|
||||||
|
// importName | null | required | nullptr | required |
|
||||||
|
// exportName | null | null | required | optional |
|
||||||
|
JSAtom* specifier = nullptr;
|
||||||
|
JSAtom* localName = nullptr;
|
||||||
|
JSAtom* importName = nullptr;
|
||||||
|
JSAtom* exportName = nullptr;
|
||||||
|
|
||||||
|
// Location used for error messages. If this is for a module request entry
|
||||||
|
// then it is the module specifier string, otherwise the import/export spec
|
||||||
|
// that failed. Exports may not fill these fields if an error cannot be
|
||||||
|
// generated such as `export let x;`.
|
||||||
|
uint32_t lineno = 0;
|
||||||
|
uint32_t column = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StencilModuleEntry(uint32_t lineno, uint32_t column)
|
||||||
|
: lineno(lineno), column(column) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static StencilModuleEntry moduleRequest(JSAtom* specifier, uint32_t lineno,
|
||||||
|
uint32_t column) {
|
||||||
|
MOZ_ASSERT(specifier);
|
||||||
|
StencilModuleEntry entry(lineno, column);
|
||||||
|
entry.specifier = specifier;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StencilModuleEntry importEntry(JSAtom* specifier, JSAtom* localName,
|
||||||
|
JSAtom* importName, uint32_t lineno,
|
||||||
|
uint32_t column) {
|
||||||
|
MOZ_ASSERT(specifier && localName && importName);
|
||||||
|
StencilModuleEntry entry(lineno, column);
|
||||||
|
entry.specifier = specifier;
|
||||||
|
entry.localName = localName;
|
||||||
|
entry.importName = importName;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StencilModuleEntry exportAsEntry(JSAtom* localName, JSAtom* exportName,
|
||||||
|
uint32_t lineno, uint32_t column) {
|
||||||
|
MOZ_ASSERT(localName && exportName);
|
||||||
|
StencilModuleEntry entry(lineno, column);
|
||||||
|
entry.localName = localName;
|
||||||
|
entry.exportName = exportName;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StencilModuleEntry exportFromEntry(JSAtom* specifier,
|
||||||
|
JSAtom* importName,
|
||||||
|
JSAtom* exportName, uint32_t lineno,
|
||||||
|
uint32_t column) {
|
||||||
|
// NOTE: The `export * from "mod";` syntax generates nullptr exportName.
|
||||||
|
MOZ_ASSERT(specifier && importName);
|
||||||
|
StencilModuleEntry entry(lineno, column);
|
||||||
|
entry.specifier = specifier;
|
||||||
|
entry.importName = importName;
|
||||||
|
entry.exportName = exportName;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This traces the JSAtoms. This will be removed once atoms are deferred from
|
||||||
|
// parsing.
|
||||||
|
void trace(JSTracer* trc);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Metadata generated by parsing module scripts, including import/export tables.
|
||||||
|
class StencilModuleMetadata {
|
||||||
|
public:
|
||||||
|
using EntryVector = JS::GCVector<StencilModuleEntry>;
|
||||||
|
|
||||||
|
EntryVector requestedModules;
|
||||||
|
EntryVector importEntries;
|
||||||
|
EntryVector localExportEntries;
|
||||||
|
EntryVector indirectExportEntries;
|
||||||
|
EntryVector starExportEntries;
|
||||||
|
|
||||||
|
explicit StencilModuleMetadata(JSContext* cx)
|
||||||
|
: requestedModules(cx),
|
||||||
|
importEntries(cx),
|
||||||
|
localExportEntries(cx),
|
||||||
|
indirectExportEntries(cx),
|
||||||
|
starExportEntries(cx) {}
|
||||||
|
|
||||||
|
bool initModule(JSContext* cx, JS::Handle<ModuleObject*> module);
|
||||||
|
|
||||||
|
void trace(JSTracer* trc);
|
||||||
|
};
|
||||||
|
|
||||||
// The lazy closed-over-binding info is represented by these types that will
|
// The lazy closed-over-binding info is represented by these types that will
|
||||||
// convert to a GCCellPtr(nullptr), GCCellPtr(JSAtom*).
|
// convert to a GCCellPtr(nullptr), GCCellPtr(JSAtom*).
|
||||||
class NullScriptThing {};
|
class NullScriptThing {};
|
||||||
|
|
|
@ -11,11 +11,13 @@
|
||||||
|
|
||||||
#include "jstypes.h" // JS_PUBLIC_API
|
#include "jstypes.h" // JS_PUBLIC_API
|
||||||
#include "builtin/ModuleObject.h" // js::{{Im,Ex}portEntry,Requested{Module,}}Object
|
#include "builtin/ModuleObject.h" // js::{{Im,Ex}portEntry,Requested{Module,}}Object
|
||||||
#include "frontend/EitherParser.h" // js::frontend::EitherParser
|
#include "frontend/CompilationInfo.h" // js::frontend::CompilationInfo
|
||||||
#include "js/GCHashTable.h" // JS::GCHash{Map,Set}
|
#include "frontend/EitherParser.h" // js::frontend::EitherParser
|
||||||
#include "js/GCVector.h" // JS::GCVector
|
#include "frontend/Stencil.h" // js::frontend::StencilModuleEntry
|
||||||
#include "js/RootingAPI.h" // JS::{Handle,Rooted}
|
#include "js/GCHashTable.h" // JS::GCHash{Map,Set}
|
||||||
#include "vm/AtomsTable.h" // js::AtomSet
|
#include "js/GCVector.h" // JS::GCVector
|
||||||
|
#include "js/RootingAPI.h" // JS::{Handle,Rooted}
|
||||||
|
#include "vm/AtomsTable.h" // js::AtomSet
|
||||||
|
|
||||||
struct JS_PUBLIC_API JSContext;
|
struct JS_PUBLIC_API JSContext;
|
||||||
class JS_PUBLIC_API JSAtom;
|
class JS_PUBLIC_API JSAtom;
|
||||||
|
@ -47,18 +49,13 @@ class MOZ_STACK_CLASS ModuleBuilder {
|
||||||
|
|
||||||
bool hasExportedName(JSAtom* name) const;
|
bool hasExportedName(JSAtom* name) const;
|
||||||
|
|
||||||
using ExportEntryVector = GCVector<ExportEntryObject*>;
|
bool buildTables(frontend::StencilModuleMetadata& metadata);
|
||||||
const ExportEntryVector& localExportEntries() const {
|
|
||||||
return localExportEntries_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool buildTables();
|
|
||||||
bool initModule(JS::Handle<ModuleObject*> module);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using RequestedModuleVector = JS::GCVector<RequestedModuleObject*>;
|
using RequestedModuleVector = JS::GCVector<frontend::StencilModuleEntry>;
|
||||||
using AtomSet = JS::GCHashSet<JSAtom*>;
|
using AtomSet = JS::GCHashSet<JSAtom*>;
|
||||||
using ImportEntryMap = JS::GCHashMap<JSAtom*, ImportEntryObject*>;
|
using ExportEntryVector = GCVector<frontend::StencilModuleEntry>;
|
||||||
|
using ImportEntryMap = JS::GCHashMap<JSAtom*, frontend::StencilModuleEntry>;
|
||||||
using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
|
using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
|
||||||
using RootedRequestedModuleVector = JS::Rooted<RequestedModuleVector>;
|
using RootedRequestedModuleVector = JS::Rooted<RequestedModuleVector>;
|
||||||
using RootedAtomSet = JS::Rooted<AtomSet>;
|
using RootedAtomSet = JS::Rooted<AtomSet>;
|
||||||
|
@ -66,23 +63,19 @@ class MOZ_STACK_CLASS ModuleBuilder {
|
||||||
|
|
||||||
JSContext* cx_;
|
JSContext* cx_;
|
||||||
frontend::EitherParser eitherParser_;
|
frontend::EitherParser eitherParser_;
|
||||||
|
|
||||||
RootedAtomSet requestedModuleSpecifiers_;
|
RootedAtomSet requestedModuleSpecifiers_;
|
||||||
RootedRequestedModuleVector requestedModules_;
|
RootedRequestedModuleVector requestedModules_;
|
||||||
RootedImportEntryMap importEntries_;
|
RootedImportEntryMap importEntries_;
|
||||||
RootedExportEntryVector exportEntries_;
|
RootedExportEntryVector exportEntries_;
|
||||||
RootedAtomSet exportNames_;
|
RootedAtomSet exportNames_;
|
||||||
RootedExportEntryVector localExportEntries_;
|
|
||||||
RootedExportEntryVector indirectExportEntries_;
|
|
||||||
RootedExportEntryVector starExportEntries_;
|
|
||||||
|
|
||||||
ImportEntryObject* importEntryFor(JSAtom* localName) const;
|
frontend::StencilModuleEntry* importEntryFor(JSAtom* localName) const;
|
||||||
|
|
||||||
bool processExportBinding(frontend::ParseNode* pn);
|
bool processExportBinding(frontend::ParseNode* pn);
|
||||||
bool processExportArrayBinding(frontend::ListNode* array);
|
bool processExportArrayBinding(frontend::ListNode* array);
|
||||||
bool processExportObjectBinding(frontend::ListNode* obj);
|
bool processExportObjectBinding(frontend::ListNode* obj);
|
||||||
|
|
||||||
bool appendImportEntryObject(JS::Handle<ImportEntryObject*> importEntry);
|
|
||||||
|
|
||||||
bool appendExportEntry(JS::Handle<JSAtom*> exportName,
|
bool appendExportEntry(JS::Handle<JSAtom*> exportName,
|
||||||
JS::Handle<JSAtom*> localName,
|
JS::Handle<JSAtom*> localName,
|
||||||
frontend::ParseNode* node = nullptr);
|
frontend::ParseNode* node = nullptr);
|
||||||
|
@ -92,14 +85,8 @@ class MOZ_STACK_CLASS ModuleBuilder {
|
||||||
JS::Handle<JSAtom*> importName,
|
JS::Handle<JSAtom*> importName,
|
||||||
frontend::ParseNode* node);
|
frontend::ParseNode* node);
|
||||||
|
|
||||||
bool appendExportEntryObject(JS::Handle<ExportEntryObject*> exportEntry);
|
|
||||||
|
|
||||||
bool maybeAppendRequestedModule(JS::Handle<JSAtom*> specifier,
|
bool maybeAppendRequestedModule(JS::Handle<JSAtom*> specifier,
|
||||||
frontend::ParseNode* node);
|
frontend::ParseNode* node);
|
||||||
|
|
||||||
template <typename K, typename V>
|
|
||||||
ArrayObject* createArrayFromHashMap(
|
|
||||||
const JS::Rooted<JS::GCHashMap<K, V>>& map);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче