Skip to content

Commit

Permalink
[EH] step 0 - tags support (#721)
Browse files Browse the repository at this point in the history
This is an initial, mechanical step to support the [exception handling
proposal](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md).

Not much, but it's self-contained and tested.
  • Loading branch information
andreaTP authored Jan 9, 2025
1 parent fbaf04a commit 52f07bc
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 6 deletions.
4 changes: 4 additions & 0 deletions runtime-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@
<wast>memory_trap.wast</wast>
<wast>names.wast</wast>
<wast>nop.wast</wast>
<wast>proposals/exception-handling/binary.wast</wast>
<wast>proposals/exception-handling/exports.wast</wast>
<wast>proposals/exception-handling/imports.wast</wast>
<wast>proposals/exception-handling/tag.wast</wast>
<wast>proposals/tail-call/return_call.wast</wast>
<wast>proposals/tail-call/return_call_indirect.wast</wast>
<wast>ref_func.wast</wast>
Expand Down
32 changes: 32 additions & 0 deletions runtime/src/main/java/com/dylibso/chicory/runtime/ImportTag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.dylibso.chicory.runtime;

public class ImportTag implements ImportValue {
private final String module;
private final String name;
private final TagInstance tag;

public ImportTag(String module, String name, TagInstance tag) {
this.module = module;
this.name = name;
this.tag = tag;
}

@Override
public String module() {
return module;
}

@Override
public String name() {
return name;
}

@Override
public Type type() {
return Type.TAG;
}

public TagInstance tag() {
return tag;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ enum Type {
FUNCTION,
GLOBAL,
MEMORY,
TABLE
TABLE,
TAG
}

String module();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,25 @@ public final class ImportValues {
private static final ImportGlobal[] NO_EXTERNAL_GLOBALS = new ImportGlobal[0];
private static final ImportMemory[] NO_EXTERNAL_MEMORIES = new ImportMemory[0];
private static final ImportTable[] NO_EXTERNAL_TABLES = new ImportTable[0];
private static final ImportTag[] NO_EXTERNAL_TAGS = new ImportTag[0];

private final ImportFunction[] functions;
private final ImportGlobal[] globals;
private final ImportMemory[] memories;
private final ImportTable[] tables;
private final ImportTag[] tags;

private ImportValues(
ImportFunction[] functions,
ImportGlobal[] globals,
ImportMemory[] memories,
ImportTable[] tables) {
ImportTable[] tables,
ImportTag[] tags) {
this.functions = functions.clone();
this.globals = globals.clone();
this.memories = memories.clone();
this.tables = tables.clone();
this.tags = tags.clone();
}

public ImportFunction[] functions() {
Expand Down Expand Up @@ -74,6 +78,18 @@ public ImportTable table(int idx) {
return tables[idx];
}

public ImportTag[] tags() {
return tags;
}

public int tagCount() {
return tags.length;
}

public ImportTag tag(int idx) {
return tags[idx];
}

public static Builder builder() {
return new Builder();
}
Expand All @@ -87,6 +103,7 @@ public static final class Builder {
private Collection<ImportGlobal> globals;
private Collection<ImportMemory> memories;
private Collection<ImportTable> tables;
private Collection<ImportTag> tags;

Builder() {}

Expand Down Expand Up @@ -142,6 +159,19 @@ public Builder addTable(ImportTable... table) {
return this;
}

public Builder withTags(Collection<ImportTag> tags) {
this.tags = tags;
return this;
}

public Builder addTag(ImportTag... tag) {
if (this.tags == null) {
this.tags = new ArrayList<>();
}
Collections.addAll(this.tags, tag);
return this;
}

public ImportValues build() {
final ImportValues importValues =
new ImportValues(
Expand All @@ -156,7 +186,8 @@ public ImportValues build() {
: memories.toArray(NO_EXTERNAL_MEMORIES),
tables == null
? NO_EXTERNAL_TABLES
: tables.toArray(NO_EXTERNAL_TABLES));
: tables.toArray(NO_EXTERNAL_TABLES),
tags == null ? NO_EXTERNAL_TAGS : tags.toArray(NO_EXTERNAL_TAGS));
return importValues;
}
}
Expand Down
70 changes: 70 additions & 0 deletions runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static com.dylibso.chicory.wasm.types.ExternalType.GLOBAL;
import static com.dylibso.chicory.wasm.types.ExternalType.MEMORY;
import static com.dylibso.chicory.wasm.types.ExternalType.TABLE;
import static com.dylibso.chicory.wasm.types.ExternalType.TAG;
import static java.util.Objects.requireNonNullElse;
import static java.util.Objects.requireNonNullElseGet;

Expand Down Expand Up @@ -33,6 +34,9 @@
import com.dylibso.chicory.wasm.types.MemorySection;
import com.dylibso.chicory.wasm.types.Table;
import com.dylibso.chicory.wasm.types.TableImport;
import com.dylibso.chicory.wasm.types.TagImport;
import com.dylibso.chicory.wasm.types.TagSection;
import com.dylibso.chicory.wasm.types.TagType;
import com.dylibso.chicory.wasm.types.ValueType;
import java.util.Arrays;
import java.util.HashMap;
Expand All @@ -56,6 +60,7 @@ public class Instance {
private final ImportValues imports;
private final TableInstance[] tables;
private final Element[] elements;
private final TagInstance[] tags;
private final Map<String, Export> exports;
private final ExecutionListener listener;
private final Exports fluentExports;
Expand All @@ -71,6 +76,7 @@ public class Instance {
ImportValues imports,
Table[] tables,
Element[] elements,
TagType[] tags,
Map<String, Export> exports,
Function<Instance, Machine> machineFactory,
boolean initialize,
Expand All @@ -91,6 +97,10 @@ public class Instance {
this.tables[i] = new TableInstance(tables[i]);
}
this.elements = elements.clone();
this.tags = (tags == null) ? new TagInstance[0] : new TagInstance[tags.length];
for (int i = 0; i < this.tags.length; i++) {
this.tags[i] = new TagInstance(tags[i], this);
}
this.exports = exports;
this.listener = listener;
this.fluentExports = new Exports(this);
Expand Down Expand Up @@ -299,6 +309,13 @@ public void setElement(int idx, Element val) {
elements[idx] = val;
}

public TagInstance tag(int idx) {
if (idx < imports.tagCount()) {
return imports.tag(idx).tag();
}
return tags[idx - imports.tagCount()];
}

public Machine getMachine() {
return machine;
}
Expand Down Expand Up @@ -407,6 +424,32 @@ private void validateHostGlobalType(GlobalImport i, ImportGlobal g) {
}
}

private void validateHostTagType(TagImport i, ImportTag t) {
var expectedType = module.typeSection().getType(i.tagType().typeIdx());
var gotType = t.tag().instance().type(t.tag().tagType().typeIdx());
if (expectedType.params().size() != gotType.params().size()
|| expectedType.returns().size() != gotType.returns().size()) {
throw new UnlinkableException(
"incompatible import type for tag " + t.module() + "." + t.name());
}
for (int j = 0; j < expectedType.params().size(); j++) {
var expected = expectedType.params().get(j);
var got = gotType.params().get(j);
if (expected != got) {
throw new UnlinkableException(
"incompatible import type for tag " + t.module() + "." + t.name());
}
}
for (int j = 0; j < expectedType.returns().size(); j++) {
var expected = expectedType.returns().get(j);
var got = gotType.returns().get(j);
if (expected != got) {
throw new UnlinkableException(
"incompatible import type for tag " + t.module() + "." + t.name());
}
}
}

private void validateHostTableType(TableImport i, ImportTable t) {
var minExpected = t.table().limits().min();
var maxExpected = t.table().limits().max();
Expand Down Expand Up @@ -474,21 +517,31 @@ private void validateNegativeImportType(
validateNegativeImportType(moduleName, name, importValues.globals());
validateNegativeImportType(moduleName, name, importValues.memories());
validateNegativeImportType(moduleName, name, importValues.tables());
validateNegativeImportType(moduleName, name, importValues.tags());
break;
case GLOBAL:
validateNegativeImportType(moduleName, name, importValues.functions());
validateNegativeImportType(moduleName, name, importValues.memories());
validateNegativeImportType(moduleName, name, importValues.tables());
validateNegativeImportType(moduleName, name, importValues.tags());
break;
case MEMORY:
validateNegativeImportType(moduleName, name, importValues.functions());
validateNegativeImportType(moduleName, name, importValues.globals());
validateNegativeImportType(moduleName, name, importValues.tables());
validateNegativeImportType(moduleName, name, importValues.tags());
break;
case TABLE:
validateNegativeImportType(moduleName, name, importValues.functions());
validateNegativeImportType(moduleName, name, importValues.globals());
validateNegativeImportType(moduleName, name, importValues.memories());
validateNegativeImportType(moduleName, name, importValues.tags());
break;
case TAG:
validateNegativeImportType(moduleName, name, importValues.functions());
validateNegativeImportType(moduleName, name, importValues.globals());
validateNegativeImportType(moduleName, name, importValues.memories());
validateNegativeImportType(moduleName, name, importValues.tables());
break;
}
}
Expand All @@ -505,6 +558,8 @@ private ImportValues mapHostImports(
var hostGlobalIdx = 0;
var hostMems = new ImportMemory[count.apply(MEMORY)];
var hostMemIdx = 0;
var hostTags = new ImportTag[count.apply(TAG)];
var hostTagIdx = 0;
if (hostMems.length + memoryCount > 1) {
throw new InvalidException("multiple memories");
}
Expand Down Expand Up @@ -572,6 +627,19 @@ private ImportValues mapHostImports(
}
hostTableIdx++;
break;
case TAG:
cnt = importValues.tagCount();
for (int j = 0; j < cnt; j++) {
ImportTag t = importValues.tag(j);
if (checkName.apply(t)) {
validateHostTagType((TagImport) i, t);
hostTags[hostTagIdx] = t;
found = true;
break;
}
}
hostTagIdx++;
break;
}
if (!found) {
throw new UnlinkableException(
Expand All @@ -587,6 +655,7 @@ private ImportValues mapHostImports(
.addGlobal(hostGlobals)
.addMemory(hostMems)
.addTable(hostTables)
.addTag(hostTags)
.build();
}

Expand Down Expand Up @@ -742,6 +811,7 @@ public Instance build() {
mappedHostImports,
tables,
elements,
module.tagSection().map(TagSection::types).orElse(null),
exports,
machineFactory,
initialize,
Expand Down
19 changes: 18 additions & 1 deletion runtime/src/main/java/com/dylibso/chicory/runtime/Store.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class Store {
final LinkedHashMap<QualifiedName, ImportGlobal> globals = new LinkedHashMap<>();
final LinkedHashMap<QualifiedName, ImportMemory> memories = new LinkedHashMap<>();
final LinkedHashMap<QualifiedName, ImportTable> tables = new LinkedHashMap<>();
final LinkedHashMap<QualifiedName, ImportTag> tags = new LinkedHashMap<>();

public Store() {}

Expand Down Expand Up @@ -59,14 +60,25 @@ public Store addTable(ImportTable... table) {
return this;
}

/**
* Add a tag to the store.
*/
public Store addTag(ImportTag... tag) {
for (var t : tag) {
tags.put(new QualifiedName(t.module(), t.name()), t);
}
return this;
}

/**
* Add the contents of a {@link ImportValues} instance to the store.
*/
public Store addImportValues(ImportValues importValues) {
return this.addGlobal(importValues.globals())
.addFunction(importValues.functions())
.addMemory(importValues.memories())
.addTable(importValues.tables());
.addTable(importValues.tables())
.addTag(importValues.tags());
}

/**
Expand All @@ -78,6 +90,7 @@ public ImportValues toImportValues() {
.withGlobals(globals.values())
.withMemories(memories.values())
.withTables(tables.values())
.withTags(tags.values())
.build();
}

Expand Down Expand Up @@ -121,6 +134,10 @@ public Store register(String name, Instance instance) {
GlobalInstance g = instance.global(export.index());
this.addGlobal(new ImportGlobal(name, exportName, g));
break;

case TAG:
this.addTag(new ImportTag(name, exportName, instance.tag(export.index())));
break;
}
}
return this;
Expand Down
22 changes: 22 additions & 0 deletions runtime/src/main/java/com/dylibso/chicory/runtime/TagInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.dylibso.chicory.runtime;

import com.dylibso.chicory.wasm.types.TagType;

public class TagInstance {

private final TagType tag;
private final Instance instance;

public TagInstance(TagType tag, Instance instance) {
this.tag = tag;
this.instance = instance;
}

public TagType tagType() {
return tag;
}

public Instance instance() {
return instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,11 @@ private Proposal(String remapping, String[] wabtOpts) {
}

private static Map<String, Proposal> proposals =
Map.of("tail-call", new Proposal("tc", new String[] {"--enable-tail-call"}));
Map.of(
"tail-call",
new Proposal("tc", new String[] {"--enable-tail-call"}),
"exception-handling",
new Proposal("eh", new String[] {"--enable-tail-call", "--enable-exceptions"}));

private final class TestGenerator {

Expand Down
Loading

0 comments on commit 52f07bc

Please sign in to comment.