diff --git a/pom.xml b/pom.xml index af3eaf8..fc6cd6a 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 11 - 0.0.12 + 1.0.0-M1 3.8.1 3.10.1 @@ -86,7 +86,7 @@ com.dylibso.chicory - aot + aot-experimental ${chicory.version} diff --git a/src/main/java/org/extism/chicory/sdk/ChicoryModule.java b/src/main/java/org/extism/chicory/sdk/ChicoryModule.java index 73b5b00..cb54636 100644 --- a/src/main/java/org/extism/chicory/sdk/ChicoryModule.java +++ b/src/main/java/org/extism/chicory/sdk/ChicoryModule.java @@ -1,7 +1,9 @@ package org.extism.chicory.sdk; -import com.dylibso.chicory.aot.AotMachine; -import com.dylibso.chicory.runtime.Module; +import com.dylibso.chicory.experimental.aot.AotMachine; +import com.dylibso.chicory.runtime.Instance; +import com.dylibso.chicory.wasm.Module; +import com.dylibso.chicory.wasm.Parser; import java.nio.file.Path; @@ -12,22 +14,22 @@ class ChicoryModule { static Module fromWasm(ManifestWasm m) { if (m instanceof ManifestWasmBytes) { ManifestWasmBytes mwb = (ManifestWasmBytes) m; - return Module.builder(mwb.bytes).build(); + return Parser.parse(mwb.bytes); } else if (m instanceof ManifestWasmPath) { ManifestWasmPath mwp = (ManifestWasmPath) m; - return Module.builder(Path.of(mwp.path)).build(); + return Parser.parse(Path.of(mwp.path)); } else if (m instanceof ManifestWasmFile) { ManifestWasmFile mwf = (ManifestWasmFile) m; - return Module.builder(mwf.filePath).build(); + return Parser.parse(mwf.filePath); } else if (m instanceof ManifestWasmUrl) { ManifestWasmUrl mwu = (ManifestWasmUrl) m; - return Module.builder(mwu.getUrlAsStream()).build(); + return Parser.parse(mwu.getUrlAsStream()); } else { throw new IllegalArgumentException("Unknown ManifestWasm type " + m.getClass()); } } - static Module.Builder instanceWithOptions(Module.Builder m, Manifest.Options opts) { + static Instance.Builder instanceWithOptions(Instance.Builder m, Manifest.Options opts) { if (opts == null) { return m; } diff --git a/src/main/java/org/extism/chicory/sdk/DependencyGraph.java b/src/main/java/org/extism/chicory/sdk/DependencyGraph.java index 75b0376..89d736e 100644 --- a/src/main/java/org/extism/chicory/sdk/DependencyGraph.java +++ b/src/main/java/org/extism/chicory/sdk/DependencyGraph.java @@ -3,10 +3,13 @@ import com.dylibso.chicory.log.Logger; import com.dylibso.chicory.runtime.ExportFunction; import com.dylibso.chicory.runtime.HostFunction; -import com.dylibso.chicory.runtime.HostImports; +import com.dylibso.chicory.runtime.ImportFunction; +import com.dylibso.chicory.runtime.ImportValue; +import com.dylibso.chicory.runtime.ImportValues; import com.dylibso.chicory.runtime.Instance; +import com.dylibso.chicory.runtime.Store; import com.dylibso.chicory.runtime.WasmFunctionHandle; -import com.dylibso.chicory.runtime.Module; +import com.dylibso.chicory.wasm.Module; import com.dylibso.chicory.wasm.types.Export; import com.dylibso.chicory.wasm.types.ExportSection; import com.dylibso.chicory.wasm.types.ExternalType; @@ -93,7 +96,7 @@ private void checkCollision(String moduleName, String symbol) { public void registerModule(String name, Module m) { checkCollision(name, null); - ExportSection exportSection = m.wasmModule().exportSection(); + ExportSection exportSection = m.exportSection(); for (int i = 0; i < exportSection.exportCount(); i++) { Export export = exportSection.getExport(i); String exportName = export.name(); @@ -112,10 +115,10 @@ public boolean validate() { for (var kv : modules.entrySet()) { Module m = kv.getValue(); - ImportSection imports = m.wasmModule().importSection(); + ImportSection imports = m.importSection(); for (int i = 0; i < imports.importCount(); i++) { Import imp = imports.getImport(i); - String moduleName = imp.moduleName(); + String moduleName = imp.module(); String symbolName = imp.name(); if (!registeredSymbols.containsKey(moduleName) || !registeredSymbols.get(moduleName).contains(symbolName)) { logger.warnf("Cannot find symbol: %s.%s\n", moduleName, symbolName); @@ -156,13 +159,13 @@ public Instance instantiate() { Module m = this.modules.get(moduleId); boolean satisfied = true; List trampolines = new ArrayList<>(); - ImportSection imports = m.wasmModule().importSection(); + ImportSection imports = m.importSection(); // We assume that each unique `name` in an import of the form `name.symbol` // is registered as a module with that name // // FIXME: this is actually a strong assumption, because we could // define "overrides" by overwriting individual `name.symbol` in our table. - var requiredModules = imports.stream().collect(groupingBy(Import::moduleName)); + var requiredModules = imports.stream().collect(groupingBy(Import::module)); if (!requiredModules.isEmpty()) { // We need to check whether the given import is available @@ -217,37 +220,37 @@ private Instance instantiate(String moduleId, List moreHostFunctio Module m = this.modules.get(moduleId); Objects.requireNonNull(m); - HostImports extendedHostImports = - mergeHostImports(store.toHostImports(), moreHostFunctions); + ImportValues importValues = + mergeImportValues(store.toImportValues(), moreHostFunctions); Instance instance = ChicoryModule.instanceWithOptions( - Module.builder(m.wasmModule()), this.options) - .withHostImports(extendedHostImports) + Instance.builder(m), this.options) + .withImportValues(importValues) .withStart(false) - .build().instantiate(); + .build(); this.store.register(moduleId, instance); this.instances.put(moduleId, instance); return instance; } - private HostImports mergeHostImports(HostImports hostImports, List trampolines) { - HostFunction[] hostFunctions = hostImports.functions(); - List mergedList = new ArrayList<>(trampolines); - for (HostFunction fn : hostFunctions) { + private ImportValues mergeImportValues(ImportValues hostImports, List trampolines) { + ImportFunction[] hostFunctions = hostImports.functions(); + List mergedList = new ArrayList<>(trampolines); + for (ImportFunction fn : hostFunctions) { for (HostFunction t : trampolines) { - if (t.moduleName().equals(fn.fieldName()) && t.fieldName().equals(fn.fieldName())) { + if (t.module().equals(fn.name()) && t.name().equals(fn.name())) { // If one such case exists, the "proper" function takes precedence over the trampoline. mergedList.remove(t); } } mergedList.add(fn); } - return new HostImports( - mergedList.toArray(new HostFunction[mergedList.size()]), - hostImports.globals(), - hostImports.memories(), - hostImports.tables()); + return ImportValues.builder().addFunction( + mergedList.toArray(new ImportFunction[mergedList.size()])) + .addGlobal(hostImports.globals()) + .addMemory(hostImports.memories()) + .addTable(hostImports.tables()).build(); } private HostFunction registerTrampoline(FunctionImport f, Module m) { @@ -255,9 +258,9 @@ private HostFunction registerTrampoline(FunctionImport f, Module m) { // Trampolines are not registered into the store, as they are not "real" functions. // They are instead kept separately and passed explicitly to the instance. Trampoline trampoline = this.trampolines.computeIfAbsent( - new QualifiedName(f.moduleName(), f.name()), k -> new Trampoline()); - var functionType = m.wasmModule().typeSection().getType(f.typeIndex()); - return trampoline.asHostFunction(f.moduleName(), f.name(), functionType); + new QualifiedName(f.module(), f.name()), k -> new Trampoline()); + var functionType = m.typeSection().getType(f.typeIndex()); + return trampoline.asHostFunction(f.module(), f.name(), functionType); } /** @@ -268,8 +271,8 @@ private HostFunction registerTrampoline(FunctionImport f, Module m) { public void registerFunctions(HostFunction... functions) { store.addFunction(functions); for (HostFunction f : functions) { - this.hostModules.add(f.moduleName()); - registerSymbol(f.moduleName(), f.fieldName()); + this.hostModules.add(f.module()); + registerSymbol(f.module(), f.name()); } } @@ -294,7 +297,7 @@ private Instance getMainInstance() { static final class Trampoline implements WasmFunctionHandle { WasmFunctionHandle f = - (Instance instance, Value... args) -> { + (Instance instance, long... args) -> { throw new ExtismException("Unresolved trampoline"); }; @@ -303,17 +306,17 @@ public void resolveFunction(HostFunction hf) { } public void resolveFunction(ExportFunction ef) { - this.f = (Instance instance, Value... args) -> ef.apply(args); + this.f = (Instance instance, long... args) -> ef.apply(args); } @Override - public Value[] apply(Instance instance, Value... args) { + public long[] apply(Instance instance, long... args) { return f.apply(instance, args); } public HostFunction asHostFunction(String moduleName, String name, FunctionType functionType) { - return new HostFunction(this, moduleName, name, - functionType.params(), functionType.returns()); + return new HostFunction(moduleName, name, + functionType.params(), functionType.returns(), this); } } diff --git a/src/main/java/org/extism/chicory/sdk/ExtismException.java b/src/main/java/org/extism/chicory/sdk/ExtismException.java index 2791b3a..fcee9ed 100644 --- a/src/main/java/org/extism/chicory/sdk/ExtismException.java +++ b/src/main/java/org/extism/chicory/sdk/ExtismException.java @@ -1,6 +1,6 @@ package org.extism.chicory.sdk; -public class ExtismException extends RuntimeException{ +public class ExtismException extends RuntimeException { public ExtismException(String message) { super(message); diff --git a/src/main/java/org/extism/chicory/sdk/ExtismFunctionException.java b/src/main/java/org/extism/chicory/sdk/ExtismFunctionException.java new file mode 100644 index 0000000..29743cb --- /dev/null +++ b/src/main/java/org/extism/chicory/sdk/ExtismFunctionException.java @@ -0,0 +1,19 @@ +package org.extism.chicory.sdk; + +public class ExtismFunctionException extends ExtismException { + + private final String error; + + public ExtismFunctionException(String function, String message) { + super(String.format("function %s returned an error: %s", function, message)); + this.error = message; + } + + /** + * Underlying error returned by the plugin call + */ + public String getError() { + return error; + } + +} diff --git a/src/main/java/org/extism/chicory/sdk/ExtismHostFunction.java b/src/main/java/org/extism/chicory/sdk/ExtismHostFunction.java index 17dddc2..e9af497 100644 --- a/src/main/java/org/extism/chicory/sdk/ExtismHostFunction.java +++ b/src/main/java/org/extism/chicory/sdk/ExtismHostFunction.java @@ -58,12 +58,12 @@ public void bind(CurrentPlugin p) { final HostFunction asHostFunction() { return new HostFunction( - (Instance inst, Value... args) -> handle.apply(this.currentPlugin, args), - module, name, paramTypes, returnTypes); + module, name, paramTypes, returnTypes, + (Instance inst, long... args) -> handle.apply(this.currentPlugin, args)); } @FunctionalInterface public interface Handle { - Value[] apply(CurrentPlugin currentPlugin, Value... args); + long[] apply(CurrentPlugin currentPlugin, long... args); } } diff --git a/src/main/java/org/extism/chicory/sdk/HostEnv.java b/src/main/java/org/extism/chicory/sdk/HostEnv.java index 5129d89..5e65a98 100644 --- a/src/main/java/org/extism/chicory/sdk/HostEnv.java +++ b/src/main/java/org/extism/chicory/sdk/HostEnv.java @@ -64,14 +64,19 @@ public byte[] getOutput() { return kernel.getOutput(); } + public String getError() { + return kernel.getError(); + } + public Memory memory() { return this.memory; } + public class Memory { public long length(long offset) { - return kernel.length.apply(i64(offset))[0].asLong(); + return kernel.length.apply(offset)[0]; } public com.dylibso.chicory.runtime.Memory memory() { @@ -79,7 +84,7 @@ public com.dylibso.chicory.runtime.Memory memory() { } public long alloc(long size) { - return kernel.alloc.apply(i64(size))[0].asLong(); + return kernel.alloc.apply(size)[0]; } byte[] readBytes(long offset) { @@ -113,40 +118,40 @@ public void logf(LogLevel level, String format, Object args) { logger.log(level.toChicoryLogLevel(), String.format(format, args), null); } - private Value[] logTrace(Instance instance, Value... args) { - return log(LogLevel.TRACE, args[0].asLong()); + private long[] logTrace(Instance instance, long... args) { + return log(LogLevel.TRACE, args[0]); } - private Value[] logDebug(Instance instance, Value... args) { - return log(LogLevel.DEBUG, args[0].asLong()); + private long[] logDebug(Instance instance, long... args) { + return log(LogLevel.DEBUG, args[0]); } - private Value[] logInfo(Instance instance, Value... args) { - return log(LogLevel.INFO, args[0].asLong()); + private long[] logInfo(Instance instance, long... args) { + return log(LogLevel.INFO, args[0]); } - private Value[] logWarn(Instance instance, Value... args) { - return log(LogLevel.WARN, args[0].asLong()); + private long[] logWarn(Instance instance, long... args) { + return log(LogLevel.WARN, args[0]); } - private Value[] logError(Instance instance, Value... args) { - return log(LogLevel.ERROR, args[0].asLong()); + private long[] logError(Instance instance, long... args) { + return log(LogLevel.ERROR, args[0]); } - private Value[] log(LogLevel level, long offset) { + private long[] log(LogLevel level, long offset) { String msg = memory().readString(offset); log(level, msg); - return new Value[0]; + return new long[0]; } HostFunction[] toHostFunctions() { return new HostFunction[]{ - new HostFunction(this::logTrace, Kernel.IMPORT_MODULE_NAME, "log_trace", List.of(ValueType.I64), List.of()), - new HostFunction(this::logDebug, Kernel.IMPORT_MODULE_NAME, "log_debug", List.of(ValueType.I64), List.of()), - new HostFunction(this::logInfo, Kernel.IMPORT_MODULE_NAME, "log_info", List.of(ValueType.I64), List.of()), - new HostFunction(this::logWarn, Kernel.IMPORT_MODULE_NAME, "log_warn", List.of(ValueType.I64), List.of()), - new HostFunction(this::logError, Kernel.IMPORT_MODULE_NAME, "log_error", List.of(ValueType.I64), List.of())}; + new HostFunction(Kernel.IMPORT_MODULE_NAME, "log_trace", List.of(ValueType.I64), List.of(), this::logTrace), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "log_debug", List.of(ValueType.I64), List.of(), this::logDebug), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "log_info", List.of(ValueType.I64), List.of(), this::logInfo), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "log_warn", List.of(ValueType.I64), List.of(), this::logWarn), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "log_error", List.of(ValueType.I64), List.of(), this::logError)}; } } @@ -163,28 +168,28 @@ public void set(String key, byte[] value) { this.vars.put(key, value); } - private Value[] varGet(Instance instance, Value... args) { + private long[] varGet(Instance instance, long... args) { // FIXME: should check MaxVarBytes to see if vars are disabled. - long ptr = args[0].asLong(); + long ptr = args[0]; String key = memory().readString(ptr); byte[] value = get(key); - Value result; + long result; if (value == null) { // Value not found - result = i64(0); + result = 0; } else { long rPtr = memory().writeBytes(value); - result = i64(rPtr); + result = rPtr; } - return new Value[]{result}; + return new long[]{result}; } - private Value[] varSet(Instance instance, Value... args) { + private long[] varSet(Instance instance, long... args) { // FIXME: should check MaxVarBytes before committing. - long keyPtr = args[0].asLong(); - long valuePtr = args[1].asLong(); + long keyPtr = args[0]; + long valuePtr = args[1]; String key = memory().readString(keyPtr); // Remove if the value offset is 0 @@ -194,14 +199,14 @@ private Value[] varSet(Instance instance, Value... args) { byte[] value = memory().readBytes(valuePtr); set(key, value); } - return new Value[0]; + return new long[0]; } HostFunction[] toHostFunctions() { return new HostFunction[]{ - new HostFunction(this::varGet, Kernel.IMPORT_MODULE_NAME, "var_get", List.of(ValueType.I64), List.of(ValueType.I64)), - new HostFunction(this::varSet, Kernel.IMPORT_MODULE_NAME, "var_set", List.of(ValueType.I64, ValueType.I64), List.of()), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "var_get", List.of(ValueType.I64), List.of(ValueType.I64), this::varGet), + new HostFunction(Kernel.IMPORT_MODULE_NAME, "var_set", List.of(ValueType.I64, ValueType.I64), List.of(), this::varSet), }; } } @@ -218,24 +223,24 @@ public String get(String key) { return config.get(key); } - private Value[] configGet(Instance instance, Value... args) { - long ptr = args[0].asLong(); + private long[] configGet(Instance instance, long... args) { + long ptr = args[0]; String key = memory().readString(ptr); String value = get(key); - Value result; + long result; if (value == null) { // Value not found - result = i64(0); + result = 0; } else { long rPtr = memory().writeString(value); - result = i64(rPtr); + result = rPtr; } - return new Value[]{result}; + return new long[]{result}; } HostFunction[] toHostFunctions() { return new HostFunction[]{ - new HostFunction(this::configGet, Kernel.IMPORT_MODULE_NAME, "config_get", List.of(ValueType.I64), List.of(ValueType.I64)) + new HostFunction(Kernel.IMPORT_MODULE_NAME, "config_get", List.of(ValueType.I64), List.of(ValueType.I64), this::configGet) }; } diff --git a/src/main/java/org/extism/chicory/sdk/Kernel.java b/src/main/java/org/extism/chicory/sdk/Kernel.java index 80a2f1f..759ba49 100644 --- a/src/main/java/org/extism/chicory/sdk/Kernel.java +++ b/src/main/java/org/extism/chicory/sdk/Kernel.java @@ -3,14 +3,11 @@ import com.dylibso.chicory.runtime.ExportFunction; import com.dylibso.chicory.runtime.HostFunction; import com.dylibso.chicory.runtime.Instance; -import com.dylibso.chicory.runtime.Module; -import com.dylibso.chicory.wasm.types.Value; +import com.dylibso.chicory.wasm.Parser; import com.dylibso.chicory.wasm.types.ValueType; import java.util.List; -import static com.dylibso.chicory.wasm.types.Value.i64; - public class Kernel { static final String IMPORT_MODULE_NAME = "extism:host/env"; final com.dylibso.chicory.runtime.Memory instanceMemory; @@ -36,7 +33,7 @@ public class Kernel { final ExportFunction memoryBytes; public Kernel() { - Instance kernel = module().instantiate(); + Instance kernel = instance(); instanceMemory = kernel.memory(); alloc = kernel.export("alloc"); free = kernel.export("free"); @@ -60,23 +57,28 @@ public Kernel() { memoryBytes = kernel.export("memory_bytes"); } - public static Module module() { + public static Instance instance() { var kernelStream = Kernel.class.getClassLoader().getResourceAsStream("extism-runtime.wasm"); - return Module.builder(kernelStream).build(); + return Instance.builder(Parser.parse(kernelStream)).build(); } public void setInput(byte[] input) { - var ptr = alloc.apply(i64(input.length))[0]; - instanceMemory.write(ptr.asInt(), input); - inputSet.apply(ptr, i64(input.length)); + var ptr = alloc.apply(input.length)[0]; + instanceMemory.write((int) ptr, input); + inputSet.apply(ptr, input.length); } byte[] getOutput() { var ptr = outputOffset.apply()[0]; var len = outputLen.apply()[0]; - return instanceMemory.readBytes(ptr.asInt(), len.asInt()); + return instanceMemory.readBytes((int) ptr, (int) len); } + public String getError() { + long ptr = errorGet.apply()[0]; + long len = length.apply(ptr)[0]; + return instanceMemory.readString((int) ptr, (int) len); + } HostFunction[] toHostFunctions() { var hostFunctions = new HostFunction[20]; @@ -84,163 +86,183 @@ HostFunction[] toHostFunctions() { hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> alloc.apply(args), IMPORT_MODULE_NAME, "alloc", List.of(ValueType.I64), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> alloc.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> free.apply(args), IMPORT_MODULE_NAME, "free", List.of(ValueType.I64), - List.of()); + List.of(), + (Instance instance, long... args) -> free.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> length.apply(args), IMPORT_MODULE_NAME, "length", List.of(ValueType.I64), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> length.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> lengthUnsafe.apply(args), IMPORT_MODULE_NAME, "length_unsafe", List.of(ValueType.I64), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> lengthUnsafe.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> loadU8.apply(args), IMPORT_MODULE_NAME, "load_u8", List.of(ValueType.I64), - List.of(ValueType.I32)); + List.of(ValueType.I32), + (Instance instance, long... args) -> loadU8.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> loadU64.apply(args), IMPORT_MODULE_NAME, "load_u64", List.of(ValueType.I64), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> loadU64.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> inputLoadU8.apply(args), IMPORT_MODULE_NAME, "input_load_u8", List.of(ValueType.I64), - List.of(ValueType.I32)); + List.of(ValueType.I32), + (Instance instance, long... args) -> inputLoadU8.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> inputLoadU64.apply(args), IMPORT_MODULE_NAME, "input_load_u64", List.of(ValueType.I64), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> inputLoadU64.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> storeU8.apply(args), IMPORT_MODULE_NAME, "store_u8", List.of(ValueType.I64, ValueType.I32), - List.of()); + List.of(), + (Instance instance, long... args) -> storeU8.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> storeU64.apply(args), IMPORT_MODULE_NAME, "store_u64", List.of(ValueType.I64, ValueType.I64), - List.of()); + List.of(), + (Instance instance, long... args) -> storeU64.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> inputSet.apply(args), IMPORT_MODULE_NAME, "input_set", List.of(ValueType.I64, ValueType.I64), - List.of()); + List.of(), + (Instance instance, long... args) -> inputSet.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> inputLen.apply(args), IMPORT_MODULE_NAME, "input_length", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> inputLen.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> inputOffset.apply(args), IMPORT_MODULE_NAME, "input_offset", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> inputOffset.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> outputSet.apply(args), IMPORT_MODULE_NAME, "output_set", List.of(ValueType.I64, ValueType.I64), - List.of()); + List.of(), + (Instance instance, long... args) -> outputSet.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> outputLen.apply(args), IMPORT_MODULE_NAME, "output_length", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> outputLen.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> outputOffset.apply(args), IMPORT_MODULE_NAME, "output_offset", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> outputOffset.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> reset.apply(args), IMPORT_MODULE_NAME, "reset", List.of(), - List.of()); + List.of(), + (Instance instance, long... args) -> reset.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> errorSet.apply(args), IMPORT_MODULE_NAME, "error_set", List.of(ValueType.I64), - List.of()); + List.of(), + (Instance instance, long... args) -> errorSet.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> errorGet.apply(args), IMPORT_MODULE_NAME, "error_get", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> errorGet.apply(args) + ); hostFunctions[count++] = new HostFunction( - (Instance instance, Value... args) -> memoryBytes.apply(args), IMPORT_MODULE_NAME, "memory_bytes", List.of(), - List.of(ValueType.I64)); + List.of(ValueType.I64), + (Instance instance, long... args) -> memoryBytes.apply(args) + ); return hostFunctions; } } diff --git a/src/main/java/org/extism/chicory/sdk/Plugin.java b/src/main/java/org/extism/chicory/sdk/Plugin.java index 69ad9c7..eadb278 100644 --- a/src/main/java/org/extism/chicory/sdk/Plugin.java +++ b/src/main/java/org/extism/chicory/sdk/Plugin.java @@ -66,11 +66,12 @@ public HostEnv.Memory memory() { public byte[] call(String funcName, byte[] input) { var func = mainInstance.export(funcName); hostEnv.setInput(input); - var result = func.apply()[0].asInt(); + var result = func.apply()[0]; if (result == 0) { return hostEnv.getOutput(); } else { - throw new ExtismException("Failed"); + String error = hostEnv.getError(); + throw new ExtismFunctionException(funcName, error); } } } diff --git a/src/main/java/org/extism/chicory/sdk/Store.java b/src/main/java/org/extism/chicory/sdk/Store.java deleted file mode 100644 index 9ced1e7..0000000 --- a/src/main/java/org/extism/chicory/sdk/Store.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.extism.chicory.sdk; - -import com.dylibso.chicory.runtime.ExportFunction; -import com.dylibso.chicory.runtime.GlobalInstance; -import com.dylibso.chicory.runtime.HostFunction; -import com.dylibso.chicory.runtime.HostGlobal; -import com.dylibso.chicory.runtime.HostImports; -import com.dylibso.chicory.runtime.HostMemory; -import com.dylibso.chicory.runtime.HostTable; -import com.dylibso.chicory.runtime.Instance; -import com.dylibso.chicory.wasm.Module; -import com.dylibso.chicory.wasm.types.Export; -import com.dylibso.chicory.wasm.types.ExportSection; -import com.dylibso.chicory.wasm.types.FunctionType; -import java.util.LinkedHashMap; -import java.util.Objects; - -/** - * The runtime storage for all function, global, memory, table instances. - */ -class Store { - final LinkedHashMap functions = new LinkedHashMap<>(); - final LinkedHashMap globals = new LinkedHashMap<>(); - final LinkedHashMap memories = new LinkedHashMap<>(); - final LinkedHashMap tables = new LinkedHashMap<>(); - - public Store() {} - - /** - * Add a function to the store. - */ - public Store addFunction(HostFunction... function) { - for (var f : function) { - functions.put(new QualifiedName(f.moduleName(), f.fieldName()), f); - } - return this; - } - - /** - * Add a global to the store. - */ - public Store addGlobal(HostGlobal... global) { - for (var g : global) { - globals.put(new QualifiedName(g.moduleName(), g.fieldName()), g); - } - return this; - } - - /** - * Add a memory to the store. - */ - public Store addMemory(HostMemory... memory) { - for (var m : memory) { - memories.put(new QualifiedName(m.moduleName(), m.fieldName()), m); - } - return this; - } - - /** - * Add a table to the store. - */ - public Store addTable(HostTable... table) { - for (var t : table) { - tables.put(new QualifiedName(t.moduleName(), t.fieldName()), t); - } - return this; - } - - /** - * Add the contents of a {@link HostImports} instance to the store. - */ - public Store addHostImports(HostImports hostImports) { - return this.addGlobal(hostImports.globals()) - .addFunction(hostImports.functions()) - .addMemory(hostImports.memories()) - .addTable(hostImports.tables()); - } - - /** - * Convert the contents of a store to a {@link HostImports} instance. - */ - public HostImports toHostImports() { - return new HostImports( - functions.values().toArray(new HostFunction[0]), - globals.values().toArray(new HostGlobal[0]), - memories.values().toArray(new HostMemory[0]), - tables.values().toArray(new HostTable[0])); - } - - /** - * Register an instance in the store with the given name. - * All the exported functions, globals, memories, and tables are added to the store - * with the given name. - * - * For instance, if a module named "myModule" exports a function - * named "myFunction", the function will be added to the store with the name "myFunction.myModule". - * - */ - public Store register(String name, Instance instance) { - var exportSection = instance.module().exports().values(); - for (var export : exportSection) { - String exportName = export.name(); - switch (export.exportType()) { - case FUNCTION: - ExportFunction f = instance.export(exportName); - FunctionType ftype = instance.type(instance.functionType(export.index())); - this.addFunction( - new HostFunction( - (inst, args) -> f.apply(args), - name, - exportName, - ftype.params(), - ftype.returns())); - break; - - case TABLE: - this.addTable(new HostTable(name, exportName, instance.table(export.index()))); - break; - - case MEMORY: - this.addMemory(new HostMemory(name, exportName, instance.memory())); - break; - - case GLOBAL: - GlobalInstance g = instance.global(export.index()); - this.addGlobal(new HostGlobal(name, exportName, g)); - break; - } - } - return this; - } - - /** - * A shorthand for instantiating a module and registering it in the store. - */ - public Instance instantiate(String name, Module m) { - HostImports hostImports = toHostImports(); - Instance instance = com.dylibso.chicory.runtime.Module.builder(m).withHostImports(hostImports).build().instantiate(); - register(name, instance); - return instance; - } - - /** - * QualifiedName is internally used to use pairs (moduleName, name) as keys in the store. - */ - static class QualifiedName { - private final String moduleName; - private final String fieldName; - - public QualifiedName(String moduleName, String fieldName) { - this.moduleName = moduleName; - this.fieldName = fieldName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof QualifiedName)) { - return false; - } - QualifiedName qualifiedName = (QualifiedName) o; - return Objects.equals(moduleName, qualifiedName.moduleName) - && Objects.equals(fieldName, qualifiedName.fieldName); - } - - @Override - public int hashCode() { - return Objects.hash(moduleName, fieldName); - } - } -} diff --git a/src/test/java/org/extism/chicory/sdk/DependencyGraphTest.java b/src/test/java/org/extism/chicory/sdk/DependencyGraphTest.java index 6d99d11..6537e5d 100644 --- a/src/test/java/org/extism/chicory/sdk/DependencyGraphTest.java +++ b/src/test/java/org/extism/chicory/sdk/DependencyGraphTest.java @@ -3,13 +3,14 @@ import com.dylibso.chicory.log.SystemLogger; import com.dylibso.chicory.runtime.Instance; import com.dylibso.chicory.wasi.WasiPreview1; -import com.dylibso.chicory.runtime.Module; -import com.dylibso.chicory.wasm.types.Value; +import com.dylibso.chicory.wasm.Module; import junit.framework.TestCase; import java.io.IOException; import java.io.InputStream; +import static com.dylibso.chicory.wasm.Parser.parse; + public class DependencyGraphTest extends TestCase { public void testCircularDeps() throws IOException { @@ -25,8 +26,8 @@ public void testCircularDeps() throws IOException { Instance main = dg.instantiate(); - Value[] result = main.export("real_do_expr").apply(); - assertEquals(60, result[0].asInt()); + long[] result = main.export("real_do_expr").apply(); + assertEquals(60, result[0]); } @@ -51,8 +52,8 @@ public void testCircularDepsMore() throws IOException { Instance mainInst = dg.instantiate(); - Value[] result = mainInst.export("real_do_expr").apply(); - assertEquals(60, result[0].asInt()); + long[] result = mainInst.export("real_do_expr").apply(); + assertEquals(60, (int) result[0]); } // Let's try to register them in a different order: @@ -66,8 +67,8 @@ public void testCircularDepsMore() throws IOException { Instance mainInst = dg.instantiate(); - Value[] result = mainInst.export("real_do_expr").apply(); - assertEquals(60, result[0].asInt()); + long[] result = mainInst.export("real_do_expr").apply(); + assertEquals(60, (int) result[0]); } } @@ -98,10 +99,6 @@ public void testInstantiate() throws IOException { assertSame("when invoked twice, instantiate() returns the same instance", mainInst, mainInst2); } - private Module parse(InputStream is1) throws IOException { - return Module.builder(is1.readAllBytes()).build(); - } - private WasiPreview1 wasiPreview1() { return new WasiPreview1(new SystemLogger()); } diff --git a/src/test/java/org/extism/chicory/sdk/ExtismHostFunctionTest.java b/src/test/java/org/extism/chicory/sdk/ExtismHostFunctionTest.java index 0d12e90..4fb4fdd 100644 --- a/src/test/java/org/extism/chicory/sdk/ExtismHostFunctionTest.java +++ b/src/test/java/org/extism/chicory/sdk/ExtismHostFunctionTest.java @@ -6,12 +6,14 @@ import com.dylibso.chicory.wasm.types.Value; import junit.framework.TestCase; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; public class ExtismHostFunctionTest extends TestCase { public void testFunction() { var f = ExtismHostFunction.of("myfunc", List.of(), List.of(), - (CurrentPlugin p, Value... args) -> { + (CurrentPlugin p, long... args) -> { p.log().log(LogLevel.INFO, "hello world"); return null; }); @@ -26,7 +28,7 @@ public void testFunction() { HostFunction hostFunction = f.asHostFunction(); f.bind(new CurrentPlugin(plugin)); Instance instance = null; - Value[] args = null; + long[] args = null; hostFunction.handle().apply(instance, args); } }