blob: 8aa357feeb88dfb090878bd01629e9237befb406 [file]
-- WAMR for the wasm scripting backend. Flags proven by the luau_wasm EH
-- spike: sw-bounds artifacts must never unwind through hardware traps
-- (the longjmp skips the sjlj glue's native frames) and libc-wasi must be
-- compiled in (without it emscripten-built module ctors spin; see
-- spike_eh/README.md). Bounds checks default sw; wasm_hw_bounds below.
local dependency = require('dependency')
-- The patch set carries the rive fast-interp fixes (linear_mem_size
-- refreshes around growth, gated OOB diagnostics); a clone without them is
-- subtly wrong under memory growth.
local wamr = dependency.github('bytecodealliance/wasm-micro-runtime', 'WAMR-2.4.5', {
patches = path.join(path.getdirectory(_SCRIPT), 'wamr_patches'),
})
-- Header-only simd library the fast interpreter's v128 handlers compile
-- against; upstream fetches the same tag through CMake FetchContent.
local simde = dependency.github('simd-everywhere/simde', 'v0.8.2')
-- Struct layouts in wamr's internal headers follow these; any rive TU that
-- includes them (the tier transplant) must compile with the identical set
-- or instance layouts silently diverge.
local wamrConfigDefines = {
'WASM_ENABLE_INTERP=1',
'WASM_ENABLE_FAST_INTERP=1',
'WASM_ENABLE_AOT=1',
'WASM_ENABLE_JIT=0',
'WASM_ENABLE_LIBC_BUILTIN=1',
'WASM_ENABLE_LIBC_WASI=1',
'WASM_ENABLE_MODULE_INST_CONTEXT=1',
'WASM_ENABLE_BULK_MEMORY=1',
-- Simde-backed v128 in the fast interpreter; scalar modules
-- translate the same as before, simd modules stop being refused.
'WASM_ENABLE_SIMD=1',
'WASM_ENABLE_SIMDE=1',
'WASM_DISABLE_STACK_HW_BOUND_CHECK=1',
'BH_MALLOC=wasm_runtime_malloc',
'BH_FREE=wasm_runtime_free',
}
-- Opt-in hw bounds serve AOT artifacts compiled --bounds-checks=0 only:
-- patch 0009 keeps the interpreter sw-checked and patch 0010 keeps sw
-- artifacts unwinding by checked returns, so the Luau lane never takes
-- a hardware trap. Native stack checks stay sw everywhere (artifacts
-- must carry --stack-bounds-checks=1).
if not _OPTIONS['wasm_hw_bounds'] then
table.insert(wamrConfigDefines, 'WASM_DISABLE_HW_BOUND_CHECK=1')
end
if os.target() == 'windows' then
-- We link wamr statically; under clang's msvc mode wasm_export.h and
-- wasm_c_api.h otherwise declare every API dllimport.
table.insert(wamrConfigDefines, 'WASM_RUNTIME_API_EXTERN=')
table.insert(wamrConfigDefines, 'WASM_API_EXTERN=')
end
-- os.target() stays the host under --for_android; the option is the
-- truth for the platform dir.
local forAndroid = _OPTIONS['for_android'] ~= nil
local platformDir = forAndroid and 'android'
or os.target() == 'linux' and 'linux'
or os.target() == 'windows' and 'windows'
or 'darwin'
project('wamr')
do
kind('StaticLib')
language('C')
warnings('Off')
-- Vendored dep nobody debugs into: an unoptimized interpreter is 6x
-- slower, so every config builds it optimized. NDEBUG matches the CMake
-- Release baseline; without it the interpreter's computed-goto dispatch
-- tail-merges into a single prediction-killing branch.
optimize('Speed')
defines({ 'NDEBUG' })
-- Replicated per-handler dispatch is what makes the fast interpreter
-- fast; default heuristics tail-merge the computed gotos into a single
-- indirect branch (+27% on box2d). Guarded by bench/check_dispatch_sites.
-- LTO would run codegen at link where these -mllvm knobs cannot reach,
-- so this library opts out and keeps its dispatch replication.
buildoptions({ '-fno-lto' })
-- The tail-dup knobs need llvm 19; older clangs build correct but
-- slower dispatch, still caught by the dispatch-site guard where it runs.
-- The probe runs host clang; cross toolchains (the NDK's) may reject
-- the knobs the host accepts, so cross builds keep default dispatch.
local devNull = os.ishost('windows') and 'NUL' or '/dev/null'
local _, tailDupProbe = os.outputof(
'clang -fsyntax-only -x c ' .. devNull ..
' -mllvm -tail-dup-pred-size=5000' ..
' -mllvm -tail-dup-succ-size=5000 2>&1'
)
if tailDupProbe == 0 and _OPTIONS['for_android'] == nil then
buildoptions({
'-mllvm -tail-dup-pred-size=5000',
'-mllvm -tail-dup-succ-size=5000',
})
end
defines(wamrConfigDefines)
filter({ 'system:macosx' })
defines({ 'BH_PLATFORM_DARWIN' })
filter({ 'system:linux' })
defines({ 'BH_PLATFORM_LINUX' })
filter({ 'system:android' })
defines({ 'BH_PLATFORM_ANDROID' })
filter({ 'system:windows' })
defines({
'BH_PLATFORM_WINDOWS',
'HAVE_STRUCT_TIMESPEC',
'_WINSOCK_DEPRECATED_NO_WARNINGS',
})
filter({})
-- Per-lane arch beats host arch: universal builds compile both lanes
-- on one machine and each must get its own invoke shim and relocs.
local archOption = _OPTIONS['arch']
local machine = os.outputof('uname -m')
local isArm64
-- 'host' is the option's default, not an explicit lane.
if archOption ~= nil and archOption ~= '' and archOption ~= 'host' then
isArm64 = archOption == 'arm64' or archOption == 'aarch64'
else
isArm64 = machine == 'arm64' or machine == 'aarch64'
end
local isArm32 = forAndroid and archOption == 'arm'
-- The quoted string define goes through buildoptions pre-escaped so both
-- the gmake and ninja generators deliver the quotes to the compiler.
if isArm32 then
-- NDK armv7 compiles thumb2 with NEON/VFP by default. Upstream's
-- thumb reloc does pointer arithmetic clang 18 makes a hard error.
-- The THUMBV7 string matters: the aot loader matches it against
-- wamrc's thumbv7 artifacts (bare THUMB defaults to thumbv4t).
defines({ 'BUILD_TARGET_THUMB_VFP' })
buildoptions({
'-DBUILD_TARGET=\\"THUMBV7\\"',
'-Wno-int-conversion',
})
elseif isArm64 then
defines({ 'BUILD_TARGET_AARCH64' })
buildoptions({ '-DBUILD_TARGET=\\"AARCH64\\"' })
else
defines({ 'BUILD_TARGET_X86_64' })
buildoptions({ '-DBUILD_TARGET=\\"X86_64\\"' })
end
-- em64 is WAMR's x86-64 SysV invoke shim. With WASM_ENABLE_SIMD the
-- invoke marshaling widens float slots to v128, so the shim must be the
-- _simd variant or int registers load from the wrong offsets. arm32 has
-- no simd invoke variant; its marshaling never widens. Windows takes
-- the mingw shim: same Win64 ABI as MSVC targets, and GAS syntax that
-- clang's integrated assembler handles without ml64.
local invokeNative = isArm32 and 'invokeNative_thumb_vfp.s'
or isArm64 and 'invokeNative_aarch64_simd.s'
or os.target() == 'windows' and 'invokeNative_mingw_x64_simd.s'
or 'invokeNative_em64_simd.s'
local aotReloc = isArm32 and 'aot_reloc_thumb.c'
or isArm64 and 'aot_reloc_aarch64.c'
or 'aot_reloc_x86_64.c'
includedirs({
wamr .. '/core/iwasm/include',
wamr .. '/core/iwasm/common',
wamr .. '/core/iwasm/aot',
wamr .. '/core/iwasm/interpreter',
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include',
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src',
wamr .. '/core/shared/include',
wamr .. '/core/shared/platform/include',
-- platform_internal.h comes from the per-platform dir.
wamr .. '/core/shared/platform/' .. platformDir,
wamr .. '/core/shared/platform/common/libc-util',
wamr .. '/core/shared/mem-alloc',
-- wasm_runtime_common.h pulls the wasi primitives when libc-wasi is
-- on, which our config always is.
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src',
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include',
wamr .. '/core/shared/utils',
wamr .. '/core/shared/utils/uncommon',
simde,
})
files({
wamr .. '/core/iwasm/common/*.c',
wamr .. '/core/iwasm/common/arch/' .. invokeNative,
wamr .. '/core/iwasm/interpreter/wasm_loader.c',
wamr .. '/core/iwasm/interpreter/wasm_runtime.c',
wamr .. '/core/iwasm/interpreter/wasm_interp_fast.c',
wamr .. '/core/iwasm/aot/*.c',
wamr .. '/core/iwasm/aot/arch/' .. aotReloc,
wamr .. '/core/iwasm/libraries/libc-builtin/*.c',
wamr .. '/core/iwasm/libraries/libc-wasi/**.c',
wamr .. '/core/shared/platform/' .. platformDir .. '/*.c',
-- Windows replaces the posix layer wholesale; win_atomic is C++.
os.target() == 'windows'
and (wamr .. '/core/shared/platform/windows/*.cpp')
or (wamr .. '/core/shared/platform/common/posix/*.c'),
wamr .. '/core/shared/platform/common/memory/*.c',
wamr .. '/core/shared/platform/common/libc-util/*.c',
wamr .. '/core/shared/mem-alloc/*.c',
wamr .. '/core/shared/mem-alloc/ems/*.c',
wamr .. '/core/shared/utils/*.c',
wamr .. '/core/shared/utils/uncommon/*.c',
})
if os.target() == 'windows' then
-- Linux perf-map support; leans on pid_t/getpid.
removefiles({ wamr .. '/core/iwasm/aot/aot_perf_map.c' })
end
end
return {
wamr = wamr,
configDefines = wamrConfigDefines,
internalIncludes = {
wamr .. '/core/iwasm/interpreter',
wamr .. '/core/iwasm/aot',
wamr .. '/core/iwasm/common',
wamr .. '/core/shared/include',
wamr .. '/core/shared/platform/include',
-- platform_internal.h comes from the per-platform dir.
wamr .. '/core/shared/platform/' .. platformDir,
wamr .. '/core/shared/mem-alloc',
-- wasm_runtime_common.h pulls the wasi primitives when libc-wasi is
-- on, which our config always is.
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src',
wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include',
wamr .. '/core/shared/utils',
},
}