Search documentation

Search starts with current English documentation · ASPL 0.7.0

Enter a complete name such as read_line, or words about a topic.

    العربية
    Source files

    Open one UTF-8 .aspl or .لبات file, up to 1 MiB, in a new draft. It stays in this browser and does not run automatically.

    Browser-local WebAssembly constraints for the ASPL MVP

    ASPL MVP · Historical MVP scope

    Archived ASPL MVP specification. Original English source only; no Arabic counterpart is available. These historical rules are not a complete ASPL 0.6.0 reference.

    On this page

    Browser-local WebAssembly constraints for the ASPL MVP

    Researched on 2026-08-28 against the current WebAssembly specification and official browser and Emscripten documentation.

    Decision

    Build the browser playground from the same portable C compiler core and register VM as the Linux tool. Compile those C sources ahead of time with Emscripten into one WebAssembly module plus its JavaScript loader. Run that module inside a dedicated Web Worker.

    The playground should accept source text through an in-memory API, compile it to ASPL bytecode, and execute that bytecode in the VM. It should not create or run an ELF file. It should also reject arbitrary C interoperability at execution time because a browser cannot load the user's Linux shared libraries.

    Keep the first browser build single-threaded. Give each run an instruction budget, an explicit memory ceiling, and a wall-clock timeout enforced by terminating the worker. Statically link all browser components and expose only the few JavaScript bindings the editor needs.

    This report treats "the C compiler" as the ASPL compiler implemented in C. It does not propose shipping Clang or Emscripten in the browser to compile C source. That would be a separate and much larger product.

    What can be shared with Linux

    Emscripten uses Clang and LLVM to compile C and C++ into WebAssembly, supplies libc support, and emits JavaScript that loads and supports the compiled module. Portable compiler and VM code is therefore a good fit. Code tied to the Linux runtime still needs a platform boundary. Emscripten describes its toolchain and runtime support.

    WebAssembly itself defines no system calls or operating-system APIs. A host supplies all outside capabilities through imports. This is the hard boundary behind the rest of the findings. WebAssembly portability documentation.

    The shared C code should cover lexing, parsing, type checking, bytecode emission, bytecode validation, and interpretation. Put these Linux-only operations behind separate interfaces:

    • ELF packaging
    • shared-library loading and symbol lookup
    • command-line argument and environment handling
    • host file access
    • process creation or replacement

    The browser adapter should drive a buffer-oriented entry point rather than pretend to be the Linux CLI. A suitable shape is source bytes in, then diagnostics, bytecode, standard output, and an exit status out. Exact C names belong to the compiler-pipeline design ticket.

    Filesystem behavior

    Browser code cannot directly access the host filesystem. Emscripten provides a virtual filesystem so synchronous C file calls can still work. Its default MEMFS lives only in memory and loses writes on reload. IDBFS can persist data through IndexedDB, but persistence uses FS.syncfs(). WORKERFS gives worker code read-only access to browser File and Blob values. Emscripten filesystem overview and filesystem API reference.

    The MVP does not need any of those filesystems for compilation. Pass editor text into WebAssembly memory and return results through exported functions or callbacks. Let ordinary JavaScript handle opening, saving, and downloading files. This avoids persistence semantics, path semantics, and temporary-file cleanup in the compiler.

    If the first C port still calls fopen or creates temporary files, use MEMFS as a short-term compatibility layer. Do not present it as access to the user's disk. Once the compiler is buffer-oriented, test -sFILESYSTEM=0; Emscripten says this removes filesystem support but also rules out file-oriented standard I/O such as fprintf. Emscripten settings reference.

    Dynamic loading and C interoperability

    Emscripten's dlopen support loads Emscripten-built WebAssembly side modules from the virtual filesystem. It does not load an x86-64 ELF .so. The main module owns the system libraries and JavaScript runtime, dynamic linking adds overhead, and the default main-module mode disables dead-code elimination. Emscripten also notes unresolved symbols can survive until a failing call at runtime. Emscripten dynamic-linking documentation.

    The playground should therefore statically link the ASPL compiler and VM into one WebAssembly module. It should not use MAIN_MODULE, SIDE_MODULE, dlopen, or dlsym in the MVP.

    ASPL may parse and type-check an extern C declaration in the browser if sharing the front end makes that natural. It must issue a clear target error before execution when a program tries to call one. A small future browser host API could expose individually reviewed functions through a fixed registry, but it would not be arbitrary C interoperability. The website must label dynamic C calls and native ELF execution as Linux-only.

    Process APIs and generated output

    The browser has no native process model for the compiled C program. Emscripten explicitly does not support multiprocessing through fork(), and browser execution must return control to the event loop or it can hang its execution context. Emscripten pthread limitations and runtime main-loop guidance.

    The browser build must never depend on spawning a compiler, assembler, linker, VM, or child ASPL process. Compilation and bytecode execution happen as function calls inside the loaded module. The Linux tool may still emit ELF bytes, but the playground should stop after bytecode emission and run that bytecode directly. Producing a downloadable ELF file could be added later, but the browser cannot execute it.

    Worker model and responsiveness

    A dedicated Web Worker runs scripts off the page's UI thread and communicates with the page through messages. The page can immediately stop a stuck worker with Worker.terminate(). MDN's Web Worker guide and Worker.terminate() reference.

    Use one dedicated worker for compilation and VM execution. Keep the editor, rendering, and timeout controller on the main thread. When a timeout expires, terminate the worker and create a fresh one. This protects page responsiveness even when the ASPL program loops forever or the compiler itself gets stuck.

    Worker termination alone is too coarse for normal resource accounting. The register VM should also decrement an instruction budget at dispatch boundaries and stop with a normal diagnostic when it reaches zero. Limit source length, bytecode length, output length, stack depth, register counts, and VM allocations before execution. These checks also make normal failures distinguishable from a killed worker.

    Do not enable C pthreads for the MVP. Emscripten implements them through SharedArrayBuffer, and deployed pthread builds require cross-origin isolation headers such as COOP and COEP. Thread creation also has browser event-loop and worker-pool constraints. Emscripten pthread documentation and MDN's COOP guidance.

    A plain dedicated worker does not require SharedArrayBuffer or those cross-origin isolation headers. That keeps hosting and third-party website integration simpler.

    Memory limits

    The WebAssembly JavaScript interface permits a 32-bit memory maximum of 4 GiB, but implementations may fail below specified limits because of available resources. Emscripten's current memory-growth default caps growth at 2 GiB, which is still far too large to use as a playground policy. WebAssembly JavaScript Interface limits and Emscripten memory settings.

    Set an application-level ceiling much lower than the platform maximum. Either use fixed WebAssembly memory or enable growth with an explicit MAXIMUM_MEMORY; choose the number after measuring the compiler and VM on the conformance corpus. Check every guest allocation independently because the compiler, VM, and ASPL program share the module's linear memory.

    Output and download size

    An Emscripten browser build normally produces a .wasm file plus JavaScript runtime support. Emscripten recommends -Os or -Oz for size, says --closure 1 can shrink the JavaScript, and allows unused runtime environments and filesystem support to be removed. Emscripten WebAssembly output documentation and optimization guidance.

    Start the release build with these constraints, then measure instead of treating the flags as a settled recipe:

    • one statically linked module
    • -Oz at compile and link time
    • -sENVIRONMENT=worker
    • -sMODULARIZE -sEXPORT_ES6
    • an explicit, minimal export list
    • no pthreads, dynamic linking, or packaged files
    • -sFILESYSTEM=0 if the buffer-oriented port permits it
    • gzip transfer compression on the website

    MODULARIZE provides an asynchronous factory and keeps generated state out of the global scope. Restricting ENVIRONMENT removes support for runtimes the bundle will not use. Emscripten modularized-output documentation and ENVIRONMENT setting reference.

    Serve .wasm as application/wasm so the browser can use streaming compilation and instantiation. MDN documents the MIME requirement.

    Do not set a download-size promise until a prototype includes the real parser tables, Unicode data, diagnostics, and VM. Record raw and compressed JavaScript and WebAssembly sizes separately, plus first-load startup time on each supported browser.

    Isolation and trust boundary

    WebAssembly isolates a module from the browser host and bounds accesses to its linear memory. It does not make C objects inside that memory safe from each other. The WebAssembly security model explicitly notes that one object in linear memory can overwrite an adjacent object even though the module cannot escape its memory region. WebAssembly security model.

    For ASPL, that means the browser sandbox protects the website and operating system from ordinary module memory access, but it does not by itself protect the C compiler and VM from malformed ASPL bytecode. The browser build still needs:

    • bytecode validation before execution
    • checked register, constant, branch, and function indexes
    • checked ASPL memory operations
    • bounded recursion, allocation, output, and instruction count
    • a fixed or empty browser host-call registry

    Do not expose a generic JavaScript evaluator, network bridge, filesystem bridge, or dynamic symbol lookup to ASPL bytecode. WebAssembly code can reach only imports supplied by the host, so a narrow import list is the effective capability boundary. This conclusion follows from WebAssembly's import model and security rules, not from an Emscripten promise about guest bytecode.

    The worker adds failure containment and a reliable kill switch, but it is not the semantic sandbox between the ASPL program and the VM. Bytecode validation and VM checks provide that boundary.

    Required prototype checks

    The documentation settles the architecture, but measurement must settle a few build choices:

    1. Compile the shared C sources with a pinned Emscripten SDK and list every Linux-specific compile failure.
    2. Prove the compiler can accept source and return diagnostics and bytecode without filesystem calls.
    3. Prove Arabic and English conformance programs compile and run in the worker.
    4. Verify that C-call attempts receive the documented browser-target diagnostic.
    5. Trigger instruction, memory, output, recursion, and wall-clock limits deliberately.
    6. Measure raw and compressed artifacts, first load, warm compile, and warm execution in the supported browsers.
    7. Confirm the site works without cross-origin isolation headers.

    Consequences for later decisions

    The browser playground is a second host for the compiler and VM, not a second ASPL backend. It shares the source-to-bytecode semantics with Linux and replaces Linux packaging and C loading with a deliberately empty browser host layer. This keeps the playground honest: it proves the language and VM locally, while clearly excluding the two capabilities browsers cannot provide.

    Browse pages