Files
bifrost/examples/plugins/hello-world-wasm-go/memory.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

90 lines
2.5 KiB
Go

package main
import "unsafe"
// ============================================================================
// Memory Management
// ============================================================================
// heapSize is the fixed size of the pre-allocated heap.
// This must be large enough to handle all allocations during the plugin lifetime.
// The heap is never reallocated to ensure all pointers remain valid.
const heapSize = 4 * 1024 * 1024 // 4MB fixed heap
// heapBase is a fixed-size buffer that is never reallocated.
// All allocations come from this buffer to ensure pointer stability.
var heapBase []byte
// heapOffset tracks the next available position in heapBase.
var heapOffset uint32 = 0
// heapBasePtr caches the base pointer of heapBase for efficient offset-to-pointer conversion.
var heapBasePtr uintptr
func init() {
// Pre-allocate the fixed heap once at startup.
// This ensures heapBase is never reallocated after pointers are handed out.
heapBase = make([]byte, heapSize)
heapBasePtr = uintptr(unsafe.Pointer(&heapBase[0]))
}
//export plugin_malloc
func plugin_malloc(size uint32) uint32 {
if size == 0 {
return 0
}
// Align to 8-byte boundary
alignedSize := (size + 7) &^ 7
// Check if we have enough space (no reallocation allowed)
if heapOffset+alignedSize > uint32(len(heapBase)) {
// Allocation failure - heap exhausted
// Return 0 to indicate failure rather than reallocating
return 0
}
// Return pointer to the allocated region
ptr := uint32(heapBasePtr + uintptr(heapOffset))
heapOffset += alignedSize
return ptr
}
//export plugin_free
func plugin_free(ptr uint32) {
// No-op: we use a simple bump allocator without individual frees.
// Memory is reclaimed when the plugin is unloaded.
}
// plugin_reset resets the heap allocator, allowing memory to be reused.
// This should only be called when no allocated memory is in use.
//
//export plugin_reset
func plugin_reset() {
heapOffset = 0
}
func packResult(ptr uint32, length uint32) uint64 {
return (uint64(ptr) << 32) | uint64(length)
}
func writeBytes(data []byte) uint64 {
if len(data) == 0 {
return 0
}
// Allocate from the stable heap
ptr := plugin_malloc(uint32(len(data)))
if ptr == 0 {
// Allocation failed
return 0
}
// Copy data into the allocated region
offset := ptr - uint32(heapBasePtr)
copy(heapBase[offset:offset+uint32(len(data))], data)
return packResult(ptr, uint32(len(data)))
}
func readInput(ptr, length uint32) []byte {
if length == 0 {
return nil
}
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), length)
}