Skip to content

Zero-Copy Data

The typical WASM data flow has 5 serialization steps:

JS: JSON.stringify(request) ← serialize
JS: write JSON bytes to WASM memory ← copy
Go: json.Unmarshal(reqBytes) ← parse
Go: json.Marshal(response) ← serialize
JS: JSON.parse(respText) ← parse

With zerobuf:

JS: write request fields to WASM memory (zerobuf layout) ← direct write
Go: read fields at fixed offsets ← direct read
Go: write response fields at fixed offsets ← direct write
JS: read response fields from WASM memory ← direct read

No serialization. No parsing. Just pointer reads on shared memory.

Each field is a 16-byte slot: [tag:u8][pad:3][payloadA:u32][payloadB:f64]

Tags: 0=null, 1=bool, 2=i32, 3=f64, 4=string

Strings are stored as [byteLen:u32][utf8 bytes...] with a pointer in the payload.

// Read a zerobuf string from a tagged value slot
func readZBString(slotAddr uintptr) string {
headerPtr := uintptr(*(*uint32)(unsafe.Pointer(slotAddr + 4)))
byteLen := *(*uint32)(unsafe.Pointer(headerPtr))
bytes := unsafe.Slice((*byte)(unsafe.Pointer(headerPtr+4)), int(byteLen))
return string(bytes)
}

Go and Zig share the same WASM linear memory. Go allocates data, passes the pointer to Zig — no copy:

data := []float64{1, 2, 3, 4, 5, 6, 7, 8}
ptr := uint32(uintptr(unsafe.Pointer(&data[0])))
// Zig reads from the same memory, runs SIMD v128 instructions
sum := gomode.ZigSimdSumF64(ptr, uint32(len(data)))
// Zig writes back to the same memory (in-place scale)
gomode.ZigSimdScaleF64(ptr, uint32(len(data)), 2.0)

This is a direct function call within the same WASM binary — compiled to a single call instruction. No imports, no JS, no overhead.

Routereq/secDescription
/3,764Hello world (Go only)
/simd3,692Go → Zig SIMD (sum, dot, scale, minmax)

Identical throughput. The Zig SIMD call path adds no measurable overhead.