main.go raw

   1  // Trivial test organ: echoes input back with a prefix.
   2  // Built with: GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o trivial.wasm .
   3  package main
   4  
   5  import "unsafe"
   6  
   7  // Memory pool: a simple bump allocator for guest-side allocations.
   8  // This avoids Go GC issues in WASM by using a fixed buffer.
   9  var pool [1 << 20]byte // 1MB
  10  var poolOffset uint32
  11  
  12  //go:wasmexport alloc
  13  func alloc(size uint32) uint32 {
  14  	if poolOffset+size > uint32(len(pool)) {
  15  		// Reset if exhausted (simple strategy for short-lived calls).
  16  		poolOffset = 0
  17  	}
  18  	ptr := poolOffset
  19  	poolOffset += size
  20  	return uint32(uintptr(unsafe.Pointer(&pool[ptr])))
  21  }
  22  
  23  //go:wasmexport dealloc
  24  func dealloc(ptr uint32, size uint32) {
  25  	// No-op with bump allocator. Memory is reclaimed on pool reset.
  26  }
  27  
  28  //go:wasmexport organ_type
  29  func organ_type() uint32 {
  30  	s := "enzyme"
  31  	ptr := alloc(uint32(len(s)))
  32  	copy(pool[ptr-uint32(uintptr(unsafe.Pointer(&pool[0]))):], s)
  33  	return ptr
  34  }
  35  
  36  //go:wasmexport organ_version
  37  func organ_version() uint64 {
  38  	return 1
  39  }
  40  
  41  //go:wasmexport process
  42  func process(inputPtr uint32, inputLen uint32) uint64 {
  43  	// Read input from our pool by computing offset.
  44  	base := uint32(uintptr(unsafe.Pointer(&pool[0])))
  45  	offset := inputPtr - base
  46  
  47  	if offset+inputLen > uint32(len(pool)) {
  48  		// Out of bounds — return empty.
  49  		return 0
  50  	}
  51  
  52  	input := pool[offset : offset+inputLen]
  53  
  54  	if len(input) == 0 {
  55  		return 0
  56  	}
  57  
  58  	opcode := input[0]
  59  	data := input[1:]
  60  
  61  	var result []byte
  62  
  63  	switch opcode {
  64  	case 0x01: // CanDigest: return 0x01 if input contains "package "
  65  		result = []byte{0x00}
  66  		for i := 0; i+8 <= len(data); i++ {
  67  			if string(data[i:i+8]) == "package " {
  68  				result = []byte{0x01}
  69  				break
  70  			}
  71  		}
  72  
  73  	case 0x02: // Digest: return the input prefixed with "digested:"
  74  		prefix := []byte("digested:")
  75  		result = make([]byte, len(prefix)+len(data))
  76  		copy(result, prefix)
  77  		copy(result[len(prefix):], data)
  78  
  79  	default:
  80  		result = []byte("unknown opcode")
  81  	}
  82  
  83  	// Write result to pool.
  84  	outPtr := alloc(uint32(len(result)))
  85  	outOffset := outPtr - base
  86  	copy(pool[outOffset:], result)
  87  
  88  	// Pack pointer and length into uint64.
  89  	return uint64(outPtr)<<32 | uint64(len(result))
  90  }
  91  
  92  func main() {}
  93