run.sh (8912B)
1 #!/usr/bin/env bash 2 # test/wasm-target/run.sh — Wasm-target structural-grep tests, on the shared 3 # corpus harness (test/lib/kit_corpus.sh). 4 # 5 # Each check compiles a tiny C or toy fixture with `kit cc -target 6 # wasm32-none -c` and asserts a structural property of the produced module: 7 # opcode bytes, export names, or import declarations. The oracle is a 8 # structural grep over the raw module bytes; the opcode magic numbers and 9 # import (module, field) names live as metadata inside the lane bodies. 10 # 11 # Lanes (each is one structural check — there is no opt/tuple axis): 12 # ASM inline-asm WAT template lowers to i32.popcnt (0x69), and an 13 # escaping `br 0` is rejected with a "wasm target:" diagnostic. 14 # IMP extern C symbols emit (import ...) decls under the default `env` 15 # module and honor import_module/import_name attribute overrides. 16 # MCP copy_bytes/set_bytes lower to memory.copy (0xfc 0x0a) and 17 # memory.fill (0xfc 0x0b), not byte-loops. 18 # MEX the linear memory is exported under the conventional name "memory". 19 # 20 # All lane hooks write only under $KIT_WORK and record via kit_*, so the runner 21 # is parallel-safe by construction; KIT_WASM_TARGET_PARALLEL flips dispatch. 22 set -u 23 24 ROOT=$(cd "$(dirname "$0")/../.." && pwd) 25 export KIT_LIB_DIR="$ROOT/test/lib" 26 . "$ROOT/test/lib/kit_corpus.sh" 27 28 SRC_DIR="$ROOT/test/wasm-target" 29 BUILD_DIR="$ROOT/build/test/wasm-target" 30 KIT_BIN="${KIT:-$ROOT/build/kit}" 31 mkdir -p "$BUILD_DIR" 32 33 # Preserve the original per-script semantics: a missing-toolchain/missing-fixture 34 # SKIP (was a per-check exit 2 that the old run.sh counted as skip but did NOT 35 # let fail the run) must not gate this harness's exit. Override the corpus 36 # engine's default (KIT_SKIP_IS_FAILURE=1) back to "skip is informational". 37 KIT_SKIP_IS_FAILURE=0 38 39 # Toy fixtures live in the shared toy corpus; allow override (preserves the 40 # original TOY_FIXTURE knob from check_memory_{copy,export}.sh). 41 TOY_MEMCPY_FIXTURE="${TOY_FIXTURE_MEMCPY:-$ROOT/test/toy/cases/131_memcpy_uses_bulk.toy}" 42 TOY_EXPORT_FIXTURE="${TOY_FIXTURE_EXPORT:-$ROOT/test/toy/cases/01_return_const.toy}" 43 44 PAR="${KIT_WASM_TARGET_PARALLEL:-1}" 45 46 # Driver presence gates every check: a missing driver SKIPs (was exit 2 in the 47 # per-script harnesses). Surfaced as a SKIP per lane via the hooks below. 48 have_kit=0 49 [ -x "$KIT_BIN" ] && have_kit=1 50 51 # wasm32-none -c <src> -> <out>; logs KIT_WORK-confined. Returns nonzero on 52 # compile failure (lane decides pass/skip/fail). 53 wt_compile() { # SRC OUT TAG 54 "$KIT_BIN" cc -target wasm32-none -c "$1" -o "$2" \ 55 >"$KIT_WORK/$3.cc.out" 2>"$KIT_WORK/$3.cc.err" 56 } 57 58 # Hex-dump $1 with no whitespace, for opcode-byte greps. (od is universally 59 # available; matches the original check_asm.sh / check_memory_copy.sh dumps.) 60 wt_hex() { od -An -tx1 -v "$1" | tr -d ' \n'; } 61 62 # ---- lane: inline-asm WAT template (check_asm.sh) -------------------------- 63 # i32.popcnt encodes as 0x69 in the wasm binary format; an escaping top-level 64 # `br 0` must be rejected before emission with a "wasm target:" diagnostic. 65 kit_lane_ASM() { 66 if [ "$have_kit" -eq 0 ]; then kit_skip "wasm-target/asm" "kit driver missing at $KIT_BIN"; return; fi 67 68 local out="$KIT_WORK/asm_popcnt.wasm" 69 if ! wt_compile "$SRC_DIR/asm_popcnt.c" "$out" asm_popcnt; then 70 kit_fail "wasm-target/asm-popcnt" "kit cc -target wasm32-none failed for asm_popcnt.c" 71 sed 's/^/ | /' "$KIT_WORK/asm_popcnt.cc.err" >&2 72 return 73 fi 74 if wt_hex "$out" | grep -q '69'; then kit_pass "wasm-target/asm-popcnt" 75 else kit_fail "wasm-target/asm-popcnt" "missing i32.popcnt opcode (0x69)"; fi 76 77 # Negative oracle: escaping `br 0` must be rejected (nonzero) with a 78 # "wasm target:" stderr diagnostic. 79 local neg="$KIT_WORK/asm_branch_escape.wasm" 80 if wt_compile "$SRC_DIR/asm_branch_escape.c" "$neg" asm_branch_escape; then 81 kit_fail "wasm-target/asm-branch-escape" "compiled but should have been rejected" 82 elif grep -F "wasm target:" "$KIT_WORK/asm_branch_escape.cc.err" >/dev/null 2>&1; then 83 kit_pass "wasm-target/asm-branch-escape" 84 else 85 kit_fail "wasm-target/asm-branch-escape" "rejection lacks 'wasm target:' diagnostic" 86 sed 's/^/ | /' "$KIT_WORK/asm_branch_escape.cc.err" >&2 87 fi 88 } 89 90 # ---- lane: import declarations (check_imports.sh) -------------------------- 91 # Wasm import sections encode (module, field) as length-prefixed UTF-8 plain 92 # text, so a `grep -F` over the raw bytes is enough. 93 _wt_check_strings() { # LABEL WASM STR... 94 local label=$1 wasm=$2; shift 2 95 local s ok=1 96 for s in "$@"; do 97 if ! grep -F "$s" "$wasm" >/dev/null 2>&1; then 98 ok=0 99 printf 'expected substring %s in %s\n' "$s" "$wasm" >&2 100 fi 101 done 102 [ "$ok" -eq 1 ] && kit_pass "$label" || kit_fail "$label" "missing expected import substring(s)" 103 } 104 kit_lane_IMP() { 105 if [ "$have_kit" -eq 0 ]; then kit_skip "wasm-target/imports" "kit driver missing at $KIT_BIN"; return; fi 106 107 # Default module/field: env / host_add. 108 local out="$KIT_WORK/import_decl.wasm" 109 if wt_compile "$SRC_DIR/import_decl.c" "$out" import_decl; then 110 _wt_check_strings "wasm-target/import-default" "$out" "env" "host_add" 111 else 112 kit_fail "wasm-target/import-default" "kit cc -target wasm32-none failed for import_decl.c" 113 sed 's/^/ | /' "$KIT_WORK/import_decl.cc.err" >&2 114 fi 115 116 # Attribute-override module/field: custom / add. 117 out="$KIT_WORK/import_decl_attribute.wasm" 118 if wt_compile "$SRC_DIR/import_decl_attribute.c" "$out" import_decl_attribute; then 119 _wt_check_strings "wasm-target/import-attribute" "$out" "custom" "add" 120 else 121 kit_fail "wasm-target/import-attribute" "kit cc -target wasm32-none failed for import_decl_attribute.c" 122 sed 's/^/ | /' "$KIT_WORK/import_decl_attribute.cc.err" >&2 123 fi 124 } 125 126 # ---- lane: bulk-memory opcodes (check_memory_copy.sh) ---------------------- 127 # Magic numbers mirror the wasm spec opcode encoding (keep in sync with 128 # WASM_INSN_MEMORY_{COPY,FILL} in src/wasm/insn.c): 129 # memory.copy = 0xfc 0x0a memory.fill = 0xfc 0x0b 130 kit_lane_MCP() { 131 if [ "$have_kit" -eq 0 ]; then kit_skip "wasm-target/memory-copy" "kit driver missing at $KIT_BIN"; return; fi 132 if [ ! -f "$TOY_MEMCPY_FIXTURE" ]; then kit_skip "wasm-target/memory-copy" "missing toy fixture $TOY_MEMCPY_FIXTURE"; return; fi 133 134 local out="$KIT_WORK/$(basename "$TOY_MEMCPY_FIXTURE" .toy).wasm" 135 if ! wt_compile "$TOY_MEMCPY_FIXTURE" "$out" memory_copy; then 136 kit_fail "wasm-target/memory-copy" "kit cc -target wasm32-none failed for $TOY_MEMCPY_FIXTURE" 137 sed 's/^/ | /' "$KIT_WORK/memory_copy.cc.err" >&2 138 return 139 fi 140 local hex; hex=$(wt_hex "$out") 141 local ok=1 142 printf '%s' "$hex" | grep -q 'fc0a' || { ok=0; echo "memory.copy (0xfc 0x0a) not present in $out" >&2; } 143 printf '%s' "$hex" | grep -q 'fc0b' || { ok=0; echo "memory.fill (0xfc 0x0b) not present in $out" >&2; } 144 [ "$ok" -eq 1 ] && kit_pass "wasm-target/memory-copy" || kit_fail "wasm-target/memory-copy" "missing bulk-memory opcode(s)" 145 } 146 147 # ---- lane: memory export (check_memory_export.sh) -------------------------- 148 # The linear memory must be exported under the conventional name "memory" for 149 # browser/wasmtime/wasmer/Node host runtimes. 150 kit_lane_MEX() { 151 if [ "$have_kit" -eq 0 ]; then kit_skip "wasm-target/memory-export" "kit driver missing at $KIT_BIN"; return; fi 152 if [ ! -f "$TOY_EXPORT_FIXTURE" ]; then kit_skip "wasm-target/memory-export" "missing toy fixture $TOY_EXPORT_FIXTURE"; return; fi 153 154 local out="$KIT_WORK/memory_export.wasm" 155 if ! wt_compile "$TOY_EXPORT_FIXTURE" "$out" memory_export; then 156 kit_fail "wasm-target/memory-export" "kit cc -target wasm32-none failed for $TOY_EXPORT_FIXTURE" 157 sed 's/^/ | /' "$KIT_WORK/memory_export.cc.err" >&2 158 return 159 fi 160 if grep -F "memory" "$out" >/dev/null 2>&1; then kit_pass "wasm-target/memory-export" 161 else kit_fail "wasm-target/memory-export" "produced module does not contain export name 'memory'"; fi 162 } 163 164 # ---- drive the structural checks ------------------------------------------- 165 # A single synthetic case fans the checks out across lanes (no opt/tuple axis). 166 # Use this dir's fixture .c files as the corpus glob (the engine needs >=1 167 # match); KIT_READ_CASE collapses to one driving case so each lane fires once. 168 printf 'test-wasm-target target=wasm32-none\n' 169 170 # Single-item corpus: pick exactly one fixture as the matrix driver so every 171 # lane runs exactly once. The lane bodies reference fixtures by absolute path, 172 # not via KIT_SRC, since one check may touch several fixtures. 173 wt_pick_one() { [ "$KIT_BASE" = "asm_popcnt" ] || KIT_SKIP_NA_CASE=1; } 174 175 KIT_LABEL=test-wasm-target KIT_BUILD_DIR="$BUILD_DIR" \ 176 KIT_CORPUS_GLOBS="$SRC_DIR/*.c" KIT_CORPUS_EXT=c KIT_SIDECAR_DIR="$SRC_DIR" \ 177 KIT_LANES="ASM IMP MCP MEX" KIT_OPT_LEVELS="" KIT_TUPLES="wasm32-none" \ 178 KIT_TARGETS_EXT="" KIT_READ_CASE=wt_pick_one KIT_PARALLELIZABLE="$PAR" \ 179 kit_corpus_run 180 181 kit_summary test-wasm-target 182 kit_exit