functionWrapperGenerator =
+ functionName -> arguments -> this.instance.nativeCallExportedFunction(this.instance.instancePointer, functionName, arguments);
+
+ /**
+ * Generate the exported function wrapper.
+ */
+ private Function generateFunctionWrapper(String functionName) {
+ return this.functionWrapperGenerator.apply(functionName);
+ }
+}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Instance.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Instance.java
new file mode 100644
index 000000000000..b59d1f90612b
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Instance.java
@@ -0,0 +1,74 @@
+package org.apache.shenyu.wasm;
+
+/**
+ * `Instance` is a Java class that represents a WebAssembly instance.
+ *
+ * Example:
+ * {@code
+ * Instance instance = new Instance(wasmBytes);
+ * }
+ */
+public class Instance {
+ /**
+ * Native bindings.
+ */
+ static {
+ if (!Native.LOADED_EMBEDDED_LIBRARY) {
+ System.loadLibrary("wasmer_jni");
+ }
+ }
+ private native long nativeInstantiate(Instance self, byte[] moduleBytes) throws RuntimeException;
+ private native void nativeDrop(long instancePointer);
+ protected native Object[] nativeCallExportedFunction(long instancePointer, String exportName, Object[] arguments) throws RuntimeException;
+ protected static native void nativeInitializeExportedFunctions(long instancePointer);
+ protected static native void nativeInitializeExportedMemories(long instancePointer);
+
+ /**
+ * All WebAssembly exports.
+ */
+ public final Exports exports;
+
+ /**
+ The instance pointer.
+ */
+ protected long instancePointer;
+
+ /**
+ * The constructor instantiates a new WebAssembly instance based on
+ * WebAssembly bytes.
+ *
+ * @param moduleBytes WebAssembly bytes.
+ */
+ public Instance(byte[] moduleBytes) throws RuntimeException {
+ this.exports = new Exports(this);
+
+ long instancePointer = this.nativeInstantiate(this, moduleBytes);
+ this.instancePointer = instancePointer;
+
+ nativeInitializeExportedFunctions(instancePointer);
+ nativeInitializeExportedMemories(instancePointer);
+ }
+
+ protected Instance() {
+ this.exports = new Exports(this);
+ }
+
+ /**
+ * Delete an instance object pointer.
+ */
+ public void close() {
+ if (this.instancePointer != 0L) {
+ this.nativeDrop(this.instancePointer);
+ this.instancePointer = 0L;
+ }
+ }
+
+ /**
+ * Delete an instance object pointer, which is called by the garbage collector
+ * before an object is removed from the memory.
+ */
+ @Override
+ public void finalize() {
+ this.close();
+ }
+}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Memory.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Memory.java
new file mode 100644
index 000000000000..7da291245dbf
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Memory.java
@@ -0,0 +1,75 @@
+package org.apache.shenyu.wasm;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import org.apache.shenyu.wasm.exports.Export;
+
+/**
+ * `Memory` is a Java class that represents a WebAssembly memory.
+ *
+ * Example:
+ * {@code
+ * Instance instance = new Instance(wasmBytes);
+ * Memory memory = instance.exports.getMemory("memory-name");
+ * ByteBuffer memoryBuffer = memory.buffer();
+ *
+ * // Write bytes.
+ * memoryBuffer.position(0);
+ * memoryBuffer.put(new byte[]{1, 2, 3, 4, 5});
+ *
+ * // Read bytes.
+ * byte[] bytes = new byte[5];
+ * memoryBuffer.position(0);
+ * memoryBuffer.get(bytes);
+ * }
+ */
+public class Memory implements Export {
+ private native void nativeMemoryView(Memory memory, long memoryPointer);
+ private native int nativeMemoryGrow(Memory memory, long memoryPointer, int page);
+
+ /**
+ * Represents the actual WebAssembly memory data, borrowed from the runtime (in Rust).
+ * The `setBuffer` method must be used to set this attribute.
+ */
+ private ByteBuffer buffer;
+ private long memoryPointer;
+
+ private Memory() {
+ // This object is instantiated by Rust.
+ }
+
+ /**
+ * Return a _new_ direct byte buffer borrowing the memory data.
+ *
+ * @return A new direct byte buffer.
+ */
+ public ByteBuffer buffer() {
+ this.nativeMemoryView(this, this.memoryPointer);
+
+ return this.buffer;
+ }
+
+ /**
+ * Set the `ByteBuffer` of this memory. See `Memory.buffer` to learn more.
+ *
+ * In addition, this method correctly sets the endianess of the `ByteBuffer`.
+ */
+ private void setBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+
+ // Ensure the endianess matches WebAssemly specification.
+ if (this.buffer.order() != ByteOrder.LITTLE_ENDIAN) {
+ this.buffer.order(ByteOrder.LITTLE_ENDIAN);
+ }
+ }
+
+ /**
+ * Grow this memory by the specified number of pages.
+ *
+ * @param page The number of pages to grow. 1 page size is 64KiB.
+ * @return The previous number of pages.
+ */
+ public int grow(int page) {
+ return this.nativeMemoryGrow(this, this.memoryPointer, page);
+ }
+}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Module.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Module.java
new file mode 100644
index 000000000000..51e2a4ac14f3
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Module.java
@@ -0,0 +1,110 @@
+package org.apache.shenyu.wasm;
+
+/**
+ * `Module` is a Java class that represents a WebAssembly module.
+ *
+ * Example:
+ * {@code
+ * boolean isValid = Module.validate(wasmBytes);
+ *
+ * Module module = new Module(wasmBytes);
+ * Instance instance = module.instantiate();
+ * }
+ */
+public class Module {
+ /**
+ * Native bindings.
+ */
+ static {
+ if (!Native.LOADED_EMBEDDED_LIBRARY) {
+ System.loadLibrary("wasmer_jni");
+ }
+ }
+ private native long nativeModuleInstantiate(Module self, byte[] moduleBytes) throws RuntimeException;
+ private native void nativeDrop(long modulePointer);
+ private native long nativeInstantiate(long modulePointer, Instance instance);
+ private static native boolean nativeValidate(byte[] moduleBytes);
+ private native byte[] nativeSerialize(long modulePointer);
+ private static native long nativeDeserialize(Module module, byte[] serializedBytes);
+
+ private long modulePointer;
+
+
+ /**
+ * Check that given bytes represent a valid WebAssembly module.
+ *
+ * @param moduleBytes WebAssembly bytes.
+ * @return true if, and only if, given bytes are valid as a WebAssembly module.
+ */
+ public static boolean validate(byte[] moduleBytes) {
+ return Module.nativeValidate(moduleBytes);
+ }
+
+ /**
+ * The constructor instantiates a new WebAssembly module based on
+ * WebAssembly bytes.
+ *
+ * @param moduleBytes WebAssembly bytes.
+ */
+ public Module(byte[] moduleBytes) throws RuntimeException {
+ long modulePointer = this.nativeModuleInstantiate(this, moduleBytes);
+ this.modulePointer = modulePointer;
+ }
+
+ private Module() {}
+
+ /**
+ * Delete a module object pointer.
+ */
+ public void close() {
+ if (this.modulePointer != 0L) {
+ this.nativeDrop(this.modulePointer);
+ this.modulePointer = 0L;
+ }
+ }
+
+ /**
+ * Delete a module object pointer, which is called by the garbage collector
+ * before an object is removed from the memory.
+ */
+ @Override
+ public void finalize() {
+ this.close();
+ }
+
+ /**
+ * Create an instance object based on a module object.
+ *
+ * @return Instance object.
+ */
+ public Instance instantiate() {
+ Instance instance = new Instance();
+ long instancePointer = this.nativeInstantiate(this.modulePointer, instance);
+ instance.instancePointer = instancePointer;
+
+ Instance.nativeInitializeExportedFunctions(instancePointer);
+ Instance.nativeInitializeExportedMemories(instancePointer);
+ return instance;
+ }
+
+ /**
+ * Create a serialized byte array from a WebAssembly module.
+ *
+ * @return Serialized bytes.
+ */
+ public byte[] serialize() {
+ return this.nativeSerialize(this.modulePointer);
+ }
+
+ /**
+ * Create an original Module object from a byte array.
+ *
+ * @return Module object.
+ */
+ public static Module deserialize(byte[] serializedBytes) {
+ Module module = new Module();
+ long modulePointer = Module.nativeDeserialize(module, serializedBytes);
+ module.modulePointer = modulePointer;
+ return module;
+ }
+}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Native.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Native.java
new file mode 100644
index 000000000000..3013f2ce9361
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/Native.java
@@ -0,0 +1,97 @@
+/**
+ * Code reduced and simplified from zmq integration in Java. See
+ * https://github.com/zeromq/jzmq/blob/3384ea1c04876426215fe76b5d1aabc58c099ca0/jzmq-jni/src/main/java/org/zeromq/EmbeddedLibraryTools.java.
+ */
+
+package org.apache.shenyu.wasm;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+
+public class Native {
+ public static final boolean LOADED_EMBEDDED_LIBRARY;
+
+ static {
+ LOADED_EMBEDDED_LIBRARY = loadEmbeddedLibrary();
+ }
+
+ private Native() {}
+
+ public static String getCurrentPlatformIdentifier() {
+ String osName = System.getProperty("os.name").toLowerCase();
+
+ if (osName.contains("windows")) {
+ osName = "windows";
+ } else if (osName.contains("mac os x")) {
+ osName = "darwin";
+ } else {
+ osName = osName.replaceAll("\\s+", "_");
+ }
+
+ return osName + "-" + System.getProperty("os.arch");
+ }
+
+ private static boolean loadEmbeddedLibrary() {
+ boolean usingEmbedded = false;
+
+ // attempt to locate embedded native library within JAR at following location:
+ // /NATIVE/${os.arch}/${os.name}/[libwasmer.so|libwasmer.dylib|wasmer.dll]
+ String[] libs;
+ final String libsFromProps = System.getProperty("wasmer-native");
+
+ if (libsFromProps == null) {
+ libs = new String[]{"libwasmer_jni.so", "libwasmer_jni.dylib", "wasmer_jni.dll"};
+ } else {
+ libs = libsFromProps.split(",");
+ }
+
+ StringBuilder url = new StringBuilder();
+ url.append("/org/wasmer/native/");
+ url.append(getCurrentPlatformIdentifier()).append("/");
+
+ URL nativeLibraryUrl = null;
+
+ // loop through extensions, stopping after finding first one
+ for (String lib: libs) {
+ nativeLibraryUrl = Module.class.getResource(url.toString() + lib);
+
+ if (nativeLibraryUrl != null) {
+ break;
+ }
+ }
+
+ if (nativeLibraryUrl != null) {
+ // native library found within JAR, extract and load
+ try {
+ final File libfile = File.createTempFile("wasmer_jni", ".lib");
+ libfile.deleteOnExit(); // just in case
+
+ final InputStream in = nativeLibraryUrl.openStream();
+ final OutputStream out = new BufferedOutputStream(new FileOutputStream(libfile));
+
+ int len = 0;
+ byte[] buffer = new byte[8192];
+
+ while ((len = in.read(buffer)) > -1) {
+ out.write(buffer, 0, len);
+ }
+
+ out.close();
+ in.close();
+ System.load(libfile.getAbsolutePath());
+
+ usingEmbedded = true;
+ } catch (IOException x) {
+ // mission failed, do nothing
+ }
+
+ }
+
+ return usingEmbedded;
+ }
+}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Export.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Export.java
new file mode 100644
index 000000000000..e7303280f3c3
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Export.java
@@ -0,0 +1,7 @@
+package org.apache.shenyu.wasm.exports;
+
+/**
+ * Represent a WebAssembly instance export. It could be a function, a
+ * memory etc.
+ */
+public interface Export {}
diff --git a/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Function.java b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Function.java
new file mode 100644
index 000000000000..fdb638b9e4bf
--- /dev/null
+++ b/shenyu-wasm/shenyu-wasm-runtime/src/main/java/org/apache/shenyu/wasm/exports/Function.java
@@ -0,0 +1,15 @@
+package org.apache.shenyu.wasm.exports;
+
+/**
+ * Functional interface for WebAssembly exported functions, i.e. it
+ * creates a new type for a closure that mimics a WebAssembly exported
+ * function.
+ *
+ * The apply method takes an arbitrary number of arguments and returns
+ * an output.
+ */
+@FunctionalInterface
+public interface Function extends Export {
+ @SuppressWarnings("unchecked")
+ public Object[] apply(Object... inputs);
+}