- deep_eq returns false immediately when both sides are string-like and
the bit-compare failed (strings are interned, so bit-equality IS string
equality) — trims the type-check chain on the hot failed-compare path
of string-tag dispatch (a.kind == "...")
- pre-reserve thread stacks (value stack, scopes, calls, mes, loops)
- splash_bench: string_cmp workload, arith_hostmode (instruction limit +
run budget installed, the game-host configuration; measured: the two
per-instruction counters cost ~nothing, branch prediction hides them),
BENCH_ONLY profiler filter
Tried and rejected: batching consecutive value-pushes in run_core into
one dispatch iteration — the scan overhead outweighed the per-value
limit/budget checks it skipped (they were already free); reverted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Interpreter perf pass on platform/script, semantics-preserving:
- ValueMap hybrid small-map: object maps linear-scan a vec below 16
entries and spill to a HashMap above (scopes/call-args/small objects
never hash)
- compound scope assigns (+=, -=, ...) locate their slot with ONE
proto-chain walk instead of a read walk plus a write walk
- for-loop iterations clear and reuse the iteration scope in place when
nothing captured it (closure capture -> REFFED -> fresh scope); loop
scopes no longer copy the parent scope vec
- 'for i in a..b' captures end/step at loop entry when the range object
is un-REFFED; stored (mutable) ranges keep live per-iteration lookups
- trap error-queue + trap.on polled via one Cell<u8> bitfield per
instruction instead of a RefCell borrow + Option<enum> Cell read
- ADD checks the number fast path before the string check
Measured (splash_bench, medians of 3 A/B runs): array_iter -27%,
method_call -21%, array_index -21%, for-range loops -19%, object_churn
and field r/w -8..9%, fib -7%, sandbox-style composite tick -6%.
Adds platform/script/test/src/bin/splash_bench.rs (run with
cargo run -p makepad-script-test --bin splash_bench --release,
BENCH_ONLY=<name> loops one workload for profilers) and parity asserts
for the touched edges: mid-loop range end/step mutation stays live on
stored ranges, closures pin their iteration's scope, selective capture
does not leak across reused scopes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Entity lookup O(log n): shared entity_index_sorted helper, single
push_entity spawn path with ascending-id assert + per-tick sorted
debug_assert — the sorted-Vec invariant is now enforced, not hoped
- WorldSnapshot captures next_id: failed-eval rollback can no longer mint
colliding ids under surviving entities (review defect fixed)
- game.log buffered (1s/16KiB/eval-boundary flush), agent RPC poll gated
on one .agent dir-mtime stat — no per-tick file I/O left
- Camera rig authoritative on GameWorld (orbit/chase state); widget keeps
only device-input accumulation; mailbox drain order unchanged
- Per-tick cumulative script budget: with_instruction_limit reports
consumption (incl. trap-wipe subtlety), gamemaker tick holds ONE 500k
pool across on_tick + timers + touch events
- Tape probe verified BYTE-IDENTICAL vs pre-cleanup reference
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Escape barrier: every checked store funnel tags stored objects REFFED
(stored => REFFED structural), ret==args guards at native completion,
fn-arg bind-time barrier (closure-captured scopes retained args untagged
-> latent use-after-free under eager release)
- vm.release_transient() for host per-call objects; *_unchecked pushes are
the releasable-container path; call_with_scope native branch no longer
leaks one scope object per Rust->native vm.call()
- pump_widget_async: dead-isolate reclaim every pump + needs_gc-gated
round-robin mark/sweep — isolate heaps were never collected before
- res.rs: resource path cache was Cx-global and cached handle VALUES across
VMs, so isolate heaps held main-heap handle indices (exposed by the first
isolate mark pass ever to run). Now: data shared globally, handles minted
per-heap, cache keyed (heap_key, path), per-heap detach on GC
- vm.gc() no longer shrink_to_fits every run; explicit gc_and_compact()
- script-test: GC campaign suite (flat-heap tick loops, retained-input
survival, escaped-scope capture, isolate churn collection)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>