@@ -198,67 +198,79 @@ pub unsafe fn cabi_realloc(
198198/// import shim instead asks a host-installed resolver for its implementation
199199/// the first time it's called, identifying the import by its core module and
200200/// function name as plain strings. The host installs the resolver once per
201- /// loaded library through `__wit_bindgen_set_import_resolver`, so the
202- /// bindings themselves define no global symbols at all — any number of
203- /// `generate!` invocations (even of the same world) can coexist in one
204- /// binary.
201+ /// loaded library through `__wit_bindgen_set_import_resolver`, so the import
202+ /// shims define no global symbols at all and any number of `generate!`
203+ /// invocations can share one resolver. (Export symbols and world markers are
204+ /// a separate matter: those are global, so binding the same world twice in
205+ /// one binary needs `export_prefix` and `type_section_suffix` respectively to
206+ /// avoid duplicate symbols.)
207+ ///
208+ /// Because each shim caches the pointer the resolver handed it, installing a
209+ /// resolver a second time has no effect on imports that have already been
210+ /// called. Hosts are expected to install one before calling any export.
205211#[ cfg( not( target_arch = "wasm32" ) ) ]
206212mod native_imports {
213+ use core:: ffi:: { CStr , c_char} ;
207214 use core:: sync:: atomic:: { AtomicPtr , Ordering } ;
208215
209216 /// A host-provided callback returning the implementation of the import
210- /// named by `module`/`name` (the canonical ABI core import names, e.g.
211- /// `my:pkg/iface` and `[method]res.frob`), or null if the host doesn't
212- /// implement it. The returned pointer must be a function with the
213- /// import's core signature. `ctx` is the value passed alongside the
214- /// resolver, returned to the host on every call.
215- pub type ImportResolver = unsafe extern "C" fn (
216- ctx : * mut ( ) ,
217- module : * const u8 ,
218- module_len : usize ,
219- name : * const u8 ,
220- name_len : usize ,
221- ) -> * mut ( ) ;
217+ /// named by `import`, or null if the host doesn't implement it. The
218+ /// returned pointer must be a function with the import's core signature.
219+ /// `ctx` is the value passed alongside the resolver, returned to the host
220+ /// on every call.
221+ ///
222+ /// `import` is the import's canonical ABI core module and function name
223+ /// joined by `#`, as a single NUL-terminated string — for example
224+ /// `my:pkg/iface@1.0.0#[method]res.frob`, or `$root#some-func` for a
225+ /// function imported at the top level of a world. (Note the package
226+ /// version trails the interface name here, unlike in a world name.) It
227+ /// points into the guest's static data and stays valid for as long as the
228+ /// library is loaded, so a host may use it as a lookup key without
229+ /// copying it.
230+ pub type ImportResolver = unsafe extern "C" fn ( ctx : * mut ( ) , import : * const c_char ) -> * mut ( ) ;
222231
223232 static RESOLVER : AtomicPtr < ( ) > = AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ;
224233 static RESOLVER_CTX : AtomicPtr < ( ) > = AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ;
225234
226235 /// Installs the import resolver for this linkage unit. Hosts call this
227236 /// (typically via `dlsym`) after loading the library and before calling
228237 /// any export.
238+ ///
239+ /// Passing `None` for `resolver` uninstalls the current one. That only
240+ /// affects imports which haven't been resolved yet; imports already
241+ /// called keep the pointer they cached.
229242 #[ unsafe( no_mangle) ]
230243 pub unsafe extern "C" fn __wit_bindgen_set_import_resolver (
231- resolver : ImportResolver ,
244+ resolver : Option < ImportResolver > ,
232245 ctx : * mut ( ) ,
233246 ) {
247+ let resolver = match resolver {
248+ Some ( resolver) => resolver as * mut ( ) ,
249+ None => core:: ptr:: null_mut ( ) ,
250+ } ;
234251 RESOLVER_CTX . store ( ctx, Ordering :: Relaxed ) ;
235252 // The release store of the resolver publishes the context above.
236- RESOLVER . store ( resolver as * mut ( ) , Ordering :: Release ) ;
253+ RESOLVER . store ( resolver, Ordering :: Release ) ;
237254 }
238255
239256 /// Called by generated import shims on their first invocation.
240- pub fn resolve_import ( module : & str , name : & str ) -> * mut ( ) {
257+ ///
258+ /// `import` is the `module#name` string described on [`ImportResolver`].
259+ pub fn resolve_import ( import : & CStr ) -> * mut ( ) {
260+ let display = import. to_str ( ) . unwrap_or ( "<invalid utf-8>" ) ;
241261 let resolver = RESOLVER . load ( Ordering :: Acquire ) ;
242262 assert ! (
243263 !resolver. is_null( ) ,
244- "import `{module}#{name }` was called before the host installed an \
264+ "import `{display }` was called before the host installed an \
245265 import resolver via `__wit_bindgen_set_import_resolver`"
246266 ) ;
247267 let ctx = RESOLVER_CTX . load ( Ordering :: Relaxed ) ;
248268 let resolver: ImportResolver = unsafe { core:: mem:: transmute ( resolver) } ;
249- let ptr = unsafe {
250- resolver (
251- ctx,
252- module. as_ptr ( ) ,
253- module. len ( ) ,
254- name. as_ptr ( ) ,
255- name. len ( ) ,
256- )
257- } ;
269+ let ptr = unsafe { resolver ( ctx, import. as_ptr ( ) ) } ;
258270 assert ! (
259271 !ptr. is_null( ) ,
260272 "the host's import resolver provided no implementation for \
261- import `{module}#{name }`"
273+ import `{display }`"
262274 ) ;
263275 ptr
264276 }
0 commit comments