perf(context): pass actor sp through registers, not TLS

switch_to_actor takes the target sp in rdi and returns the actor's
next saved sp in rax (handed over by switch_to_scheduler's shim).
Deletes the ACTOR_SP thread-local and halves the helper calls per
one-way switch (2 -> 1); the scheduler loop also drops its
set_actor_sp/get_actor_sp TLS round-trips. SCHEDULER_SP stays: a
yielding actor at arbitrary call depth has no argument channel back.

asm before/after in outputs/history.md session 1-2. Tests: 354 pass.
This commit is contained in:
claude-asm-audit
2026-08-21 12:22:45 +00:00
parent 741c10337b
commit d7082eb266
3 changed files with 54 additions and 58 deletions
+2 -4
View File
@@ -116,7 +116,7 @@ use crate::actor::{
take_last_outcome, Actor, Outcome,
};
use crate::channel::Sender;
use crate::context::{get_actor_sp, set_actor_sp, switch_to_actor};
use crate::context::switch_to_actor;
use crate::io::IoThread;
use crate::monitor::{Down, DownReason, MonitorId};
use crate::pid::Pid;
@@ -2228,7 +2228,6 @@ fn schedule_loop(inner: &Arc<RuntimeInner>, slot_idx: usize) {
.current_pid_index
.store(pid.index(), Ordering::Relaxed);
set_actor_sp(sp);
set_current_pid(pid);
crate::preempt::set_current_stop(stop_flag);
crate::preempt::set_current_slot(slot as *const Slot);
@@ -2254,7 +2253,7 @@ fn schedule_loop(inner: &Arc<RuntimeInner>, slot_idx: usize) {
crate::causal::on_resume(slot);
crate::te!(crate::trace::Event::Resume(pid));
unsafe { switch_to_actor() };
let saved_sp = unsafe { switch_to_actor(sp) };
PREEMPTION_ENABLED.with(|c| c.set(false));
// RFC 016 Chunk 2: charge the cycles this resume consumed to the actor
@@ -2268,7 +2267,6 @@ fn schedule_loop(inner: &Arc<RuntimeInner>, slot_idx: usize) {
crate::preempt::clear_current_slot();
let intent = YIELD_INTENT.with(|c| c.get());
let saved_sp = get_actor_sp();
slot.sp.store(saved_sp, Ordering::Relaxed);
// RFC 019 §2: sampled high-water — one branch + at most one store
// into the line the store above just dirtied. Relaxed and advisory;