Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 77 additions & 37 deletions src/passes/MakeSharedObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct LazyTable {
// The names of conversion functions, if ever used.
Name refToIndexName;
Name indexToRefName;
// Initial elements used to populate the table via an active element segment.
std::vector<Expression*> init;

LazyTable(Name base, Type type) : base(base), type(type) {}

Expand Down Expand Up @@ -190,28 +192,36 @@ struct LazyTable {
wasm->addFunction(std::move(func));
}

// Returns true if the table was added. (If it is never used, it will not be
// added.)
bool maybeAdd(Address initial, Address max) {
// Add the table, conversion functions, and active element segment if the
// table was ever used.
void maybeAdd(Address max) {
assert(wasm);
if (!name) {
return false;
return;
}
Table* table = wasm->addTable(Builder::makeTable(name));
table->type = type;
table->initial = initial;
table->initial = init.size();
table->max = max;
if (refToIndexName) {
addRefToIndexFunction();
}
if (indexToRefName) {
addIndexToRefFunction();
}
return true;
if (!init.empty()) {
Builder builder(*wasm);
Name segName = Names::getValidElementSegmentName(*wasm, base);
auto* offset = builder.makeConst(Literal(int32_t(0)));
auto* segment = wasm->addElementSegment(
Builder::makeElementSegment(segName, name, offset));
segment->type = type;
segment->data = std::move(init);
}
}

bool isTableType(Type t) const {
return t.isRef() && Type::isSubType(t, type);
return t.isRef() && !t.isNull() && Type::isSubType(t, type);
}

bool hasTableType(Type t) const {
Expand Down Expand Up @@ -264,10 +274,16 @@ struct MakeSharedObjects
Type funcref = Type(HeapTypes::func, Nullable);
Type externref = Type(HeapTypes::ext, Nullable);

// Tables storing unshared funcrefs and externrefs that are lowered to shared
// i31ref indices inside the module.
LazyTable funcTable{"funcs", funcref};
LazyTable externTable{"externs", externref};
std::vector<Name> funcs;

// Map from function name to index in `funcTable`.
std::unordered_map<Name, Index> funcIndices;

// Imported helper functions used to lower `extern.convert_any` and
// `any.convert_extern`, if needed.
Name anyToExternName;
Name externToAnyName;

Expand All @@ -287,10 +303,11 @@ struct MakeSharedObjects
return externToAnyName;
}

Index getIndex(Name func) {
auto [it, inserted] = funcIndices.insert({func, funcs.size()});
Index getIndex(RefFunc* curr) {
auto [it, inserted] =
funcIndices.insert({curr->func, funcTable.init.size()});
if (inserted) {
funcs.push_back(func);
funcTable.init.push_back(curr);
}
return it->second;
}
Expand Down Expand Up @@ -488,8 +505,8 @@ struct MakeSharedObjects

void visitRefFunc(RefFunc* curr) {
Builder builder(*getModule());
replaceCurrent(builder.makeRefI31(
builder.makeConst(Literal(getIndex(curr->func))), Shared));
replaceCurrent(
builder.makeRefI31(builder.makeConst(Literal(getIndex(curr))), Shared));
}

std::unordered_map<CallRef*, HeapType> callRefTypes;
Expand Down Expand Up @@ -718,7 +735,47 @@ struct MakeSharedObjects

void visitElementSegment(ElementSegment* curr) { updateType(curr->type); }

void visitGlobal(Global* curr) { updateType(curr->type); }
// Create a new imported global with the original externref type and add it
// to the externref table at instantiation time. The original global ceases to
// be an import and is initialized to the shared i31 table index so internal
// uses of the global receive the table index.
void wrapGlobalImport(Global* global, Type origType) {
Builder builder(*getModule());
Name origName = global->name;
Name importName =
Names::getValidGlobalName(*getModule(), origName.toString() + "$import");

auto importGlobal = std::make_unique<Global>();
importGlobal->name = importName;
importGlobal->module = global->module;
importGlobal->base = global->base;
importGlobal->type = origType;
importGlobal->mutable_ = false;
importGlobal->hasExplicitName = true;

Index index = externTable.init.size();
externTable.init.push_back(builder.makeGlobalGet(importName, origType));

global->module = Name();
global->base = Name();
global->init =
builder.makeRefI31(builder.makeConst(Literal(int32_t(index))), Shared);

getModule()->addGlobal(std::move(importGlobal));
}

struct GlobalImportToWrap {
Global* global;
Type origType;
};
std::vector<GlobalImportToWrap> globalImportsToWrap;

void visitGlobal(Global* curr) {
if (curr->imported() && externTable.isTableType(curr->type)) {
globalImportsToWrap.push_back({curr, curr->type});
}
updateType(curr->type);
}

void doWalkModule(Module* wasm) {
funcTable.wasm = wasm;
Expand Down Expand Up @@ -759,6 +816,9 @@ struct MakeSharedObjects

rewriteTypes();

for (auto& info : globalImportsToWrap) {
wrapGlobalImport(info.global, info.origType);
}
for (auto& info : importsToWrap) {
wrapImport(info.func, info.origType);
}
Expand All @@ -773,9 +833,10 @@ struct MakeSharedObjects
}
}

addFunctionTable();
funcTable.maybeAdd(funcTable.init.size());
addExternTable();
ReFinalize().run(getPassRunner(), wasm);
ReFinalize().walkModuleCode(wasm);
}

void rewriteTypes() {
Expand Down Expand Up @@ -822,27 +883,6 @@ struct MakeSharedObjects
rewriter.mapTypeNamesAndIndices(oldToNew);
}

void addFunctionTable() {
if (!funcTable.maybeAdd(funcs.size(), funcs.size())) {
return;
}
if (funcs.empty()) {
return;
}
Builder builder(*getModule());
Name segName = Names::getValidElementSegmentName(*getModule(), "funcs");
auto* offset = builder.makeConst(Literal(int32_t(0)));
auto* segment = getModule()->addElementSegment(
Builder::makeElementSegment(segName, funcTable.getName(), offset));
segment->type = funcTable.type;

segment->data.reserve(funcs.size());
for (auto func : funcs) {
segment->data.push_back(
builder.makeRefFunc(func, getModule()->getFunction(func)->type));
}
}

void addAnyToExternFunction() {
Type sharedAnyNullable = Type(HeapTypes::any.getBasic(Shared), Nullable);
Type externrefNullable = Type(HeapTypes::ext, Nullable);
Expand All @@ -866,7 +906,7 @@ struct MakeSharedObjects
}

void addExternTable() {
externTable.maybeAdd(0, Table::kUnlimitedSize);
externTable.maybeAdd(Table::kUnlimitedSize);
if (anyToExternName) {
addAnyToExternFunction();
}
Expand Down
Loading
Loading