mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
Enable DBT JIT on Apple Silicon
The DBT design (docs/DBT-PORTABILITY.md) anticipated Apple AArch64 as a target sharing AAPCS64 with Linux, with only the JIT memory model differing — and dbt_jit_mem.h already abstracted that difference (MAP_JIT, pthread_jit_write_protect_np, sys_icache_invalidate). The two remaining gaps were: (1) configure.ac explicitly errored on darwin+aarch64, and (2) every code-write region had a matching jit_write_end (via dbt_flush_code) but no jit_write_begin to flip JIT pages out of execute-only mode under Apple's strict W^X. - mux/configure.ac (and the corresponding hunk hand-applied to mux/configure to avoid an autoconf 2.71->2.73 rewrite of the whole generated file): drop the AArch64-darwin error and fall through to dbt_a64_sysv. - mux/modules/engine/dbt.cpp: bracket every leaf code-write region with jit_write_begin(). Specifically, dbt_init's trampoline emit, both branches of dbt_reset (blob NOP-pad and full-reset trampoline emit), the per-iteration translate inside dbt_pretranslate (per-iter to avoid nesting under that function's recursion), the translate paths in dbt_run and dbt_resume, and the backpatch_jmp loop in dbt_resolve_chains. The conditional flush in resolve_chains becomes unconditional so begin/end pairs stay balanced when no patches resolved. Also drop the now-redundant final dbt_flush_code at the end of dbt_pretranslate (each iteration self-flushes). On non-Apple platforms jit_write_begin compiles to a no-op, so this is zero-cost everywhere except Apple Silicon, where it adds one per-thread write-protect toggle per write region (cheap MSR write). Verified: make install with --enable-jit on aarch64-apple-darwin selects DBT_BACKEND=dbt_a64_sysv, builds dbt.eo + dbt_a64_sysv.eo + engine.so cleanly, and netmux dlopens engine.so without unresolved symbols. Actual JIT execution under load (smoke tests) still TODO. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b5bdf36684
commit
2a1776e276
3 changed files with 22 additions and 16 deletions
5
mux/configure
vendored
5
mux/configure
vendored
|
|
@ -6712,10 +6712,7 @@ printf %s "checking DBT backend for host platform... " >&6; }
|
|||
DBT_BACKEND="dbt_x64_sysv" ;;
|
||||
esac ;;
|
||||
aarch64|arm64)
|
||||
case "$host_os" in
|
||||
darwin*) as_fn_error $? "JIT not yet implemented for AArch64 macOS (Apple W^X backend needed)" "$LINENO" 5 ;;
|
||||
*) DBT_BACKEND="dbt_a64_sysv" ;;
|
||||
esac ;;
|
||||
DBT_BACKEND="dbt_a64_sysv" ;;
|
||||
riscv64)
|
||||
as_fn_error $? "JIT not yet implemented for native RV64 (backend needed)" "$LINENO" 5 ;;
|
||||
*)
|
||||
|
|
|
|||
|
|
@ -242,10 +242,7 @@ if test "x$jit_enabled" = "xyes"; then
|
|||
DBT_BACKEND="dbt_x64_sysv" ;;
|
||||
esac ;;
|
||||
aarch64|arm64)
|
||||
case "$host_os" in
|
||||
darwin*) AC_MSG_ERROR([JIT not yet implemented for AArch64 macOS (Apple W^X backend needed)]) ;;
|
||||
*) DBT_BACKEND="dbt_a64_sysv" ;;
|
||||
esac ;;
|
||||
DBT_BACKEND="dbt_a64_sysv" ;;
|
||||
riscv64)
|
||||
AC_MSG_ERROR([JIT not yet implemented for native RV64 (backend needed)]) ;;
|
||||
*)
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ int dbt_init(dbt_state_t *dbt, uint8_t *memory, size_t memory_size,
|
|||
}
|
||||
|
||||
// Emit trampoline at the start of the code buffer.
|
||||
jit_write_begin();
|
||||
dbt_backend_emit_trampoline(dbt);
|
||||
dbt_flush_code(dbt, 0);
|
||||
|
||||
|
|
@ -225,6 +226,7 @@ void dbt_reset(dbt_state_t *dbt, uint8_t *memory, size_t memory_size,
|
|||
// program code. On x86-64, each NOP is 1 byte (0x90).
|
||||
// On AArch64, NOPs are 4 bytes so N is rounded up to a
|
||||
// multiple of 4.
|
||||
jit_write_begin();
|
||||
{
|
||||
static int pad = -1;
|
||||
if (pad < 0) {
|
||||
|
|
@ -262,6 +264,7 @@ void dbt_reset(dbt_state_t *dbt, uint8_t *memory, size_t memory_size,
|
|||
dbt->patches.clear();
|
||||
dbt->pending_patch_targets.clear();
|
||||
dbt->code_used = 0;
|
||||
jit_write_begin();
|
||||
dbt_backend_emit_trampoline(dbt);
|
||||
dbt->num_intrinsics = 0;
|
||||
memset(dbt->intrinsics, 0, sizeof(dbt->intrinsics));
|
||||
|
|
@ -409,16 +412,20 @@ void dbt_pretranslate(dbt_state_t *dbt, uint64_t guest_pc) {
|
|||
}
|
||||
|
||||
// Translate if not already cached.
|
||||
// Brackets are per-iteration so dbt_pretranslate's recursion
|
||||
// (function-call discovery) doesn't nest write-mode toggles.
|
||||
if (!dbt_cache_lookup(dbt, pc)) {
|
||||
jit_write_begin();
|
||||
uint8_t *code = dbt_backend_translate_block(dbt, pc);
|
||||
if (!code) continue;
|
||||
if (!code) {
|
||||
dbt_flush_code(dbt, dbt->code_used);
|
||||
continue;
|
||||
}
|
||||
dbt_cache_insert(dbt, pc, code);
|
||||
dbt_backpatch_chains(dbt, pc, code);
|
||||
dbt_flush_code(dbt, static_cast<uint32_t>(code - dbt->code_buf));
|
||||
}
|
||||
}
|
||||
|
||||
// Flush I-cache for all code generated during blob pretranslation.
|
||||
dbt_flush_code(dbt, 0);
|
||||
}
|
||||
|
||||
void dbt_resolve_chains(dbt_state_t *dbt) {
|
||||
|
|
@ -431,6 +438,7 @@ void dbt_resolve_chains(dbt_state_t *dbt) {
|
|||
uint32_t resolved = 0;
|
||||
uint32_t already_ok = 0;
|
||||
uint32_t unresolvable = 0;
|
||||
jit_write_begin();
|
||||
for (size_t i = 0; i < dbt->patches.size(); i++) {
|
||||
uint64_t target = dbt->patches[i].target_pc;
|
||||
if (target == 0) continue;
|
||||
|
|
@ -465,10 +473,10 @@ void dbt_resolve_chains(dbt_state_t *dbt) {
|
|||
resolved, already_ok, unresolvable,
|
||||
static_cast<unsigned>(dbt->patches.size()));
|
||||
|
||||
// Flush I-cache for any backpatched JMP targets.
|
||||
if (resolved > 0) {
|
||||
dbt_flush_code(dbt, 0);
|
||||
}
|
||||
// Flush I-cache for any backpatched JMP targets, and balance the
|
||||
// jit_write_begin above (always required so write protection is
|
||||
// restored on Apple Silicon even when no patches resolved).
|
||||
dbt_flush_code(dbt, resolved > 0 ? 0 : dbt->code_used);
|
||||
}
|
||||
|
||||
int dbt_run(dbt_state_t *dbt, uint64_t entry_pc, uint64_t stack_top) {
|
||||
|
|
@ -530,8 +538,10 @@ int dbt_run(dbt_state_t *dbt, uint64_t entry_pc, uint64_t stack_top) {
|
|||
static_cast<unsigned long long>(pc));
|
||||
}
|
||||
} else {
|
||||
jit_write_begin();
|
||||
code = dbt_backend_translate_block(dbt, pc);
|
||||
if (!code) {
|
||||
dbt_flush_code(dbt, dbt->code_used);
|
||||
dbt->dispatch_count = dispatch_count;
|
||||
return -1; // code buffer full
|
||||
}
|
||||
|
|
@ -613,8 +623,10 @@ int dbt_resume(dbt_state_t *dbt, uint64_t entry_pc) {
|
|||
static_cast<unsigned long long>(pc));
|
||||
}
|
||||
} else {
|
||||
jit_write_begin();
|
||||
code = dbt_backend_translate_block(dbt, pc);
|
||||
if (!code) {
|
||||
dbt_flush_code(dbt, dbt->code_used);
|
||||
dbt->dispatch_count = dispatch_count;
|
||||
return -1; // code buffer full
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue