mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
Merge pull request #2113 from brazilofmux/fix/2107-str-pool-fargs-unmoved
fix(jit): grow the string pool without sliding FARGS (#2107)
This commit is contained in:
commit
1c050049ad
3 changed files with 61 additions and 26 deletions
|
|
@ -284,27 +284,38 @@ struct rv_compiler {
|
|||
static constexpr size_t MEM_SIZE = 0x540000; // 4 MB map + 1 MB heap + 256 KB doubles scratch
|
||||
static constexpr uint64_t CODE_BASE = 0x0000;
|
||||
static constexpr uint64_t CODE_LIMIT = 0x1000;
|
||||
// String pool sized to hold one full LBUF (32768) of constants (#2066).
|
||||
// Previously STR_LIMIT was 0x4000 (12 KB) while OUT_SLOT tracked LBUF at
|
||||
// 32 KB, so any expression whose pooled constants exceeded ~12 KB fell
|
||||
// back to the AST evaluator with COMPILATION FAILED. FARGS moved up to
|
||||
// keep the same 16 KB capacity without overlapping the string region.
|
||||
// Cached programs from the old layout fail the fargs-range check on load
|
||||
// and recompile cleanly.
|
||||
static constexpr uint64_t STR_BASE = 0x1000;
|
||||
static constexpr uint64_t STR_LIMIT = 0x9000; // STR_BASE + 0x8000 (= LBUF_SIZE)
|
||||
static constexpr uint64_t FARGS_BASE = 0x9000;
|
||||
static constexpr uint64_t FARGS_LIMIT= 0xD000; // FARGS_BASE + 0x4000
|
||||
// Guest one-shot layout (#2066, #2107):
|
||||
//
|
||||
// CODE 0x0000 .. 0x1000 (4 KB)
|
||||
// (gap) 0x1000 .. 0x4000 (was the 12 KB string pool; unused)
|
||||
// FARGS 0x4000 .. 0x8000 (16 KB) — UNMOVED from pre-#2066
|
||||
// STR 0x8000 .. 0x10000 (32 KB = LBUF_SIZE)
|
||||
// BLOB 0x10000 ..
|
||||
//
|
||||
// #2066 first grew STR by sliding FARGS up (STR 0x1000-0x9000, FARGS
|
||||
// 0x9000-0xD000). That was enough to make nested Lua-in-softcode JIT
|
||||
// SIGSEGV on at least one host (#2107) while this box stayed green —
|
||||
// so FARGS stays at its historical window and the enlarged string
|
||||
// pool takes the free gap that used to sit under the legacy OUT_BASE
|
||||
// and before the blob. 0x1000-0x4000 is left empty on purpose: a
|
||||
// contiguous STR bump allocator cannot share it with a fixed FARGS.
|
||||
//
|
||||
// Cached programs from any prior layout fail the range checks on
|
||||
// load (and the blob_version now includes these constants, #2107).
|
||||
static constexpr uint64_t FARGS_BASE = 0x4000;
|
||||
static constexpr uint64_t FARGS_LIMIT= 0x8000;
|
||||
static constexpr uint64_t STR_BASE = 0x8000;
|
||||
static constexpr uint64_t STR_LIMIT = 0x10000; // STR_BASE + 0x8000 (= LBUF_SIZE)
|
||||
|
||||
static constexpr uint64_t BLOB_BASE = 0x10000;
|
||||
static constexpr uint64_t BLOB_LIMIT = 0x40000;
|
||||
|
||||
static_assert(CODE_LIMIT == STR_BASE,
|
||||
"code region must abut the string pool");
|
||||
static_assert(STR_LIMIT == FARGS_BASE,
|
||||
"string pool must abut the fargs pool");
|
||||
static_assert(FARGS_LIMIT <= BLOB_BASE,
|
||||
"fargs pool must not overlap the blob region");
|
||||
static_assert(CODE_LIMIT <= FARGS_BASE,
|
||||
"code region must not overlap the fargs pool");
|
||||
static_assert(FARGS_LIMIT == STR_BASE,
|
||||
"fargs pool must abut the string pool");
|
||||
static_assert(STR_LIMIT == BLOB_BASE,
|
||||
"string pool must abut the blob region");
|
||||
static_assert(STR_LIMIT - STR_BASE >= 32768,
|
||||
"string pool must hold one LBUF of constants (#2066)");
|
||||
|
||||
|
|
@ -314,10 +325,9 @@ struct rv_compiler {
|
|||
// frame size. Each slot is STACK_TOP - 8 - (N+1)*OUT_SLOT.
|
||||
// Addresses are compile-time constants (STACK_TOP is fixed).
|
||||
//
|
||||
// Legacy OUT_BASE retained for backward compatibility with
|
||||
// cached programs and output clearing.
|
||||
// OUT_BASE was a legacy fixed output base at 0x8000; the stack
|
||||
// allocator superseded it and nothing reads the constant (#2107).
|
||||
//
|
||||
static constexpr uint64_t OUT_BASE = 0x8000; // legacy (unused by new alloc)
|
||||
static constexpr int OUT_SLOT = 32768; // = LBUF_SIZE
|
||||
static constexpr uint64_t OUT_STACK_LIMIT = 0x81000; // lowest valid output addr
|
||||
// Bit 30, not bit 31: RV64 LUI sign-extends bit 31 to 64 bits,
|
||||
|
|
|
|||
|
|
@ -528,6 +528,16 @@ static bool tier2_load(const char *path, uint64_t guest_base) {
|
|||
// Deliberately excludes the dbt_* units: they execute the stored RV64
|
||||
// rather than produce it, so invalidating on their account would discard
|
||||
// the cache for no gain. See jit_tier1_stamp.h.
|
||||
// Layout constants are part of the key (#2107): a guest-address
|
||||
// map change (STR/FARGS bases) rewrites every baked pointer in the
|
||||
// code and pool blobs, and must not reuse a row written under the
|
||||
// previous map even when __DATE__/__TIME__ happened not to move.
|
||||
static const uint64_t layout[] = {
|
||||
rv_compiler::CODE_BASE, rv_compiler::CODE_LIMIT,
|
||||
rv_compiler::STR_BASE, rv_compiler::STR_LIMIT,
|
||||
rv_compiler::FARGS_BASE, rv_compiler::FARGS_LIMIT,
|
||||
rv_compiler::BLOB_BASE, rv_compiler::MEM_SIZE,
|
||||
};
|
||||
const void *parts[] = {
|
||||
JIT_COMPILER_VERSION,
|
||||
JIT_BUILD_STAMP,
|
||||
|
|
@ -539,6 +549,7 @@ static bool tier2_load(const char *path, uint64_t guest_base) {
|
|||
&hdr,
|
||||
s_tier2.image.data(),
|
||||
entries.empty() ? nullptr : entries.data(),
|
||||
layout,
|
||||
};
|
||||
const size_t sizes[] = {
|
||||
sizeof(JIT_COMPILER_VERSION) - 1,
|
||||
|
|
@ -552,8 +563,9 @@ static bool tier2_load(const char *path, uint64_t guest_base) {
|
|||
sizeof(hdr),
|
||||
s_tier2.code_size,
|
||||
entries.size() * sizeof(rv64_blob_entry),
|
||||
sizeof(layout),
|
||||
};
|
||||
s_blob_version = sha1_hex_parts(parts, sizes, 10);
|
||||
s_blob_version = sha1_hex_parts(parts, sizes, 11);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -891,6 +903,13 @@ static void tier2_lazy_init() {
|
|||
// Still hash the compiler version so tier 1 upgrades invalidate. Same
|
||||
// per-unit stamps as the loaded path (#2061) -- without them this leg has
|
||||
// the identical hole, and it is the leg a blob-less build runs on.
|
||||
// Layout is in the key for the same reason as the blob-loaded path (#2107).
|
||||
static const uint64_t layout[] = {
|
||||
rv_compiler::CODE_BASE, rv_compiler::CODE_LIMIT,
|
||||
rv_compiler::STR_BASE, rv_compiler::STR_LIMIT,
|
||||
rv_compiler::FARGS_BASE, rv_compiler::FARGS_LIMIT,
|
||||
rv_compiler::BLOB_BASE, rv_compiler::MEM_SIZE,
|
||||
};
|
||||
const void *parts[] = {
|
||||
JIT_COMPILER_VERSION,
|
||||
JIT_BUILD_STAMP,
|
||||
|
|
@ -899,6 +918,7 @@ static void tier2_lazy_init() {
|
|||
TIER1_STAMP_HIR_SSA,
|
||||
TIER1_STAMP_HIR_OPT,
|
||||
TIER1_STAMP_HIR_CODEGEN,
|
||||
layout,
|
||||
};
|
||||
const size_t sizes[] = {
|
||||
sizeof(JIT_COMPILER_VERSION) - 1,
|
||||
|
|
@ -908,8 +928,9 @@ static void tier2_lazy_init() {
|
|||
strlen(TIER1_STAMP_HIR_SSA),
|
||||
strlen(TIER1_STAMP_HIR_OPT),
|
||||
strlen(TIER1_STAMP_HIR_CODEGEN),
|
||||
sizeof(layout),
|
||||
};
|
||||
s_blob_version = sha1_hex_parts(parts, sizes, 7);
|
||||
s_blob_version = sha1_hex_parts(parts, sizes, 8);
|
||||
}
|
||||
|
||||
void tier2_ensure(void) {
|
||||
|
|
@ -1986,9 +2007,13 @@ static compiled_program reconstruct_from_cache(
|
|||
} else if (rec.memory_blob && rec.memory_len > 0) {
|
||||
// Legacy format: single memory blob covering code+str+fargs.
|
||||
// Extract the occupied regions into compact vectors.
|
||||
// Cap at the highest of the three pool ends (#2107: STR now sits
|
||||
// above FARGS, so FARGS_LIMIT is no longer the image high water).
|
||||
int copy_len = rec.memory_len;
|
||||
if (copy_len > static_cast<int>(rv_compiler::FARGS_LIMIT)) {
|
||||
copy_len = static_cast<int>(rv_compiler::FARGS_LIMIT);
|
||||
const int layout_end = static_cast<int>(
|
||||
(std::max)(rv_compiler::STR_LIMIT, rv_compiler::FARGS_LIMIT));
|
||||
if (copy_len > layout_end) {
|
||||
copy_len = layout_end;
|
||||
}
|
||||
const auto *base = static_cast<const uint8_t *>(rec.memory_blob);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
# A JIT-compiled expression that evaluates another expression (u(), ulocal(),
|
||||
# or any outer construct wrapping one) runs the inner compile on the shared
|
||||
# heap, whose string pool lives at 0x40000..0x60000 rather than the one-shot
|
||||
# compiler's 0x1000..0x9000 (#2066). hir_codegen's FP slot allocator bounded
|
||||
# itself against the static rv_compiler::STR_LIMIT instead of this compile's
|
||||
# compiler's 0x8000..0x10000 (#2066/#2107). hir_codegen's FP slot allocator
|
||||
# bounded itself against the static rv_compiler::STR_LIMIT instead of this
|
||||
# own str_pool_limit, so every FP slot address stayed 0 and all float
|
||||
# temporaries aliased guest address 0 (#1159).
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue