@@ -9,13 +9,18 @@ use crate::store::MemoryInstance;
99use crate :: {
1010 Error , Function , FunctionTyped , Global , Imports , Memory , Result , Store , StoreItem , Table , Tag , Trap , WasmValue ,
1111} ;
12+ #[ cfg( feature = "std" ) ]
13+ use crate :: { MemoryShared , store:: SHARED_MEM_BIT } ;
1214
1315/// A typed view over an exported extern value.
1416pub enum ExternItem {
1517 /// Exported function handle.
1618 Func ( Function ) ,
1719 /// Exported memory reference.
1820 Memory ( Memory ) ,
21+ /// Exported shared memory.
22+ #[ cfg( feature = "std" ) ]
23+ MemoryShared ( MemoryShared ) ,
1924 /// Exported table reference.
2025 Table ( Table ) ,
2126 /// Exported global reference.
@@ -57,6 +62,8 @@ struct ModuleInstanceInner {
5762 func_addrs : Box < [ FuncAddr ] > ,
5863 table_addrs : Box < [ TableAddr ] > ,
5964 mem_addrs : Box < [ MemAddr ] > ,
65+ #[ cfg( feature = "std" ) ]
66+ shared_backings : Box < [ ( MemAddr , MemoryShared ) ] > ,
6067 global_addrs : Box < [ GlobalAddr ] > ,
6168 tag_addrs : Box < [ TagAddr ] > ,
6269 elem_addrs : Box < [ ElemAddr ] > ,
@@ -187,6 +194,19 @@ impl ModuleInstance {
187194 }
188195
189196 fn instantiate_inner ( store : & mut Store , module : & Module , imports : & [ crate :: Extern ] ) -> Result < Self > {
197+ if module. memory_types . iter ( ) . any ( |ty| ty. shared ( ) && ty. page_count_max_declared ( ) . is_none ( ) )
198+ || module. imports . iter ( ) . any ( |import| {
199+ matches ! ( import. kind, ImportKind :: Memory ( ty) if ty. shared( ) && ty. page_count_max_declared( ) . is_none( ) )
200+ } )
201+ {
202+ return Err ( Error :: UnsupportedFeature ( "shared memory requires a maximum" ) ) ;
203+ }
204+ #[ cfg( not( feature = "std" ) ) ]
205+ if module. memory_types . iter ( ) . any ( MemoryType :: shared)
206+ || module. imports . iter ( ) . any ( |import| matches ! ( import. kind, ImportKind :: Memory ( ty) if ty. shared( ) ) )
207+ {
208+ return Err ( Error :: UnsupportedFeature ( "shared memory requires std" ) ) ;
209+ }
190210 let type_addrs = store. register_module_types ( & module. types ) ;
191211 let id = store. next_module_instance_id ( ) ;
192212 let mut addrs = crate :: imports:: ResolvedImports :: new ( store, module, & type_addrs, imports) ?;
@@ -205,13 +225,23 @@ impl ModuleInstance {
205225 let elem_addrs = store. alloc_elements ( & addrs. funcs , & addrs. globals , & module. elements , & type_addrs) ?;
206226 let data_addrs = store. alloc_data ( & module. data ) ;
207227
228+ #[ cfg( feature = "std" ) ]
229+ let shared_backings = addrs
230+ . memories
231+ . iter ( )
232+ . filter ( |& & addr| addr & SHARED_MEM_BIT != 0 )
233+ . map ( |& addr| ( addr, store. state . shared_memories [ ( addr & !SHARED_MEM_BIT ) as usize ] . clone ( ) ) )
234+ . collect ( ) ;
235+
208236 let instance = ModuleInstanceInner {
209237 store_id : store. id ( ) ,
210238 id,
211239 type_addrs,
212240 func_addrs : addrs. funcs . into_boxed_slice ( ) ,
213241 table_addrs : addrs. tables . into_boxed_slice ( ) ,
214242 mem_addrs : addrs. memories . into_boxed_slice ( ) ,
243+ #[ cfg( feature = "std" ) ]
244+ shared_backings,
215245 global_addrs : addrs. globals . into_boxed_slice ( ) ,
216246 tag_addrs : addrs. tags . into_boxed_slice ( ) ,
217247 elem_addrs,
@@ -295,7 +325,17 @@ impl ModuleInstance {
295325 ExternItem :: Table ( Table ( StoreItem :: new ( self . 0 . store_id , self . resolve_table_addr ( export. index ) ) ) )
296326 }
297327 ExternalKind :: Memory => {
298- ExternItem :: Memory ( Memory ( StoreItem :: new ( self . 0 . store_id , self . resolve_mem_addr ( export. index ) ) ) )
328+ let addr = self . resolve_mem_addr ( export. index ) ;
329+ #[ cfg( feature = "std" ) ]
330+ if addr & SHARED_MEM_BIT != 0 {
331+ ExternItem :: MemoryShared (
332+ self . shared_backing ( addr) . expect ( "exported shared memory has a backing" ) ,
333+ )
334+ } else {
335+ ExternItem :: Memory ( Memory ( StoreItem :: new ( self . 0 . store_id , addr) ) )
336+ }
337+ #[ cfg( not( feature = "std" ) ) ]
338+ ExternItem :: Memory ( Memory ( StoreItem :: new ( self . 0 . store_id , addr) ) )
299339 }
300340 ExternalKind :: Global => {
301341 ExternItem :: Global ( Global ( StoreItem :: new ( self . 0 . store_id , self . resolve_global_addr ( export. index ) ) ) )
@@ -352,7 +392,13 @@ impl ModuleInstance {
352392 ExternVal :: Func ( addr) => {
353393 Ok ( ExternItem :: Func ( Function { item : StoreItem :: new ( self . 0 . store_id , addr) , module_id : self . id ( ) } ) )
354394 }
355- ExternVal :: Memory ( addr) => Ok ( ExternItem :: Memory ( Memory ( StoreItem :: new ( self . 0 . store_id , addr) ) ) ) ,
395+ ExternVal :: Memory ( addr) => {
396+ #[ cfg( feature = "std" ) ]
397+ if addr & SHARED_MEM_BIT != 0 {
398+ return Ok ( ExternItem :: MemoryShared ( self . shared_backing ( addr) ?) ) ;
399+ }
400+ Ok ( ExternItem :: Memory ( Memory ( StoreItem :: new ( self . 0 . store_id , addr) ) ) )
401+ }
356402 ExternVal :: Table ( addr) => Ok ( ExternItem :: Table ( Table ( StoreItem :: new ( self . 0 . store_id , addr) ) ) ) ,
357403 ExternVal :: Global ( addr) => Ok ( ExternItem :: Global ( Global ( StoreItem :: new ( self . 0 . store_id , addr) ) ) ) ,
358404 ExternVal :: Tag ( addr) => Ok ( ExternItem :: Tag ( Tag ( StoreItem :: new ( self . 0 . store_id , addr) ) ) ) ,
@@ -482,11 +528,32 @@ impl ModuleInstance {
482528 /// Get a memory export by name.
483529 pub fn memory ( & self , name : & str ) -> Result < Memory > {
484530 match self . require_export ( name) ? {
485- ExternVal :: Memory ( mem_addr) => Ok ( Memory ( StoreItem :: new ( self . 0 . store_id , mem_addr) ) ) ,
531+ ExternVal :: Memory ( mem_addr) if mem_addr & crate :: store:: SHARED_MEM_BIT == 0 => {
532+ Ok ( Memory ( StoreItem :: new ( self . 0 . store_id , mem_addr) ) )
533+ }
486534 _ => cold ! ( Err ( Error :: Other ( format!( "Export is not a memory: {name}" ) ) ) ) ,
487535 }
488536 }
489537
538+ #[ cfg( feature = "std" ) ]
539+ fn shared_backing ( & self , addr : MemAddr ) -> Result < MemoryShared > {
540+ self . 0
541+ . shared_backings
542+ . iter ( )
543+ . find ( |( index, _) | * index == addr)
544+ . map ( |( _, backing) | backing. clone ( ) )
545+ . ok_or_else ( || Error :: Other ( "invalid shared memory address" . into ( ) ) )
546+ }
547+
548+ /// Returns a shared memory export by name.
549+ #[ cfg( feature = "std" ) ]
550+ pub fn memory_shared ( & self , name : & str ) -> Result < MemoryShared > {
551+ match self . require_export ( name) ? {
552+ ExternVal :: Memory ( addr) if addr & SHARED_MEM_BIT != 0 => self . shared_backing ( addr) ,
553+ _ => Err ( Error :: Other ( format ! ( "Export is not a shared memory: {name}" ) ) ) ,
554+ }
555+ }
556+
490557 /// Get a memory by its module-local index.
491558 ///
492559 /// This exposes an internal module-owned memory directly and bypasses the
@@ -496,7 +563,11 @@ impl ModuleInstance {
496563 #[ cfg_attr( docsrs, doc( cfg( feature = "guest-debug" ) ) ) ]
497564 #[ cfg( feature = "guest-debug" ) ]
498565 pub fn memory_by_index ( & self , memory_index : MemAddr ) -> Result < Memory > {
499- Ok ( Memory ( StoreItem :: new ( self . 0 . store_id , Self :: index_addr ( & self . 0 . mem_addrs , memory_index, "memory" ) ?) ) )
566+ let addr = Self :: index_addr ( & self . 0 . mem_addrs , memory_index, "memory" ) ?;
567+ if addr & crate :: store:: SHARED_MEM_BIT != 0 {
568+ return Err ( Error :: UnsupportedFeature ( "use shared memory access for this index" ) ) ;
569+ }
570+ Ok ( Memory ( StoreItem :: new ( self . 0 . store_id , addr) ) )
500571 }
501572
502573 /// Get a table export by name.
0 commit comments