From d4961978ecdc685731b6dae573f4ac9df1c10fc3 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 13 Feb 2026 09:58:45 +0000 Subject: [PATCH] =?UTF-8?q?test:=20Cycle=2048=20=E2=80=94=20self-send,=20b?= =?UTF-8?q?it=20rotation,=20bit=20counting,=20selective=20stop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - guest_sends_to_self_via_framed_address: self-send bounces through, reaches inbox - guest_uses_bit_rotation: i32.rotl instruction - guest_uses_bit_counting: i32.clz, i32.ctz, i32.popcnt instructions - stop_every_other_actor_remaining_work: stop 5 of 10, other 5 still respond All 208 tests pass. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski --- crates/wasm-actor/tests/wasm_actor.rs | 130 ++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index 0db5050..6f2d586 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -7278,4 +7278,134 @@ fn guest_mirrors_full_message() { let msg = inbox.try_recv().expect("should receive mirrored full message"); // Payload = full original message (address + payload) assert_eq!(msg.0, original_msg.0, "should receive exact copy of full message"); +} + +// ── Guest sends to self (WASM actor address from host) ────────────────────── + +#[test] +fn guest_sends_to_self_via_framed_address() { + // The payload contains the WASM actor's own address as the dest. + // This creates a self-send that should be delivered next tick. + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, guest_wasm("echo")).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let wasm_addr = rt.spawn(actor).unwrap(); + + // Frame with wasm_addr as dest, payload is a framed msg for inbox + let inner = framed_msg(inbox.addr(), b"self-bounce"); + rt.send_to(wasm_addr, framed_msg(&wasm_addr, &inner.0)).unwrap(); + rt.tick(); // echo sends inner to itself + rt.tick(); // processes inner, echoes payload to inbox + + let msg = inbox.try_recv().expect("self-send should eventually reach inbox"); + assert_eq!(msg.0, b"self-bounce"); +} + +// ── Guest with i32.rotr/rotl bit rotation ─────────────────────────────────── + +#[test] +fn guest_uses_bit_rotation() { + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Rotate left: 1 << 4 = 16 (i32.rotl(1, 4) = 16) + (i32.store8 (i32.const 200) + (i32.rotl (i32.const 1) (i32.const 4)) + ) + (call $send (local.get $ptr) (i32.const 200) (i32.const 1)) + ) + ) + "#; + let wasm = wat::parse_str(wat).unwrap(); + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, wasm).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + rt.send_to(addr, framed_msg(inbox.addr(), b"rot")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0[0], 16, "rotl(1, 4) = 16"); +} + +// ── Guest with i32.clz/ctz/popcnt ────────────────────────────────────────── + +#[test] +fn guest_uses_bit_counting() { + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; clz(256) = 23 (256 = 0x100, 23 leading zeros in 32-bit) + (i32.store8 (i32.const 200) (i32.clz (i32.const 256))) + ;; ctz(256) = 8 (256 = 0x100, 8 trailing zeros) + (i32.store8 (i32.const 201) (i32.ctz (i32.const 256))) + ;; popcnt(0xFF) = 8 (8 bits set) + (i32.store8 (i32.const 202) (i32.popcnt (i32.const 255))) + (call $send (local.get $ptr) (i32.const 200) (i32.const 3)) + ) + ) + "#; + let wasm = wat::parse_str(wat).unwrap(); + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, wasm).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + rt.send_to(addr, framed_msg(inbox.addr(), b"bits")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0[0], 23, "clz(256) = 23"); + assert_eq!(msg.0[1], 8, "ctz(256) = 8"); + assert_eq!(msg.0[2], 8, "popcnt(255) = 8"); +} + +// ── Spawn 10 actors, stop every other one, remaining still work ───────────── + +#[test] +fn stop_every_other_actor_remaining_work() { + let engine = SharedEngine::new().unwrap(); + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + + let mut addrs = Vec::new(); + for _ in 0..10 { + let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap(); + addrs.push(rt.spawn(actor).unwrap()); + } + + // Stop even-indexed actors + for (i, addr) in addrs.iter().enumerate() { + if i % 2 == 0 { + rt.stop_actor(*addr); + } + } + rt.tick(); + rt.tick(); + + // Send to all — only odd-indexed should respond + for (i, addr) in addrs.iter().enumerate() { + rt.send_to(*addr, framed_msg(inbox.addr(), &[i as u8])).ok(); + } + rt.tick(); + + let mut received = Vec::new(); + while let Some(msg) = inbox.try_recv() { + received.push(msg.0[0]); + } + received.sort(); + assert_eq!(received, vec![1, 3, 5, 7, 9], "only odd-indexed actors should respond"); } \ No newline at end of file