Skip to content
Merged
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
17 changes: 17 additions & 0 deletions runtime/src/main/java/run/endive/runtime/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,23 @@ private Map<String, Export> genExports(ExportSection export) {
return exports;
}

/**
* Builds the instance.
*
* <p>If building fails, for example due to invalid or unsupported Wasm code, an exception
* is thrown. In many cases that exception will be a {@link WasmEngineException} or a
* subclass of it, but callers should be prepared to handle any kind of {@code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would not stress:

but callers should be prepared to handle any kind of {@code* RuntimeException}

isn't it "always true"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, at least not for all libraries. Many (including the JDK) often try to document all exceptions with @throws / throws, and any undeclared exception is considered a bug. That helps the user to determine which exact exceptions to catch, instead of wildcard catch (Exception) or catch (RuntimeException).

Though I understand that ensuring this for Endive might not be easily possible, due to Wasm being quite complex and there being lots of potential error cases (and detecting all might cause overhead).

So I think it would be useful to explicitly point out to users that just catching WasmEngineException is probably not enough.

Or the question is, is a non-WasmEngineException only expected for malformed code?
(But currently even Endive itself has explicit throw new RuntimeException; see #151).

* RuntimeException}.<br>
* When such exceptions occur depends on how the code is compiled and executed:
*
* <ul>
* <li>runtime compilation: many exceptions are thrown already when this {@code build()}
* method is called
* <li>interpreter: many exceptions are only thrown once the Wasm code is executed
* </ul>
*
* @throws RuntimeException if the Wasm code is invalid or contains unsupported instructions
*/
public Instance build() {
Map<String, Export> exports = genExports(module.exportSection());
var globalInitializers = module.globalSection().globals();
Expand Down
10 changes: 4 additions & 6 deletions runtime/src/main/java/run/endive/runtime/OpcodeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -917,12 +917,10 @@ public static long unboxFromTable(int tableValue, Instance instance, ValType ele
impl = java.lang.invoke.VarHandle::fullFence;
} catch (NoSuchMethodError e) {
try {
// Suppress IntelliJ warning about module-info.java needing `requires
// jdk.unsupported` for
// `sun.misc.Unsafe`. This code here is only a fallback when `VarHandle::fullFence`
// is unavailable,
// which is only the case for Java < 9 (and therefore module-info.java is
// irrelevant).
// Suppress IntelliJ warning about module-info.java needing
// `requires jdk.unsupported` for `sun.misc.Unsafe`. This code here is only a
// fallback when `VarHandle::fullFence` is unavailable, which is only the case for
// Java < 9 (and therefore module-info.java is irrelevant).
@SuppressWarnings("Java9ReflectionClassVisibility")
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
var theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
Expand Down
28 changes: 28 additions & 0 deletions wasm/src/main/java/run/endive/wasm/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@

/**
* Parser for Web Assembly binaries.
*
* <p>If parsing fails, for example due to invalid or unsupported Wasm code, an exception is thrown.
* In many cases that exception will be a {@link WasmEngineException} or a subclass of it, but
* callers should be prepared to handle any kind of {@code RuntimeException}.
*/
@SuppressWarnings("UnnecessaryCodeBlock")
public final class Parser {
Expand Down Expand Up @@ -229,18 +233,30 @@ public Parser build() {
}
}

/**
* @throws RuntimeException if parsing fails
*/
public static WasmModule parse(InputStream input) {
return new Parser().parse(() -> input);
}

/**
* @throws RuntimeException if parsing fails
*/
public static WasmModule parse(byte[] buffer) {
return new Parser().parse(() -> new ByteArrayInputStream(buffer));
}

/**
* @throws RuntimeException if parsing fails
*/
public static WasmModule parse(File file) {
return parse(file.toPath());
}

/**
* @throws RuntimeException if parsing fails
*/
public static WasmModule parse(Path path) {
return new Parser()
.parse(
Expand All @@ -254,6 +270,9 @@ public static WasmModule parse(Path path) {
});
}

/**
* @throws RuntimeException if parsing fails
*/
public WasmModule parse(Supplier<InputStream> inputStreamSupplier) {
WasmModule.Builder moduleBuilder = WasmModule.builder();
moduleBuilder.withValidation(validate);
Expand Down Expand Up @@ -282,6 +301,9 @@ public WasmModule parse(Supplier<InputStream> inputStreamSupplier) {
return moduleBuilder.build();
}

/**
* @throws RuntimeException if parsing fails
*/
public void parse(InputStream in, ParserListener listener) {
parse(in, listener, true);
}
Expand Down Expand Up @@ -445,10 +467,16 @@ private void parse(InputStream in, ParserListener listener, boolean decode) {
}
}

/**
* @throws RuntimeException if parsing fails
*/
public static void parseWithoutDecoding(byte[] bytes, ParserListener listener) {
new Parser().parseWithoutDecoding(new ByteArrayInputStream(bytes), listener);
}

/**
* @throws RuntimeException if parsing fails
*/
public void parseWithoutDecoding(InputStream in, ParserListener listener) {
parse(in, listener, false);
}
Expand Down
Loading