first commit
This commit is contained in:
89
examples/plugins/hello-world-wasm-go/memory.go
Normal file
89
examples/plugins/hello-world-wasm-go/memory.go
Normal file
@@ -0,0 +1,89 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user