github.com/wasilibs/nottinygc@v0.7.2-0.20240312114022-d59c9478ef51/finalizer.go (about) 1 // Copyright wasilibs authors 2 // SPDX-License-Identifier: MIT 3 4 //go:build gc.custom 5 6 package nottinygc 7 8 /* 9 void GC_register_finalizer(void* obj, void* fn, void* cd, void** ofn, void** ocn); 10 void onFinalizer(void* obj, void* fn); 11 */ 12 import "C" 13 import "unsafe" 14 15 var finalizers = map[uint64]interface{}{} 16 17 var finalizersIdx = uint64(0) 18 19 //go:linkname SetFinalizer runtime.SetFinalizer 20 func SetFinalizer(obj interface{}, finalizer interface{}) { 21 if _, ok := finalizer.(func(interface{})); !ok { 22 // Until function invocation with reflection is supported by TinyGo, we cannot support arbitrary finalizers. 23 // We make a best-effort attempt to support the generic func(interface{}). For other finalizers, we silently 24 // ignore, which would be the behavior for all finalizers with the default allocator. 25 return 26 } 27 28 finalizersIdx++ 29 finKey := finalizersIdx 30 finalizers[finKey] = finalizer 31 32 in := (*_interface)(unsafe.Pointer(&obj)) 33 34 rf := (*registeredFinalizer)(cmalloc(unsafe.Sizeof(registeredFinalizer{}))) 35 rf.typecode = in.typecode 36 rf.finKey = finKey 37 38 C.GC_register_finalizer(in.value, C.onFinalizer, unsafe.Pointer(rf), nil, nil) 39 } 40 41 //export onFinalizer 42 func onFinalizer(obj unsafe.Pointer, data unsafe.Pointer) { 43 defer cfree(data) 44 45 rf := (*registeredFinalizer)(data) 46 finalizer := finalizers[rf.finKey] 47 delete(finalizers, rf.finKey) 48 49 var in interface{} 50 inFields := (*_interface)(unsafe.Pointer(&in)) 51 inFields.typecode = rf.typecode 52 inFields.value = obj 53 54 switch f := finalizer.(type) { 55 case func(interface{}): 56 f(in) 57 default: 58 panic("BUG: SetFinalizer should have filtered out non-supported finalizer interface") 59 } 60 } 61 62 type _interface struct { 63 typecode uintptr 64 value unsafe.Pointer 65 } 66 67 type registeredFinalizer struct { 68 typecode uintptr 69 finKey uint64 70 }