Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
build/
generated/
mquickjs_build_native
mquickjs_atom.h
mqjs_stdlib.h
*.o
*.d
*.wasm
*.host.o
/wasi_snapshot_preview1.reactor.wasm
/output.txt
mqjs
example
example_stdlib
mqjs_stdlib
mquickjs_build
mquickjs_build_atoms
test_builtin.bin
dtoa_test
libm_test
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "packages/wasi-sdk"]
path = packages/wasi-sdk
url = https://github.com/WebAssembly/wasi-sdk
[submodule "packages/wasmedge"]
path = packages/wasmedge
url = https://github.com/WasmEdge/WasmEdge
76 changes: 76 additions & 0 deletions Makefile.wasi
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
WASI_SDK_PATH ?= /opt/wasi-sdk
CC = $(WASI_SDK_PATH)/bin/clang
ADAPTER ?= wasi_snapshot_preview1.reactor.wasm

# -mexec-model is only valid for linking, not compilation
CFLAGS = -Oz -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_PROCESS_CLOCKS \
-Werror=implicit-function-declaration -fno-math-errno -fno-trapping-math \
--target=wasm32-wasi -mllvm -wasm-enable-sjlj

LDFLAGS = --target=wasm32-wasi -mexec-model=reactor \
-Wl,--no-entry -Wl,--export=cabi_realloc -Wl,--export=__wasm_call_ctors \
-lwasi-emulated-signal -lwasi-emulated-process-clocks -lsetjmp -lm

BUILD_DIR = build
GEN_DIR = generated

OBJS = $(BUILD_DIR)/mquickjs.o $(BUILD_DIR)/cutils.o $(BUILD_DIR)/dtoa.o $(BUILD_DIR)/libm.o \
$(BUILD_DIR)/microquickjs.o $(BUILD_DIR)/glue.o $(BUILD_DIR)/wasi_preview1_stubs.o

all: $(BUILD_DIR)/microquickjs.component.wasm

$(BUILD_DIR):
mkdir -p $(BUILD_DIR)

# Native build tool to generate stdlib headers
mquickjs_build_native: mquickjs_build.c mqjs_stdlib.c cutils.c
gcc -O2 -Wall -I. $^ -o $@ -lm

$(BUILD_DIR)/mquickjs_atom.h: mquickjs_build_native | $(BUILD_DIR)
./mquickjs_build_native -a -m32 > $@

$(BUILD_DIR)/mqjs_stdlib.h: mquickjs_build_native | $(BUILD_DIR)
./mquickjs_build_native -m32 > $@

headers: $(BUILD_DIR)/mquickjs_atom.h $(BUILD_DIR)/mqjs_stdlib.h

# wit-bindgen code generation
$(GEN_DIR)/microquickjs.c $(GEN_DIR)/microquickjs.h: microquickjs.wit
mkdir -p $(GEN_DIR)
wit-bindgen c microquickjs.wit --out-dir $(GEN_DIR) --world microquickjs

# Wasm object files
$(BUILD_DIR)/mquickjs.o: mquickjs.c $(BUILD_DIR)/mquickjs_atom.h $(BUILD_DIR)/mqjs_stdlib.h | $(BUILD_DIR)
$(CC) $(CFLAGS) -I. -I$(BUILD_DIR) -c $< -o $@

$(BUILD_DIR)/cutils.o: cutils.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -I. -c $< -o $@

$(BUILD_DIR)/dtoa.o: dtoa.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -I. -c $< -o $@

$(BUILD_DIR)/libm.o: libm.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -I. -c $< -o $@

$(BUILD_DIR)/microquickjs.o: $(GEN_DIR)/microquickjs.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -I$(GEN_DIR) -c $< -o $@

$(BUILD_DIR)/glue.o: glue.c $(GEN_DIR)/microquickjs.h $(BUILD_DIR)/mqjs_stdlib.h | $(BUILD_DIR)
$(CC) $(CFLAGS) -I. -I$(GEN_DIR) -I$(BUILD_DIR) -c $< -o $@

$(BUILD_DIR)/wasi_preview1_stubs.o: wasi_preview1_stubs.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@

# Core Wasm module
$(BUILD_DIR)/core.wasm: $(OBJS) $(GEN_DIR)/microquickjs.c
$(CC) $(OBJS) $(GEN_DIR)/microquickjs_component_type.o $(LDFLAGS) -o $@

# Final Component
$(BUILD_DIR)/microquickjs.component.wasm: $(BUILD_DIR)/core.wasm microquickjs.wit $(ADAPTER)
wasm-tools component embed ./microquickjs.wit $< --world microquickjs --output $(BUILD_DIR)/embedded.wasm
wasm-tools component new $(BUILD_DIR)/embedded.wasm --adapt wasi_snapshot_preview1=$(ADAPTER) --output $@

clean:
rm -rf $(BUILD_DIR) $(GEN_DIR) mquickjs_build_native

.PHONY: all headers clean
69 changes: 69 additions & 0 deletions README.WASI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# MicroQuickJS WASI 0.2 Component

This project ports MicroQuickJS to a WASI 0.2 WebAssembly Component.

## Exported Interface

The component exports the `engine` interface via the following WIT definition:

```wit
package local:microquickjs;

interface engine {
resource js-value {
is-int: func() -> bool;
is-bool: func() -> bool;
is-null: func() -> bool;
is-undefined: func() -> bool;
is-exception: func() -> bool;
is-number: func() -> bool;
is-string: func() -> bool;
is-error: func() -> bool;
is-function: func() -> bool;

to-string: func() -> string;
to-int32: func() -> s32;
to-float64: func() -> f64;

get-property: func(name: string) -> js-value;
set-property: func(name: string, val: borrow<js-value>);

call: func(args: list<borrow<js-value>>) -> js-value;
}

new-int32: func(val: s32) -> js-value;
new-float64: func(val: f64) -> js-value;
new-bool: func(val: bool) -> js-value;
new-string: func(val: string) -> js-value;
new-object: func() -> js-value;
new-array: func() -> js-value;

get-global-object: func() -> js-value;

eval: func(code: string) -> result<string, string>;
}

world microquickjs {
export engine;
}
```

## Building

Prerequisites:
- **WASI SDK**: [https://github.com/WebAssembly/wasi-sdk](https://github.com/WebAssembly/wasi-sdk) (Set `WASI_SDK_PATH` to your installation directory).
- **Tooling**: `wit-bindgen`, `wasm-tools`, `gcc` (for native helper).
- **Adapter**: `wasi_snapshot_preview1.reactor.wasm` should be present in the root directory.

Run the build:
```bash
make -f Makefile.wasi
```

The final component will be at `build/microquickjs.component.wasm`.

## Architecture & Implementation

- **Arena Memory**: Uses a fixed 4MiB static arena for JS heap, ensuring predictable memory footprint.
- **Error Handling**: Uses the WebAssembly Exception Handling proposal for robust `setjmp/longjmp` support.
- **Memory Safety**: Uses the Component Model Canonical ABI with `cabi_realloc` for all host-returned strings.
2 changes: 1 addition & 1 deletion dtoa.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "cutils.h"
#include "dtoa.h"

/*
/*
TODO:
- test n_digits=101 instead of 100
- simplify subnormal handling
Expand Down
Loading