<-- back

Breaking WASM's text barrier in Supernova


After weeks of fighting with WebAssembly’s text communication limitations, I finally got it working. What started as a simple error, Import #0 "env" "logString": function import requires a callable, turned into way more work than I expected, but ultimately got me seamless text communication between WASM modules and the Supernova kernel.

WASM’s annoying text problem

Building Supernova, I knew WebAssembly would be essential for real application isolation and performance. My 41worker runtime already handles JavaScript executables perfectly through Web Workers, but I needed AsmRuntime to support compiled languages like AssemblyScript, Rust, and C++.

The issue? WebAssembly modules can only pass numbers back and forth with JavaScript. No strings, no objects, no complex data… just integers and floats. For an operating system that needs file paths, error messages, and inter-process communication, this was a huge roadblock.

The IPC Manager: A real WASM application

The breakthrough came when I was testing my IPC Manager (ipcman), a critical Supernova system component written in AssemblyScript. The IPC Manager handles inter-process communication between applications running in different Web Workers—basically Supernova’s message routing system.

I simplified AssemblyScript code to the following:

export function createFile(path: string): i32 {
  // creates a file at the given path and indicates success with a return code
}

export function logMessage(message: string): void {
  // sends a message to the kernel for logging
}

The IPC Manager needs to log status messages, handle file operations for message queuing, and communicate complex routing decisions back to the kernel. But when I tried to run it, I hit that annoying logString import error.

AssemblyScript’s sneaky requirements

The issue wasn’t random—it came from AssemblyScript’s build process. When compiling the IPC Manager, the build system generated a JavaScript glue file (release.js) that automatically creates host binding imports, including logString, even when the WASM module doesn’t use them.

Here’s what I found in the IPC Manager’s generated release.js:

logString(i) {
  // assembly/env/logString(~lib/string/String) => void
  i = __liftString(i >>> 0);
  logString(i);
}

AssemblyScript was expecting the host environment (my AsmRuntime) to provide this function to handle its internal string format—pointers to memory locations where string data lives with length prefixes.

Bridging memory and text

I built a complete text communication system in AsmRuntime that could satisfy AssemblyScript’s requirements while letting the IPC Manager communicate properly:

Reading strings from WASM memory

Note: this includes proprietary kernel-level code. Some parts may not be fully disclosed.

logString: (ptr: number) => {
  if (!ptr) return;
  
  try {
    if (this.wasmInstance && this.exports?.memory) {
      const memory = this.exports.memory;
      
      // AssemblyScript stores string length 4 bytes before the pointer
      const len = new Uint32Array(memory.buffer)[ptr - 4 >>> 2];
      
      const stringData = new Uint8Array(memory.buffer, ptr, len);
      const str = new TextDecoder().decode(stringData);
      console.log(`[WASM logString] ${str}`);
    }
  } catch (e) {
    console.error(`[WASM logString] Error reading string: ${e}`);
  }
}

Encoding strings for WASM

static encodeStringAsInts(str: string): number[] {
  const encoder = new TextEncoder();
  const bytes = encoder.encode(str);
  const ints: number[] = [];
  
  // First int is the length
  ints.push(bytes.length);
  
  // Pack 4 bytes into each integer (32 bits)
  for (let i = 0; i < bytes.length; i += 4) {
    let value = 0;
    for (let j = 0; j < 4 && i + j < bytes.length; j++) {
      value |= bytes[i + j] << (j * 8);
    }
    ints.push(value);
  }
  
  return ints;
}

System-level WASM components

With text communication working, the IPC Manager could finally run properly. But more importantly, this opened the door for other critical system components to be written in WASM:

  • File system drivers that need to handle path strings and metadata
  • Security modules that process permission strings and user credentials
  • Network handlers that parse URLs and protocol data
  • Device drivers that work with hardware identifiers and configuration strings

The IPC Manager was just the first; now any system component can be implemented in high-performance compiled languages while still participating fully in Supernova’s bi-directional communication ecosystem.

Runtime equality

This breakthrough means WASM applications in Supernova now have the same communication abilities as JavaScript ones. The IPC Manager can:

  • Route messages between processes with full string-based addressing
  • Log detailed debugging information about message routing decisions
  • Handle complex file operations for message persistence and queuing
  • Communicate errors and status back to the kernel in human-readable form

Most importantly, this maintains Supernova’s API unification principle. Whether a system component is written in JavaScript or AssemblyScript, it accesses resources through the same interfaces.

What’s coming next

With the IPC Manager running successfully, I’m expanding WASM support throughout Supernova:

  • Window management for graphical applications
  • Input handling for keyboard and mouse events
  • Network communication for web services and APIs
  • Protocol handlers for Supernova’s HTTP services

Building a Web OS means solving problems that don’t exist in normal development. Getting the IPC Manager working in WASM was a crucial milestone that proves Supernova can truly bridge the gap between high-level web technologies and low-level system programming.



about the author

Pablo Gracia is a high school student from California. He is passionate about technology and music. He is the creator of this blog and the author of all the posts. He is also the creator of the Supernova Experience.

View more blog posts