github.com/higress-group/nottinygc@v0.0.0-20231101025119-e93c4c2f8520/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  }