diff --git a/src/main/java/io/github/kawamuray/wasmtime/Engine.java b/src/main/java/io/github/kawamuray/wasmtime/Engine.java
index 2a61dd3..063d368 100644
--- a/src/main/java/io/github/kawamuray/wasmtime/Engine.java
+++ b/src/main/java/io/github/kawamuray/wasmtime/Engine.java
@@ -6,6 +6,14 @@
import lombok.Getter;
import lombok.experimental.Accessors;
+/**
+ * An Engine which is a global context for compilation and management of wasm modules.
+ *
+ * Engines store global configuration preferences such as compilation settings, enabled features, etc.
+ * You'll likely only need at most one of these for a program.
+ *
+ * @see Rust Documentation
+ */
@Accessors(fluent = true)
@EqualsAndHashCode
@AllArgsConstructor(access = AccessLevel.PACKAGE)
diff --git a/src/main/java/io/github/kawamuray/wasmtime/ExportType.java b/src/main/java/io/github/kawamuray/wasmtime/ExportType.java
new file mode 100644
index 0000000..4cf4866
--- /dev/null
+++ b/src/main/java/io/github/kawamuray/wasmtime/ExportType.java
@@ -0,0 +1,46 @@
+package io.github.kawamuray.wasmtime;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+
+@Accessors(fluent = true)
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+public class ExportType {
+ @Getter
+ private final ExternType type;
+
+ @Getter(AccessLevel.PACKAGE)
+ private final Object typeObj;
+
+ @Getter
+ private final String name;
+
+ private void ensureType(ExternType expected) {
+ if (type != expected) {
+ throw new RuntimeException(
+ String.format("ImportType expected to have type %s but is actually %s", expected, type));
+ }
+ }
+
+ public FuncType func() {
+ ensureType(ExternType.FUNC);
+ return (FuncType) typeObj;
+ }
+
+ public GlobalType global() {
+ ensureType(ExternType.GLOBAL);
+ return (GlobalType) typeObj;
+ }
+
+ public MemoryType memory() {
+ ensureType(ExternType.MEMORY);
+ return (MemoryType) typeObj;
+ }
+
+ public TableType table() {
+ ensureType(ExternType.TABLE);
+ return (TableType) typeObj;
+ }
+}
diff --git a/src/main/java/io/github/kawamuray/wasmtime/ExternType.java b/src/main/java/io/github/kawamuray/wasmtime/ExternType.java
new file mode 100644
index 0000000..bb4d097
--- /dev/null
+++ b/src/main/java/io/github/kawamuray/wasmtime/ExternType.java
@@ -0,0 +1,11 @@
+package io.github.kawamuray.wasmtime;
+
+public enum ExternType {
+ FUNC,
+ GLOBAL,
+ TABLE,
+ MEMORY,
+ // TODO: Currently Unsupported
+ INSTANCE,
+ MODULE
+}
diff --git a/src/main/java/io/github/kawamuray/wasmtime/Func.java b/src/main/java/io/github/kawamuray/wasmtime/Func.java
index c1aa1ff..feedcad 100644
--- a/src/main/java/io/github/kawamuray/wasmtime/Func.java
+++ b/src/main/java/io/github/kawamuray/wasmtime/Func.java
@@ -1,16 +1,26 @@
package io.github.kawamuray.wasmtime;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A WebAssembly function which can be called.
+ *
+ * This type is either provided by a WebAssembly Module or implemented in Java as a Host-function.
+ *
+ * A Func "belongs" to the store that it was originally created within. Operations on a Func only work with the store
+ * it belongs to. Otherwise an exception will be thrown.
+ *
+ * @see Rust Documentation
+ */
@Slf4j
@Accessors(fluent = true)
@AllArgsConstructor(access = AccessLevel.PACKAGE)
diff --git a/src/main/java/io/github/kawamuray/wasmtime/ImportType.java b/src/main/java/io/github/kawamuray/wasmtime/ImportType.java
index baea6d7..d3b6c3a 100644
--- a/src/main/java/io/github/kawamuray/wasmtime/ImportType.java
+++ b/src/main/java/io/github/kawamuray/wasmtime/ImportType.java
@@ -8,18 +8,8 @@
@Accessors(fluent = true)
@AllArgsConstructor(access = AccessLevel.PACKAGE)
public class ImportType {
- public enum Type {
- FUNC,
- GLOBAL,
- TABLE,
- MEMORY,
- // TODO: Currently Unsupported
- INSTANCE,
- MODULE
- }
-
@Getter
- private final Type type;
+ private final ExternType type;
@Getter(AccessLevel.PACKAGE)
private final Object typeObj;
@@ -30,7 +20,7 @@ public enum Type {
@Getter
private final String name;
- private void ensureType(ImportType.Type expected) {
+ private void ensureType(ExternType expected) {
if (type != expected) {
throw new RuntimeException(
String.format("ImportType expected to have type %s but is actually %s", expected, type));
@@ -38,22 +28,22 @@ private void ensureType(ImportType.Type expected) {
}
public FuncType func() {
- ensureType(ImportType.Type.FUNC);
+ ensureType(ExternType.FUNC);
return (FuncType) typeObj;
}
public GlobalType global() {
- ensureType(ImportType.Type.GLOBAL);
+ ensureType(ExternType.GLOBAL);
return (GlobalType) typeObj;
}
public MemoryType memory() {
- ensureType(ImportType.Type.MEMORY);
+ ensureType(ExternType.MEMORY);
return (MemoryType) typeObj;
}
public TableType table() {
- ensureType(ImportType.Type.TABLE);
+ ensureType(ExternType.TABLE);
return (TableType) typeObj;
}
}
diff --git a/src/main/java/io/github/kawamuray/wasmtime/Module.java b/src/main/java/io/github/kawamuray/wasmtime/Module.java
index 4e4cbdc..72634c8 100644
--- a/src/main/java/io/github/kawamuray/wasmtime/Module.java
+++ b/src/main/java/io/github/kawamuray/wasmtime/Module.java
@@ -25,6 +25,8 @@ public static Module fromBinary(Engine engine, byte[] bytes) {
public native ImportType[] imports();
+ public native ExportType[] exports();
+
@Override
public native void dispose();
diff --git a/src/main/java/io/github/kawamuray/wasmtime/Store.java b/src/main/java/io/github/kawamuray/wasmtime/Store.java
index f4a34fc..f091eec 100644
--- a/src/main/java/io/github/kawamuray/wasmtime/Store.java
+++ b/src/main/java/io/github/kawamuray/wasmtime/Store.java
@@ -6,6 +6,47 @@
import lombok.Getter;
import lombok.experimental.Accessors;
+/**
+ * A Store is a collection of WebAssembly instances and host-defined state.
+ *
+ * All WebAssembly instances and items will be attached to and refer to a Store. For example instances, functions,
+ * globals, and tables are all attached to a Store. Instances are created by instantiating a Module within a Store.
+ *
+ * A Store is intended to be a short-lived object in a program. No form of GC is implemented at this time so once an
+ * instance is created within a Store it will not be deallocated until the Store itself is dropped. This makes Store
+ * unsuitable for creating an unbounded number of instances in it because Store will never release this memory. It’s
+ * recommended to have a Store correspond roughly to the lifetime of a "main instance" that an embedding is interested
+ * in executing.
+ *
+ *
Type parameter T
+ *
+ * Each Store has a type parameter T associated with it. This T represents state defined by the host.
+ * This state will be accessible through the Caller type that host-defined functions get access to.
+ * This T is suitable for storing Store-specific information which imported functions may want access to.
+ *
+ * The data T can be accessed through methods like Store::data and Store::data_mut.
+ * Stores, contexts, oh my
+ *
+ * Most methods in Wasmtime take something of the form AsContext or AsContextMut as the first argument.
+ * These two traits allow ergonomically passing in the context you currently have to any method.
+ * The primary two sources of contexts are:
+ *
+ * Store<T>
+ * Caller<'_, T>
+ *
+ * corresponding to what you create and what you have access to in a host function. You can also explicitly acquire
+ * a StoreContext or StoreContextMut and pass that around as well.
+ *
+ * Note that all methods on Store are mirrored onto StoreContext, StoreContextMut, and Caller. This way no matter what
+ * form of context you have you can call various methods, create objects, etc.
+ *
+ *
Stores and Default
+ *
+ * You can create a store with default configuration settings using Store::default(). This will create a
+ * brand new Engine with default configuration (see Config for more information).
+ *
+ * @param State defined by the host
+ */
@Accessors(fluent = true)
@AllArgsConstructor(access = AccessLevel.PACKAGE)
public class Store implements Disposable {
diff --git a/src/test/java/io/github/kawamuray/wasmtime/ModuleTest.java b/src/test/java/io/github/kawamuray/wasmtime/ModuleTest.java
index 25dee18..4dbc716 100644
--- a/src/test/java/io/github/kawamuray/wasmtime/ModuleTest.java
+++ b/src/test/java/io/github/kawamuray/wasmtime/ModuleTest.java
@@ -33,6 +33,15 @@ public class ModuleTest {
" (func (export \"run\") (call $hello))\n" +
")").getBytes();
+ private static final byte[] EXPORT_WAT_BINARY = ("(module"
+ + " (memory (export \"memmy\") 20 22)\n"
+ + " (table (export \"tabby\") 0 1 funcref)\n"
+ + " (export \"globby\" (global 0)) (global i32 (i32.const 0))\n"
+ + " (func (export \"life\") (param $p1 i32) (param $p2 i32) (result i32)"
+ + " (i32.const 42)\n"
+ + " )"
+ + ")").getBytes();
+
@Test
public void testCreateDispose() {
try (Engine engine = new Engine()) {
@@ -75,6 +84,43 @@ public void testAccessImports() {
}
}
+ @Test
+ public void testAccessExport() {
+ try (
+ Engine engine = new Engine();
+ Module module = new Module(engine, EXPORT_WAT_BINARY)
+ ) {
+ runExportTest(module, new TestExportData[]{
+ TestExportData.memory("memmy", 20, 22),
+ TestExportData.table("tabby", Val.Type.FUNC_REF, 0, 1),
+ TestExportData.global("globby", Val.Type.I32, Mutability.CONST),
+ TestExportData.func("life", new Val.Type[]{Val.Type.I32, Val.Type.I32}, new Val.Type[]{Val.Type.I32}),
+ });
+ }
+ }
+
+ private void runExportTest(Module module, TestExportData>[] testData) {
+ int i = 0;
+ for (ExportType export : module.exports()) {
+ Assert.assertTrue("Test Data not big enough", testData.length > i);
+ TestExportData> data = testData[i];
+ Assert.assertEquals(data.getName(), export.name());
+ Assert.assertEquals(data.getType(), export.type());
+ checkExportType(data, export);
+ i += 1;
+ }
+ Assert.assertEquals("Not Every Test Case was returned", testData.length, i);
+ }
+
+ private void checkExportType(TestExportData data, ExportType type) {
+ Class clazz = data.getClazz();
+ Object typeObj = type.typeObj();
+ Assert.assertNotNull("Type Object is null", typeObj);
+ Class> typeObjClass = typeObj.getClass();
+ Assert.assertTrue(String.format("Expected Type is different. Expected %s but was %s", clazz, typeObjClass), clazz.isAssignableFrom(typeObjClass));
+ data.verify(type, typeObj);
+ }
+
private void runImportTest(Module module, TestImportData>[] testData) {
int i = 0;
for (ImportType imp : module.imports()) {
@@ -98,18 +144,101 @@ private void checkImportType(TestImportData data, ImportType type) {
data.verify(type, typeObj);
}
+ @Data
+ private static class TestExportData {
+ private final String name;
+ private final ExternType type;
+ private final Class clazz;
+ private final Consumer verifyExport;
+ private final Consumer consumer;
+
+ public static TestExportData func(String name, Val.Type[] params, Val.Type[] results) {
+ return new TestExportData<>(
+ name, ExternType.FUNC, FuncType.class,
+ mod -> {
+ Assert.assertEquals(mod.typeObj(), mod.func());
+ Assert.assertThrows(RuntimeException.class, mod::global);
+ Assert.assertThrows(RuntimeException.class, mod::memory);
+ Assert.assertThrows(RuntimeException.class, mod::table);
+ },
+ func -> {
+ Assert.assertArrayEquals(params, func.getParams());
+ Assert.assertArrayEquals(results, func.getResults());
+ }
+ );
+ }
+
+ public static TestExportData memory(String name, int min, int max) {
+ return new TestExportData<>(
+ name, ExternType.MEMORY, MemoryType.class,
+ mod -> {
+ Assert.assertThrows(RuntimeException.class, mod::func);
+ Assert.assertThrows(RuntimeException.class, mod::global);
+ Assert.assertEquals(mod.typeObj(), mod.memory());
+ Assert.assertThrows(RuntimeException.class, mod::table);
+ },
+ mem -> {
+ MemoryType.Limit limit = mem.limit();
+ Assert.assertEquals(min, limit.min());
+ Assert.assertEquals(max, limit.max());
+ }
+ );
+ }
+
+ public static TestExportData table(String name, Val.Type content, int min, int max) {
+ return new TestExportData<>(
+ name, ExternType.TABLE, TableType.class,
+ mod -> {
+ Assert.assertThrows(RuntimeException.class, mod::func);
+ Assert.assertThrows(RuntimeException.class, mod::global);
+ Assert.assertThrows(RuntimeException.class, mod::memory);
+ Assert.assertEquals(mod.typeObj(), mod.table());
+ },
+ table -> {
+ Assert.assertEquals(content, table.element());
+
+ MemoryType.Limit limit = table.limit();
+ Assert.assertEquals(min, limit.min());
+ Assert.assertEquals(max, limit.max());
+ }
+ );
+ }
+
+ public static TestExportData global(String name, Val.Type content, Mutability mutability) {
+ return new TestExportData<>(
+ name, ExternType.GLOBAL, GlobalType.class,
+ mod -> {
+ Assert.assertThrows(RuntimeException.class, mod::func);
+ Assert.assertEquals(mod.typeObj(), mod.global());
+ Assert.assertThrows(RuntimeException.class, mod::memory);
+ Assert.assertThrows(RuntimeException.class, mod::table);
+ },
+ global -> {
+ Assert.assertEquals(content, global.getContent());
+ Assert.assertEquals(mutability, global.getMutability());
+ }
+ );
+ }
+
+ @SuppressWarnings("unchecked")
+ public void verify(final ExportType imp, final Object typeObj) {
+ this.verifyExport.accept(imp);
+ this.consumer.accept((T) typeObj);
+ }
+ }
+
@Data
private static class TestImportData {
private final String module;
private final String name;
- private final ImportType.Type type;
+ private final ExternType type;
private final Class clazz;
private final Consumer verifyImport;
private final Consumer consumer;
static TestImportData memory(String module, String name, int min, int max) {
return new TestImportData<>(
- module, name, ImportType.Type.MEMORY, MemoryType.class,
+ module, name, ExternType.MEMORY, MemoryType.class,
mod -> {
Assert.assertThrows(RuntimeException.class, mod::func);
Assert.assertThrows(RuntimeException.class, mod::global);
@@ -126,7 +255,7 @@ static TestImportData memory(String module, String name, int min, in
static TestImportData global(String module, String name, Val.Type content, Mutability mutability) {
return new TestImportData<>(
- module, name, ImportType.Type.GLOBAL, GlobalType.class,
+ module, name, ExternType.GLOBAL, GlobalType.class,
mod -> {
Assert.assertThrows(RuntimeException.class, mod::func);
Assert.assertEquals(mod.typeObj(), mod.global());
@@ -142,7 +271,7 @@ static TestImportData global(String module, String name, Val.Type co
static TestImportData func(String module, String name, Val.Type[] params, Val.Type[] results) {
return new TestImportData<>(
- module, name, ImportType.Type.FUNC, FuncType.class,
+ module, name, ExternType.FUNC, FuncType.class,
mod -> {
Assert.assertEquals(mod.typeObj(), mod.func());
Assert.assertThrows(RuntimeException.class, mod::global);
@@ -158,7 +287,7 @@ static TestImportData func(String module, String name, Val.Type[] para
public static TestImportData table(String module, String name, Val.Type content, int min, int max) {
return new TestImportData<>(
- module, name, ImportType.Type.TABLE, TableType.class,
+ module, name, ExternType.TABLE, TableType.class,
mod -> {
Assert.assertThrows(RuntimeException.class, mod::func);
Assert.assertThrows(RuntimeException.class, mod::global);
diff --git a/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/imp.rs b/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/imp.rs
index 74b47e5..59fdc36 100644
--- a/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/imp.rs
+++ b/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/imp.rs
@@ -1,17 +1,16 @@
use super::JniModule;
use crate::errors::{self, Result};
-use crate::wval::types_into_java_array;
-use crate::{interop, utils, wmut, wval};
+use crate::{interop, utils};
use jni::objects::{JClass, JObject, JString};
-use jni::sys::{jbyteArray, jint, jlong, jobjectArray};
+use jni::sys::{jbyteArray, jlong, jobjectArray};
use jni::JNIEnv;
-use wasmtime::{Engine, ExternType, Limits, Module};
+use wasmtime::{Engine, Module};
+use crate::wextern::{EXTERN_TYPE_CLASS, type_into_java};
pub(super) struct JniModuleImpl;
const OBJECT_CLASS: &'static str = "java/lang/Object";
-const LIMIT_TYPE: &str = "io/github/kawamuray/wasmtime/MemoryType$Limit";
-pub const IMPORT_TYPE_CLASS: &'static str = "io/github/kawamuray/wasmtime/ImportType$Type";
+pub const STRING_CLASS: &str = "java/lang/String";
impl<'a> JniModule<'a> for JniModuleImpl {
type Error = errors::Error;
@@ -21,8 +20,32 @@ impl<'a> JniModule<'a> for JniModuleImpl {
Ok(())
}
+ fn exports(env: &JNIEnv, this: JObject) -> std::result::Result {
+ const EXPORT_TYPE: &str = "io/github/kawamuray/wasmtime/ExportType";
+ let module = interop::get_inner::(env, this)?;
+ let it = module.exports();
+ let mut exports = Vec::with_capacity(it.len());
+ for obj in it {
+ let name = env.new_string(obj.name());
+ let (ty, ty_obj) = type_into_java(env, obj.ty())?;
+ let export = env.new_object(
+ EXPORT_TYPE,
+ format!(
+ "(L{};L{};L{};)V",
+ EXTERN_TYPE_CLASS, OBJECT_CLASS, STRING_CLASS
+ ),
+ &[
+ ty.into_inner().into(),
+ ty_obj.into_inner().into(),
+ name?.into(),
+ ],
+ )?;
+ exports.push(export);
+ }
+ Ok(utils::into_java_array(env, EXPORT_TYPE, exports)?)
+ }
+
fn imports(env: &JNIEnv, this: JObject) -> std::result::Result {
- const STRING_CLASS: &str = "java/lang/String";
const IMPORT_TYPE: &str = "io/github/kawamuray/wasmtime/ImportType";
let module = interop::get_inner::(env, this)?;
@@ -30,78 +53,18 @@ impl<'a> JniModule<'a> for JniModuleImpl {
let mut imports = Vec::with_capacity(it.len());
for obj in it {
let module = obj.module();
- let (ty, ty_obj) = match obj.ty() {
- ExternType::Func(func) => {
- let results = types_into_java_array(env, func.results());
- let params = types_into_java_array(env, func.params());
-
- (
- into_java_import_type(env, "FUNC"),
- env.new_object(
- "io/github/kawamuray/wasmtime/FuncType",
- format!("([L{};[L{};)V", wval::VAL_TYPE, wval::VAL_TYPE),
- &[params?.into(), results?.into()],
- ),
- )
- }
- ExternType::Global(global) => (
- into_java_import_type(env, "GLOBAL"),
- env.new_object(
- "io/github/kawamuray/wasmtime/GlobalType",
- format!("(L{};L{};)V", wval::VAL_TYPE, wmut::MUT_TYPE),
- &[
- wval::type_into_java(env, global.content().to_owned())?
- .into_inner()
- .into(),
- wmut::mutability_into_java(env, global.mutability())?
- .into_inner()
- .into(),
- ],
- ),
- ),
- ExternType::Table(tab) => {
- const TABLE_TYPE: &str = "io/github/kawamuray/wasmtime/TableType";
- let limit = limit_into_java(env, tab.limits());
- let val = wval::type_into_java(env, tab.element().to_owned());
- let table = env.new_object(
- TABLE_TYPE,
- format!("(L{};L{};)V", wval::VAL_TYPE, LIMIT_TYPE),
- &[val?.into_inner().into(), limit?.into_inner().into()],
- );
-
- (into_java_import_type(env, "TABLE"), table)
- }
- ExternType::Memory(mem) => {
- const MEMORY_TYPE: &str = "io/github/kawamuray/wasmtime/MemoryType";
- let limit = limit_into_java(env, mem.limits());
- let mem = env.new_object(
- MEMORY_TYPE,
- format!("(L{};)V", LIMIT_TYPE),
- &[limit?.into_inner().into()],
- );
-
- (into_java_import_type(env, "MEMORY"), mem)
- }
- // WebAssembly module-linking proposal
- ExternType::Instance(_) => {
- (into_java_import_type(env, "INSTANCE"), Ok(JObject::null()))
- }
- // WebAssembly module-linking proposal
- ExternType::Module(_) => {
- (into_java_import_type(env, "MODULE"), Ok(JObject::null()))
- }
- };
+ let (ty, ty_obj) = type_into_java(env, obj.ty())?;
let name = obj.name().unwrap_or_else(|| "");
let import = env.new_object(
IMPORT_TYPE,
format!(
"(L{};L{};L{};L{};)V",
- IMPORT_TYPE_CLASS, OBJECT_CLASS, STRING_CLASS, STRING_CLASS
+ EXTERN_TYPE_CLASS, OBJECT_CLASS, STRING_CLASS, STRING_CLASS
),
&[
- ty?.into_inner().into(),
- ty_obj?.into_inner().into(),
+ ty.into_inner().into(),
+ ty_obj.into_inner().into(),
env.new_string(module)?.into(),
env.new_string(name)?.into(),
],
@@ -146,17 +109,3 @@ impl<'a> JniModule<'a> for JniModuleImpl {
Ok(interop::into_raw::(module))
}
}
-
-fn limit_into_java<'a>(env: &'a JNIEnv, limits: &Limits) -> jni::errors::Result> {
- let min = limits.min() as jint;
- let max = match limits.max() {
- None => -1,
- Some(max) => max as jint,
- };
- env.new_object(LIMIT_TYPE, "(II)V", &[min.into(), max.into()])
-}
-
-pub fn into_java_import_type<'a>(env: &'a JNIEnv, ty: &'a str) -> jni::errors::Result> {
- env.get_static_field(IMPORT_TYPE_CLASS, ty, format!("L{};", IMPORT_TYPE_CLASS))?
- .l()
-}
diff --git a/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/mod.rs b/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/mod.rs
index c893163..27f9551 100644
--- a/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/mod.rs
+++ b/wasmtime-jni/src/io_github_kawamuray_wasmtime_Module/mod.rs
@@ -22,6 +22,7 @@ macro_rules! wrap_error {
trait JniModule<'a> {
type Error: Desc<'a, JThrowable<'a>>;
fn dispose(env: &JNIEnv, this: JObject) -> Result<(), Self::Error>;
+ fn exports(env: &JNIEnv, this: JObject) -> Result;
fn imports(env: &JNIEnv, this: JObject) -> Result;
fn new_from_binary(
env: &JNIEnv,
@@ -48,6 +49,18 @@ extern "system" fn Java_io_github_kawamuray_wasmtime_Module_dispose(env: JNIEnv,
wrap_error!(env, JniModuleImpl::dispose(&env, this), Default::default())
}
+#[no_mangle]
+extern "system" fn Java_io_github_kawamuray_wasmtime_Module_exports(
+ env: JNIEnv,
+ this: JObject,
+) -> jobjectArray {
+ wrap_error!(
+ env,
+ JniModuleImpl::exports(&env, this),
+ JObject::null().into_inner()
+ )
+}
+
#[no_mangle]
extern "system" fn Java_io_github_kawamuray_wasmtime_Module_imports(
env: JNIEnv,
diff --git a/wasmtime-jni/src/wextern.rs b/wasmtime-jni/src/wextern.rs
index c250dad..27913b0 100644
--- a/wasmtime-jni/src/wextern.rs
+++ b/wasmtime-jni/src/wextern.rs
@@ -1,8 +1,14 @@
use crate::errors::{Error, Result};
-use crate::{interop, utils};
+use crate::{interop, utils, wval};
use jni::objects::JObject;
use jni::JNIEnv;
-use wasmtime::{Extern, Func, Global, Memory, Table};
+use jni::sys::jint;
+use wasmtime::{Extern, ExternType, Func, Global, Limits, Memory, Table};
+use crate::wmut::{MUT_TYPE, mutability_into_java};
+use crate::wval::VAL_TYPE;
+
+pub const EXTERN_TYPE_CLASS: &'static str = "io/github/kawamuray/wasmtime/ExternType";
+const LIMIT_TYPE: &str = "io/github/kawamuray/wasmtime/MemoryType$Limit";
pub fn from_java(env: &JNIEnv, obj: JObject) -> Result {
let ty = env
@@ -96,6 +102,68 @@ pub fn into_java<'a>(env: &'a JNIEnv, ext: Extern) -> Result> {
})
}
+pub fn type_into_java<'a>(env: &'a JNIEnv, ty: ExternType) -> Result<(JObject<'a>, JObject<'a>)> {
+ let (ty, ty_obj) = match ty {
+ ExternType::Func(func) => {
+ let results = wval::types_into_java_array(env, func.results());
+ let params = wval::types_into_java_array(env, func.params());
+
+ (
+ into_java_extern_type(env, "FUNC"),
+ env.new_object(
+ "io/github/kawamuray/wasmtime/FuncType",
+ format!("([L{};[L{};)V", VAL_TYPE, VAL_TYPE),
+ &[params?.into(), results?.into()],
+ ),
+ )
+ }
+ ExternType::Global(global) => (
+ into_java_extern_type(env, "GLOBAL"),
+ env.new_object(
+ "io/github/kawamuray/wasmtime/GlobalType",
+ format!("(L{};L{};)V", VAL_TYPE, MUT_TYPE),
+ &[
+ wval::type_into_java(env, global.content().to_owned())?
+ .into_inner()
+ .into(),
+ mutability_into_java(env, global.mutability())?
+ .into_inner()
+ .into(),
+ ],
+ ),
+ ),
+ ExternType::Table(tab) => {
+ const TABLE_TYPE: &str = "io/github/kawamuray/wasmtime/TableType";
+ let limit = limit_into_java(env, tab.limits());
+ let val = wval::type_into_java(env, tab.element().to_owned());
+ let table = env.new_object(
+ TABLE_TYPE,
+ format!("(L{};L{};)V", VAL_TYPE, LIMIT_TYPE),
+ &[val?.into_inner().into(), limit?.into_inner().into()],
+ );
+
+ (into_java_extern_type(env, "TABLE"), table)
+ }
+ ExternType::Memory(mem) => {
+ const MEMORY_TYPE: &str = "io/github/kawamuray/wasmtime/MemoryType";
+ let limit = limit_into_java(env, mem.limits());
+ let mem = env.new_object(
+ MEMORY_TYPE,
+ format!("(L{};)V", LIMIT_TYPE),
+ &[limit?.into_inner().into()],
+ );
+
+ (into_java_extern_type(env, "MEMORY"), mem)
+ }
+ // WebAssembly module-linking proposal
+ ExternType::Instance(_) => (into_java_extern_type(env, "INSTANCE"), Ok(JObject::null())),
+ // WebAssembly module-linking proposal
+ ExternType::Module(_) => (into_java_extern_type(env, "MODULE"), Ok(JObject::null())),
+ };
+
+ Ok((ty?, ty_obj?))
+}
+
pub fn unknown<'a>(env: &'a JNIEnv) -> Result> {
Ok(env
.get_static_field(
@@ -105,3 +173,17 @@ pub fn unknown<'a>(env: &'a JNIEnv) -> Result> {
)?
.l()?)
}
+
+fn limit_into_java<'a>(env: &'a JNIEnv, limits: &Limits) -> jni::errors::Result> {
+ let min = limits.min() as jint;
+ let max = match limits.max() {
+ None => -1,
+ Some(max) => max as jint,
+ };
+ env.new_object(LIMIT_TYPE, "(II)V", &[min.into(), max.into()])
+}
+
+fn into_java_extern_type<'a>(env: &'a JNIEnv, ty: &'a str) -> jni::errors::Result> {
+ env.get_static_field(EXTERN_TYPE_CLASS, ty, format!("L{};", EXTERN_TYPE_CLASS))?
+ .l()
+}