Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
5 changes: 4 additions & 1 deletion scripts/test/fuzzing.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@
'stack_switching_suspend.wast',
'stack_switching_resume.wast',
'stack_switching_resume_throw.wast',
'stack_switching_switch.wast'
'stack_switching_switch.wast',
# TODO: fuzzer support for type imports
'type-imports.wast',
'type-imports.wat'
]


Expand Down
42 changes: 42 additions & 0 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4959,6 +4959,37 @@ BinaryenExportRef BinaryenGetExportByIndex(BinaryenModuleRef module,
return exports[index].get();
}

// Type Exports

BinaryenTypeExportRef BinaryenAddTypeExport(BinaryenModuleRef module,
BinaryenHeapType type,
const char* externalName) {
auto* ret = new TypeExport();
ret->heaptype = HeapType(type);
ret->name = externalName;
((Module*)module)->addTypeExport(ret);
return ret;
}
BinaryenTypeExportRef BinaryenGetTypeExport(BinaryenModuleRef module,
const char* externalName) {
return ((Module*)module)->getTypeExportOrNull(externalName);
}
void BinaryenRemoveTypeExport(BinaryenModuleRef module,
const char* externalName) {
((Module*)module)->removeTypeExport(externalName);
}
BinaryenIndex BinaryenGetNumTypeExports(BinaryenModuleRef module) {
return ((Module*)module)->typeExports.size();
}
BinaryenTypeExportRef BinaryenGetTypeExportByIndex(BinaryenModuleRef module,
BinaryenIndex index) {
const auto& exports = ((Module*)module)->typeExports;
if (exports.size() <= index) {
Fatal() << "invalid export index.";
}
return exports[index].get();
}

BinaryenTableRef BinaryenAddTable(BinaryenModuleRef module,
const char* name,
BinaryenIndex initial,
Expand Down Expand Up @@ -5928,6 +5959,17 @@ const char* BinaryenExportGetValue(BinaryenExportRef export_) {
return ((Export*)export_)->value.str.data();
}

//
// =========== Type export operations ===========
//

const char* BinaryenTypeExportGetName(BinaryenTypeExportRef export_) {
return ((TypeExport*)export_)->name.str.data();
}
BinaryenHeapType BinaryenTypeExportGetHeapType(BinaryenTypeExportRef export_) {
return ((TypeExport*)export_)->heaptype.getID();
}

//
// ========= Custom sections =========
//
Expand Down
31 changes: 31 additions & 0 deletions src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,26 @@ BINARYEN_API BinaryenIndex BinaryenGetNumExports(BinaryenModuleRef module);
BINARYEN_API BinaryenExportRef
BinaryenGetExportByIndex(BinaryenModuleRef module, BinaryenIndex index);

// Type exports

BINARYEN_REF(TypeExport);

// Adds a type export to the module.
BINARYEN_API BinaryenTypeExportRef BinaryenAddTypeExport(
BinaryenModuleRef module, BinaryenHeapType type, const char* externalName);
// Gets a type export reference by external name. Returns NULL if the export
// does not exist.
BINARYEN_API BinaryenTypeExportRef
BinaryenGetTypeExport(BinaryenModuleRef module, const char* externalName);
// Removes a type export by external name.
BINARYEN_API void BinaryenRemoveTypeExport(BinaryenModuleRef module,
const char* externalName);
// Gets the number of type exports in the module.
BINARYEN_API BinaryenIndex BinaryenGetNumTypeExports(BinaryenModuleRef module);
// Gets the type export at the specified index.
BINARYEN_API BinaryenTypeExportRef
BinaryenGetTypeExportByIndex(BinaryenModuleRef module, BinaryenIndex index);

// Globals

BINARYEN_REF(Global);
Expand Down Expand Up @@ -3315,6 +3335,17 @@ BINARYEN_API const char* BinaryenExportGetName(BinaryenExportRef export_);
// Gets the internal name of the specified export.
BINARYEN_API const char* BinaryenExportGetValue(BinaryenExportRef export_);

//
// ========== Type Export Operations ==========
//

// Gets the external name of the specified export.
BINARYEN_API const char*
BinaryenTypeExportGetName(BinaryenTypeExportRef export_);
// Gets the internal name of the specified export.
BINARYEN_API BinaryenHeapType
BinaryenTypeExportGetHeapType(BinaryenTypeExportRef export_);

//
// ========= Custom sections =========
//
Expand Down
1 change: 1 addition & 0 deletions src/ir/gc-type-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ inline std::optional<Field> getField(HeapType type, Index index = 0) {
return type.getArray().element;
case HeapTypeKind::Func:
case HeapTypeKind::Cont:
case HeapTypeKind::Import:
case HeapTypeKind::Basic:
break;
}
Expand Down
18 changes: 17 additions & 1 deletion src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,9 @@ InsertOrderedMap<HeapType, HeapTypeInfo> collectHeapTypeInfo(
for (auto& curr : wasm.elementSegments) {
info.note(curr->type);
}
for (auto& curr : wasm.typeExports) {
info.note(curr->heaptype);
}

// Collect info from functions in parallel.
ModuleUtils::ParallelFunctionAnalysis<TypeInfos, Immutable, InsertOrderedMap>
Expand Down Expand Up @@ -655,11 +658,15 @@ void classifyTypeVisibility(Module& wasm,
case ExternalKind::Tag:
notePublic(wasm.getTag(ex->value)->type);
continue;
case ExternalKind::Type:
case ExternalKind::Invalid:
break;
}
WASM_UNREACHABLE("unexpected export kind");
}
for (auto& ex : wasm.typeExports) {
notePublic(ex->heaptype);
}

// Ignorable public types are public.
for (auto type : getIgnorablePublicTypes()) {
Expand Down Expand Up @@ -793,6 +800,11 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
}
}

std::vector<bool> isImport(groups.size());
for (size_t i = 0; i < groups.size(); ++i) {
isImport[i] = groups[i][0].isImport();
}

// If we've preserved the input type order on the module, we have to respect
// that first. Use the index of the first type from each group. In principle
// we could try to do something more robust like take the minimum index of all
Expand All @@ -812,7 +824,11 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
}
}

auto order = TopologicalSort::minSort(deps, [&](size_t a, size_t b) {
auto order = TopologicalSort::minSort(deps, [&](size_t a, size_t b) -> bool {
// Imports should be first
if (isImport[a] != isImport[b]) {
return isImport[a];
}
auto indexA = groupTypeIndices[a];
auto indexB = groupTypeIndices[b];
// Groups with indices must be sorted before groups without indices to
Expand Down
6 changes: 4 additions & 2 deletions src/ir/names.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ inline Name getValidName(Name root,
inline Name getValidExportName(Module& module, Name root) {
return getValidName(
root,
[&](Name test) { return !module.getExportOrNull(test); },
module.exports.size());
[&](Name test) {
return !module.getTypeExportOrNull(test) && !module.getExportOrNull(test);
},
module.typeExports.size() + module.exports.size());
}
inline Name getValidGlobalName(Module& module, Name root) {
return getValidName(
Expand Down
1 change: 1 addition & 0 deletions src/ir/subtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct SubTypes {
break;
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Import:
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
Expand Down
6 changes: 6 additions & 0 deletions src/ir/type-updating.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ GlobalTypeRewriter::TypeMap GlobalTypeRewriter::rebuildTypes(
}
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Import: {
break;
}
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
Expand Down Expand Up @@ -302,6 +305,9 @@ void GlobalTypeRewriter::mapTypes(const TypeMap& oldToNewTypes) {
for (auto& tag : wasm.tags) {
tag->type = updater.getNew(tag->type);
}
for (auto& exp : wasm.typeExports) {
exp->heaptype = updater.getNew(exp->heaptype);
}
}

void GlobalTypeRewriter::mapTypeNamesAndIndices(const TypeMap& oldToNewTypes) {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/context-decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Result<> addExports(Lexer& in,
const std::vector<Name>& exports,
ExternalKind kind) {
for (auto name : exports) {
if (wasm.getExportOrNull(name)) {
if (wasm.getTypeExportOrNull(name) || wasm.getExportOrNull(name)) {
// TODO: Fix error location
return in.err("repeated export name");
}
Expand Down
70 changes: 66 additions & 4 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,10 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
std::vector<DefPos> dataDefs;
std::vector<DefPos> tagDefs;

// Type imports: name, positions of type and import names.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Type imports: name, positions of type and import names.
// Type imports: name, export names, import names, and type index.

std::vector<std::tuple<Name, std::vector<Name>, ImportNames, Index>>
typeImports;

// Positions of export definitions.
std::vector<Index> exportDefs;

Expand All @@ -957,6 +961,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {

// Used to verify that all imports come before all non-imports.
bool hasNonImport = false;
bool hasTypeDefinition = false;

Result<> checkImport(Index pos, ImportNames* import) {
if (import) {
Expand All @@ -978,9 +983,10 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
void setOpen() {}
void setShared() {}
Result<> addSubtype(HeapTypeT) { return Ok{}; }
void finishTypeDef(Name name, Index pos) {
void finishTypeDef(Name name, const std::vector<Name>& exports, Index pos) {
// TODO: type annotations
typeDefs.push_back({name, pos, Index(typeDefs.size()), {}});
hasTypeDefinition = true;
}
size_t getRecGroupStartIndex() { return 0; }
void addRecGroup(Index, size_t) {}
Expand Down Expand Up @@ -1092,10 +1098,28 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
TypeUseT type,
Index pos);

Result<> addTypeImport(Name name,
const std::vector<Name>& exports,
ImportNames* import,
Index pos,
Index typePos) {
if (hasTypeDefinition) {
return in.err(pos, "type import after type definitions");
}
typeDefs.push_back({name, pos, Index(typeDefs.size()), {}});
typeImports.push_back({name, exports, *import, typePos});
return Ok{};
}

Result<> addExport(Index pos, Ok, Name, ExternalKind) {
exportDefs.push_back(pos);
return Ok{};
}

Result<> addTypeExport(Index pos, Ok, Name) {
exportDefs.push_back(pos);
return Ok{};
}
};

// Phase 2: Parse type definitions into a TypeBuilder.
Expand All @@ -1108,12 +1132,15 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {
// Parse the names of types and fields as we go.
std::vector<TypeNames> names;

// Keep track of type exports
std::vector<std::vector<Name>> typeExports;

// The index of the subtype definition we are parsing.
Index index = 0;

ParseTypeDefsCtx(Lexer& in, TypeBuilder& builder, const IndexMap& typeIndices)
: TypeParserCtx<ParseTypeDefsCtx>(typeIndices), in(in), builder(builder),
names(builder.size()) {}
names(builder.size()), typeExports(builder.size()) {}

TypeT makeRefType(HeapTypeT ht, Nullability nullability) {
return builder.getTempRefType(ht, nullability);
Expand Down Expand Up @@ -1154,7 +1181,18 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {
return Ok{};
}

void finishTypeDef(Name name, Index pos) { names[index++].name = name; }
void finishTypeDef(Name name, const std::vector<Name>& exports, Index pos) {
typeExports[index] = exports;
names[index++].name = name;
}

Result<> addTypeImport(Name name,
const std::vector<Name>& exports,
ImportNames* import,
Index pos,
Index typePos) {
return Ok{};
}

size_t getRecGroupStartIndex() { return index; }

Expand Down Expand Up @@ -1403,6 +1441,14 @@ struct ParseModuleTypesCtx : TypeParserCtx<ParseModuleTypesCtx>,
t->type = use.type;
return Ok{};
}

Result<> addTypeImport(Name name,
const std::vector<Name>& exports,
ImportNames* import,
Index pos,
Index typePos) {
return Ok{};
}
};

// Phase 5: Parse module element definitions, including instructions.
Expand Down Expand Up @@ -1757,14 +1803,30 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return Ok{};
}

Result<> addTypeImport(Name,
const std::vector<Name> exports,
ImportNames* import,
Index pos,
Index typePos) {
return Ok{};
}

Result<> addExport(Index pos, Name value, Name name, ExternalKind kind) {
if (wasm.getExportOrNull(name)) {
if (wasm.getTypeExportOrNull(name) || wasm.getExportOrNull(name)) {
return in.err(pos, "duplicate export");
}
wasm.addExport(builder.makeExport(name, value, kind));
return Ok{};
}

Result<> addTypeExport(Index pos, HeapType heaptype, Name name) {
if (wasm.getTypeExportOrNull(name) || wasm.getTypeExportOrNull(name)) {
return in.err(pos, "duplicate export");
}
wasm.addTypeExport(builder.makeTypeExport(name, heaptype));
return Ok{};
}

Result<Index> addScratchLocal(Index pos, Type type) {
if (!func) {
return in.err(pos,
Expand Down
19 changes: 19 additions & 0 deletions src/parser/parse-2-typedefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Result<> parseTypeDefs(
std::unordered_map<HeapType, std::unordered_map<Name, Index>>& typeNames) {
TypeBuilder builder(decls.typeDefs.size());
ParseTypeDefsCtx ctx(input, builder, typeIndices);
for (auto& [name, exports, importNames, pos] : decls.typeImports) {
WithPosition with(ctx, pos);
auto heaptype = typetype(ctx);
CHECK_ERR(heaptype);
builder[ctx.index] = Import(importNames.mod, importNames.nm, *heaptype);
ctx.typeExports[ctx.index] = exports;
ctx.names[ctx.index++].name = name;
}
for (auto& recType : decls.recTypeDefs) {
WithPosition with(ctx, recType.pos);
CHECK_ERR(rectype(ctx));
Expand All @@ -49,6 +57,17 @@ Result<> parseTypeDefs(
}
}
}
for (size_t i = 0; i < types.size(); ++i) {
for (Name& name : ctx.typeExports[i]) {
if (decls.wasm.getTypeExportOrNull(name) ||
decls.wasm.getExportOrNull(name)) {
// TODO: Fix error location
return ctx.in.err("repeated export name");
}
decls.wasm.addTypeExport(
Builder(decls.wasm).makeTypeExport(name, types[i]));
}
}
return Ok{};
}

Expand Down
Loading
Loading