flang компилятор доказывает, что программа не зациклится 0.6.2 GitHub

WebAssembly получается через C даром: девятая цель печати не нужна

Печатая в C, мы уже печатаем в WebAssembly. clang --target=wasm32-wasi собирает наш порождённый C как есть, и собранное отвечает то же самое — значения, коды отказов и тексты диагностик побайтово. Отдельный генератор в WebAssembly писать не надо: он был бы девятым местом, где расходится семантика, а выигрыша не даёт никакого.

Это заодно закрывает настоящую проблему, найденную исследованием модульности: печатая в JavaScript, мы отдаём программу в чужую семантику. В WebAssembly семантика остаётся нашей, потому что это тот же наш C, только другим компилятором.

Чем подтверждено. Ветка work/wasm-cherez-c от 6e186c5, отчёт docs/wasm-via-c.md, оснастка scripts/wasm-compare.mjs. Корпус flang/test/corpus-grid.mjs — 94 программы, 8799 точек, расхождений 0 — под двумя средами WASI (node:wasi и wasmtime 47.0.3). Правок в исходниках ноль, предупреждений ноль под -std=c99 -Wall -Wextra -Werror -pedantic -O2. Планировщик процессов переехал целиком: 8 примеров, 16 прогонов × 5 семян = 80 сверок журнала доставок побайтово, потому что flang_conc.c не включает ничего, кроме четырёх заголовков C99. Сам компилятор (4.5 МБ порождённого C) собирается в модуль 4 567 408 байт и правильно проверяет настоящие файлы. Единственная необязательная правка печати — цель wasm в порождаемом Makefile, +17/−2 строки, измерено правкой копии и проверено сборкой, в дерево не внесено.

Чем ограничено. Три числа, без которых обещание не держится. Первое: собирать надо с -DFL_STACK_ROOM_FALLBACK=8388608u вместе с -Wl,-z,stack-size=8388608 — иначе см. no-guard-page-in-wasm. Второе: node:wasi обрывает стандартный ввод крупнее ~128 КиБ, поданный через трубу, и это не лечится правкой в C (проверено: +3 строки не помогают); wasmtime не теряет ничего, но требует -W max-wasm-stack=8388608, потому что по умолчанию даёт 512 КиБ и обрывает рекурсию раньше обычной сборки. Третье: потолок адресного пространства wasm32 — 4080.1 МиБ (65 282 страницы), и на сортировке вставками программа перестаёт помещаться между 8000 и 12 000 элементов, тогда как обычная сборка считает и на 24 000, взяв 18.7 ГиБ. Это следствие того, что arena-never-releases, а не свойство WebAssembly: почини область памяти — стена уедет во столько же раз.

Не переезжает ровно один файл — flang_repl.c, человеческая оболочка: в WASI нет ни sigaction, ни mkdtemp, и флагами это не лечится. Оба вызова нужны ей затем, чтобы спрашивать у мира, а в WebAssembly мира нет по определению. В песочницу едет компилятор, а не оболочка, — и это ровно то, что нужно.

Цена: модуль толще обычного бинарника в 2.637 раза на корпусе, запуск дороже в 15.4 раза (3.7 мс против 56.6 мс), а счёт не медленнее — 0.70× и 0.89× на двух сортировках по 2000 элементов.

Связано: what-is-deferred, no-guard-page-in-wasm, arena-never-releases, byte-for-byte-comparison, the-instrument-lied-not-the-subject