Skip to content

Commit ce3c1a7

Browse files
c-api: component-model: Lookup function from an instance (#10675)
* c-api: component-model: Lookup function from an instance * c-api: component-model: Take strings as `wasm_name_t` * Use export indices * Shared `CHECK_ERR` macro * Pass names as a pointer and a size, return nullable pointers * Use `std::str::from_utf8()` instead of `str::from_utf8()` * Remove doc link?
1 parent 97f1b1d commit ce3c1a7

File tree

14 files changed

+292
-37
lines changed

14 files changed

+292
-37
lines changed

crates/c-api/include/wasmtime/component.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define WASMTIME_COMPONENT_H
33

44
#include <wasmtime/component/component.h>
5+
#include <wasmtime/component/func.h>
56
#include <wasmtime/component/instance.h>
67
#include <wasmtime/component/linker.h>
78

crates/c-api/include/wasmtime/component/component.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,33 @@ wasmtime_component_clone(const wasmtime_component_t *component);
108108
*/
109109
WASM_API_EXTERN void wasmtime_component_delete(wasmtime_component_t *component);
110110

111+
typedef struct wasmtime_component_export_index_t
112+
wasmtime_component_export_index_t;
113+
114+
/**
115+
* \brief Looks up a specific export of this component by \p name optionally
116+
* nested within the \p instance provided.
117+
*
118+
* \param component the component to look up \p name in
119+
* \param instance_export_index optional (i.e. nullable) instance to look up in
120+
* \param name the name of the export
121+
* \param name_len length of \p name in bytes
122+
* \return export index if found, else NULL
123+
*/
124+
WASM_API_EXTERN wasmtime_component_export_index_t *
125+
wasmtime_component_get_export_index(
126+
const wasmtime_component_t *component,
127+
const wasmtime_component_export_index_t *instance_export_index,
128+
const char *name, size_t name_len);
129+
130+
/**
131+
* \brief Deletes a #wasmtime_component_export_index_t
132+
*
133+
* \param export_index the export index to delete
134+
*/
135+
WASM_API_EXTERN void wasmtime_component_export_index_delete(
136+
wasmtime_component_export_index_t *export_index);
137+
111138
#ifdef __cplusplus
112139
} // extern "C"
113140
#endif
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef WASMTIME_COMPONENT_FUNC_H
2+
#define WASMTIME_COMPONENT_FUNC_H
3+
4+
#include <wasmtime/conf.h>
5+
6+
#ifdef WASMTIME_FEATURE_COMPONENT_MODEL
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
/// \brief Representation of a function in Wasmtime.
13+
///
14+
/// Functions in Wasmtime are represented as an index into a store and don't
15+
/// have any data or destructor associated with the value. Functions cannot
16+
/// interoperate between #wasmtime_store_t instances and if the wrong function
17+
/// is passed to the wrong store then it may trigger an assertion to abort the
18+
/// process.
19+
typedef struct wasmtime_component_func {
20+
/// Internal identifier of what store this belongs to, never zero.
21+
uint64_t store_id;
22+
/// Internal index within the store.
23+
size_t index;
24+
} wasmtime_component_func_t;
25+
26+
#ifdef __cplusplus
27+
} // extern "C"
28+
#endif
29+
30+
#endif // WASMTIME_FEATURE_COMPONENT_MODEL
31+
32+
#endif // WASMTIME_COMPONENT_FUNC_H

crates/c-api/include/wasmtime/component/instance.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#ifndef WASMTIME_COMPONENT_INSTANCE_H
22
#define WASMTIME_COMPONENT_INSTANCE_H
33

4+
#include <wasmtime/component/component.h>
5+
#include <wasmtime/component/func.h>
46
#include <wasmtime/conf.h>
7+
#include <wasmtime/store.h>
58

69
#ifdef WASMTIME_FEATURE_COMPONENT_MODEL
710

@@ -23,6 +26,38 @@ typedef struct wasmtime_component_instance {
2326
size_t index;
2427
} wasmtime_component_instance_t;
2528

29+
/**
30+
* \brief A methods similar to \fn wasmtime_component_get_export_index() except
31+
* for this instance.
32+
*
33+
* \param instance the instance to look up \p name in
34+
* \param context the context where \p instance lives in
35+
* \param instance_export_index optional (i.e. nullable) instance to look up in
36+
* \param name the name of the export
37+
* \param name_len length of \p name in bytes
38+
* \return export index if found, else NULL
39+
*/
40+
WASM_API_EXTERN wasmtime_component_export_index_t *
41+
wasmtime_component_instance_get_export_index(
42+
const wasmtime_component_instance_t *instance, wasmtime_context_t *context,
43+
const wasmtime_component_export_index_t *instance_export_index,
44+
const char *name, size_t name_len);
45+
46+
/**
47+
* \brief Looks up an exported function by name within this
48+
* #wasmtime_component_instance_t.
49+
*
50+
* \param instance the instance to look up this name in
51+
* \param context the store that \p instance lives in
52+
* \param export_index the export index of the function
53+
* \param func_out if found, the function corresponding to \p name
54+
* \return boolean marking if a function for \p name was found
55+
*/
56+
WASM_API_EXTERN bool wasmtime_component_instance_get_func(
57+
const wasmtime_component_instance_t *instance, wasmtime_context_t *context,
58+
const wasmtime_component_export_index_t *export_index,
59+
wasmtime_component_func_t *func_out);
60+
2661
#ifdef __cplusplus
2762
} // extern "C"
2863
#endif

crates/c-api/include/wasmtime/component/linker.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,14 @@ wasmtime_component_linker_delete(wasmtime_component_linker_t *linker);
8181
*
8282
* \param linker_instance the linker instance from which the new one is created
8383
* \param name new instance name
84+
* \param name_len length of \p name in bytes
8485
* \param linker_instance_out on success, the new #component_linker_instance_t
8586
* \return on success `NULL`, otherwise an error
8687
*/
8788
WASM_API_EXTERN wasmtime_error_t *
8889
wasmtime_component_linker_instance_add_instance(
8990
wasmtime_component_linker_instance_t *linker_instance, const char *name,
91+
size_t name_len,
9092
wasmtime_component_linker_instance_t **linker_instance_out);
9193

9294
/**
@@ -98,12 +100,13 @@ wasmtime_component_linker_instance_add_instance(
98100
*
99101
* \param linker_instance the instance to define the module in
100102
* \param name the module name
103+
* \param name_len length of \p name in bytes
101104
* \param module the module
102105
* \return on success `NULL`, otherwise an error
103106
*/
104107
WASM_API_EXTERN wasmtime_error_t *wasmtime_component_linker_instance_add_module(
105108
wasmtime_component_linker_instance_t *linker_instance, const char *name,
106-
const wasmtime_module_t *module);
109+
size_t name_len, const wasmtime_module_t *module);
107110

108111
/**
109112
* \brief Deletes a #wasmtime_component_linker_instance_t

crates/c-api/src/component/component.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ffi::{c_char, CStr};
22

33
use anyhow::Context;
4-
use wasmtime::component::Component;
4+
use wasmtime::component::{Component, ComponentExportIndex};
55

66
use crate::{wasm_byte_vec_t, wasm_config_t, wasm_engine_t, wasmtime_error_t};
77

@@ -85,3 +85,38 @@ pub unsafe extern "C" fn wasmtime_component_clone(
8585

8686
#[unsafe(no_mangle)]
8787
pub unsafe extern "C" fn wasmtime_component_delete(_component: Box<wasmtime_component_t>) {}
88+
89+
#[repr(transparent)]
90+
pub struct wasmtime_component_export_index_t {
91+
pub(crate) export_index: ComponentExportIndex,
92+
}
93+
94+
#[unsafe(no_mangle)]
95+
pub unsafe extern "C" fn wasmtime_component_get_export_index(
96+
component: &wasmtime_component_t,
97+
instance_export_index: *const wasmtime_component_export_index_t,
98+
name: *const u8,
99+
name_len: usize,
100+
) -> Option<Box<wasmtime_component_export_index_t>> {
101+
let name = unsafe { std::slice::from_raw_parts(name, name_len) };
102+
let Ok(name) = std::str::from_utf8(name) else {
103+
return None;
104+
};
105+
106+
let instance_export_index = if instance_export_index.is_null() {
107+
None
108+
} else {
109+
Some((*instance_export_index).export_index)
110+
};
111+
112+
component
113+
.component
114+
.get_export_index(instance_export_index.as_ref(), &name)
115+
.map(|export_index| Box::new(wasmtime_component_export_index_t { export_index }))
116+
}
117+
118+
#[unsafe(no_mangle)]
119+
pub unsafe extern "C" fn wasmtime_component_export_index_delete(
120+
_export_index: Box<wasmtime_component_export_index_t>,
121+
) {
122+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use wasmtime::component::{Func, Instance};
2+
3+
use crate::WasmtimeStoreContextMut;
4+
5+
use super::wasmtime_component_export_index_t;
6+
7+
#[unsafe(no_mangle)]
8+
pub unsafe extern "C" fn wasmtime_component_instance_get_export_index(
9+
instance: &Instance,
10+
context: WasmtimeStoreContextMut<'_>,
11+
instance_export_index: *const wasmtime_component_export_index_t,
12+
name: *const u8,
13+
name_len: usize,
14+
) -> Option<Box<wasmtime_component_export_index_t>> {
15+
let name = unsafe { std::slice::from_raw_parts(name, name_len) };
16+
let Ok(name) = std::str::from_utf8(name) else {
17+
return None;
18+
};
19+
20+
let instance_export_index = if instance_export_index.is_null() {
21+
None
22+
} else {
23+
Some((*instance_export_index).export_index)
24+
};
25+
26+
instance
27+
.get_export_index(context, instance_export_index.as_ref(), &name)
28+
.map(|export_index| Box::new(wasmtime_component_export_index_t { export_index }))
29+
}
30+
31+
#[unsafe(no_mangle)]
32+
pub unsafe extern "C" fn wasmtime_component_instance_get_func(
33+
instance: &Instance,
34+
context: WasmtimeStoreContextMut<'_>,
35+
export_index: &wasmtime_component_export_index_t,
36+
func_out: &mut Func,
37+
) -> bool {
38+
if let Some(func) = instance.get_func(context, export_index.export_index) {
39+
*func_out = func;
40+
true
41+
} else {
42+
false
43+
}
44+
}

crates/c-api/src/component/linker.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
use std::ffi::{c_char, CStr};
2-
3-
use anyhow::Context;
41
use wasmtime::component::{Instance, Linker, LinkerInstance};
52

63
use crate::{
@@ -57,15 +54,16 @@ pub unsafe extern "C" fn wasmtime_component_linker_delete(
5754
#[unsafe(no_mangle)]
5855
pub unsafe extern "C" fn wasmtime_component_linker_instance_add_instance<'a>(
5956
linker_instance: &'a mut wasmtime_component_linker_instance_t<'a>,
60-
name: *const c_char,
57+
name: *const u8,
58+
name_len: usize,
6159
linker_instance_out: &mut *mut wasmtime_component_linker_instance_t<'a>,
6260
) -> Option<Box<wasmtime_error_t>> {
63-
let name = unsafe { CStr::from_ptr(name) };
64-
let result = name
65-
.to_str()
66-
.context("input name is not valid utf-8")
67-
.and_then(|name| linker_instance.linker_instance.instance(name));
61+
let name = unsafe { std::slice::from_raw_parts(name, name_len) };
62+
let Ok(name) = std::str::from_utf8(name) else {
63+
return crate::bad_utf8();
64+
};
6865

66+
let result = linker_instance.linker_instance.instance(&name);
6967
crate::handle_result(result, |linker_instance| {
7068
*linker_instance_out = Box::into_raw(Box::new(wasmtime_component_linker_instance_t {
7169
linker_instance,
@@ -76,14 +74,18 @@ pub unsafe extern "C" fn wasmtime_component_linker_instance_add_instance<'a>(
7674
#[unsafe(no_mangle)]
7775
pub unsafe extern "C" fn wasmtime_component_linker_instance_add_module(
7876
linker_instance: &mut wasmtime_component_linker_instance_t,
79-
name: *const c_char,
77+
name: *const u8,
78+
name_len: usize,
8079
module: &wasmtime_module_t,
8180
) -> Option<Box<wasmtime_error_t>> {
82-
let name = unsafe { CStr::from_ptr(name) };
83-
let result = name
84-
.to_str()
85-
.context("input name is not valid utf-8")
86-
.and_then(|name| linker_instance.linker_instance.module(name, &module.module));
81+
let name = unsafe { std::slice::from_raw_parts(name, name_len) };
82+
let Ok(name) = std::str::from_utf8(name) else {
83+
return crate::bad_utf8();
84+
};
85+
86+
let result = linker_instance
87+
.linker_instance
88+
.module(&name, &module.module);
8789

8890
crate::handle_result(result, |_| ())
8991
}

crates/c-api/src/component/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
mod component;
2+
mod instance;
23
mod linker;
34

45
pub use component::*;
6+
pub use instance::*;
57
pub use linker::*;

crates/c-api/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ add_capi_test(tests FILES
3333
func.cc
3434
component/instantiate.cc
3535
component/define_module.cc
36+
component/lookup_func.cc
3637
error.cc
3738
config.cc
3839
wat.cc

0 commit comments

Comments
 (0)