///|
priv struct StoreFuncrefMappingOwner {
registration : Int32
store_addr : Int32
func_ptr : Int64
} derive(Debug)
///|
/// One Store-local function address and its native executable pointer.
pub struct StoreFuncrefEntry {
store_addr : Int32
func_ptr : Int64
} derive(Debug, Eq)
///|
pub fn StoreFuncrefEntry::StoreFuncrefEntry(
store_addr~ : Int32,
func_ptr~ : Int64,
) -> StoreFuncrefEntry {
{ store_addr, func_ptr, }
}
///|
priv struct StoreFuncrefRegistry {
store_to_ptr : Map[Int32, Array[StoreFuncrefMappingOwner]]
ptr_to_store : Map[Int64, Array[StoreFuncrefMappingOwner]]
next_registration : Ref[Int32]
mut native : @native_bridge.NativeCallableRegistry?
owners : Array[NativeCallableOwner]
} derive(Debug)
///|
struct StoreFuncrefRegistration {
registry : StoreFuncrefRegistry
registration : Int32
entries : Array[StoreFuncrefEntry]
active : Ref[Bool]
}
///|
fn StoreFuncrefRegistry::new() -> StoreFuncrefRegistry {
{
store_to_ptr: Map([]),
ptr_to_store: Map([]),
next_registration: Ref(0),
native: None,
owners: [],
}
}
///|
fn remove_store_funcref_owner(
owners : Array[StoreFuncrefMappingOwner],
registration : Int32,
) -> Unit {
for i in 0.. ignore
return
}
}
}
///|
fn StoreFuncrefRegistry::register(
self : StoreFuncrefRegistry,
entries : Array[StoreFuncrefEntry],
) -> StoreFuncrefRegistration {
let registration = self.next_registration.val
self.next_registration.val = registration + 1
for entry in entries {
let { store_addr, func_ptr, } = entry
if store_addr < 0 || func_ptr == 0L {
continue
}
let owner = { registration, store_addr, func_ptr, }
match self.store_to_ptr.get(store_addr) {
Some(owners) => owners.push(owner)
None => self.store_to_ptr.set(store_addr, [owner])
}
match self.ptr_to_store.get(func_ptr) {
Some(owners) => owners.push(owner)
None => self.ptr_to_store.set(func_ptr, [owner])
}
}
self.publish_functions()
{ registry: self, registration, entries, active: Ref(true), }
}
///|
pub fn StoreFuncrefRegistration::release(
self : StoreFuncrefRegistration,
) -> Unit {
if !self.active.val {
return
}
self.active.val = false
for entry in self.entries {
let { store_addr, func_ptr, } = entry
if self.registry.store_to_ptr.get(store_addr) is Some(owners) {
remove_store_funcref_owner(owners, self.registration)
if owners.is_empty() {
self.registry.store_to_ptr.remove(store_addr)
}
}
if self.registry.ptr_to_store.get(func_ptr) is Some(owners) {
remove_store_funcref_owner(owners, self.registration)
if owners.is_empty() {
self.registry.ptr_to_store.remove(func_ptr)
}
}
}
self.registry.publish_functions()
}
///|
fn StoreFuncrefRegistry::lookup_ptr(
self : StoreFuncrefRegistry,
store_addr : Int32,
) -> Int64? {
match self.store_to_ptr.get(store_addr) {
Some(owners) if !owners.is_empty() =>
Some(owners[owners.length() - 1].func_ptr)
_ => None
}
}
///|
fn StoreFuncrefRegistry::lookup_store_addr(
self : StoreFuncrefRegistry,
func_ptr : Int64,
) -> Int32? {
match self.ptr_to_store.get(func_ptr) {
Some(owners) if !owners.is_empty() =>
Some(owners[owners.length() - 1].store_addr)
_ => None
}
}
///|
fn StoreFuncrefRegistry::entries(
self : StoreFuncrefRegistry,
) -> Array[StoreFuncrefEntry] {
let entries : Array[StoreFuncrefEntry] = []
for func_ptr, owners in self.ptr_to_store {
if func_ptr != 0L && !owners.is_empty() {
entries.push({
store_addr: owners[owners.length() - 1].store_addr,
func_ptr,
})
}
}
entries
}
///|
fn StoreFuncrefRegistry::clear(self : StoreFuncrefRegistry) -> Unit {
self.store_to_ptr.clear()
self.ptr_to_store.clear()
self.publish_functions()
self.native = None
let owners = self.owners.copy()
self.owners.clear()
self.owners.shrink_to_fit()
for owner in owners {
(owner.release)()
}
}
///|
pub fn Store::register_jit_funcrefs(
self : Store,
entries : Array[StoreFuncrefEntry],
release_owner~ : () -> Unit = fn() { },
) -> StoreFuncrefRegistration {
self.funcref_registry.owners.push({ release: release_owner, })
self.funcref_registry.register(entries)
}
///|
pub fn Store::lookup_jit_funcref_ptr(
self : Store,
store_addr : Int32,
) -> Int64? {
self.funcref_registry.lookup_ptr(store_addr)
}
///|
pub fn Store::lookup_jit_funcref_store_addr(
self : Store,
func_ptr : Int64,
) -> Int32? {
self.funcref_registry.lookup_store_addr(func_ptr)
}
///|
pub fn Store::jit_funcref_entries(self : Store) -> Array[StoreFuncrefEntry] {
self.funcref_registry.entries()
}
///|
priv struct NativeCallableOwner {
release : () -> Unit
}
///|
impl Debug for NativeCallableOwner with fn to_repr(_self) {
Repr::literal("NativeCallableOwner")
}
///|
fn StoreFuncrefRegistry::publish_functions(self : StoreFuncrefRegistry) -> Unit {
if self.native is Some(registry) {
let functions : Array[(Int32, Int64)] = []
for address, owners in self.store_to_ptr {
if !owners.is_empty() {
functions.push((address, owners[owners.length() - 1].func_ptr))
}
}
registry.replace_functions(
functions,
self.entries().map(entry => (entry.func_ptr, entry.store_addr)),
)
}
}