From 62fac77e12b50c3b1e13d216168bfb6cb8dbf0f8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:00:38 -0800 Subject: [PATCH 001/263] Add stub example --- docs/.vitepress/config.js | 1 + docs/src/examples/tree.md | 15 ++++++ examples/Cargo.lock | 10 ++++ examples/Cargo.toml | 1 + examples/tree/.gitignore | 2 + examples/tree/Cargo.toml | 18 +++++++ examples/tree/deploy/tree-keypair.json | 66 ++++++++++++++++++++++++++ examples/tree/src/lib.rs | 4 ++ examples/tree/src/program.rs | 11 +++++ examples/tree/src/tests.rs | 1 + examples/tree/src/tree/tree.s | 5 ++ 11 files changed, 134 insertions(+) create mode 100644 docs/src/examples/tree.md create mode 100644 examples/tree/.gitignore create mode 100644 examples/tree/Cargo.toml create mode 100644 examples/tree/deploy/tree-keypair.json create mode 100644 examples/tree/src/lib.rs create mode 100644 examples/tree/src/program.rs create mode 100644 examples/tree/src/tests.rs create mode 100644 examples/tree/src/tree/tree.s diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 1418e948..7a2152d4 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -40,6 +40,7 @@ export default { { text: "Fibonacci", link: "/examples/fibonacci" }, { text: "Transfer", link: "/examples/transfer" }, { text: "Counter", link: "/examples/counter" }, + { text: "Tree", link: "/examples/tree" }, ], }, { diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md new file mode 100644 index 00000000..5becd78b --- /dev/null +++ b/docs/src/examples/tree.md @@ -0,0 +1,15 @@ +# Tree + + + +## Overview + + + +## :white_check_mark: All tests + +::: details `tests.rs` + +<<< ../../../examples/tree/src/tests.rs{rs:line-numbers} + +::: diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 1eb40022..5096be0a 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -3566,6 +3566,16 @@ dependencies = [ "test-utils", ] +[[package]] +name = "tree" +version = "0.1.0" +dependencies = [ + "mollusk-svm", + "pinocchio", + "solana-sdk", + "test-utils", +] + [[package]] name = "typenum" version = "1.19.0" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a150c96a..a8c99252 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -7,6 +7,7 @@ members = [ "hello-dasmac", "memo", "transfer", + "tree", "utils/build-examples", "utils/deps/build", "utils/deps/program" diff --git a/examples/tree/.gitignore b/examples/tree/.gitignore new file mode 100644 index 00000000..5c70e2f5 --- /dev/null +++ b/examples/tree/.gitignore @@ -0,0 +1,2 @@ +deploy/* +!deploy/tree-keypair.json diff --git a/examples/tree/Cargo.toml b/examples/tree/Cargo.toml new file mode 100644 index 00000000..0fe4dde9 --- /dev/null +++ b/examples/tree/Cargo.toml @@ -0,0 +1,18 @@ +[dependencies] +pinocchio.workspace = true + +[dev-dependencies] +mollusk-svm.workspace = true +solana-sdk.workspace = true +test-utils.path = "../utils/test-utils" + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true + +[package] +edition = "2021" +name = "tree" +version = "0.1.0" diff --git a/examples/tree/deploy/tree-keypair.json b/examples/tree/deploy/tree-keypair.json new file mode 100644 index 00000000..dbfa0759 --- /dev/null +++ b/examples/tree/deploy/tree-keypair.json @@ -0,0 +1,66 @@ +[ + 144, + 189, + 2, + 152, + 30, + 247, + 50, + 7, + 149, + 57, + 33, + 33, + 80, + 8, + 156, + 153, + 50, + 94, + 197, + 163, + 207, + 177, + 54, + 147, + 219, + 169, + 113, + 90, + 102, + 192, + 17, + 126, + 180, + 183, + 33, + 135, + 191, + 238, + 124, + 63, + 243, + 193, + 203, + 40, + 64, + 131, + 49, + 191, + 80, + 28, + 145, + 125, + 189, + 141, + 216, + 39, + 227, + 119, + 47, + 101, + 198, + 184, + 72, + 169 +] diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs new file mode 100644 index 00000000..b74a95a0 --- /dev/null +++ b/examples/tree/src/lib.rs @@ -0,0 +1,4 @@ +mod program; + +#[cfg(test)] +mod tests; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs new file mode 100644 index 00000000..48ca7a41 --- /dev/null +++ b/examples/tree/src/program.rs @@ -0,0 +1,11 @@ +use pinocchio::{entrypoint, AccountView, Address, ProgramResult}; + +entrypoint!(process_instruction); + +fn process_instruction( + _program_id: &Address, + _accounts: &[AccountView], + _instruction_data: &[u8], +) -> ProgramResult { + Ok(()) +} diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/tree/src/tests.rs @@ -0,0 +1 @@ + diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s new file mode 100644 index 00000000..81762bde --- /dev/null +++ b/examples/tree/src/tree/tree.s @@ -0,0 +1,5 @@ +.globl entrypoint + +entrypoint: + mov64 r0, 0 + exit From 873f4fae1878b7b6fd4b83980d7b9a1cfd6d4821 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:08:34 -0800 Subject: [PATCH 002/263] Use lazy stub --- examples/tree/artifacts/dumps/asm.txt | 50 +++++++++++ examples/tree/artifacts/dumps/rs.txt | 109 +++++++++++++++++++++++ examples/tree/artifacts/rs-disassembly.s | 5 ++ examples/tree/src/lib.rs | 1 + examples/tree/src/program.rs | 15 ++-- 5 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 examples/tree/artifacts/dumps/asm.txt create mode 100644 examples/tree/artifacts/dumps/rs.txt create mode 100644 examples/tree/artifacts/rs-disassembly.s diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt new file mode 100644 index 00000000..435654bf --- /dev/null +++ b/examples/tree/artifacts/dumps/asm.txt @@ -0,0 +1,50 @@ +tree.so +ELF Header + Magic 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class ELF64 + Data 2's complement, little endian + Version 1 (current) + OS/ABI UNIX - System V + ABI Version 0 + Type DYN (Shared object file) + Machine EM_BPF + Version 0x1 + Entry point address 0x40 + Start of program headers 64 (bytes into file) + Start of section headers 96 (bytes into file) + Flags 0x0 + Size of this header 64 (bytes) + Size of program headers 56 (bytes) + Number of program headers 0 + Size of section headers 64 (bytes) + Number of section headers 3 + Section header string table index 2 +There are 3 section headers, starting at offset 0x60 + +Section Headers + [Nr] Name Type Address Off Size ES Flg Lk Inf Al + [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 + [ 1] .text PROGBITS 0000000000000040 000040 000010 00 AX 0 0 4 + [ 2] .s STRTAB 0000000000000000 000050 00000a 00 0 0 1 +Key to Flags + W (write), A (alloc), X (execute), M (merge), S (strings), I (info), + L (link order), O (extra OS processing required), G (group), T (TLS), + C (compressed), x (unknown), o (OS specific), E (exclude), + R (retain), p (processor specific) + +There are no program headers in this file. + + Section to Segment mapping + Segment Sections... + None .text .s + +There are no relocations in this file. +There are no section groups in this file. + +tree.so file format elf64-bpf + +Disassembly of section .text + +0000000000000040 <.text> + 8 b7 00 00 00 00 00 00 00 r0 = 0x0 + 9 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt new file mode 100644 index 00000000..ec1f5096 --- /dev/null +++ b/examples/tree/artifacts/dumps/rs.txt @@ -0,0 +1,109 @@ +tree.so +ELF Header + Magic 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class ELF64 + Data 2's complement, little endian + Version 1 (current) + OS/ABI UNIX - System V + ABI Version 0 + Type DYN (Shared object file) + Machine Solana Bytecode Format + Version 0x1 + Entry point address 0x0 + Start of program headers 64 (bytes into file) + Start of section headers 2600 (bytes into file) + Flags 0x4 + Size of this header 64 (bytes) + Size of program headers 56 (bytes) + Number of program headers 4 + Size of section headers 64 (bytes) + Number of section headers 8 + Section header string table index 6 +There are 8 section headers, starting at offset 0xa28 + +Section Headers + [Nr] Name Type Address Off Size ES Flg Lk Inf Al + [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 + [ 1] .text PROGBITS 0000000000000000 000120 000018 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000138 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000140 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000140 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000140 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0004b8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0004f6 000532 00 0 0 1 +Key to Flags + W (write), A (alloc), X (execute), M (merge), S (strings), I (info), + L (link order), O (extra OS processing required), G (group), T (TLS), + C (compressed), x (unknown), o (OS specific), E (exclude), + R (retain), p (processor specific) + +Elf file type is DYN (Shared object file) +Entry point 0x0 +There are 4 program headers, starting at offset 64 + +Program Headers + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000018 0x000018 E 0x8 + LOAD 0x000138 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000140 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000140 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + + Section to Segment mapping + Segment Sections... + 00 .text + 01 .rodata + 02 .bss.stack + 03 .bss.heap + None .symtab .shstrtab .strtab + +There are no relocations in this file. + +Symbol table '.symtab' contains 37 entries + Num Value Size Type Bind Vis Ndx Name + 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.f7f35e91187ba07f-cgu.0 + 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 68vyx9rfiautweaa6qunv68kh + 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 + 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 + 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 + 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 + 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 + 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 + 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 + 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 + 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 + 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 + 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 + 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 + 32 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start + 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end + 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start + 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end + 36 0000000000000000 24 FUNC GLOBAL DEFAULT 1 entrypoint +There are no section groups in this file. + +tree.so file format elf64-sbf + +Disassembly of section .text + +0000000000000000 + 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 + 8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 10 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s new file mode 100644 index 00000000..50457dc6 --- /dev/null +++ b/examples/tree/artifacts/rs-disassembly.s @@ -0,0 +1,5 @@ +.globl entrypoint + +entrypoint: + mov64 r0, 0 + exit diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs index b74a95a0..569ef2f5 100644 --- a/examples/tree/src/lib.rs +++ b/examples/tree/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(test), no_std)] mod program; #[cfg(test)] diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 48ca7a41..5bf7a274 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,11 +1,12 @@ -use pinocchio::{entrypoint, AccountView, Address, ProgramResult}; +use pinocchio::{ + entrypoint::InstructionContext, lazy_program_entrypoint, no_allocator, nostd_panic_handler, + ProgramResult, +}; -entrypoint!(process_instruction); +lazy_program_entrypoint!(process_instruction); +nostd_panic_handler!(); +no_allocator!(); -fn process_instruction( - _program_id: &Address, - _accounts: &[AccountView], - _instruction_data: &[u8], -) -> ProgramResult { +pub fn process_instruction(_context: InstructionContext) -> ProgramResult { Ok(()) } From 0b6555baa2dbc84294ea97715225d4f286224b50 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:13:38 -0800 Subject: [PATCH 003/263] Clean up background consistency --- docs/src/examples/fibonacci.md | 2 +- docs/src/examples/tree.md | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/src/examples/fibonacci.md b/docs/src/examples/fibonacci.md index c279ee7b..fb1fda1f 100644 --- a/docs/src/examples/fibonacci.md +++ b/docs/src/examples/fibonacci.md @@ -4,7 +4,7 @@ -## :1234: Fibonacci sequence background +## :1234: Background The [Fibonacci sequence] is a classic mathematical sequence where each number is the sum of the two preceding ones, typically starting with $F(0) = 0$ and diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 5becd78b..4c0877e6 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -2,9 +2,7 @@ -## Overview - - +## Background ## :white_check_mark: All tests From c7e234c615e3ae45525f90722d742cb0f29f0361 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:16:01 -0800 Subject: [PATCH 004/263] Update memo layout --- docs/src/examples/memo.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/src/examples/memo.md b/docs/src/examples/memo.md index 1b0d5d8f..65b8c06c 100644 --- a/docs/src/examples/memo.md +++ b/docs/src/examples/memo.md @@ -4,7 +4,13 @@ -## :world_map: Memory map background +## :desktop_computer: Background + +This program logs arbitrary message data passed via instruction data. It accepts +no accounts and simply writes the provided bytes to the program log using the +[`sol_log_`] syscall. If any accounts are passed, the program returns an error. + +## :world_map: Memory map layout The [SBPF instruction set architecture] defines 12 registers, including 10 general-purpose registers `r0` through `r9`. At the start of instruction From b34183e595cd6424707ae2c00ec8026eb0eb6120 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:21:32 -0800 Subject: [PATCH 005/263] Write background --- docs/src/examples/tree.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 4c0877e6..3049c649 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -4,6 +4,11 @@ ## Background +This example implements a [red-black tree][wikipedia tree page] in both +[SBPF assembly](../index.md) and Rust. It benchmarks various operations and code +paths side-by-side for a comprehensive breakdown of assembly vs Rust +performance. + ## :white_check_mark: All tests ::: details `tests.rs` @@ -11,3 +16,5 @@ <<< ../../../examples/tree/src/tests.rs{rs:line-numbers} ::: + +[wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree \ No newline at end of file From fe27b5361bfc9120db97ea48d5e40d9c67056dd4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 16:41:31 -0800 Subject: [PATCH 006/263] Add constant injection scaffolding --- examples/Cargo.lock | 83 +++++++++++----- examples/Cargo.toml | 6 ++ examples/tree/Cargo.toml | 4 + examples/tree/build-macros/Cargo.toml | 13 +++ examples/tree/build-macros/src/lib.rs | 138 ++++++++++++++++++++++++++ examples/tree/build.rs | 8 ++ examples/tree/src/tree/tree.s | 5 + examples/tree/types/Cargo.toml | 11 ++ examples/tree/types/src/injection.rs | 24 +++++ examples/tree/types/src/lib.rs | 20 ++++ 10 files changed, 287 insertions(+), 25 deletions(-) create mode 100644 examples/tree/build-macros/Cargo.toml create mode 100644 examples/tree/build-macros/src/lib.rs create mode 100644 examples/tree/build.rs create mode 100644 examples/tree/types/Cargo.toml create mode 100644 examples/tree/types/src/injection.rs create mode 100644 examples/tree/types/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 5096be0a..71b032a0 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -254,7 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -280,7 +280,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -355,7 +355,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -493,7 +493,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -527,6 +527,16 @@ dependencies = [ "regex", ] +[[package]] +name = "build-macros" +version = "0.1.0" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "bv" version = "0.11.1" @@ -554,7 +564,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -627,7 +637,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -667,6 +677,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "counter" version = "0.1.0" @@ -767,7 +786,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -884,7 +903,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -929,7 +948,7 @@ checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -949,7 +968,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1255,7 +1274,7 @@ checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1576,7 +1595,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1718,9 +1737,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1750,14 +1769,14 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -2000,7 +2019,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2999,7 +3018,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3419,9 +3438,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -3462,7 +3481,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3473,7 +3492,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3574,6 +3593,7 @@ dependencies = [ "pinocchio", "solana-sdk", "test-utils", + "types", ] [[package]] @@ -3582,12 +3602,25 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "types" +version = "0.1.0" +dependencies = [ + "build-macros", +] + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unreachable" version = "1.0.0" @@ -3715,7 +3748,7 @@ checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3735,5 +3768,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a8c99252..72d3827c 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,6 +8,8 @@ members = [ "memo", "transfer", "tree", + "tree/build-macros", + "tree/types", "utils/build-examples", "utils/deps/build", "utils/deps/program" @@ -16,13 +18,17 @@ resolver = "2" [workspace.dependencies] cargo-manifest = "0.19.1" +convert_case = "0.11.0" fib-rs = "1.0.0" mollusk-svm = "0.10.1" pinocchio = {version = "0.10.1", features = ["cpi"]} pinocchio-system = "0.5.0" +proc-macro2 = "1.0.106" +quote = "1.0.44" regex = "1.12.2" solana-rent = "3.0.0" solana-sdk = "3.0.0" +syn = { version = "2.0.114", features = ["full"] } [workspace.lints.rust] unexpected_cfgs = {level = "warn", check-cfg = ['cfg(target_os, values("solana"))']} diff --git a/examples/tree/Cargo.toml b/examples/tree/Cargo.toml index 0fe4dde9..1d8d137d 100644 --- a/examples/tree/Cargo.toml +++ b/examples/tree/Cargo.toml @@ -1,5 +1,9 @@ +[build-dependencies] +types = { path = "types", features = ["std"] } + [dependencies] pinocchio.workspace = true +types.path = "types" [dev-dependencies] mollusk-svm.workspace = true diff --git a/examples/tree/build-macros/Cargo.toml b/examples/tree/build-macros/Cargo.toml new file mode 100644 index 00000000..2845d260 --- /dev/null +++ b/examples/tree/build-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "build-macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +convert_case.workspace = true +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true diff --git a/examples/tree/build-macros/src/lib.rs b/examples/tree/build-macros/src/lib.rs new file mode 100644 index 00000000..d03c2592 --- /dev/null +++ b/examples/tree/build-macros/src/lib.rs @@ -0,0 +1,138 @@ +use convert_case::{Case, Casing}; +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput, Fields, Lit, Meta}; + +/// Derive macro for generating ASM error code constants from an enum. +/// +/// Each variant must have a doc comment that will become the ASM comment. +/// Variant names are converted from PascalCase to SCREAMING_SNAKE_CASE +/// and prefixed with `E_`. +/// +/// # Example +/// ```ignore +/// #[derive(AsmErrorCodes)] +/// pub enum ErrorCodes { +/// /// An invalid number of accounts were passed. +/// NAccounts, +/// /// The user account has nonzero data length. +/// UserData, +/// } +/// ``` +/// +/// Generates: +/// ```text +/// # Error codes. +/// # ------------ +/// .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. +/// .equ E_USER_DATA, 2 # The user account has nonzero data length. +/// ``` +#[proc_macro_derive(AsmErrorCodes)] +pub fn derive_asm_error_codes(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; + + let variants = match &input.data { + Data::Enum(data) => &data.variants, + _ => { + return syn::Error::new_spanned(&input, "AsmErrorCodes can only be derived for enums") + .to_compile_error() + .into(); + } + }; + + let mut error_entries = Vec::new(); + + for (idx, variant) in variants.iter().enumerate() { + // Ensure no fields. + if !matches!(variant.fields, Fields::Unit) { + return syn::Error::new_spanned( + &variant.fields, + "AsmErrorCodes variants must be unit variants (no fields)", + ) + .to_compile_error() + .into(); + } + + // Extract doc comment. + let doc_comment = extract_doc_comment(&variant.attrs); + let doc_comment = match doc_comment { + Some(doc) => doc, + None => { + return syn::Error::new_spanned( + &variant.ident, + format!("Variant `{}` must have a doc comment", variant.ident), + ) + .to_compile_error() + .into(); + } + }; + + // Validate doc comment ends with period. + if !doc_comment.ends_with('.') { + return syn::Error::new_spanned( + &variant.ident, + format!( + "Doc comment for `{}` must end with a period: {:?}", + variant.ident, doc_comment + ), + ) + .to_compile_error() + .into(); + } + + // Convert variant name to SCREAMING_SNAKE_CASE. + let asm_name = format!( + "E_{}", + variant.ident.to_string().to_case(Case::UpperSnake) + ); + + // Error codes start at 1. + let value = idx + 1; + + error_entries.push((asm_name, value, doc_comment)); + } + + // Generate the to_asm() implementation. + let asm_lines: Vec = error_entries + .iter() + .map(|(name, value, comment)| format!(".equ {}, {} # {}", name, value, comment)) + .collect(); + + let header = "# Error codes.\n# ------------"; + let body = asm_lines.join("\n"); + + let expanded = quote! { + impl #name { + /// Generate ASM constants for this enum. + pub fn to_asm() -> alloc::string::String { + alloc::format!("{}\n{}\n", #header, #body) + } + } + }; + + TokenStream::from(expanded) +} + +/// Extract the doc comment from attributes. +fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { + let mut doc_parts = Vec::new(); + + for attr in attrs { + if attr.path().is_ident("doc") { + if let Meta::NameValue(meta) = &attr.meta { + if let syn::Expr::Lit(expr_lit) = &meta.value { + if let Lit::Str(lit_str) = &expr_lit.lit { + doc_parts.push(lit_str.value().trim().to_string()); + } + } + } + } + } + + if doc_parts.is_empty() { + None + } else { + Some(doc_parts.join(" ")) + } +} diff --git a/examples/tree/build.rs b/examples/tree/build.rs new file mode 100644 index 00000000..7ba69174 --- /dev/null +++ b/examples/tree/build.rs @@ -0,0 +1,8 @@ +use std::path::Path; + +fn main() { + // Inject constants into ASM file. + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let asm_path = Path::new(manifest_dir).join("src/tree/tree.s"); + types::inject_asm(&asm_path); +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 81762bde..88d3a2f2 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,3 +1,8 @@ +# Error codes. +# ------------ +.equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. +.equ E_USER_DATA, 2 # The user account has nonzero data length. + .globl entrypoint entrypoint: diff --git a/examples/tree/types/Cargo.toml b/examples/tree/types/Cargo.toml new file mode 100644 index 00000000..880edd76 --- /dev/null +++ b/examples/tree/types/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "types" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +std = [] + +[dependencies] +build-macros.path = "../build-macros" diff --git a/examples/tree/types/src/injection.rs b/examples/tree/types/src/injection.rs new file mode 100644 index 00000000..83e10092 --- /dev/null +++ b/examples/tree/types/src/injection.rs @@ -0,0 +1,24 @@ +use crate::ErrorCodes; +use std::fs; +use std::path::Path; + +/// Inject generated constants into the ASM file. +/// +/// This replaces everything before `.globl entrypoint` with the generated constants. +pub fn inject_asm(asm_path: &Path) { + const GLOBAL_ENTRYPOINT: &str = ".globl entrypoint"; + + let content = fs::read_to_string(asm_path).expect("Failed to read assembly file"); + + let global_pos = content + .find(GLOBAL_ENTRYPOINT) + .expect("Could not find '.globl entrypoint' in assembly file"); + + let after_global = &content[global_pos..]; + let constants = ErrorCodes::to_asm(); + let new_content = std::format!("{}\n{}", constants, after_global); + + if new_content != content { + fs::write(asm_path, new_content).expect("Failed to write assembly file"); + } +} diff --git a/examples/tree/types/src/lib.rs b/examples/tree/types/src/lib.rs new file mode 100644 index 00000000..6ceb76fe --- /dev/null +++ b/examples/tree/types/src/lib.rs @@ -0,0 +1,20 @@ +#![no_std] + +extern crate alloc; +use build_macros::AsmErrorCodes; + +#[cfg(feature = "std")] +mod injection; +#[cfg(feature = "std")] +pub use injection::inject_asm; +#[cfg(feature = "std")] +extern crate std; + +#[derive(AsmErrorCodes)] +#[repr(u64)] +pub enum ErrorCodes { + /// An invalid number of accounts were passed. + NAccounts, + /// The user account has nonzero data length. + UserData, +} From ce70042d217dc74f3d0849f2af81e3b3745ea71f Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Feb 2026 17:08:45 -0800 Subject: [PATCH 007/263] Add constants macro --- examples/tree/build-macros/src/lib.rs | 176 +++++++++++++++++++++++++- examples/tree/src/tree/tree.s | 5 +- examples/tree/types/src/injection.rs | 6 +- examples/tree/types/src/lib.rs | 11 +- 4 files changed, 192 insertions(+), 6 deletions(-) diff --git a/examples/tree/build-macros/src/lib.rs b/examples/tree/build-macros/src/lib.rs index d03c2592..2475abc4 100644 --- a/examples/tree/build-macros/src/lib.rs +++ b/examples/tree/build-macros/src/lib.rs @@ -1,7 +1,11 @@ use convert_case::{Case, Casing}; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields, Lit, Meta}; +use syn::{ + braced, + parse::{Parse, ParseStream}, + parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, Visibility, +}; /// Derive macro for generating ASM error code constants from an enum. /// @@ -136,3 +140,173 @@ fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { Some(doc_parts.join(" ")) } } + +// ============================================================================ +// asm_constants! macro +// ============================================================================ + +struct ConstantDef { + doc: String, + name: Ident, + value: LitInt, +} + +struct ConstantGroup { + doc: String, + vis: Visibility, + name: Ident, + prefix: Option, + constants: Vec, +} + +struct AsmConstantsInput { + groups: Vec, +} + +impl Parse for AsmConstantsInput { + fn parse(input: ParseStream) -> syn::Result { + let mut groups = Vec::new(); + + while !input.is_empty() { + // Parse doc comments for the module. + let attrs = input.call(syn::Attribute::parse_outer)?; + let doc = extract_doc_comment(&attrs) + .ok_or_else(|| input.error("Module must have a doc comment"))?; + + // Parse visibility and `mod`. + let vis: Visibility = input.parse()?; + input.parse::()?; + let name: Ident = input.parse()?; + + // Parse module body. + let content; + braced!(content in input); + + // Check for optional prefix. + let prefix = if content.peek(Ident) { + let ident: Ident = content.parse()?; + if ident == "prefix" { + content.parse::()?; + let prefix_lit: syn::LitStr = content.parse()?; + content.parse::()?; + Some(prefix_lit.value()) + } else { + return Err(syn::Error::new(ident.span(), "Expected 'prefix' or constant")); + } + } else { + None + }; + + // Parse constants. + let mut constants = Vec::new(); + while !content.is_empty() { + let const_attrs = content.call(syn::Attribute::parse_outer)?; + let const_doc = extract_doc_comment(&const_attrs) + .ok_or_else(|| content.error("Constant must have a doc comment"))?; + + let const_name: Ident = content.parse()?; + content.parse::()?; + let const_value: LitInt = content.parse()?; + + // Optional trailing comma. + let _ = content.parse::(); + + constants.push(ConstantDef { + doc: const_doc, + name: const_name, + value: const_value, + }); + } + + groups.push(ConstantGroup { + doc, + vis, + name, + prefix, + constants, + }); + } + + Ok(AsmConstantsInput { groups }) + } +} + +/// Macro for defining groups of ASM constants. +/// +/// # Example +/// ```ignore +/// asm_constants! { +/// /// Memory map. +/// pub mod memory_map { +/// /// Number of accounts expected. +/// N_ACCOUNTS = 2, +/// /// Offset to instruction data. +/// IX_DATA = 8, +/// } +/// +/// /// Error codes. +/// pub mod error_codes { +/// prefix = "E_", +/// /// An invalid number of accounts were passed. +/// N_ACCOUNTS = 1, +/// } +/// } +/// ``` +#[proc_macro] +pub fn asm_constants(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as AsmConstantsInput); + + let modules = input.groups.iter().map(|group| { + let vis = &group.vis; + let mod_name = &group.name; + let prefix = group.prefix.as_deref().unwrap_or(""); + + // Generate Rust constants. + let const_defs = group.constants.iter().map(|c| { + let name = &c.name; + let value = &c.value; + let doc = &c.doc; + quote! { + #[doc = #doc] + pub const #name: u64 = #value; + } + }); + + // Generate ASM output. + let header_text = &group.doc; + let header_line = "-".repeat(header_text.len()); + let header = format!("# {}\n# {}", header_text, header_line); + + let asm_lines: Vec = group + .constants + .iter() + .map(|c| { + format!( + ".equ {}{}, {} # {}", + prefix, + c.name.to_string(), + c.value, + c.doc + ) + }) + .collect(); + let body = asm_lines.join("\n"); + + quote! { + #vis mod #mod_name { + #(#const_defs)* + + /// Generate ASM constants for this module. + pub fn to_asm() -> alloc::string::String { + alloc::format!("{}\n{}\n", #header, #body) + } + } + } + }); + + let expanded = quote! { + #(#modules)* + }; + + TokenStream::from(expanded) +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 88d3a2f2..c35b6e94 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,8 +1,11 @@ +# Memory map. +# ----------- +.equ N_ACCOUNTS, 2 # Number of accounts expected. + # Error codes. # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. .equ E_USER_DATA, 2 # The user account has nonzero data length. - .globl entrypoint entrypoint: diff --git a/examples/tree/types/src/injection.rs b/examples/tree/types/src/injection.rs index 83e10092..3ddaae8b 100644 --- a/examples/tree/types/src/injection.rs +++ b/examples/tree/types/src/injection.rs @@ -1,4 +1,4 @@ -use crate::ErrorCodes; +use crate::{memory_map, ErrorCodes}; use std::fs; use std::path::Path; @@ -15,8 +15,8 @@ pub fn inject_asm(asm_path: &Path) { .expect("Could not find '.globl entrypoint' in assembly file"); let after_global = &content[global_pos..]; - let constants = ErrorCodes::to_asm(); - let new_content = std::format!("{}\n{}", constants, after_global); + let constants = std::format!("{}\n{}", memory_map::to_asm(), ErrorCodes::to_asm()); + let new_content = std::format!("{}{}", constants, after_global); if new_content != content { fs::write(asm_path, new_content).expect("Failed to write assembly file"); diff --git a/examples/tree/types/src/lib.rs b/examples/tree/types/src/lib.rs index 6ceb76fe..9002e078 100644 --- a/examples/tree/types/src/lib.rs +++ b/examples/tree/types/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] extern crate alloc; -use build_macros::AsmErrorCodes; #[cfg(feature = "std")] mod injection; @@ -10,6 +9,8 @@ pub use injection::inject_asm; #[cfg(feature = "std")] extern crate std; +use build_macros::{asm_constants, AsmErrorCodes}; + #[derive(AsmErrorCodes)] #[repr(u64)] pub enum ErrorCodes { @@ -18,3 +19,11 @@ pub enum ErrorCodes { /// The user account has nonzero data length. UserData, } + +asm_constants! { + /// Memory map. + pub mod memory_map { + /// Number of accounts expected. + N_ACCOUNTS = 2, + } +} From 9ce1f7db387de01b1872fc242943175e178f534c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:15:44 -0800 Subject: [PATCH 008/263] Rename to common --- examples/Cargo.lock | 16 ++++++++-------- examples/Cargo.toml | 2 +- examples/tree/Cargo.toml | 4 ++-- examples/tree/build.rs | 2 +- examples/tree/{types => common}/Cargo.toml | 2 +- examples/tree/{types => common}/src/injection.rs | 0 examples/tree/{types => common}/src/lib.rs | 0 7 files changed, 13 insertions(+), 13 deletions(-) rename examples/tree/{types => common}/Cargo.toml (89%) rename examples/tree/{types => common}/src/injection.rs (100%) rename examples/tree/{types => common}/src/lib.rs (100%) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 71b032a0..e646d158 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -665,6 +665,13 @@ dependencies = [ "unreachable", ] +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "build-macros", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -3589,11 +3596,11 @@ dependencies = [ name = "tree" version = "0.1.0" dependencies = [ + "common", "mollusk-svm", "pinocchio", "solana-sdk", "test-utils", - "types", ] [[package]] @@ -3602,13 +3609,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "types" -version = "0.1.0" -dependencies = [ - "build-macros", -] - [[package]] name = "unicode-ident" version = "1.0.22" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 72d3827c..bf1cf964 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -9,7 +9,7 @@ members = [ "transfer", "tree", "tree/build-macros", - "tree/types", + "tree/common", "utils/build-examples", "utils/deps/build", "utils/deps/program" diff --git a/examples/tree/Cargo.toml b/examples/tree/Cargo.toml index 1d8d137d..87eb5e99 100644 --- a/examples/tree/Cargo.toml +++ b/examples/tree/Cargo.toml @@ -1,9 +1,9 @@ [build-dependencies] -types = { path = "types", features = ["std"] } +common = { path = "common", features = ["std"] } [dependencies] pinocchio.workspace = true -types.path = "types" +common.path = "common" [dev-dependencies] mollusk-svm.workspace = true diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 7ba69174..c9187bc7 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -4,5 +4,5 @@ fn main() { // Inject constants into ASM file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); let asm_path = Path::new(manifest_dir).join("src/tree/tree.s"); - types::inject_asm(&asm_path); + common::inject_asm(&asm_path); } diff --git a/examples/tree/types/Cargo.toml b/examples/tree/common/Cargo.toml similarity index 89% rename from examples/tree/types/Cargo.toml rename to examples/tree/common/Cargo.toml index 880edd76..07155934 100644 --- a/examples/tree/types/Cargo.toml +++ b/examples/tree/common/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "types" +name = "common" version = "0.1.0" edition = "2021" diff --git a/examples/tree/types/src/injection.rs b/examples/tree/common/src/injection.rs similarity index 100% rename from examples/tree/types/src/injection.rs rename to examples/tree/common/src/injection.rs diff --git a/examples/tree/types/src/lib.rs b/examples/tree/common/src/lib.rs similarity index 100% rename from examples/tree/types/src/lib.rs rename to examples/tree/common/src/lib.rs From ada10d29308f7f35f2e0adce43382bfdb4a38354 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:24:56 -0800 Subject: [PATCH 009/263] Refactor interface --- examples/Cargo.lock | 16 ++++++------- examples/Cargo.toml | 2 +- examples/tree/Cargo.toml | 4 ++-- examples/tree/build.rs | 19 +++++++++++++-- examples/tree/common/src/injection.rs | 24 ------------------- .../tree/{common => interface}/Cargo.toml | 6 +---- .../src/lib.rs => interface/src/common.rs} | 11 --------- examples/tree/interface/src/lib.rs | 9 +++++++ examples/tree/interface/src/stack.rs | 1 + 9 files changed, 39 insertions(+), 53 deletions(-) delete mode 100644 examples/tree/common/src/injection.rs rename examples/tree/{common => interface}/Cargo.toml (66%) rename examples/tree/{common/src/lib.rs => interface/src/common.rs} (69%) create mode 100644 examples/tree/interface/src/lib.rs create mode 100644 examples/tree/interface/src/stack.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index e646d158..41344d45 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -665,13 +665,6 @@ dependencies = [ "unreachable", ] -[[package]] -name = "common" -version = "0.1.0" -dependencies = [ - "build-macros", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -1227,6 +1220,13 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "interface" +version = "0.1.0" +dependencies = [ + "build-macros", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -3596,7 +3596,7 @@ dependencies = [ name = "tree" version = "0.1.0" dependencies = [ - "common", + "interface", "mollusk-svm", "pinocchio", "solana-sdk", diff --git a/examples/Cargo.toml b/examples/Cargo.toml index bf1cf964..13621118 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -9,7 +9,7 @@ members = [ "transfer", "tree", "tree/build-macros", - "tree/common", + "tree/interface", "utils/build-examples", "utils/deps/build", "utils/deps/program" diff --git a/examples/tree/Cargo.toml b/examples/tree/Cargo.toml index 87eb5e99..40e66a0b 100644 --- a/examples/tree/Cargo.toml +++ b/examples/tree/Cargo.toml @@ -1,9 +1,9 @@ [build-dependencies] -common = { path = "common", features = ["std"] } +interface.path = "interface" [dependencies] pinocchio.workspace = true -common.path = "common" +interface.path = "interface" [dev-dependencies] mollusk-svm.workspace = true diff --git a/examples/tree/build.rs b/examples/tree/build.rs index c9187bc7..8a32a34b 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,8 +1,23 @@ -use std::path::Path; +use std::{fs, path::Path}; fn main() { // Inject constants into ASM file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); let asm_path = Path::new(manifest_dir).join("src/tree/tree.s"); - common::inject_asm(&asm_path); + + const MARKER: &str = ".globl entrypoint"; + + let content = fs::read_to_string(&asm_path).unwrap(); + let marker_pos = content.find(MARKER).unwrap(); + + let constants = format!( + "{}\n{}", + interface::memory_map::to_asm(), + interface::ErrorCodes::to_asm() + ); + let new_content = format!("{}{}", constants, &content[marker_pos..]); + + if new_content != content { + fs::write(&asm_path, new_content).unwrap(); + } } diff --git a/examples/tree/common/src/injection.rs b/examples/tree/common/src/injection.rs deleted file mode 100644 index 3ddaae8b..00000000 --- a/examples/tree/common/src/injection.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::{memory_map, ErrorCodes}; -use std::fs; -use std::path::Path; - -/// Inject generated constants into the ASM file. -/// -/// This replaces everything before `.globl entrypoint` with the generated constants. -pub fn inject_asm(asm_path: &Path) { - const GLOBAL_ENTRYPOINT: &str = ".globl entrypoint"; - - let content = fs::read_to_string(asm_path).expect("Failed to read assembly file"); - - let global_pos = content - .find(GLOBAL_ENTRYPOINT) - .expect("Could not find '.globl entrypoint' in assembly file"); - - let after_global = &content[global_pos..]; - let constants = std::format!("{}\n{}", memory_map::to_asm(), ErrorCodes::to_asm()); - let new_content = std::format!("{}{}", constants, after_global); - - if new_content != content { - fs::write(asm_path, new_content).expect("Failed to write assembly file"); - } -} diff --git a/examples/tree/common/Cargo.toml b/examples/tree/interface/Cargo.toml similarity index 66% rename from examples/tree/common/Cargo.toml rename to examples/tree/interface/Cargo.toml index 07155934..fedce035 100644 --- a/examples/tree/common/Cargo.toml +++ b/examples/tree/interface/Cargo.toml @@ -1,11 +1,7 @@ [package] -name = "common" +name = "interface" version = "0.1.0" edition = "2021" -[features] -default = [] -std = [] - [dependencies] build-macros.path = "../build-macros" diff --git a/examples/tree/common/src/lib.rs b/examples/tree/interface/src/common.rs similarity index 69% rename from examples/tree/common/src/lib.rs rename to examples/tree/interface/src/common.rs index 9002e078..0b41e46a 100644 --- a/examples/tree/common/src/lib.rs +++ b/examples/tree/interface/src/common.rs @@ -1,14 +1,3 @@ -#![no_std] - -extern crate alloc; - -#[cfg(feature = "std")] -mod injection; -#[cfg(feature = "std")] -pub use injection::inject_asm; -#[cfg(feature = "std")] -extern crate std; - use build_macros::{asm_constants, AsmErrorCodes}; #[derive(AsmErrorCodes)] diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs new file mode 100644 index 00000000..83463e7f --- /dev/null +++ b/examples/tree/interface/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] + +extern crate alloc; + +mod common; +mod stack; + +pub use common::*; +pub use stack::*; diff --git a/examples/tree/interface/src/stack.rs b/examples/tree/interface/src/stack.rs new file mode 100644 index 00000000..ebaf35ed --- /dev/null +++ b/examples/tree/interface/src/stack.rs @@ -0,0 +1 @@ +//! Stack frame layouts for assembly routines. From 6f098608ab140497f0d64858d30147aa1f81d083 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:33:05 -0800 Subject: [PATCH 010/263] Clean up layout --- examples/tree/build.rs | 15 +++++++-------- examples/tree/interface/src/lib.rs | 2 -- examples/tree/interface/src/stack.rs | 2 +- examples/tree/src/tree/tree.s | 1 + 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 8a32a34b..8b9f33e7 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,22 +1,21 @@ use std::{fs, path::Path}; +const ENTRYPOINT_START: &str = ".globl entrypoint"; + fn main() { - // Inject constants into ASM file. + // Read in the assembly file and find the entrypoint marker. let manifest_dir = env!("CARGO_MANIFEST_DIR"); let asm_path = Path::new(manifest_dir).join("src/tree/tree.s"); - - const MARKER: &str = ".globl entrypoint"; - let content = fs::read_to_string(&asm_path).unwrap(); - let marker_pos = content.find(MARKER).unwrap(); + let marker_pos = content.find(ENTRYPOINT_START).unwrap(); + // Generate the constants and insert them before the entrypoint marker. let constants = format!( "{}\n{}", interface::memory_map::to_asm(), - interface::ErrorCodes::to_asm() + interface::ErrorCodes::to_asm(), ); - let new_content = format!("{}{}", constants, &content[marker_pos..]); - + let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { fs::write(&asm_path, new_content).unwrap(); } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 83463e7f..6771ad11 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,5 +1,3 @@ -#![no_std] - extern crate alloc; mod common; diff --git a/examples/tree/interface/src/stack.rs b/examples/tree/interface/src/stack.rs index ebaf35ed..8b137891 100644 --- a/examples/tree/interface/src/stack.rs +++ b/examples/tree/interface/src/stack.rs @@ -1 +1 @@ -//! Stack frame layouts for assembly routines. + diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index c35b6e94..b840492a 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -6,6 +6,7 @@ # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. .equ E_USER_DATA, 2 # The user account has nonzero data length. + .globl entrypoint entrypoint: From 9213a0f0fc47ff49723a7acbda837bb8d2b22fe0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:51:40 -0800 Subject: [PATCH 011/263] Clean up macros --- examples/tree/build-macros/src/lib.rs | 103 ++++++++++++++++---------- examples/tree/build.rs | 2 +- examples/tree/interface/src/common.rs | 15 ++-- examples/tree/src/tree/tree.s | 4 +- 4 files changed, 74 insertions(+), 50 deletions(-) diff --git a/examples/tree/build-macros/src/lib.rs b/examples/tree/build-macros/src/lib.rs index 2475abc4..d57a8127 100644 --- a/examples/tree/build-macros/src/lib.rs +++ b/examples/tree/build-macros/src/lib.rs @@ -4,18 +4,18 @@ use quote::quote; use syn::{ braced, parse::{Parse, ParseStream}, - parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, Visibility, + parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, }; -/// Derive macro for generating ASM error code constants from an enum. +/// Attribute macro for defining error code enums shared between Rust and ASM. /// -/// Each variant must have a doc comment that will become the ASM comment. -/// Variant names are converted from PascalCase to SCREAMING_SNAKE_CASE -/// and prefixed with `E_`. +/// Automatically adds `#[repr(u64)]` to the enum. Each variant must have a doc +/// comment that will become the ASM comment. Variant names are converted from +/// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. /// /// # Example /// ```ignore -/// #[derive(AsmErrorCodes)] +/// #[error_codes] /// pub enum ErrorCodes { /// /// An invalid number of accounts were passed. /// NAccounts, @@ -24,35 +24,38 @@ use syn::{ /// } /// ``` /// -/// Generates: +/// Generates ASM: /// ```text /// # Error codes. /// # ------------ /// .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. /// .equ E_USER_DATA, 2 # The user account has nonzero data length. /// ``` -#[proc_macro_derive(AsmErrorCodes)] -pub fn derive_asm_error_codes(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); +#[proc_macro_attribute] +pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as DeriveInput); let name = &input.ident; + let vis = &input.vis; + let attrs = &input.attrs; let variants = match &input.data { Data::Enum(data) => &data.variants, _ => { - return syn::Error::new_spanned(&input, "AsmErrorCodes can only be derived for enums") + return syn::Error::new_spanned(&input, "error_codes can only be applied to enums") .to_compile_error() .into(); } }; let mut error_entries = Vec::new(); + let mut variant_defs = Vec::new(); for (idx, variant) in variants.iter().enumerate() { // Ensure no fields. if !matches!(variant.fields, Fields::Unit) { return syn::Error::new_spanned( &variant.fields, - "AsmErrorCodes variants must be unit variants (no fields)", + "error_codes variants must be unit variants (no fields)", ) .to_compile_error() .into(); @@ -85,16 +88,21 @@ pub fn derive_asm_error_codes(input: TokenStream) -> TokenStream { .into(); } - // Convert variant name to SCREAMING_SNAKE_CASE. - let asm_name = format!( - "E_{}", - variant.ident.to_string().to_case(Case::UpperSnake) - ); + // Convert variant name to SCREAMING_SNAKE_CASE for ASM. + let asm_name = format!("E_{}", variant.ident.to_string().to_case(Case::UpperSnake)); // Error codes start at 1. let value = idx + 1; error_entries.push((asm_name, value, doc_comment)); + + // Preserve variant with its attributes. + let variant_ident = &variant.ident; + let variant_attrs = &variant.attrs; + variant_defs.push(quote! { + #(#variant_attrs)* + #variant_ident + }); } // Generate the to_asm() implementation. @@ -107,6 +115,12 @@ pub fn derive_asm_error_codes(input: TokenStream) -> TokenStream { let body = asm_lines.join("\n"); let expanded = quote! { + #(#attrs)* + #[repr(u64)] + #vis enum #name { + #(#variant_defs),* + } + impl #name { /// Generate ASM constants for this enum. pub fn to_asm() -> alloc::string::String { @@ -141,19 +155,15 @@ fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { } } -// ============================================================================ -// asm_constants! macro -// ============================================================================ - struct ConstantDef { doc: String, name: Ident, + ty: syn::Type, value: LitInt, } struct ConstantGroup { doc: String, - vis: Visibility, name: Ident, prefix: Option, constants: Vec, @@ -173,9 +183,7 @@ impl Parse for AsmConstantsInput { let doc = extract_doc_comment(&attrs) .ok_or_else(|| input.error("Module must have a doc comment"))?; - // Parse visibility and `mod`. - let vis: Visibility = input.parse()?; - input.parse::()?; + // Parse group name (always pub). let name: Ident = input.parse()?; // Parse module body. @@ -191,7 +199,10 @@ impl Parse for AsmConstantsInput { content.parse::()?; Some(prefix_lit.value()) } else { - return Err(syn::Error::new(ident.span(), "Expected 'prefix' or constant")); + return Err(syn::Error::new( + ident.span(), + "Expected 'prefix' or constant", + )); } } else { None @@ -205,6 +216,8 @@ impl Parse for AsmConstantsInput { .ok_or_else(|| content.error("Constant must have a doc comment"))?; let const_name: Ident = content.parse()?; + content.parse::()?; + let const_ty: syn::Type = content.parse()?; content.parse::()?; let const_value: LitInt = content.parse()?; @@ -214,13 +227,13 @@ impl Parse for AsmConstantsInput { constants.push(ConstantDef { doc: const_doc, name: const_name, + ty: const_ty, value: const_value, }); } groups.push(ConstantGroup { doc, - vis, name, prefix, constants, @@ -231,44 +244,56 @@ impl Parse for AsmConstantsInput { } } -/// Macro for defining groups of ASM constants. +/// Macro for defining groups of constants shared between Rust and ASM. +/// +/// Constants must specify their Rust type. Values are validated at compile time +/// to fit within i32 range (sBPF immediate constraint). +/// +/// See for sBPF documentation. Immediates are +/// sign-extended from 32-bit, so values must fit in i32 range. /// /// # Example /// ```ignore -/// asm_constants! { +/// constant_group! { /// /// Memory map. -/// pub mod memory_map { +/// memory_map { /// /// Number of accounts expected. -/// N_ACCOUNTS = 2, +/// N_ACCOUNTS: u64 = 2, /// /// Offset to instruction data. -/// IX_DATA = 8, +/// IX_DATA: usize = 8, /// } /// /// /// Error codes. -/// pub mod error_codes { +/// error_codes { /// prefix = "E_", /// /// An invalid number of accounts were passed. -/// N_ACCOUNTS = 1, +/// N_ACCOUNTS: u32 = 1, /// } /// } /// ``` #[proc_macro] -pub fn asm_constants(input: TokenStream) -> TokenStream { +pub fn constant_group(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as AsmConstantsInput); let modules = input.groups.iter().map(|group| { - let vis = &group.vis; let mod_name = &group.name; let prefix = group.prefix.as_deref().unwrap_or(""); - // Generate Rust constants. + // Generate Rust constants with i32 bounds checking for ASM compatibility. let const_defs = group.constants.iter().map(|c| { let name = &c.name; + let ty = &c.ty; let value = &c.value; let doc = &c.doc; + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); quote! { #[doc = #doc] - pub const #name: u64 = #value; + pub const #name: #ty = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); } }); @@ -293,7 +318,7 @@ pub fn asm_constants(input: TokenStream) -> TokenStream { let body = asm_lines.join("\n"); quote! { - #vis mod #mod_name { + pub mod #mod_name { #(#const_defs)* /// Generate ASM constants for this module. diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 8b9f33e7..385cdc1c 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -13,7 +13,7 @@ fn main() { let constants = format!( "{}\n{}", interface::memory_map::to_asm(), - interface::ErrorCodes::to_asm(), + interface::Error::to_asm(), ); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0b41e46a..3546b539 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,18 +1,17 @@ -use build_macros::{asm_constants, AsmErrorCodes}; +use build_macros::{constant_group, error_codes}; -#[derive(AsmErrorCodes)] -#[repr(u64)] -pub enum ErrorCodes { +#[error_codes] +pub enum Error { /// An invalid number of accounts were passed. NAccounts, /// The user account has nonzero data length. UserData, } -asm_constants! { - /// Memory map. - pub mod memory_map { +constant_group! { + /// Memory map layout. + memory_map { /// Number of accounts expected. - N_ACCOUNTS = 2, + N_ACCOUNTS: u64 = 2, } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b840492a..bb5a0887 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,5 +1,5 @@ -# Memory map. -# ----------- +# Memory map layout. +# ------------------ .equ N_ACCOUNTS, 2 # Number of accounts expected. # Error codes. From 7c121b2d3e8d4cc47028cef36558bdad6feb4470 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:02:24 -0800 Subject: [PATCH 012/263] Clean up macros more --- examples/Cargo.lock | 22 +- examples/Cargo.toml | 2 +- examples/tree/build-macros/src/lib.rs | 18 +- examples/tree/interface/Cargo.toml | 2 +- examples/tree/interface/src/common.rs | 2 +- .../tree/{build-macros => macros}/Cargo.toml | 2 +- examples/tree/macros/src/lib.rs | 337 ++++++++++++++++++ 7 files changed, 361 insertions(+), 24 deletions(-) rename examples/tree/{build-macros => macros}/Cargo.toml (89%) create mode 100644 examples/tree/macros/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 41344d45..93c7a005 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -527,16 +527,6 @@ dependencies = [ "regex", ] -[[package]] -name = "build-macros" -version = "0.1.0" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "bv" version = "0.11.1" @@ -1224,7 +1214,7 @@ dependencies = [ name = "interface" version = "0.1.0" dependencies = [ - "build-macros", + "macros", ] [[package]] @@ -1404,6 +1394,16 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "macros" +version = "0.1.0" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "memchr" version = "2.7.6" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 13621118..bbe98c66 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,7 +8,7 @@ members = [ "memo", "transfer", "tree", - "tree/build-macros", + "tree/macros", "tree/interface", "utils/build-examples", "utils/deps/build", diff --git a/examples/tree/build-macros/src/lib.rs b/examples/tree/build-macros/src/lib.rs index d57a8127..8f0fa0ee 100644 --- a/examples/tree/build-macros/src/lib.rs +++ b/examples/tree/build-macros/src/lib.rs @@ -246,11 +246,11 @@ impl Parse for AsmConstantsInput { /// Macro for defining groups of constants shared between Rust and ASM. /// -/// Constants must specify their Rust type. Values are validated at compile time -/// to fit within i32 range (sBPF immediate constraint). +/// Constants must specify their Rust type. Values are validated at compile time since they must +/// [fit in an `i32`][i32-imm], except for [`i64` immediates in `lddw`][lddw-bypass]. /// -/// See for sBPF documentation. Immediates are -/// sign-extended from 32-bit, so values must fit in i32 range. +/// [i32-imm](https://github.com/anza-xya/sbpf/blob/v0.14.2/src/assembler.rs#L262-L264) +/// [lddw-bypass](https://github.com/alnoki/sbpf/blob/v0.14.2/src/assembler.rs#L484-L500) /// /// # Example /// ```ignore @@ -263,11 +263,11 @@ impl Parse for AsmConstantsInput { /// IX_DATA: usize = 8, /// } /// -/// /// Error codes. -/// error_codes { -/// prefix = "E_", -/// /// An invalid number of accounts were passed. -/// N_ACCOUNTS: u32 = 1, +/// /// Another group. +/// my_group { +/// prefix = "MY_PREFIX", +/// /// Foo constant. +/// FOO: u32 = 1, /// } /// } /// ``` diff --git a/examples/tree/interface/Cargo.toml b/examples/tree/interface/Cargo.toml index fedce035..c0a5d679 100644 --- a/examples/tree/interface/Cargo.toml +++ b/examples/tree/interface/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -build-macros.path = "../build-macros" +macros.path = "../macros" diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 3546b539..1515a1cf 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,4 +1,4 @@ -use build_macros::{constant_group, error_codes}; +use macros::{constant_group, error_codes}; #[error_codes] pub enum Error { diff --git a/examples/tree/build-macros/Cargo.toml b/examples/tree/macros/Cargo.toml similarity index 89% rename from examples/tree/build-macros/Cargo.toml rename to examples/tree/macros/Cargo.toml index 2845d260..1adbb0ec 100644 --- a/examples/tree/build-macros/Cargo.toml +++ b/examples/tree/macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "build-macros" +name = "macros" version = "0.1.0" edition = "2021" diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs new file mode 100644 index 00000000..d57a8127 --- /dev/null +++ b/examples/tree/macros/src/lib.rs @@ -0,0 +1,337 @@ +use convert_case::{Case, Casing}; +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + braced, + parse::{Parse, ParseStream}, + parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, +}; + +/// Attribute macro for defining error code enums shared between Rust and ASM. +/// +/// Automatically adds `#[repr(u64)]` to the enum. Each variant must have a doc +/// comment that will become the ASM comment. Variant names are converted from +/// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. +/// +/// # Example +/// ```ignore +/// #[error_codes] +/// pub enum ErrorCodes { +/// /// An invalid number of accounts were passed. +/// NAccounts, +/// /// The user account has nonzero data length. +/// UserData, +/// } +/// ``` +/// +/// Generates ASM: +/// ```text +/// # Error codes. +/// # ------------ +/// .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. +/// .equ E_USER_DATA, 2 # The user account has nonzero data length. +/// ``` +#[proc_macro_attribute] +pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as DeriveInput); + let name = &input.ident; + let vis = &input.vis; + let attrs = &input.attrs; + + let variants = match &input.data { + Data::Enum(data) => &data.variants, + _ => { + return syn::Error::new_spanned(&input, "error_codes can only be applied to enums") + .to_compile_error() + .into(); + } + }; + + let mut error_entries = Vec::new(); + let mut variant_defs = Vec::new(); + + for (idx, variant) in variants.iter().enumerate() { + // Ensure no fields. + if !matches!(variant.fields, Fields::Unit) { + return syn::Error::new_spanned( + &variant.fields, + "error_codes variants must be unit variants (no fields)", + ) + .to_compile_error() + .into(); + } + + // Extract doc comment. + let doc_comment = extract_doc_comment(&variant.attrs); + let doc_comment = match doc_comment { + Some(doc) => doc, + None => { + return syn::Error::new_spanned( + &variant.ident, + format!("Variant `{}` must have a doc comment", variant.ident), + ) + .to_compile_error() + .into(); + } + }; + + // Validate doc comment ends with period. + if !doc_comment.ends_with('.') { + return syn::Error::new_spanned( + &variant.ident, + format!( + "Doc comment for `{}` must end with a period: {:?}", + variant.ident, doc_comment + ), + ) + .to_compile_error() + .into(); + } + + // Convert variant name to SCREAMING_SNAKE_CASE for ASM. + let asm_name = format!("E_{}", variant.ident.to_string().to_case(Case::UpperSnake)); + + // Error codes start at 1. + let value = idx + 1; + + error_entries.push((asm_name, value, doc_comment)); + + // Preserve variant with its attributes. + let variant_ident = &variant.ident; + let variant_attrs = &variant.attrs; + variant_defs.push(quote! { + #(#variant_attrs)* + #variant_ident + }); + } + + // Generate the to_asm() implementation. + let asm_lines: Vec = error_entries + .iter() + .map(|(name, value, comment)| format!(".equ {}, {} # {}", name, value, comment)) + .collect(); + + let header = "# Error codes.\n# ------------"; + let body = asm_lines.join("\n"); + + let expanded = quote! { + #(#attrs)* + #[repr(u64)] + #vis enum #name { + #(#variant_defs),* + } + + impl #name { + /// Generate ASM constants for this enum. + pub fn to_asm() -> alloc::string::String { + alloc::format!("{}\n{}\n", #header, #body) + } + } + }; + + TokenStream::from(expanded) +} + +/// Extract the doc comment from attributes. +fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { + let mut doc_parts = Vec::new(); + + for attr in attrs { + if attr.path().is_ident("doc") { + if let Meta::NameValue(meta) = &attr.meta { + if let syn::Expr::Lit(expr_lit) = &meta.value { + if let Lit::Str(lit_str) = &expr_lit.lit { + doc_parts.push(lit_str.value().trim().to_string()); + } + } + } + } + } + + if doc_parts.is_empty() { + None + } else { + Some(doc_parts.join(" ")) + } +} + +struct ConstantDef { + doc: String, + name: Ident, + ty: syn::Type, + value: LitInt, +} + +struct ConstantGroup { + doc: String, + name: Ident, + prefix: Option, + constants: Vec, +} + +struct AsmConstantsInput { + groups: Vec, +} + +impl Parse for AsmConstantsInput { + fn parse(input: ParseStream) -> syn::Result { + let mut groups = Vec::new(); + + while !input.is_empty() { + // Parse doc comments for the module. + let attrs = input.call(syn::Attribute::parse_outer)?; + let doc = extract_doc_comment(&attrs) + .ok_or_else(|| input.error("Module must have a doc comment"))?; + + // Parse group name (always pub). + let name: Ident = input.parse()?; + + // Parse module body. + let content; + braced!(content in input); + + // Check for optional prefix. + let prefix = if content.peek(Ident) { + let ident: Ident = content.parse()?; + if ident == "prefix" { + content.parse::()?; + let prefix_lit: syn::LitStr = content.parse()?; + content.parse::()?; + Some(prefix_lit.value()) + } else { + return Err(syn::Error::new( + ident.span(), + "Expected 'prefix' or constant", + )); + } + } else { + None + }; + + // Parse constants. + let mut constants = Vec::new(); + while !content.is_empty() { + let const_attrs = content.call(syn::Attribute::parse_outer)?; + let const_doc = extract_doc_comment(&const_attrs) + .ok_or_else(|| content.error("Constant must have a doc comment"))?; + + let const_name: Ident = content.parse()?; + content.parse::()?; + let const_ty: syn::Type = content.parse()?; + content.parse::()?; + let const_value: LitInt = content.parse()?; + + // Optional trailing comma. + let _ = content.parse::(); + + constants.push(ConstantDef { + doc: const_doc, + name: const_name, + ty: const_ty, + value: const_value, + }); + } + + groups.push(ConstantGroup { + doc, + name, + prefix, + constants, + }); + } + + Ok(AsmConstantsInput { groups }) + } +} + +/// Macro for defining groups of constants shared between Rust and ASM. +/// +/// Constants must specify their Rust type. Values are validated at compile time +/// to fit within i32 range (sBPF immediate constraint). +/// +/// See for sBPF documentation. Immediates are +/// sign-extended from 32-bit, so values must fit in i32 range. +/// +/// # Example +/// ```ignore +/// constant_group! { +/// /// Memory map. +/// memory_map { +/// /// Number of accounts expected. +/// N_ACCOUNTS: u64 = 2, +/// /// Offset to instruction data. +/// IX_DATA: usize = 8, +/// } +/// +/// /// Error codes. +/// error_codes { +/// prefix = "E_", +/// /// An invalid number of accounts were passed. +/// N_ACCOUNTS: u32 = 1, +/// } +/// } +/// ``` +#[proc_macro] +pub fn constant_group(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as AsmConstantsInput); + + let modules = input.groups.iter().map(|group| { + let mod_name = &group.name; + let prefix = group.prefix.as_deref().unwrap_or(""); + + // Generate Rust constants with i32 bounds checking for ASM compatibility. + let const_defs = group.constants.iter().map(|c| { + let name = &c.name; + let ty = &c.ty; + let value = &c.value; + let doc = &c.doc; + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); + quote! { + #[doc = #doc] + pub const #name: #ty = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + } + }); + + // Generate ASM output. + let header_text = &group.doc; + let header_line = "-".repeat(header_text.len()); + let header = format!("# {}\n# {}", header_text, header_line); + + let asm_lines: Vec = group + .constants + .iter() + .map(|c| { + format!( + ".equ {}{}, {} # {}", + prefix, + c.name.to_string(), + c.value, + c.doc + ) + }) + .collect(); + let body = asm_lines.join("\n"); + + quote! { + pub mod #mod_name { + #(#const_defs)* + + /// Generate ASM constants for this module. + pub fn to_asm() -> alloc::string::String { + alloc::format!("{}\n{}\n", #header, #body) + } + } + } + }); + + let expanded = quote! { + #(#modules)* + }; + + TokenStream::from(expanded) +} From d2ef14908602bdfe176e7cc7d4da19537c49c612 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:16:26 -0800 Subject: [PATCH 013/263] Tweak macros --- examples/tree/build.rs | 2 +- examples/tree/interface/src/common.rs | 4 +- examples/tree/macros/src/lib.rs | 87 ++++++++++++++++++++------- examples/tree/src/tree/tree.s | 4 +- 4 files changed, 69 insertions(+), 28 deletions(-) diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 385cdc1c..b87c4d1a 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -12,7 +12,7 @@ fn main() { // Generate the constants and insert them before the entrypoint marker. let constants = format!( "{}\n{}", - interface::memory_map::to_asm(), + interface::input_buffer::to_asm(), interface::Error::to_asm(), ); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1515a1cf..54d0b73f 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -9,8 +9,8 @@ pub enum Error { } constant_group! { - /// Memory map layout. - memory_map { + /// Input buffer layout. + input_buffer { /// Number of accounts expected. N_ACCOUNTS: u64 = 2, } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index d57a8127..96bda3f0 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -7,6 +7,12 @@ use syn::{ parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, }; +/// Maximum line length for ASM output. +const MAX_LINE_LEN: usize = 75; + +/// Maximum comment length (accounting for `# ` prefix). +const MAX_COMMENT_LEN: usize = MAX_LINE_LEN - "# ".len(); + /// Attribute macro for defining error code enums shared between Rust and ASM. /// /// Automatically adds `#[repr(u64)]` to the enum. Each variant must have a doc @@ -14,6 +20,7 @@ use syn::{ /// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. /// /// # Example +/// /// ```ignore /// #[error_codes] /// pub enum ErrorCodes { @@ -25,6 +32,7 @@ use syn::{ /// ``` /// /// Generates ASM: +/// /// ```text /// # Error codes. /// # ------------ @@ -75,14 +83,11 @@ pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { } }; - // Validate doc comment ends with period. - if !doc_comment.ends_with('.') { + // Validate doc comment. + if let Err(e) = validate_doc_comment(&doc_comment) { return syn::Error::new_spanned( &variant.ident, - format!( - "Doc comment for `{}` must end with a period: {:?}", - variant.ident, doc_comment - ), + format!("Variant `{}`: {}", variant.ident, e), ) .to_compile_error() .into(); @@ -108,10 +113,10 @@ pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { // Generate the to_asm() implementation. let asm_lines: Vec = error_entries .iter() - .map(|(name, value, comment)| format!(".equ {}, {} # {}", name, value, comment)) + .map(|(name, value, comment)| asm_equ_line(name, value, comment)) .collect(); - let header = "# Error codes.\n# ------------"; + let header = asm_header("Error codes."); let body = asm_lines.join("\n"); let expanded = quote! { @@ -132,6 +137,39 @@ pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } +/// Generate an ASM section header with auto-width dashes. +fn asm_header(title: &str) -> String { + let dash_len = title.len().min(MAX_COMMENT_LEN); + format!("# {}\n# {}", title, "-".repeat(dash_len)) +} + +/// Validate a doc comment: must end with period and fit within max length. +fn validate_doc_comment(comment: &str) -> Result<(), String> { + if !comment.ends_with('.') { + return Err(format!("Doc comment must end with a period: {:?}", comment)); + } + if comment.len() > MAX_COMMENT_LEN { + return Err(format!( + "Doc comment exceeds max length of {} chars (got {}): {:?}", + MAX_COMMENT_LEN, + comment.len(), + comment + )); + } + Ok(()) +} + +/// Format an ASM .equ line. If inline comment would exceed max line length, +/// put the comment on its own line above. +fn asm_equ_line(name: &str, value: impl std::fmt::Display, comment: &str) -> String { + let inline = format!(".equ {}, {} # {}", name, value, comment); + if inline.len() <= MAX_LINE_LEN { + inline + } else { + format!("# {}\n.equ {}, {}", comment, name, value) + } +} + /// Extract the doc comment from attributes. fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { let mut doc_parts = Vec::new(); @@ -183,6 +221,11 @@ impl Parse for AsmConstantsInput { let doc = extract_doc_comment(&attrs) .ok_or_else(|| input.error("Module must have a doc comment"))?; + // Validate group doc comment. + if let Err(e) = validate_doc_comment(&doc) { + return Err(input.error(format!("Group doc comment: {}", e))); + } + // Parse group name (always pub). let name: Ident = input.parse()?; @@ -215,6 +258,11 @@ impl Parse for AsmConstantsInput { let const_doc = extract_doc_comment(&const_attrs) .ok_or_else(|| content.error("Constant must have a doc comment"))?; + // Validate constant doc comment. + if let Err(e) = validate_doc_comment(&const_doc) { + return Err(content.error(e)); + } + let const_name: Ident = content.parse()?; content.parse::()?; let const_ty: syn::Type = content.parse()?; @@ -263,11 +311,11 @@ impl Parse for AsmConstantsInput { /// IX_DATA: usize = 8, /// } /// -/// /// Error codes. -/// error_codes { -/// prefix = "E_", -/// /// An invalid number of accounts were passed. -/// N_ACCOUNTS: u32 = 1, +/// /// Stack frame offsets. +/// stack_offsets { +/// prefix = "SF_", +/// /// Offset to user pubkey. +/// USER_PUBKEY: u64 = 0, /// } /// } /// ``` @@ -298,21 +346,14 @@ pub fn constant_group(input: TokenStream) -> TokenStream { }); // Generate ASM output. - let header_text = &group.doc; - let header_line = "-".repeat(header_text.len()); - let header = format!("# {}\n# {}", header_text, header_line); + let header = asm_header(&group.doc); let asm_lines: Vec = group .constants .iter() .map(|c| { - format!( - ".equ {}{}, {} # {}", - prefix, - c.name.to_string(), - c.value, - c.doc - ) + let full_name = format!("{}{}", prefix, c.name); + asm_equ_line(&full_name, &c.value, &c.doc) }) .collect(); let body = asm_lines.join("\n"); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index bb5a0887..b973ecab 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,5 +1,5 @@ -# Memory map layout. -# ------------------ +# Input buffer layout. +# -------------------- .equ N_ACCOUNTS, 2 # Number of accounts expected. # Error codes. From 0b15657ac9a4879af6c54bdf6ca561d08426f5c1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:25:41 -0800 Subject: [PATCH 014/263] Begin input buffer/offset calculations --- examples/tree/interface/Cargo.toml | 1 + examples/tree/interface/src/asm.rs | 22 ++++++++++++++++++++++ examples/tree/interface/src/lib.rs | 4 ++-- examples/tree/interface/src/stack.rs | 1 - examples/tree/src/tree/tree.s | 2 +- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 examples/tree/interface/src/asm.rs delete mode 100644 examples/tree/interface/src/stack.rs diff --git a/examples/tree/interface/Cargo.toml b/examples/tree/interface/Cargo.toml index c0a5d679..69a9a945 100644 --- a/examples/tree/interface/Cargo.toml +++ b/examples/tree/interface/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] macros.path = "../macros" +pinocchio.workspace = true diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs new file mode 100644 index 00000000..84940ad4 --- /dev/null +++ b/examples/tree/interface/src/asm.rs @@ -0,0 +1,22 @@ +use pinocchio::Address; + +struct InputBuffer { + n_accounts: u64, + user: InputAccount<0>, + tree: InputAccount<0>, +} + +#[repr(C)] +struct InputAccount { + non_dup_marker: u8, + is_signer: u8, + is_writable: u8, + is_executable: u8, + original_data_len: [u8; 4], + pubkey: [u8; size_of::
()], + owner: [u8; size_of::
()], + lamports: u64, + data_len: u64, + data_padded: [u8; DATA_PADDED_LEN], + rent_epoch: u64, +} diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 6771ad11..8cb47f2a 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,7 +1,7 @@ extern crate alloc; +mod asm; mod common; -mod stack; +pub use asm::*; pub use common::*; -pub use stack::*; diff --git a/examples/tree/interface/src/stack.rs b/examples/tree/interface/src/stack.rs deleted file mode 100644 index 8b137891..00000000 --- a/examples/tree/interface/src/stack.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b973ecab..a61c065f 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -10,5 +10,5 @@ .globl entrypoint entrypoint: - mov64 r0, 0 + exit From 2a3ac50baf329d6fd1474e03a80fde5ab06f9a1f Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:41:27 -0800 Subject: [PATCH 015/263] Update scaffolding --- examples/Cargo.lock | 1 + examples/tree/build.rs | 7 ++----- examples/tree/interface/src/common.rs | 5 +++++ examples/tree/interface/src/lib.rs | 2 +- examples/tree/macros/src/lib.rs | 10 ++++++++-- examples/tree/src/program.rs | 17 ++++++++++++++--- examples/tree/src/tree/tree.s | 2 +- 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 93c7a005..8e3a4048 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -1215,6 +1215,7 @@ name = "interface" version = "0.1.0" dependencies = [ "macros", + "pinocchio", ] [[package]] diff --git a/examples/tree/build.rs b/examples/tree/build.rs index b87c4d1a..892c7539 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,3 +1,4 @@ +use interface::*; use std::{fs, path::Path}; const ENTRYPOINT_START: &str = ".globl entrypoint"; @@ -10,11 +11,7 @@ fn main() { let marker_pos = content.find(ENTRYPOINT_START).unwrap(); // Generate the constants and insert them before the entrypoint marker. - let constants = format!( - "{}\n{}", - interface::input_buffer::to_asm(), - interface::Error::to_asm(), - ); + let constants = format!("{}\n{}", input_buffer::to_asm(), Error::to_asm(),); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { fs::write(&asm_path, new_content).unwrap(); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 54d0b73f..274d35e8 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -15,3 +15,8 @@ constant_group! { N_ACCOUNTS: u64 = 2, } } + +#[repr(C, packed)] +struct InstructionData { + discriminator: u8, +} diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 8cb47f2a..b9d6d08e 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,7 +1,7 @@ extern crate alloc; mod asm; -mod common; +pub mod common; pub use asm::*; pub use common::*; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 96bda3f0..80552896 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -15,7 +15,7 @@ const MAX_COMMENT_LEN: usize = MAX_LINE_LEN - "# ".len(); /// Attribute macro for defining error code enums shared between Rust and ASM. /// -/// Automatically adds `#[repr(u64)]` to the enum. Each variant must have a doc +/// Automatically adds `#[repr(u32)]` to the enum. Each variant must have a doc /// comment that will become the ASM comment. Variant names are converted from /// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. /// @@ -121,11 +121,17 @@ pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { let expanded = quote! { #(#attrs)* - #[repr(u64)] + #[repr(u32)] #vis enum #name { #(#variant_defs),* } + impl From<#name> for u32 { + fn from(e: #name) -> u32 { + e as u32 + } + } + impl #name { /// Generate ASM constants for this enum. pub fn to_asm() -> alloc::string::String { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 5bf7a274..4959b0a6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,12 +1,23 @@ +use interface::common::*; use pinocchio::{ - entrypoint::InstructionContext, lazy_program_entrypoint, no_allocator, nostd_panic_handler, - ProgramResult, + entrypoint::InstructionContext, error::ProgramError, lazy_program_entrypoint, no_allocator, + nostd_panic_handler, ProgramResult, }; +/// If condition is true, return the given error. +macro_rules! if_err { + ($cond:expr, $variant:ident) => { + if $cond { + return Err(ProgramError::Custom(Error::$variant.into())); + } + }; +} + lazy_program_entrypoint!(process_instruction); nostd_panic_handler!(); no_allocator!(); -pub fn process_instruction(_context: InstructionContext) -> ProgramResult { +pub fn process_instruction(context: InstructionContext) -> ProgramResult { + if_err!(context.remaining() != input_buffer::N_ACCOUNTS, NAccounts); Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a61c065f..b973ecab 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -10,5 +10,5 @@ .globl entrypoint entrypoint: - + mov64 r0, 0 exit From 1dbc38755c5d662bc49ca387127efe0880c74ca6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:12:18 -0800 Subject: [PATCH 016/263] Add group extension --- examples/tree/build.rs | 2 +- examples/tree/interface/src/asm.rs | 27 +-- examples/tree/interface/src/common.rs | 5 - examples/tree/interface/src/lib.rs | 4 +- examples/tree/macros/src/lib.rs | 226 ++++++++++++++++++++------ examples/tree/src/tree/tree.s | 3 +- 6 files changed, 186 insertions(+), 81 deletions(-) diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 892c7539..c3fe8457 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -11,7 +11,7 @@ fn main() { let marker_pos = content.find(ENTRYPOINT_START).unwrap(); // Generate the constants and insert them before the entrypoint marker. - let constants = format!("{}\n{}", input_buffer::to_asm(), Error::to_asm(),); + let constants = format!("{}\n{}", input_buffer::to_asm(), Error::to_asm()); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { fs::write(&asm_path, new_content).unwrap(); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 84940ad4..b4bcab06 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,22 +1,9 @@ -use pinocchio::Address; +extern crate alloc; -struct InputBuffer { - n_accounts: u64, - user: InputAccount<0>, - tree: InputAccount<0>, -} +use macros::extend_constant_group; -#[repr(C)] -struct InputAccount { - non_dup_marker: u8, - is_signer: u8, - is_writable: u8, - is_executable: u8, - original_data_len: [u8; 4], - pubkey: [u8; size_of::
()], - owner: [u8; size_of::
()], - lamports: u64, - data_len: u64, - data_padded: [u8; DATA_PADDED_LEN], - rent_epoch: u64, -} +extend_constant_group!(input_buffer { + prefix = "IB", + /// Number of accounts passed in input. + N_ACCOUNTS_OFF = 0, +}); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 274d35e8..54d0b73f 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -15,8 +15,3 @@ constant_group! { N_ACCOUNTS: u64 = 2, } } - -#[repr(C, packed)] -struct InstructionData { - discriminator: u8, -} diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index b9d6d08e..8a11e48a 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,7 +1,7 @@ extern crate alloc; mod asm; -pub mod common; +mod common; pub use asm::*; -pub use common::*; +pub use common::Error; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 80552896..7e9aa294 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -209,7 +209,6 @@ struct ConstantDef { struct ConstantGroup { doc: String, name: Ident, - prefix: Option, constants: Vec, } @@ -232,31 +231,13 @@ impl Parse for AsmConstantsInput { return Err(input.error(format!("Group doc comment: {}", e))); } - // Parse group name (always pub). + // Parse group name. let name: Ident = input.parse()?; // Parse module body. let content; braced!(content in input); - // Check for optional prefix. - let prefix = if content.peek(Ident) { - let ident: Ident = content.parse()?; - if ident == "prefix" { - content.parse::()?; - let prefix_lit: syn::LitStr = content.parse()?; - content.parse::()?; - Some(prefix_lit.value()) - } else { - return Err(syn::Error::new( - ident.span(), - "Expected 'prefix' or constant", - )); - } - } else { - None - }; - // Parse constants. let mut constants = Vec::new(); while !content.is_empty() { @@ -289,7 +270,6 @@ impl Parse for AsmConstantsInput { groups.push(ConstantGroup { doc, name, - prefix, constants, }); } @@ -301,37 +281,30 @@ impl Parse for AsmConstantsInput { /// Macro for defining groups of constants shared between Rust and ASM. /// /// Constants must specify their Rust type. Values are validated at compile time -/// to fit within i32 range (sBPF immediate constraint). -/// -/// See for sBPF documentation. Immediates are -/// sign-extended from 32-bit, so values must fit in i32 range. +/// to fit within i32 range (sBPF immediate constraint). The prefix is automatically +/// joined with an underscore. /// /// # Example /// ```ignore /// constant_group! { -/// /// Memory map. -/// memory_map { +/// /// Input buffer layout. +/// input_buffer { /// /// Number of accounts expected. /// N_ACCOUNTS: u64 = 2, -/// /// Offset to instruction data. -/// IX_DATA: usize = 8, -/// } -/// -/// /// Stack frame offsets. -/// stack_offsets { -/// prefix = "SF_", -/// /// Offset to user pubkey. -/// USER_PUBKEY: u64 = 0, /// } /// } +/// // Usage: input_buffer::to_asm("IB") -> ".equ IB_N_ACCOUNTS, 2 # ..." /// ``` +/// +/// To extend a group with ASM-only constants, use `extend_constant_group!`. #[proc_macro] pub fn constant_group(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as AsmConstantsInput); let modules = input.groups.iter().map(|group| { let mod_name = &group.name; - let prefix = group.prefix.as_deref().unwrap_or(""); + let max_line_len = MAX_LINE_LEN; + let header = asm_header(&group.doc); // Generate Rust constants with i32 bounds checking for ASM compatibility. let const_defs = group.constants.iter().map(|c| { @@ -351,26 +324,39 @@ pub fn constant_group(input: TokenStream) -> TokenStream { } }); - // Generate ASM output. - let header = asm_header(&group.doc); - - let asm_lines: Vec = group - .constants - .iter() - .map(|c| { - let full_name = format!("{}{}", prefix, c.name); - asm_equ_line(&full_name, &c.value, &c.doc) - }) - .collect(); - let body = asm_lines.join("\n"); + let const_names: Vec = group.constants.iter().map(|c| c.name.to_string()).collect(); + let const_values: Vec = group.constants.iter().map(|c| c.value.to_string()).collect(); + let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); quote! { pub mod #mod_name { #(#const_defs)* - /// Generate ASM constants for this module. - pub fn to_asm() -> alloc::string::String { - alloc::format!("{}\n{}\n", #header, #body) + /// Generate ASM constants for this module with the given prefix. + /// Prefix is automatically joined with underscore (e.g., "IB" -> "IB_NAME"). + pub fn to_asm(prefix: &str) -> alloc::string::String { + use alloc::string::String; + use alloc::format; + + let mut result = String::from(#header); + result.push('\n'); + + let names = [#(#const_names),*]; + let values = [#(#const_values),*]; + let docs = [#(#const_docs),*]; + + for i in 0..names.len() { + let full_name = format!("{}_{}", prefix, names[i]); + let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + } + result.push('\n'); + } + + result } } } @@ -382,3 +368,139 @@ pub fn constant_group(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +/// ASM-only constant (no Rust type needed). +struct AsmConstantDef { + doc: String, + name: Ident, + value: LitInt, +} + +/// Input for extend_constant_group! macro. +struct ExtendConstantGroupInput { + name: Ident, + prefix: String, + constants: Vec, +} + +impl Parse for ExtendConstantGroupInput { + fn parse(input: ParseStream) -> syn::Result { + // Parse module name. + let name: Ident = input.parse()?; + + // Parse body. + let content; + braced!(content in input); + + // Parse prefix = "..." + let ident: Ident = content.parse()?; + if ident != "prefix" { + return Err(syn::Error::new( + ident.span(), + "First item must be 'prefix = \"...\"'", + )); + } + content.parse::()?; + let prefix_lit: syn::LitStr = content.parse()?; + let prefix = prefix_lit.value(); + content.parse::()?; + + // Parse constants (ASM-only, no type needed). + let mut constants = Vec::new(); + while !content.is_empty() { + let const_attrs = content.call(syn::Attribute::parse_outer)?; + let const_doc = extract_doc_comment(&const_attrs) + .ok_or_else(|| content.error("Constant must have a doc comment"))?; + + if let Err(e) = validate_doc_comment(&const_doc) { + return Err(content.error(e)); + } + + let const_name: Ident = content.parse()?; + content.parse::()?; + let const_value: LitInt = content.parse()?; + + // Optional trailing comma. + let _ = content.parse::(); + + constants.push(AsmConstantDef { + doc: const_doc, + name: const_name, + value: const_value, + }); + } + + Ok(ExtendConstantGroupInput { + name, + prefix, + constants, + }) + } +} + +/// Macro for extending a constant group with ASM-only constants. +/// +/// This creates a module that re-exports the base group's constants from +/// `crate::common::{name}` and adds ASM-only constants. The `to_asm()` function +/// combines both under one header. The prefix is automatically joined with an underscore. +/// +/// # Example +/// ```ignore +/// extend_constant_group!(input_buffer { +/// prefix = "IB", +/// /// Offset to number of accounts field. +/// N_ACCOUNTS_OFF = 0, +/// }); +/// // Creates `input_buffer` module that: +/// // - Re-exports all constants from crate::common::input_buffer +/// // - Adds ASM-only constants (N_ACCOUNTS_OFF) +/// // - to_asm() outputs all constants with "IB_" prefix under one header +/// ``` +#[proc_macro] +pub fn extend_constant_group(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ExtendConstantGroupInput); + + let mod_name = &input.name; + let prefix = &input.prefix; + let max_line_len = MAX_LINE_LEN; + + let const_names: Vec = input.constants.iter().map(|c| c.name.to_string()).collect(); + let const_values: Vec = input.constants.iter().map(|c| c.value.to_string()).collect(); + let const_docs: Vec = input.constants.iter().map(|c| c.doc.clone()).collect(); + + let expanded = quote! { + pub mod #mod_name { + use alloc::string::String; + use alloc::format; + + // Re-export base group's constants. + pub use crate::common::#mod_name::*; + + /// Generate combined ASM (base + extension) with prefix. + pub fn to_asm() -> String { + // Base group adds header and its constants. + let mut result = crate::common::#mod_name::to_asm(#prefix); + + // Add extension constants (no separate header). + let names = [#(#const_names),*]; + let values = [#(#const_values),*]; + let docs = [#(#const_docs),*]; + + for i in 0..names.len() { + let full_name = format!("{}_{}", #prefix, names[i]); + let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + } + result.push('\n'); + } + + result + } + } + }; + + TokenStream::from(expanded) +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b973ecab..9a61e764 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,6 +1,7 @@ # Input buffer layout. # -------------------- -.equ N_ACCOUNTS, 2 # Number of accounts expected. +.equ IB_N_ACCOUNTS, 2 # Number of accounts expected. +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts passed in input. # Error codes. # ------------ From bf19241e9bbfc567416a4898696fa241bf6c6daa Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:21:01 -0800 Subject: [PATCH 017/263] Update e code macros --- examples/tree/interface/src/common.rs | 7 +- examples/tree/macros/src/lib.rs | 156 +++++++++++--------------- examples/tree/src/program.rs | 4 +- examples/tree/src/tree/tree.s | 4 +- 4 files changed, 71 insertions(+), 100 deletions(-) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 54d0b73f..322a596d 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,11 +1,10 @@ use macros::{constant_group, error_codes}; -#[error_codes] -pub enum Error { +error_codes! { /// An invalid number of accounts were passed. - NAccounts, + N_ACCOUNTS_INVALID, /// The user account has nonzero data length. - UserData, + USER_HAS_DATA, } constant_group! { diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 7e9aa294..2e2254b4 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -1,10 +1,9 @@ -use convert_case::{Case, Casing}; use proc_macro::TokenStream; use quote::quote; use syn::{ braced, parse::{Parse, ParseStream}, - parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, + parse_macro_input, Ident, Lit, LitInt, Meta, Token, }; /// Maximum line length for ASM output. @@ -13,126 +12,99 @@ const MAX_LINE_LEN: usize = 75; /// Maximum comment length (accounting for `# ` prefix). const MAX_COMMENT_LEN: usize = MAX_LINE_LEN - "# ".len(); -/// Attribute macro for defining error code enums shared between Rust and ASM. +/// Error code entry: doc comment + snake_case name. +struct ErrorCodeEntry { + doc: String, + name: Ident, +} + +/// Input for error_codes! macro. +struct ErrorCodesInput { + entries: Vec, +} + +impl Parse for ErrorCodesInput { + fn parse(input: ParseStream) -> syn::Result { + let mut entries = Vec::new(); + + while !input.is_empty() { + let attrs = input.call(syn::Attribute::parse_outer)?; + let doc = extract_doc_comment(&attrs) + .ok_or_else(|| input.error("Error code must have a doc comment"))?; + + if let Err(e) = validate_doc_comment(&doc) { + return Err(input.error(e)); + } + + let name: Ident = input.parse()?; + + // Optional trailing comma. + let _ = input.parse::(); + + entries.push(ErrorCodeEntry { doc, name }); + } + + Ok(ErrorCodesInput { entries }) + } +} + +/// Macro for defining error codes shared between Rust and ASM. /// -/// Automatically adds `#[repr(u32)]` to the enum. Each variant must have a doc -/// comment that will become the ASM comment. Variant names are converted from -/// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. +/// Creates an `Error` enum with `#[repr(u32)]` and auto-numbered variants starting at 1. +/// Variant names are SCREAMING_SNAKE_CASE. ASM names have `E_` prefix added. /// /// # Example -/// /// ```ignore -/// #[error_codes] -/// pub enum ErrorCodes { +/// error_codes! { /// /// An invalid number of accounts were passed. -/// NAccounts, +/// N_ACCOUNTS_INVALID, /// /// The user account has nonzero data length. -/// UserData, +/// USER_HAS_DATA, /// } /// ``` /// -/// Generates ASM: -/// -/// ```text -/// # Error codes. -/// # ------------ -/// .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. -/// .equ E_USER_DATA, 2 # The user account has nonzero data length. -/// ``` -#[proc_macro_attribute] -pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input = parse_macro_input!(item as DeriveInput); - let name = &input.ident; - let vis = &input.vis; - let attrs = &input.attrs; - - let variants = match &input.data { - Data::Enum(data) => &data.variants, - _ => { - return syn::Error::new_spanned(&input, "error_codes can only be applied to enums") - .to_compile_error() - .into(); - } - }; +/// Generates: +/// - Rust: `enum Error { N_ACCOUNTS_INVALID, USER_HAS_DATA }` with `From for u32` +/// - ASM: `.equ E_N_ACCOUNTS_INVALID, 1` and `.equ E_USER_HAS_DATA, 2` +#[proc_macro] +pub fn error_codes(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ErrorCodesInput); - let mut error_entries = Vec::new(); let mut variant_defs = Vec::new(); + let mut asm_lines = Vec::new(); - for (idx, variant) in variants.iter().enumerate() { - // Ensure no fields. - if !matches!(variant.fields, Fields::Unit) { - return syn::Error::new_spanned( - &variant.fields, - "error_codes variants must be unit variants (no fields)", - ) - .to_compile_error() - .into(); - } - - // Extract doc comment. - let doc_comment = extract_doc_comment(&variant.attrs); - let doc_comment = match doc_comment { - Some(doc) => doc, - None => { - return syn::Error::new_spanned( - &variant.ident, - format!("Variant `{}` must have a doc comment", variant.ident), - ) - .to_compile_error() - .into(); - } - }; - - // Validate doc comment. - if let Err(e) = validate_doc_comment(&doc_comment) { - return syn::Error::new_spanned( - &variant.ident, - format!("Variant `{}`: {}", variant.ident, e), - ) - .to_compile_error() - .into(); - } - - // Convert variant name to SCREAMING_SNAKE_CASE for ASM. - let asm_name = format!("E_{}", variant.ident.to_string().to_case(Case::UpperSnake)); - - // Error codes start at 1. + for (idx, entry) in input.entries.iter().enumerate() { + let doc = &entry.doc; + let variant_name = &entry.name; + // Just add E_ prefix for ASM. + let asm_name = format!("E_{}", entry.name); let value = idx + 1; - error_entries.push((asm_name, value, doc_comment)); - - // Preserve variant with its attributes. - let variant_ident = &variant.ident; - let variant_attrs = &variant.attrs; variant_defs.push(quote! { - #(#variant_attrs)* - #variant_ident + #[doc = #doc] + #variant_name }); - } - // Generate the to_asm() implementation. - let asm_lines: Vec = error_entries - .iter() - .map(|(name, value, comment)| asm_equ_line(name, value, comment)) - .collect(); + asm_lines.push(asm_equ_line(&asm_name, &value, doc)); + } let header = asm_header("Error codes."); let body = asm_lines.join("\n"); let expanded = quote! { - #(#attrs)* #[repr(u32)] - #vis enum #name { + #[allow(non_camel_case_types)] + pub enum Error { #(#variant_defs),* } - impl From<#name> for u32 { - fn from(e: #name) -> u32 { + impl From for u32 { + fn from(e: Error) -> u32 { e as u32 } } - impl #name { + impl Error { /// Generate ASM constants for this enum. pub fn to_asm() -> alloc::string::String { alloc::format!("{}\n{}\n", #header, #body) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 4959b0a6..71a5957f 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,4 @@ -use interface::common::*; +use interface::*; use pinocchio::{ entrypoint::InstructionContext, error::ProgramError, lazy_program_entrypoint, no_allocator, nostd_panic_handler, ProgramResult, @@ -18,6 +18,6 @@ nostd_panic_handler!(); no_allocator!(); pub fn process_instruction(context: InstructionContext) -> ProgramResult { - if_err!(context.remaining() != input_buffer::N_ACCOUNTS, NAccounts); + if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS_INVALID); Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 9a61e764..fa7a6733 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -5,8 +5,8 @@ # Error codes. # ------------ -.equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. -.equ E_USER_DATA, 2 # The user account has nonzero data length. +.equ E_N_ACCOUNTS_INVALID, 1 # An invalid number of accounts were passed. +.equ E_USER_HAS_DATA, 2 # The user account has nonzero data length. .globl entrypoint From a1f1e9c8547e7ea528f85bacd0ff5e9248eed352 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:35:56 -0800 Subject: [PATCH 018/263] Begin rs impl --- examples/tree/interface/src/common.rs | 6 ++++-- examples/tree/src/program.rs | 24 ++++++++++++++++++++---- examples/tree/src/tree/tree.s | 5 +++-- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 322a596d..2cf8b26d 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -2,9 +2,11 @@ use macros::{constant_group, error_codes}; error_codes! { /// An invalid number of accounts were passed. - N_ACCOUNTS_INVALID, + N_ACCOUNTS, /// The user account has nonzero data length. - USER_HAS_DATA, + USER_DATA_LEN, + /// The tree account is a duplicate. + TREE_DUPLICATE, } constant_group! { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 71a5957f..be4734cd 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,7 +1,7 @@ use interface::*; use pinocchio::{ - entrypoint::InstructionContext, error::ProgramError, lazy_program_entrypoint, no_allocator, - nostd_panic_handler, ProgramResult, + entrypoint::InstructionContext, entrypoint::MaybeAccount, error::ProgramError, + lazy_program_entrypoint, no_allocator, nostd_panic_handler, ProgramResult, }; /// If condition is true, return the given error. @@ -13,11 +13,27 @@ macro_rules! if_err { }; } +/// Return the given error. +macro_rules! err { + ($variant:ident) => { + return Err(ProgramError::Custom(Error::$variant.into())); + }; +} + lazy_program_entrypoint!(process_instruction); nostd_panic_handler!(); no_allocator!(); -pub fn process_instruction(context: InstructionContext) -> ProgramResult { - if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS_INVALID); +pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { + // Verify the input memory map: user has no data, tree is not duplicate. + if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); + // SAFETY: number of accounts has been checked. + let user = unsafe { context.next_account_unchecked().assume_account() }; + if_err!(user.data_len() != 0, USER_DATA_LEN); + // SAFETY: number of accounts has been checked. + let tree = match unsafe { context.next_account_unchecked() } { + MaybeAccount::Account(account) => account, + MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), + }; Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index fa7a6733..bdd93672 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -5,8 +5,9 @@ # Error codes. # ------------ -.equ E_N_ACCOUNTS_INVALID, 1 # An invalid number of accounts were passed. -.equ E_USER_HAS_DATA, 2 # The user account has nonzero data length. +.equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. +.equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. +.equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. .globl entrypoint From 38d438c60ec5d84ab92f7ecb8e9ff7208cf7f1dc Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:44:25 -0800 Subject: [PATCH 019/263] Add more rs impl --- examples/tree/src/program.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index be4734cd..22838096 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,6 +1,7 @@ use interface::*; use pinocchio::{ - entrypoint::InstructionContext, entrypoint::MaybeAccount, error::ProgramError, + entrypoint::{InstructionContext, MaybeAccount}, + error::ProgramError, lazy_program_entrypoint, no_allocator, nostd_panic_handler, ProgramResult, }; @@ -8,7 +9,7 @@ use pinocchio::{ macro_rules! if_err { ($cond:expr, $variant:ident) => { if $cond { - return Err(ProgramError::Custom(Error::$variant.into())); + err!($variant); } }; } @@ -16,7 +17,7 @@ macro_rules! if_err { /// Return the given error. macro_rules! err { ($variant:ident) => { - return Err(ProgramError::Custom(Error::$variant.into())); + return Err(ProgramError::Custom(Error::$variant.into())) }; } @@ -35,5 +36,8 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; + // SAFETY: all accounts have been read. + let instruction_data = context.instruction_data_unchecked(); + let program_id = context.program_id_unchecked(); Ok(()) } From 2a08f22f642527c70f81cb139d576a2cfbf5f60a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:15:56 -0800 Subject: [PATCH 020/263] Refactor macros, make build pass --- examples/tree/interface/src/lib.rs | 2 + examples/tree/macros/src/lib.rs | 205 ++++++++++++++--------------- examples/tree/src/program.rs | 4 +- 3 files changed, 101 insertions(+), 110 deletions(-) diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 8a11e48a..a8adf1b9 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,3 +1,5 @@ +#![no_std] + extern crate alloc; mod asm; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 2e2254b4..07d965e8 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -184,69 +184,64 @@ struct ConstantGroup { constants: Vec, } -struct AsmConstantsInput { - groups: Vec, -} - -impl Parse for AsmConstantsInput { +impl Parse for ConstantGroup { fn parse(input: ParseStream) -> syn::Result { - let mut groups = Vec::new(); - - while !input.is_empty() { - // Parse doc comments for the module. - let attrs = input.call(syn::Attribute::parse_outer)?; - let doc = extract_doc_comment(&attrs) - .ok_or_else(|| input.error("Module must have a doc comment"))?; + // Parse doc comments for the module. + let attrs = input.call(syn::Attribute::parse_outer)?; + let doc = extract_doc_comment(&attrs) + .ok_or_else(|| input.error("Module must have a doc comment"))?; + + // Validate group doc comment. + if let Err(e) = validate_doc_comment(&doc) { + return Err(input.error(format!("Group doc comment: {}", e))); + } - // Validate group doc comment. - if let Err(e) = validate_doc_comment(&doc) { - return Err(input.error(format!("Group doc comment: {}", e))); - } + // Parse group name. + let name: Ident = input.parse()?; - // Parse group name. - let name: Ident = input.parse()?; + // Parse module body. + let content; + braced!(content in input); - // Parse module body. - let content; - braced!(content in input); + // Parse constants. + let mut constants = Vec::new(); + while !content.is_empty() { + let const_attrs = content.call(syn::Attribute::parse_outer)?; + let const_doc = extract_doc_comment(&const_attrs) + .ok_or_else(|| content.error("Constant must have a doc comment"))?; - // Parse constants. - let mut constants = Vec::new(); - while !content.is_empty() { - let const_attrs = content.call(syn::Attribute::parse_outer)?; - let const_doc = extract_doc_comment(&const_attrs) - .ok_or_else(|| content.error("Constant must have a doc comment"))?; + // Validate constant doc comment. + if let Err(e) = validate_doc_comment(&const_doc) { + return Err(content.error(e)); + } - // Validate constant doc comment. - if let Err(e) = validate_doc_comment(&const_doc) { - return Err(content.error(e)); - } + let const_name: Ident = content.parse()?; + content.parse::()?; + let const_ty: syn::Type = content.parse()?; + content.parse::()?; + let const_value: LitInt = content.parse()?; - let const_name: Ident = content.parse()?; - content.parse::()?; - let const_ty: syn::Type = content.parse()?; - content.parse::()?; - let const_value: LitInt = content.parse()?; - - // Optional trailing comma. - let _ = content.parse::(); - - constants.push(ConstantDef { - doc: const_doc, - name: const_name, - ty: const_ty, - value: const_value, - }); - } + // Optional trailing comma. + let _ = content.parse::(); - groups.push(ConstantGroup { - doc, - name, - constants, + constants.push(ConstantDef { + doc: const_doc, + name: const_name, + ty: const_ty, + value: const_value, }); } - Ok(AsmConstantsInput { groups }) + // Reject multiple groups in a single macro invocation. + if !input.is_empty() { + return Err(input.error("Only one constant group per macro invocation; use separate constant_group! calls")); + } + + Ok(ConstantGroup { + doc, + name, + constants, + }) } } @@ -271,71 +266,65 @@ impl Parse for AsmConstantsInput { /// To extend a group with ASM-only constants, use `extend_constant_group!`. #[proc_macro] pub fn constant_group(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as AsmConstantsInput); - - let modules = input.groups.iter().map(|group| { - let mod_name = &group.name; - let max_line_len = MAX_LINE_LEN; - let header = asm_header(&group.doc); - - // Generate Rust constants with i32 bounds checking for ASM compatibility. - let const_defs = group.constants.iter().map(|c| { - let name = &c.name; - let ty = &c.ty; - let value = &c.value; - let doc = &c.doc; - let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); - quote! { - #[doc = #doc] - pub const #name: #ty = #value; - - const #assert_name: () = assert!( - (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); - } - }); - - let const_names: Vec = group.constants.iter().map(|c| c.name.to_string()).collect(); - let const_values: Vec = group.constants.iter().map(|c| c.value.to_string()).collect(); - let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); + let group = parse_macro_input!(input as ConstantGroup); + let mod_name = &group.name; + let max_line_len = MAX_LINE_LEN; + let header = asm_header(&group.doc); + + // Generate Rust constants with i32 bounds checking for ASM compatibility. + let const_defs = group.constants.iter().map(|c| { + let name = &c.name; + let ty = &c.ty; + let value = &c.value; + let doc = &c.doc; + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); quote! { - pub mod #mod_name { - #(#const_defs)* + #[doc = #doc] + pub const #name: #ty = #value; - /// Generate ASM constants for this module with the given prefix. - /// Prefix is automatically joined with underscore (e.g., "IB" -> "IB_NAME"). - pub fn to_asm(prefix: &str) -> alloc::string::String { - use alloc::string::String; - use alloc::format; + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + } + }); - let mut result = String::from(#header); - result.push('\n'); + let const_names: Vec = group.constants.iter().map(|c| c.name.to_string()).collect(); + let const_values: Vec = group.constants.iter().map(|c| c.value.to_string()).collect(); + let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); - let names = [#(#const_names),*]; - let values = [#(#const_values),*]; - let docs = [#(#const_docs),*]; - - for i in 0..names.len() { - let full_name = format!("{}_{}", prefix, names[i]); - let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); - if inline.len() <= #max_line_len { - result.push_str(&inline); - } else { - result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); - } - result.push('\n'); - } + let expanded = quote! { + pub mod #mod_name { + #(#const_defs)* + + /// Generate ASM constants for this module with the given prefix. + /// Prefix is automatically joined with underscore (e.g., "IB" -> "IB_NAME"). + pub fn to_asm(prefix: &str) -> alloc::string::String { + use alloc::string::String; + use alloc::format; - result + let mut result = String::from(#header); + result.push('\n'); + + let names = [#(#const_names),*]; + let values = [#(#const_values),*]; + let docs = [#(#const_docs),*]; + + for i in 0..names.len() { + let full_name = format!("{}_{}", prefix, names[i]); + let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + } + result.push('\n'); } + + result } } - }); - - let expanded = quote! { - #(#modules)* }; TokenStream::from(expanded) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 22838096..4bd71c26 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -37,7 +37,7 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; // SAFETY: all accounts have been read. - let instruction_data = context.instruction_data_unchecked(); - let program_id = context.program_id_unchecked(); + let instruction_data = unsafe { context.instruction_data_unchecked() }; + let program_id = unsafe { context.program_id_unchecked() }; Ok(()) } From c8c515f64551296bd6afc55844a2e1e6a79d9139 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:23:17 -0800 Subject: [PATCH 021/263] Start input buffer map --- examples/tree/interface/src/asm.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index b4bcab06..3c50910c 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -2,8 +2,35 @@ extern crate alloc; use macros::extend_constant_group; +use pinocchio::Address; + extend_constant_group!(input_buffer { prefix = "IB", /// Number of accounts passed in input. N_ACCOUNTS_OFF = 0, }); + +#[repr(C, packed)] +struct InputAccountHeader { + non_dup_marker: u8, + is_signer: bool, + is_writable: bool, + is_executable: bool, + original_data_len: u32, + pubkey: Address, + owner: Address, + lamports: u64, + data_len: u64, +} + +#[repr(C, packed)] +struct EmptyInputAccount { + header: InputAccountHeader, + rent_epoch: u64, +} + +struct InputBuffer { + n_accounts: u64, + user: EmptyInputAccount, + tree_header: InputAccountHeader, +} From 02cede78d8d9a04a4f90c15d1f103f25af2f46a3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:24:59 -0800 Subject: [PATCH 022/263] Make repr C, packed --- examples/tree/interface/src/asm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 3c50910c..89be474b 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -29,6 +29,7 @@ struct EmptyInputAccount { rent_epoch: u64, } +#[repr(C, packed)] struct InputBuffer { n_accounts: u64, user: EmptyInputAccount, From 7b9e4650f8f4b9f3c9f61f52588af21a5d96fe90 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:34:11 -0800 Subject: [PATCH 023/263] Update offsets in constant group --- examples/tree/interface/src/asm.rs | 4 +- examples/tree/interface/src/common.rs | 2 +- examples/tree/macros/src/lib.rs | 108 +++++++++++++++++++++++--- examples/tree/src/tree/tree.s | 4 +- 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 89be474b..99b7822d 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -6,8 +6,8 @@ use pinocchio::Address; extend_constant_group!(input_buffer { prefix = "IB", - /// Number of accounts passed in input. - N_ACCOUNTS_OFF = 0, + /// Number of accounts field. + offset!(N_ACCOUNTS, InputBuffer.n_accounts), }); #[repr(C, packed)] diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 2cf8b26d..2e0acae4 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -12,7 +12,7 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { - /// Number of accounts expected. + /// Expected number of accounts. N_ACCOUNTS: u64 = 2, } } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 07d965e8..61154c13 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -334,7 +334,16 @@ pub fn constant_group(input: TokenStream) -> TokenStream { struct AsmConstantDef { doc: String, name: Ident, - value: LitInt, + kind: AsmConstantKind, +} + +/// Kind of ASM constant. +enum AsmConstantKind { + /// Direct value (i32 validated). + Value(LitInt), + /// Offset derived from struct field (i16 validated). + /// Name gets `_OFF` suffix appended. + Offset { struct_name: Ident, field_name: Ident }, } /// Input for extend_constant_group! macro. @@ -367,6 +376,9 @@ impl Parse for ExtendConstantGroupInput { content.parse::()?; // Parse constants (ASM-only, no type needed). + // Supports two syntaxes: + // NAME = value -> direct value (i32 validated) + // offset!(NAME, Struct.field) -> offset (i16 validated, _OFF suffix) let mut constants = Vec::new(); while !content.is_empty() { let const_attrs = content.call(syn::Attribute::parse_outer)?; @@ -377,9 +389,32 @@ impl Parse for ExtendConstantGroupInput { return Err(content.error(e)); } - let const_name: Ident = content.parse()?; - content.parse::()?; - let const_value: LitInt = content.parse()?; + // Check for offset!(NAME, Struct.field) syntax. + let lookahead = content.lookahead1(); + let (const_name, kind) = if lookahead.peek(Ident) { + let ident: Ident = content.parse()?; + if ident == "offset" { + // Parse offset!(NAME, Struct.field) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + inner.parse::()?; + let field_name: Ident = inner.parse()?; + // Append _OFF suffix to the name. + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + (full_name, AsmConstantKind::Offset { struct_name, field_name }) + } else { + // Regular NAME = value syntax. + content.parse::()?; + let value: LitInt = content.parse()?; + (ident, AsmConstantKind::Value(value)) + } + } else { + return Err(lookahead.error()); + }; // Optional trailing comma. let _ = content.parse::(); @@ -387,7 +422,7 @@ impl Parse for ExtendConstantGroupInput { constants.push(AsmConstantDef { doc: const_doc, name: const_name, - value: const_value, + kind, }); } @@ -405,17 +440,21 @@ impl Parse for ExtendConstantGroupInput { /// `crate::common::{name}` and adds ASM-only constants. The `to_asm()` function /// combines both under one header. The prefix is automatically joined with an underscore. /// +/// Supports two constant syntaxes: +/// - `NAME = value` - direct value (validated for i32 range) +/// - `offset!(NAME, Struct.field)` - offset (validated for i16 range, `_OFF` suffix added) +/// /// # Example /// ```ignore /// extend_constant_group!(input_buffer { /// prefix = "IB", /// /// Offset to number of accounts field. -/// N_ACCOUNTS_OFF = 0, +/// offset!(N_ACCOUNTS, InputBuffer.n_accounts), /// }); /// // Creates `input_buffer` module that: /// // - Re-exports all constants from crate::common::input_buffer -/// // - Adds ASM-only constants (N_ACCOUNTS_OFF) -/// // - to_asm() outputs all constants with "IB_" prefix under one header +/// // - Adds N_ACCOUNTS_OFF constant derived from offset_of!(InputBuffer, n_accounts) +/// // - to_asm() outputs ".equ IB_N_ACCOUNTS_OFF, 0 # ..." /// ``` #[proc_macro] pub fn extend_constant_group(input: TokenStream) -> TokenStream { @@ -425,9 +464,52 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let prefix = &input.prefix; let max_line_len = MAX_LINE_LEN; - let const_names: Vec = input.constants.iter().map(|c| c.name.to_string()).collect(); - let const_values: Vec = input.constants.iter().map(|c| c.value.to_string()).collect(); - let const_docs: Vec = input.constants.iter().map(|c| c.doc.clone()).collect(); + // Generate constant definitions and collect info for ASM. + let mut const_defs = Vec::new(); + let mut const_names = Vec::new(); + let mut const_docs = Vec::new(); + + for c in &input.constants { + let name = &c.name; + let doc = &c.doc; + let name_str = name.to_string(); + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + + const_names.push(name_str); + const_docs.push(doc.clone()); + + match &c.kind { + AsmConstantKind::Value(value) => { + // Direct value - validate i32 range. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i32 = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } + AsmConstantKind::Offset { struct_name, field_name } => { + // Offset from struct field - validate i16 range. + // Use super:: to access struct from parent module. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #field_name) as i16; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #field_name) as i64) >= (i16::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #field_name) as i64) <= (i16::MAX as i64), + "Offset must fit in i16 range" + ); + }); + } + } + } + + // Collect const idents for ASM output. + let const_idents: Vec<_> = input.constants.iter().map(|c| &c.name).collect(); let expanded = quote! { pub mod #mod_name { @@ -437,6 +519,8 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { // Re-export base group's constants. pub use crate::common::#mod_name::*; + #(#const_defs)* + /// Generate combined ASM (base + extension) with prefix. pub fn to_asm() -> String { // Base group adds header and its constants. @@ -444,7 +528,7 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { // Add extension constants (no separate header). let names = [#(#const_names),*]; - let values = [#(#const_values),*]; + let values = [#(#const_idents as i64),*]; let docs = [#(#const_docs),*]; for i in 0..names.len() { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index bdd93672..cab80cee 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,7 +1,7 @@ # Input buffer layout. # -------------------- -.equ IB_N_ACCOUNTS, 2 # Number of accounts expected. -.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts passed in input. +.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. # Error codes. # ------------ From 3bc987c81925bdc9e09ab076a25353b56cf475f3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:01:01 -0800 Subject: [PATCH 024/263] Add asm const group support --- examples/tree/build.rs | 7 +- examples/tree/interface/src/asm.rs | 13 +- examples/tree/macros/src/lib.rs | 301 +++++++++++++++++++++++------ examples/tree/src/tree/tree.s | 23 ++- 4 files changed, 278 insertions(+), 66 deletions(-) diff --git a/examples/tree/build.rs b/examples/tree/build.rs index c3fe8457..16054159 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -11,7 +11,12 @@ fn main() { let marker_pos = content.find(ENTRYPOINT_START).unwrap(); // Generate the constants and insert them before the entrypoint marker. - let constants = format!("{}\n{}", input_buffer::to_asm(), Error::to_asm()); + let constants = format!( + "{}\n{}\n{}", + Error::to_asm(), + input_buffer::to_asm(), + misc::to_asm() + ); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { fs::write(&asm_path, new_content).unwrap(); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 99b7822d..91ef8e5b 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,15 +1,24 @@ extern crate alloc; -use macros::extend_constant_group; - +use macros::{asm_constant_group, extend_constant_group}; use pinocchio::Address; extend_constant_group!(input_buffer { prefix = "IB", /// Number of accounts field. offset!(N_ACCOUNTS, InputBuffer.n_accounts), + /// User data length field. + offset!(USER_DATA_LEN, InputBuffer.user.header.data_len), }); +asm_constant_group! { + /// Miscellaneous constants. + misc { + /// Data length of zero. + DATA_LENGTH_ZERO = 0, + } +} + #[repr(C, packed)] struct InputAccountHeader { non_dup_marker: u8, diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 61154c13..64bcb55d 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -341,9 +341,244 @@ struct AsmConstantDef { enum AsmConstantKind { /// Direct value (i32 validated). Value(LitInt), - /// Offset derived from struct field (i16 validated). + /// Offset derived from struct field path (i16 validated). /// Name gets `_OFF` suffix appended. - Offset { struct_name: Ident, field_name: Ident }, + /// Supports nested fields like `Struct.field1.field2.field3`. + Offset { struct_name: Ident, field_path: Vec }, +} + +/// Input for asm_constant_group! macro. +struct AsmConstantGroupInput { + doc: String, + name: Ident, + prefix: Option, + constants: Vec, +} + +/// Parse ASM constants (shared between asm_constant_group! and extend_constant_group!). +fn parse_asm_constants(content: ParseStream) -> syn::Result> { + let mut constants = Vec::new(); + while !content.is_empty() { + let const_attrs = content.call(syn::Attribute::parse_outer)?; + let const_doc = extract_doc_comment(&const_attrs) + .ok_or_else(|| content.error("Constant must have a doc comment"))?; + + if let Err(e) = validate_doc_comment(&const_doc) { + return Err(content.error(e)); + } + + // Check for offset!(NAME, Struct.field) syntax. + let lookahead = content.lookahead1(); + let (const_name, kind) = if lookahead.peek(Ident) { + let ident: Ident = content.parse()?; + if ident == "offset" { + // Parse offset!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + // Parse field path (one or more fields separated by dots). + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + // Append _OFF suffix to the name. + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + (full_name, AsmConstantKind::Offset { struct_name, field_path }) + } else { + // Regular NAME = value syntax. + content.parse::()?; + let value: LitInt = content.parse()?; + (ident, AsmConstantKind::Value(value)) + } + } else { + return Err(lookahead.error()); + }; + + // Optional trailing comma. + let _ = content.parse::(); + + constants.push(AsmConstantDef { + doc: const_doc, + name: const_name, + kind, + }); + } + Ok(constants) +} + +impl Parse for AsmConstantGroupInput { + fn parse(input: ParseStream) -> syn::Result { + // Parse doc comment for the group. + let attrs = input.call(syn::Attribute::parse_outer)?; + let doc = extract_doc_comment(&attrs) + .ok_or_else(|| input.error("Group must have a doc comment"))?; + + if let Err(e) = validate_doc_comment(&doc) { + return Err(input.error(format!("Group doc comment: {}", e))); + } + + // Parse group name. + let name: Ident = input.parse()?; + + // Parse body. + let content; + braced!(content in input); + + // Parse optional prefix = "..." + let prefix = if content.peek(Ident) { + let fork = content.fork(); + let ident: Ident = fork.parse()?; + if ident == "prefix" && fork.peek(Token![=]) { + // Advance the actual stream. + content.parse::()?; + content.parse::()?; + let prefix_lit: syn::LitStr = content.parse()?; + content.parse::()?; + Some(prefix_lit.value()) + } else { + None + } + } else { + None + }; + + // Parse constants. + let constants = parse_asm_constants(&content)?; + + // Reject multiple groups. + if !input.is_empty() { + return Err(input.error("Only one group per macro invocation")); + } + + Ok(AsmConstantGroupInput { + doc, + name, + prefix, + constants, + }) + } +} + +/// Macro for defining ASM-only constant groups. +/// +/// Constants don't need types - values are `i64`, offsets are `i16`. +/// All values are validated at compile time to fit within i32 range (sBPF constraint). +/// +/// Supports two constant syntaxes: +/// - `NAME = value` - direct value (i64, validated for i32 range) +/// - `offset!(NAME, Struct.field)` - offset (i16, validated for i16 range, `_OFF` suffix added) +/// +/// # Example +/// ```ignore +/// asm_constant_group! { +/// /// Miscellaneous constants. +/// misc { +/// prefix = "M", +/// /// Data length of zero. +/// DATA_LENGTH_ZERO = 0, +/// } +/// } +/// // Creates `misc` module with: +/// // - pub const DATA_LENGTH_ZERO: i64 = 0; +/// // - to_asm() outputs ".equ M_DATA_LENGTH_ZERO, 0 # ..." +/// ``` +#[proc_macro] +pub fn asm_constant_group(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as AsmConstantGroupInput); + + let mod_name = &input.name; + let max_line_len = MAX_LINE_LEN; + let header = asm_header(&input.doc); + + // Generate constant definitions and collect info for ASM. + let mut const_defs = Vec::new(); + let mut const_names = Vec::new(); + let mut const_docs = Vec::new(); + + for c in &input.constants { + let name = &c.name; + let doc = &c.doc; + let name_str = name.to_string(); + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + + const_names.push(name_str); + const_docs.push(doc.clone()); + + match &c.kind { + AsmConstantKind::Value(value) => { + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i64 = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } + AsmConstantKind::Offset { struct_name, field_path } => { + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), + "Offset must fit in i16 range" + ); + }); + } + } + } + + let const_idents: Vec<_> = input.constants.iter().map(|c| &c.name).collect(); + + // Generate name formatting logic based on whether prefix is present. + let name_format = match &input.prefix { + Some(prefix) => quote! { format!("{}_{}", #prefix, names[i]) }, + None => quote! { String::from(names[i]) }, + }; + + let expanded = quote! { + pub mod #mod_name { + use alloc::string::String; + use alloc::format; + + #(#const_defs)* + + /// Generate ASM constants. + pub fn to_asm() -> String { + let mut result = String::from(#header); + result.push('\n'); + + let names = [#(#const_names),*]; + let values = [#(#const_idents as i64),*]; + let docs = [#(#const_docs),*]; + + for i in 0..names.len() { + let full_name = #name_format; + let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + } + result.push('\n'); + } + + result + } + } + }; + + TokenStream::from(expanded) } /// Input for extend_constant_group! macro. @@ -375,56 +610,8 @@ impl Parse for ExtendConstantGroupInput { let prefix = prefix_lit.value(); content.parse::()?; - // Parse constants (ASM-only, no type needed). - // Supports two syntaxes: - // NAME = value -> direct value (i32 validated) - // offset!(NAME, Struct.field) -> offset (i16 validated, _OFF suffix) - let mut constants = Vec::new(); - while !content.is_empty() { - let const_attrs = content.call(syn::Attribute::parse_outer)?; - let const_doc = extract_doc_comment(&const_attrs) - .ok_or_else(|| content.error("Constant must have a doc comment"))?; - - if let Err(e) = validate_doc_comment(&const_doc) { - return Err(content.error(e)); - } - - // Check for offset!(NAME, Struct.field) syntax. - let lookahead = content.lookahead1(); - let (const_name, kind) = if lookahead.peek(Ident) { - let ident: Ident = content.parse()?; - if ident == "offset" { - // Parse offset!(NAME, Struct.field) - content.parse::()?; - let inner; - syn::parenthesized!(inner in content); - let base_name: Ident = inner.parse()?; - inner.parse::()?; - let struct_name: Ident = inner.parse()?; - inner.parse::()?; - let field_name: Ident = inner.parse()?; - // Append _OFF suffix to the name. - let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); - (full_name, AsmConstantKind::Offset { struct_name, field_name }) - } else { - // Regular NAME = value syntax. - content.parse::()?; - let value: LitInt = content.parse()?; - (ident, AsmConstantKind::Value(value)) - } - } else { - return Err(lookahead.error()); - }; - - // Optional trailing comma. - let _ = content.parse::(); - - constants.push(AsmConstantDef { - doc: const_doc, - name: const_name, - kind, - }); - } + // Parse constants using shared parser. + let constants = parse_asm_constants(&content)?; Ok(ExtendConstantGroupInput { name, @@ -491,16 +678,16 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { ); }); } - AsmConstantKind::Offset { struct_name, field_name } => { - // Offset from struct field - validate i16 range. + AsmConstantKind::Offset { struct_name, field_path } => { + // Offset from struct field path - validate i16 range. // Use super:: to access struct from parent module. const_defs.push(quote! { #[doc = #doc] - pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #field_name) as i16; + pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #field_name) as i64) >= (i16::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #field_name) as i64) <= (i16::MAX as i64), + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), "Offset must fit in i16 range" ); }); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index cab80cee..272114b8 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,16 +1,27 @@ -# Input buffer layout. -# -------------------- -.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. -.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. - # Error codes. # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. .equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. .equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. +# Input buffer layout. +# -------------------- +.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_DATA_LEN_OFF, 88 # User data length field. + +# Miscellaneous constants. +# ------------------------ +.equ DATA_LENGTH_ZERO, 0 # Data length of zero. + .globl entrypoint entrypoint: - mov64 r0, 0 + ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. + ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. exit + +e_n_accounts: + mov64 r0, E_N_ACCOUNTS + exit \ No newline at end of file From 4e53e5c2e528a39ed03db6459b3426d85d917d2b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:10:37 -0800 Subject: [PATCH 025/263] Tweak macro logic --- examples/tree/build.rs | 32 +++++++++++++++++++++++------- examples/tree/interface/src/lib.rs | 2 +- examples/tree/macros/src/lib.rs | 22 ++++++++++---------- examples/tree/src/program.rs | 4 ++-- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 16054159..c6fbf78a 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,8 +1,14 @@ use interface::*; -use std::{fs, path::Path}; +use std::{collections::HashSet, fs, path::Path}; const ENTRYPOINT_START: &str = ".globl entrypoint"; +macro_rules! asm_groups { + ($($group:ident),* $(,)?) => { + [$($group::to_asm()),*] + }; +} + fn main() { // Read in the assembly file and find the entrypoint marker. let manifest_dir = env!("CARGO_MANIFEST_DIR"); @@ -10,13 +16,25 @@ fn main() { let content = fs::read_to_string(&asm_path).unwrap(); let marker_pos = content.find(ENTRYPOINT_START).unwrap(); + // Collect all constant groups. + let groups = asm_groups![error_codes, input_buffer, misc]; + + // Check for duplicate constant names. + let mut seen = HashSet::new(); + for group in &groups { + for line in group.lines() { + if let Some(name) = line.strip_prefix(".equ ") { + if let Some(name) = name.split(',').next() { + if !seen.insert(name.to_string()) { + panic!("Duplicate constant name: {}", name); + } + } + } + } + } + // Generate the constants and insert them before the entrypoint marker. - let constants = format!( - "{}\n{}\n{}", - Error::to_asm(), - input_buffer::to_asm(), - misc::to_asm() - ); + let constants = groups.join("\n"); let new_content = format!("{}\n{}", constants, &content[marker_pos..]); if new_content != content { fs::write(&asm_path, new_content).unwrap(); diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index a8adf1b9..f85c0603 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -6,4 +6,4 @@ mod asm; mod common; pub use asm::*; -pub use common::Error; +pub use common::error_codes; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 64bcb55d..334d7647 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -92,20 +92,20 @@ pub fn error_codes(input: TokenStream) -> TokenStream { let body = asm_lines.join("\n"); let expanded = quote! { - #[repr(u32)] - #[allow(non_camel_case_types)] - pub enum Error { - #(#variant_defs),* - } + pub mod error_codes { + #[repr(u32)] + #[allow(non_camel_case_types)] + pub enum error { + #(#variant_defs),* + } - impl From for u32 { - fn from(e: Error) -> u32 { - e as u32 + impl From for u32 { + fn from(e: error) -> u32 { + e as u32 + } } - } - impl Error { - /// Generate ASM constants for this enum. + /// Generate ASM constants for error codes. pub fn to_asm() -> alloc::string::String { alloc::format!("{}\n{}\n", #header, #body) } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 4bd71c26..85180a98 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -17,7 +17,7 @@ macro_rules! if_err { /// Return the given error. macro_rules! err { ($variant:ident) => { - return Err(ProgramError::Custom(Error::$variant.into())) + return Err(ProgramError::Custom(error_codes::error::$variant.into())) }; } @@ -30,7 +30,7 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; - if_err!(user.data_len() != 0, USER_DATA_LEN); + if_err!(!user.is_data_empty(), USER_DATA_LEN); // SAFETY: number of accounts has been checked. let tree = match unsafe { context.next_account_unchecked() } { MaybeAccount::Account(account) => account, From cce114e6bb36071e32202feaaeed96bd2103b251 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:22:16 -0800 Subject: [PATCH 026/263] Begin fast fail finalization --- examples/tree/interface/src/asm.rs | 4 ++++ examples/tree/src/tree/tree.s | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 91ef8e5b..95c61fee 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -9,6 +9,10 @@ extend_constant_group!(input_buffer { offset!(N_ACCOUNTS, InputBuffer.n_accounts), /// User data length field. offset!(USER_DATA_LEN, InputBuffer.user.header.data_len), + /// Non-duplicate marker value. + NON_DUP_MARKER = 0xff, + /// Tree non-duplicate marker field. + offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.non_dup_marker), }); asm_constant_group! { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 272114b8..d32e2f37 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,6 +9,8 @@ .equ IB_N_ACCOUNTS, 2 # Expected number of accounts. .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. +.equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. +.equ IB_TREE_NON_DUP_MARKER_OFF, 104 # Tree non-duplicate marker field. # Miscellaneous constants. # ------------------------ @@ -20,8 +22,12 @@ entrypoint: ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. + jne r2, DATA_LENGTH_ZERO, e_user_data_len # Error if user has data. exit e_n_accounts: mov64 r0, E_N_ACCOUNTS - exit \ No newline at end of file + exit + +e_user_data_len: + mov64 r0, E_USER_DATA_LEN \ No newline at end of file From 2486695974c42dc1b6ad2b617648ec460be1390c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:25:53 -0800 Subject: [PATCH 027/263] Preserve hex status --- examples/tree/macros/src/lib.rs | 63 ++++++++++++++++++++++++++------- examples/tree/src/tree/tree.s | 2 +- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 334d7647..631a5387 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -501,6 +501,8 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { let mut const_defs = Vec::new(); let mut const_names = Vec::new(); let mut const_docs = Vec::new(); + // Track value representations: Some(literal_str) for values, None for offsets. + let mut const_value_strs: Vec> = Vec::new(); for c in &input.constants { let name = &c.name; @@ -513,6 +515,8 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { match &c.kind { AsmConstantKind::Value(value) => { + // Preserve original literal representation (hex, binary, etc.). + const_value_strs.push(Some(value.to_string())); const_defs.push(quote! { #[doc = #doc] pub const #name: i64 = #value; @@ -524,6 +528,8 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { }); } AsmConstantKind::Offset { struct_name, field_path } => { + // Offsets are computed at runtime, no literal to preserve. + const_value_strs.push(None); const_defs.push(quote! { #[doc = #doc] pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; @@ -546,6 +552,14 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { None => quote! { String::from(names[i]) }, }; + // Generate value string options for preserving hex/binary literals. + let value_str_opts: Vec<_> = const_value_strs.iter().map(|opt| { + match opt { + Some(s) => quote! { Some(#s) }, + None => quote! { None }, + } + }).collect(); + let expanded = quote! { pub mod #mod_name { use alloc::string::String; @@ -558,17 +572,23 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { let mut result = String::from(#header); result.push('\n'); - let names = [#(#const_names),*]; - let values = [#(#const_idents as i64),*]; - let docs = [#(#const_docs),*]; + let names: &[&str] = &[#(#const_names),*]; + let computed_values: &[i64] = &[#(#const_idents as i64),*]; + let literal_values: &[Option<&str>] = &[#(#value_str_opts),*]; + let docs: &[&str] = &[#(#const_docs),*]; for i in 0..names.len() { let full_name = #name_format; - let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + // Use original literal if available, otherwise use computed value. + let value_str = match literal_values[i] { + Some(lit) => String::from(lit), + None => format!("{}", computed_values[i]), + }; + let inline = format!(".equ {}, {} # {}", full_name, value_str, docs[i]); if inline.len() <= #max_line_len { result.push_str(&inline); } else { - result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, value_str)); } result.push('\n'); } @@ -655,6 +675,8 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let mut const_defs = Vec::new(); let mut const_names = Vec::new(); let mut const_docs = Vec::new(); + // Track value representations: Some(literal_str) for values, None for offsets. + let mut const_value_strs: Vec> = Vec::new(); for c in &input.constants { let name = &c.name; @@ -667,7 +689,8 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { match &c.kind { AsmConstantKind::Value(value) => { - // Direct value - validate i32 range. + // Preserve original literal representation (hex, binary, etc.). + const_value_strs.push(Some(value.to_string())); const_defs.push(quote! { #[doc = #doc] pub const #name: i32 = #value; @@ -679,8 +702,8 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { }); } AsmConstantKind::Offset { struct_name, field_path } => { - // Offset from struct field path - validate i16 range. - // Use super:: to access struct from parent module. + // Offsets are computed at runtime, no literal to preserve. + const_value_strs.push(None); const_defs.push(quote! { #[doc = #doc] pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; @@ -698,6 +721,14 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { // Collect const idents for ASM output. let const_idents: Vec<_> = input.constants.iter().map(|c| &c.name).collect(); + // Generate value string options for preserving hex/binary literals. + let value_str_opts: Vec<_> = const_value_strs.iter().map(|opt| { + match opt { + Some(s) => quote! { Some(#s) }, + None => quote! { None }, + } + }).collect(); + let expanded = quote! { pub mod #mod_name { use alloc::string::String; @@ -714,17 +745,23 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let mut result = crate::common::#mod_name::to_asm(#prefix); // Add extension constants (no separate header). - let names = [#(#const_names),*]; - let values = [#(#const_idents as i64),*]; - let docs = [#(#const_docs),*]; + let names: &[&str] = &[#(#const_names),*]; + let computed_values: &[i64] = &[#(#const_idents as i64),*]; + let literal_values: &[Option<&str>] = &[#(#value_str_opts),*]; + let docs: &[&str] = &[#(#const_docs),*]; for i in 0..names.len() { let full_name = format!("{}_{}", #prefix, names[i]); - let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + // Use original literal if available, otherwise use computed value. + let value_str = match literal_values[i] { + Some(lit) => String::from(lit), + None => format!("{}", computed_values[i]), + }; + let inline = format!(".equ {}, {} # {}", full_name, value_str, docs[i]); if inline.len() <= #max_line_len { result.push_str(&inline); } else { - result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, value_str)); } result.push('\n'); } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d32e2f37..67795615 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,7 +9,7 @@ .equ IB_N_ACCOUNTS, 2 # Expected number of accounts. .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. -.equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. +.equ IB_NON_DUP_MARKER, 0xff # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 104 # Tree non-duplicate marker field. # Miscellaneous constants. From 181a1baf1d8ce1e7c8e0dbea4ed4e2e5590ef227 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:29:39 -0800 Subject: [PATCH 028/263] Complete ASM fast fail --- examples/tree/src/program.rs | 6 +++--- examples/tree/src/tree/tree.s | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 85180a98..d39706bf 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -32,12 +32,12 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { let user = unsafe { context.next_account_unchecked().assume_account() }; if_err!(!user.is_data_empty(), USER_DATA_LEN); // SAFETY: number of accounts has been checked. - let tree = match unsafe { context.next_account_unchecked() } { + let _tree = match unsafe { context.next_account_unchecked() } { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; // SAFETY: all accounts have been read. - let instruction_data = unsafe { context.instruction_data_unchecked() }; - let program_id = unsafe { context.program_id_unchecked() }; + let _instruction_data = unsafe { context.instruction_data_unchecked() }; + let _program_id = unsafe { context.program_id_unchecked() }; Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 67795615..c0c8cf49 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -23,6 +23,9 @@ entrypoint: jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. jne r2, DATA_LENGTH_ZERO, e_user_data_len # Error if user has data. + ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. + # Error if tree is duplicate account. + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate exit e_n_accounts: @@ -30,4 +33,9 @@ e_n_accounts: exit e_user_data_len: - mov64 r0, E_USER_DATA_LEN \ No newline at end of file + mov64 r0, E_USER_DATA_LEN + exit + +e_tree_duplicate: + mov64 r0, E_TREE_DUPLICATE + exit \ No newline at end of file From bbf0ec499475ba300c3bbe36232b37dca18d10d4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:46:15 -0800 Subject: [PATCH 029/263] Use pinocchio --- examples/tree/interface/src/asm.rs | 29 +++++++++-------------------- examples/tree/src/tree/tree.s | 2 +- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 95c61fee..a36f0419 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,7 +1,8 @@ extern crate alloc; use macros::{asm_constant_group, extend_constant_group}; -use pinocchio::Address; +use pinocchio::account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}; +use pinocchio::entrypoint::NON_DUP_MARKER; extend_constant_group!(input_buffer { prefix = "IB", @@ -10,9 +11,9 @@ extend_constant_group!(input_buffer { /// User data length field. offset!(USER_DATA_LEN, InputBuffer.user.header.data_len), /// Non-duplicate marker value. - NON_DUP_MARKER = 0xff, + NON_DUP_MARKER = NON_DUP_MARKER, /// Tree non-duplicate marker field. - offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.non_dup_marker), + offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.borrow_state), }); asm_constant_group! { @@ -24,27 +25,15 @@ asm_constant_group! { } #[repr(C, packed)] -struct InputAccountHeader { - non_dup_marker: u8, - is_signer: bool, - is_writable: bool, - is_executable: bool, - original_data_len: u32, - pubkey: Address, - owner: Address, - lamports: u64, - data_len: u64, -} - -#[repr(C, packed)] -struct EmptyInputAccount { - header: InputAccountHeader, +struct EmptyRuntimeAccount { + header: RuntimeAccountHeader, + data: [u8; MAX_PERMITTED_DATA_INCREASE], rent_epoch: u64, } #[repr(C, packed)] struct InputBuffer { n_accounts: u64, - user: EmptyInputAccount, - tree_header: InputAccountHeader, + user: EmptyRuntimeAccount, + tree_header: RuntimeAccountHeader, } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index c0c8cf49..35e6c15f 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -10,7 +10,7 @@ .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 0xff # Non-duplicate marker value. -.equ IB_TREE_NON_DUP_MARKER_OFF, 104 # Tree non-duplicate marker field. +.equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. # Miscellaneous constants. # ------------------------ From f669aaa336d8ccb9b610652acd1e1788fb5cb3ca Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:10:06 -0800 Subject: [PATCH 030/263] Add tree data length calcs --- examples/tree/interface/src/asm.rs | 18 +++-- examples/tree/macros/src/lib.rs | 105 +++++++++++++++++++++++------ examples/tree/src/tree/tree.s | 12 +++- 3 files changed, 106 insertions(+), 29 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index a36f0419..bc0df7aa 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,8 +1,10 @@ extern crate alloc; use macros::{asm_constant_group, extend_constant_group}; -use pinocchio::account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}; -use pinocchio::entrypoint::NON_DUP_MARKER; +use pinocchio::{ + account::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE}, + entrypoint::NON_DUP_MARKER, +}; extend_constant_group!(input_buffer { prefix = "IB", @@ -14,19 +16,25 @@ extend_constant_group!(input_buffer { NON_DUP_MARKER = NON_DUP_MARKER, /// Tree non-duplicate marker field. offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.borrow_state), + /// Tree data length field. + offset!(TREE_DATA_LEN, InputBuffer.tree_header.data_len), }); asm_constant_group! { /// Miscellaneous constants. misc { /// Data length of zero. - DATA_LENGTH_ZERO = 0, + DATA_LEN_ZERO = 0, + /// And mask for data length alignment. + DATA_LEN_AND_MASK = -8, + /// Maximum possible data length padding. + MAX_DATA_PAD = 7, } } #[repr(C, packed)] struct EmptyRuntimeAccount { - header: RuntimeAccountHeader, + header: RuntimeAccount, data: [u8; MAX_PERMITTED_DATA_INCREASE], rent_epoch: u64, } @@ -35,5 +43,5 @@ struct EmptyRuntimeAccount { struct InputBuffer { n_accounts: u64, user: EmptyRuntimeAccount, - tree_header: RuntimeAccountHeader, + tree_header: RuntimeAccount, } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 631a5387..bb1c4d68 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{ braced, - parse::{Parse, ParseStream}, + parse::{discouraged::Speculative, Parse, ParseStream}, parse_macro_input, Ident, Lit, LitInt, Meta, Token, }; @@ -234,7 +234,9 @@ impl Parse for ConstantGroup { // Reject multiple groups in a single macro invocation. if !input.is_empty() { - return Err(input.error("Only one constant group per macro invocation; use separate constant_group! calls")); + return Err(input.error( + "Only one constant group per macro invocation; use separate constant_group! calls", + )); } Ok(ConstantGroup { @@ -291,7 +293,11 @@ pub fn constant_group(input: TokenStream) -> TokenStream { }); let const_names: Vec = group.constants.iter().map(|c| c.name.to_string()).collect(); - let const_values: Vec = group.constants.iter().map(|c| c.value.to_string()).collect(); + let const_values: Vec = group + .constants + .iter() + .map(|c| c.value.to_string()) + .collect(); let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); let expanded = quote! { @@ -339,12 +345,17 @@ struct AsmConstantDef { /// Kind of ASM constant. enum AsmConstantKind { - /// Direct value (i32 validated). - Value(LitInt), + /// Literal value (i32 validated) - preserves original representation (hex, etc.). + Literal(LitInt), + /// Expression value (i32 validated) - computed at runtime, shown as decimal. + Expr(syn::Expr), /// Offset derived from struct field path (i16 validated). /// Name gets `_OFF` suffix appended. /// Supports nested fields like `Struct.field1.field2.field3`. - Offset { struct_name: Ident, field_path: Vec }, + Offset { + struct_name: Ident, + field_path: Vec, + }, } /// Input for asm_constant_group! macro. @@ -390,12 +401,26 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> } // Append _OFF suffix to the name. let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); - (full_name, AsmConstantKind::Offset { struct_name, field_path }) + ( + full_name, + AsmConstantKind::Offset { + struct_name, + field_path, + }, + ) } else { // Regular NAME = value syntax. content.parse::()?; - let value: LitInt = content.parse()?; - (ident, AsmConstantKind::Value(value)) + // Try to parse as literal first (to preserve hex/binary representation), + // otherwise parse as expression (for constants like NON_DUP_MARKER). + let fork = content.fork(); + if let Ok(lit) = fork.parse::() { + content.advance_to(&fork); + (ident, AsmConstantKind::Literal(lit)) + } else { + let expr: syn::Expr = content.parse()?; + (ident, AsmConstantKind::Expr(expr)) + } } } else { return Err(lookahead.error()); @@ -514,7 +539,7 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { const_docs.push(doc.clone()); match &c.kind { - AsmConstantKind::Value(value) => { + AsmConstantKind::Literal(value) => { // Preserve original literal representation (hex, binary, etc.). const_value_strs.push(Some(value.to_string())); const_defs.push(quote! { @@ -527,7 +552,25 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { ); }); } - AsmConstantKind::Offset { struct_name, field_path } => { + AsmConstantKind::Expr(expr) => { + // Expression (e.g., constant from another crate) - computed at runtime. + // Use super::* to access imports from parent scope. + const_value_strs.push(None); + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i64 = { use super::*; #expr as i64 }; + + const #assert_name: () = assert!( + ({ use super::*; #expr } as i64) >= (i32::MIN as i64) + && ({ use super::*; #expr } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } + AsmConstantKind::Offset { + struct_name, + field_path, + } => { // Offsets are computed at runtime, no literal to preserve. const_value_strs.push(None); const_defs.push(quote! { @@ -553,12 +596,13 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { }; // Generate value string options for preserving hex/binary literals. - let value_str_opts: Vec<_> = const_value_strs.iter().map(|opt| { - match opt { + let value_str_opts: Vec<_> = const_value_strs + .iter() + .map(|opt| match opt { Some(s) => quote! { Some(#s) }, None => quote! { None }, - } - }).collect(); + }) + .collect(); let expanded = quote! { pub mod #mod_name { @@ -688,7 +732,7 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { const_docs.push(doc.clone()); match &c.kind { - AsmConstantKind::Value(value) => { + AsmConstantKind::Literal(value) => { // Preserve original literal representation (hex, binary, etc.). const_value_strs.push(Some(value.to_string())); const_defs.push(quote! { @@ -701,7 +745,25 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { ); }); } - AsmConstantKind::Offset { struct_name, field_path } => { + AsmConstantKind::Expr(expr) => { + // Expression (e.g., constant from another crate) - computed at runtime. + // Use super::* to access imports from parent scope. + const_value_strs.push(None); + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i32 = { use super::*; #expr as i32 }; + + const #assert_name: () = assert!( + ({ use super::*; #expr } as i64) >= (i32::MIN as i64) + && ({ use super::*; #expr } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } + AsmConstantKind::Offset { + struct_name, + field_path, + } => { // Offsets are computed at runtime, no literal to preserve. const_value_strs.push(None); const_defs.push(quote! { @@ -722,12 +784,13 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let const_idents: Vec<_> = input.constants.iter().map(|c| &c.name).collect(); // Generate value string options for preserving hex/binary literals. - let value_str_opts: Vec<_> = const_value_strs.iter().map(|opt| { - match opt { + let value_str_opts: Vec<_> = const_value_strs + .iter() + .map(|opt| match opt { Some(s) => quote! { Some(#s) }, None => quote! { None }, - } - }).collect(); + }) + .collect(); let expanded = quote! { pub mod #mod_name { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 35e6c15f..6fd71273 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,12 +9,15 @@ .equ IB_N_ACCOUNTS, 2 # Expected number of accounts. .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. -.equ IB_NON_DUP_MARKER, 0xff # Non-duplicate marker value. +.equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. +.equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Miscellaneous constants. # ------------------------ -.equ DATA_LENGTH_ZERO, 0 # Data length of zero. +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. .globl entrypoint @@ -22,10 +25,13 @@ entrypoint: ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. - jne r2, DATA_LENGTH_ZERO, e_user_data_len # Error if user has data. + jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. # Error if tree is duplicate account. jne r2, IB_NON_DUP_MARKER, e_tree_duplicate + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. + and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. exit e_n_accounts: From c36c375b30cb8b27b1449b255259af3972386e93 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:11:38 -0800 Subject: [PATCH 031/263] Simplify comment --- examples/tree/src/tree/tree.s | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 6fd71273..96d45535 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -27,8 +27,7 @@ entrypoint: ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. - # Error if tree is duplicate account. - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. From 7d9e0c9c606f71bd9ffb4893361ed74c94ce77c9 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:46:48 -0800 Subject: [PATCH 032/263] Add preliminary test harness --- examples/tree/artifacts/dumps/asm.txt | 26 +- examples/tree/artifacts/dumps/rs.txt | 159 ++++++++---- examples/tree/artifacts/rs-disassembly.s | 52 ++++ .../tests/asm_no_accounts/result.txt | 4 + .../artifacts/tests/asm_no_accounts/test.txt | 4 + .../tests/asm_too_many_accounts/result.txt | 4 + .../tests/asm_too_many_accounts/test.txt | 4 + .../tests/asm_tree_duplicate/result.txt | 4 + .../tests/asm_tree_duplicate/test.txt | 4 + .../tests/asm_user_data_len/result.txt | 4 + .../tests/asm_user_data_len/test.txt | 4 + .../print_compute_units_table/result.txt | 32 +++ .../tests/print_compute_units_table/test.txt | 25 ++ .../artifacts/tests/rs_no_accounts/result.txt | 4 + .../artifacts/tests/rs_no_accounts/test.txt | 4 + .../tests/rs_too_many_accounts/result.txt | 4 + .../tests/rs_too_many_accounts/test.txt | 4 + .../tests/rs_tree_duplicate/result.txt | 4 + .../tests/rs_tree_duplicate/test.txt | 4 + .../tests/rs_user_data_len/result.txt | 4 + .../artifacts/tests/rs_user_data_len/test.txt | 4 + examples/tree/macros/src/lib.rs | 4 +- examples/tree/src/tests.rs | 226 ++++++++++++++++++ 23 files changed, 527 insertions(+), 61 deletions(-) create mode 100644 examples/tree/artifacts/tests/asm_no_accounts/result.txt create mode 100644 examples/tree/artifacts/tests/asm_no_accounts/test.txt create mode 100644 examples/tree/artifacts/tests/asm_too_many_accounts/result.txt create mode 100644 examples/tree/artifacts/tests/asm_too_many_accounts/test.txt create mode 100644 examples/tree/artifacts/tests/asm_tree_duplicate/result.txt create mode 100644 examples/tree/artifacts/tests/asm_tree_duplicate/test.txt create mode 100644 examples/tree/artifacts/tests/asm_user_data_len/result.txt create mode 100644 examples/tree/artifacts/tests/asm_user_data_len/test.txt create mode 100644 examples/tree/artifacts/tests/print_compute_units_table/result.txt create mode 100644 examples/tree/artifacts/tests/print_compute_units_table/test.txt create mode 100644 examples/tree/artifacts/tests/rs_no_accounts/result.txt create mode 100644 examples/tree/artifacts/tests/rs_no_accounts/test.txt create mode 100644 examples/tree/artifacts/tests/rs_too_many_accounts/result.txt create mode 100644 examples/tree/artifacts/tests/rs_too_many_accounts/test.txt create mode 100644 examples/tree/artifacts/tests/rs_tree_duplicate/result.txt create mode 100644 examples/tree/artifacts/tests/rs_tree_duplicate/test.txt create mode 100644 examples/tree/artifacts/tests/rs_user_data_len/result.txt create mode 100644 examples/tree/artifacts/tests/rs_user_data_len/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 435654bf..f85e1d1f 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 96 (bytes into file) + Start of section headers 208 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,13 +19,13 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 3 Section header string table index 2 -There are 3 section headers, starting at offset 0x60 +There are 3 section headers, starting at offset 0xd0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000040 000040 000010 00 AX 0 0 4 - [ 2] .s STRTAB 0000000000000000 000050 00000a 00 0 0 1 + [ 1] .text PROGBITS 0000000000000040 000040 000080 00 AX 0 0 4 + [ 2] .s STRTAB 0000000000000000 0000c0 00000a 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -46,5 +46,19 @@ tree.so file format elf64-bpf Disassembly of section .text 0000000000000040 <.text> - 8 b7 00 00 00 00 00 00 00 r0 = 0x0 - 9 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) + 9 55 02 08 00 02 00 00 00 if r2 != 0x2 goto +0x8 <.text+0x50> + 10 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 11 55 02 08 00 00 00 00 00 if r2 != 0x0 goto +0x8 <.text+0x60> + 12 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 13 55 02 08 00 ff 00 00 00 if r2 != 0xff goto +0x8 <.text+0x70> + 14 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 15 07 02 00 00 07 00 00 00 r2 += 0x7 + 16 57 02 00 00 f8 ff ff ff r2 &= -0x8 + 17 95 00 00 00 00 00 00 00 exit + 18 b7 00 00 00 01 00 00 00 r0 = 0x1 + 19 95 00 00 00 00 00 00 00 exit + 20 b7 00 00 00 02 00 00 00 r0 = 0x2 + 21 95 00 00 00 00 00 00 00 exit + 22 b7 00 00 00 03 00 00 00 r0 = 0x3 + 23 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index ec1f5096..0349fb13 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2600 (bytes into file) + Start of section headers 3296 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xa28 +There are 8 section headers, starting at offset 0xce0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000018 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000138 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000140 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000140 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000140 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0004b8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0004f6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000170 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000290 000058 00 WA 0 0 8 + [ 3] .bss.stack NOBITS 0000000200000000 0002e8 001000 00 WA 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 0002e8 001000 00 WA 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 0002e8 000408 18 7 42 8 + [ 6] .shstrtab STRTAB 0000000000000000 0006f0 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00072e 0005ac 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000018 0x000018 E 0x8 - LOAD 0x000138 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000140 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000140 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000170 0x000170 E 0x8 + LOAD 0x000290 0x0000000100000000 0x0000000100000000 0x000058 0x000058 R 0x8 + LOAD 0x0002e8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x0002e8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -58,45 +58,51 @@ Program Headers There are no relocations in this file. -Symbol table '.symtab' contains 37 entries +Symbol table '.symtab' contains 43 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.f7f35e91187ba07f-cgu.0 - 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 68vyx9rfiautweaa6qunv68kh - 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 - 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 - 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 - 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 - 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 - 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 - 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 - 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 - 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 - 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 - 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 - 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 - 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 - 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 - 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 - 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 - 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 - 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 - 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 - 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 - 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 - 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 - 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 - 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 - 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 - 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 - 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 - 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 - 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 - 32 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start - 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end - 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start - 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 24 FUNC GLOBAL DEFAULT 1 entrypoint + 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 + 2 0000000100000028 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_1 + 3 0000000100000038 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_2 + 4 0000000100000000 18 OBJECT LOCAL DEFAULT 2 .L__unnamed_7 + 5 0000000100000012 22 OBJECT LOCAL DEFAULT 2 .L__unnamed_8 + 6 00000000000000f0 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind + 7 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl + 8 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 + 9 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 + 10 0000000000000130 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 + 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 + 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 + 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 + 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 + 32 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 + 33 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 + 34 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 + 35 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 + 36 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 + 37 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 + 38 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start + 39 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end + 40 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start + 41 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end + 42 0000000000000000 240 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,6 +110,53 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - 8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 10 9d 00 00 00 00 00 00 00 return \ No newline at end of file + 0 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 10 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 18 55 02 0c 00 02 00 00 00 jne r2, 0x2, +0xc + 20 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] + 28 55 02 0b 00 ff 00 00 00 jne r2, 0xff, +0xb + 30 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 38 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 40 55 02 07 00 00 00 00 00 jne r2, 0x0, +0x7 + 48 0f 21 00 00 00 00 00 00 add64 r1, r2 + 50 07 01 00 00 6f 28 00 00 add64 r1, 0x286f + 58 57 01 00 00 f8 ff ff ff and64 r1, -0x8 + 60 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 68 2c 11 00 00 00 00 00 00 ldxb w1, [r1 + 0x0] + 70 55 01 01 00 ff 00 00 00 jne r1, 0xff, +0x1 + 78 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 80 9d 00 00 00 00 00 00 00 return + 88 b4 01 00 00 28 00 00 00 mov32 w1, 0x28 + 90 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + 98 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + a0 b4 02 00 00 38 00 00 00 mov32 w2, 0x38 + a8 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + b0 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 + b8 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 + c0 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 + c8 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 + d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + d8 07 01 00 00 10 00 00 00 add64 r1, 0x10 + e0 85 10 00 00 09 00 00 00 call 0x9 + e8 9d 00 00 00 00 00 00 00 return + +00000000000000f0 + f0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 + f8 9c 13 08 00 00 00 00 00 ldxdw r3, [r1 + 0x8] + 100 8c 34 14 00 00 00 00 00 ldxw w4, [r3 + 0x14] + 108 9c 32 08 00 00 00 00 00 ldxdw r2, [r3 + 0x8] + 110 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] + 118 8c 33 10 00 00 00 00 00 ldxw w3, [r3 + 0x10] + 120 95 00 00 00 bb 93 60 68 syscall 0x686093bb + 128 9d 00 00 00 00 00 00 00 return + +0000000000000130 + 130 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 138 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 + 140 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 + 148 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 + 150 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 158 07 01 00 00 28 00 00 00 add64 r1, 0x28 + 160 85 10 00 00 f1 ff ff ff call -0xf + 168 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 50457dc6..94afb64f 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,5 +1,57 @@ .globl entrypoint entrypoint: + add64 r10, -64 + mov64 r0, 1 + ldxdw r2, [r1+0] + jne r2, 2, jmp_0080 + ldxb r2, [r1+8] + jne r2, 255, jmp_0088 + mov64 r0, 2 + ldxdw r2, [r1+88] + jne r2, 0, jmp_0080 + add64 r1, r2 + add64 r1, 10351 + and64 r1, -8 + mov64 r0, 3 + ldxb r1, [r1+0] + jne r1, 255, jmp_0080 mov64 r0, 0 + +jmp_0080: exit + +jmp_0088: + mov32 r1, 680 + hor64 r1, 0 + stxdw [r10+16], r1 + mov32 r2, 696 + hor64 r2, 0 + stdw [r10+48], 0 + stdw [r10+24], 1 + stdw [r10+40], 0 + stdw [r10+32], 8 + mov64 r1, r10 + add64 r1, 16 + call fn_0120 + +fn_00e8: + ldxdw r2, [r1+8] + ldxw r4, [r2+20] + ldxw r3, [r2+16] + ldxdw r1, [r2+0] + ldxdw r2, [r2+8] + add64 r2, -1 + call sol_panic_ + +fn_0120: + add64 r10, -64 + stxdw [r10+48], r2 + stxdw [r10+40], r1 + sth [r10+56], 1 + mov64 r1, r10 + add64 r1, 40 + call fn_00e8 + +.rodata + data_0000: .byte 0x73, 0x72, 0x63, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2f, 0x6c, 0x61, 0x7a, 0x79, 0x2e, 0x72, 0x73, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74 diff --git a/examples/tree/artifacts/tests/asm_no_accounts/result.txt b/examples/tree/artifacts/tests/asm_no_accounts/result.txt new file mode 100644 index 00000000..56e16bab --- /dev/null +++ b/examples/tree/artifacts/tests/asm_no_accounts/result.txt @@ -0,0 +1,4 @@ +test tests::test_asm_no_accounts ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_no_accounts/test.txt b/examples/tree/artifacts/tests/asm_no_accounts/test.txt new file mode 100644 index 00000000..81c7c702 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_no_accounts/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_asm_no_accounts() { + run_no_accounts(ProgramLanguage::Assembly); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt new file mode 100644 index 00000000..c1de1a92 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt @@ -0,0 +1,4 @@ +test tests::test_asm_too_many_accounts ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt new file mode 100644 index 00000000..34851030 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_asm_too_many_accounts() { + run_too_many_accounts(ProgramLanguage::Assembly); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt b/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt new file mode 100644 index 00000000..6cf41176 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt @@ -0,0 +1,4 @@ +test tests::test_asm_tree_duplicate ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt b/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt new file mode 100644 index 00000000..795d0a06 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_asm_tree_duplicate() { + run_tree_duplicate(ProgramLanguage::Assembly); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_user_data_len/result.txt b/examples/tree/artifacts/tests/asm_user_data_len/result.txt new file mode 100644 index 00000000..edd5c6a9 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_user_data_len/result.txt @@ -0,0 +1,4 @@ +test tests::test_asm_user_data_len ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_user_data_len/test.txt b/examples/tree/artifacts/tests/asm_user_data_len/test.txt new file mode 100644 index 00000000..90ee3df2 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_user_data_len/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_asm_user_data_len() { + run_user_data_len(ProgramLanguage::Assembly); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/print_compute_units_table/result.txt b/examples/tree/artifacts/tests/print_compute_units_table/result.txt new file mode 100644 index 00000000..b35c408b --- /dev/null +++ b/examples/tree/artifacts/tests/print_compute_units_table/result.txt @@ -0,0 +1,32 @@ +### :evergreen_tree: Parsing +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts passed | 4 | 5 | +1 | +25.0% | +| Too many accounts passed | 4 | 5 | +1 | +25.0% | +| User has non-zero data length | 6 | 10 | +4 | +66.7% | +| Tree account is duplicate | 8 | 16 | +8 | +100.0% | +test tests::test_print_compute_units_table ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/print_compute_units_table/test.txt b/examples/tree/artifacts/tests/print_compute_units_table/test.txt new file mode 100644 index 00000000..ff748bd7 --- /dev/null +++ b/examples/tree/artifacts/tests/print_compute_units_table/test.txt @@ -0,0 +1,25 @@ +#[test] +fn test_print_compute_units_table() { + println!("\n### :evergreen_tree: Parsing\n"); + println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|------|-----------|------------|----------|------------|"); + + for case in Case::PARSING_CASES { + let asm_cu = case.run(ProgramLanguage::Assembly); + let rs_cu = case.run(ProgramLanguage::Rust); + let overhead = rs_cu as i64 - asm_cu as i64; + let overhead_pct = if asm_cu > 0 { + (overhead as f64 / asm_cu as f64) * 100.0 + } else { + 0.0 + }; + println!( + "| {} | {} | {} | {:+} | {:+.1}% |", + case.name(), + asm_cu, + rs_cu, + overhead, + overhead_pct + ); + } +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_no_accounts/result.txt b/examples/tree/artifacts/tests/rs_no_accounts/result.txt new file mode 100644 index 00000000..45fd880e --- /dev/null +++ b/examples/tree/artifacts/tests/rs_no_accounts/result.txt @@ -0,0 +1,4 @@ +test tests::test_rs_no_accounts ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_no_accounts/test.txt b/examples/tree/artifacts/tests/rs_no_accounts/test.txt new file mode 100644 index 00000000..e1a69a29 --- /dev/null +++ b/examples/tree/artifacts/tests/rs_no_accounts/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_rs_no_accounts() { + run_no_accounts(ProgramLanguage::Rust); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt b/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt new file mode 100644 index 00000000..3730a4ad --- /dev/null +++ b/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt @@ -0,0 +1,4 @@ +test tests::test_rs_too_many_accounts ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt b/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt new file mode 100644 index 00000000..0b789239 --- /dev/null +++ b/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_rs_too_many_accounts() { + run_too_many_accounts(ProgramLanguage::Rust); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt b/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt new file mode 100644 index 00000000..abe3ac71 --- /dev/null +++ b/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt @@ -0,0 +1,4 @@ +test tests::test_rs_tree_duplicate ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt b/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt new file mode 100644 index 00000000..7f272336 --- /dev/null +++ b/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_rs_tree_duplicate() { + run_tree_duplicate(ProgramLanguage::Rust); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_user_data_len/result.txt b/examples/tree/artifacts/tests/rs_user_data_len/result.txt new file mode 100644 index 00000000..15421030 --- /dev/null +++ b/examples/tree/artifacts/tests/rs_user_data_len/result.txt @@ -0,0 +1,4 @@ +test tests::test_rs_user_data_len ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_user_data_len/test.txt b/examples/tree/artifacts/tests/rs_user_data_len/test.txt new file mode 100644 index 00000000..e2c49a6a --- /dev/null +++ b/examples/tree/artifacts/tests/rs_user_data_len/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_rs_user_data_len() { + run_user_data_len(ProgramLanguage::Rust); +} \ No newline at end of file diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index bb1c4d68..ce4d5812 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -78,11 +78,11 @@ pub fn error_codes(input: TokenStream) -> TokenStream { let variant_name = &entry.name; // Just add E_ prefix for ASM. let asm_name = format!("E_{}", entry.name); - let value = idx + 1; + let value = (idx + 1) as u32; variant_defs.push(quote! { #[doc = #doc] - #variant_name + #variant_name = #value }); asm_lines.push(asm_equ_line(&asm_name, &value, doc)); diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 8b137891..668f7bd2 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1 +1,227 @@ +use interface::error_codes; +use mollusk_svm::program; +use mollusk_svm::result::Check; +use solana_sdk::account::Account; +use solana_sdk::instruction::{AccountMeta, Instruction}; +use solana_sdk::program_error::ProgramError; +use solana_sdk::pubkey::Pubkey; +use std::vec; +use test_utils::{setup_test, ProgramLanguage}; +enum AccountIndex { + User = 0, + Tree = 1, +} + +fn happy_path_setup( + program_language: ProgramLanguage, +) -> (test_utils::TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + (user_pubkey, Account::new(1_000_000, 0, &system_program)), + (tree_pubkey, Account::new(0, 0, &system_program)), + ]; + + (setup, instruction, accounts) +} + +// --- Test case definitions --- + +#[derive(Clone, Copy)] +enum Case { + NoAccounts, + TooManyAccounts, + UserDataLen, + TreeDuplicate, +} + +impl Case { + const PARSING_CASES: &'static [Case] = &[ + Case::NoAccounts, + Case::TooManyAccounts, + Case::UserDataLen, + Case::TreeDuplicate, + ]; + + const fn name(&self) -> &'static str { + match self { + Self::NoAccounts => "No accounts passed", + Self::TooManyAccounts => "Too many accounts passed", + Self::UserDataLen => "User has non-zero data length", + Self::TreeDuplicate => "Tree account is duplicate", + } + } + + fn run(&self, lang: ProgramLanguage) -> u64 { + match self { + Self::NoAccounts => run_no_accounts(lang), + Self::TooManyAccounts => run_too_many_accounts(lang), + Self::UserDataLen => run_user_data_len(lang), + Self::TreeDuplicate => run_tree_duplicate(lang), + } + } +} + +// --- Test runners that return CU consumption --- + +fn run_no_accounts(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, mut accounts) = happy_path_setup(lang); + + instruction.accounts.clear(); + accounts.clear(); + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::N_ACCOUNTS.into(), + ))], + ) + .compute_units_consumed +} + +fn run_too_many_accounts(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, mut accounts) = happy_path_setup(lang); + + instruction + .accounts + .push(AccountMeta::new_readonly(Pubkey::new_unique(), false)); + accounts.push(( + instruction.accounts.last().unwrap().pubkey, + Account::default(), + )); + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::N_ACCOUNTS.into(), + ))], + ) + .compute_units_consumed +} + +fn run_user_data_len(lang: ProgramLanguage) -> u64 { + let (setup, instruction, mut accounts) = happy_path_setup(lang); + + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::USER_DATA_LEN.into(), + ))], + ) + .compute_units_consumed +} + +fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, mut accounts) = happy_path_setup(lang); + + // Make tree account a duplicate of user. + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = accounts[AccountIndex::User as usize].clone(); + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::TREE_DUPLICATE.into(), + ))], + ) + .compute_units_consumed +} + +// --- Individual tests for each case/implementation --- + +#[test] +fn test_asm_no_accounts() { + run_no_accounts(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_too_many_accounts() { + run_too_many_accounts(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_user_data_len() { + run_user_data_len(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_tree_duplicate() { + run_tree_duplicate(ProgramLanguage::Assembly); +} + +#[test] +fn test_rs_no_accounts() { + run_no_accounts(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_too_many_accounts() { + run_too_many_accounts(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_user_data_len() { + run_user_data_len(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_tree_duplicate() { + run_tree_duplicate(ProgramLanguage::Rust); +} + +// --- Compute unit comparison table --- + +#[test] +fn test_print_compute_units_table() { + println!("\n### :evergreen_tree: Parsing\n"); + println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|------|-----------|------------|----------|------------|"); + + for case in Case::PARSING_CASES { + let asm_cu = case.run(ProgramLanguage::Assembly); + let rs_cu = case.run(ProgramLanguage::Rust); + let overhead = rs_cu as i64 - asm_cu as i64; + let overhead_pct = if asm_cu > 0 { + (overhead as f64 / asm_cu as f64) * 100.0 + } else { + 0.0 + }; + println!( + "| {} | {} | {} | {:+} | {:+.1}% |", + case.name(), + asm_cu, + rs_cu, + overhead, + overhead_pct + ); + } +} From 0903f2ce373da5cc3dc1a052bf69448b620a9cc4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:54:35 -0800 Subject: [PATCH 033/263] Add prelim docs include --- .../tests/{print_compute_units_table => fast_fails}/result.txt | 3 +-- .../tests/{print_compute_units_table => fast_fails}/test.txt | 3 +-- examples/tree/src/tests.rs | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) rename examples/tree/artifacts/tests/{print_compute_units_table => fast_fails}/result.txt (95%) rename examples/tree/artifacts/tests/{print_compute_units_table => fast_fails}/test.txt (88%) diff --git a/examples/tree/artifacts/tests/print_compute_units_table/result.txt b/examples/tree/artifacts/tests/fast_fails/result.txt similarity index 95% rename from examples/tree/artifacts/tests/print_compute_units_table/result.txt rename to examples/tree/artifacts/tests/fast_fails/result.txt index b35c408b..85a36c93 100644 --- a/examples/tree/artifacts/tests/print_compute_units_table/result.txt +++ b/examples/tree/artifacts/tests/fast_fails/result.txt @@ -1,11 +1,10 @@ -### :evergreen_tree: Parsing | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| | No accounts passed | 4 | 5 | +1 | +25.0% | | Too many accounts passed | 4 | 5 | +1 | +25.0% | | User has non-zero data length | 6 | 10 | +4 | +66.7% | | Tree account is duplicate | 8 | 16 | +8 | +100.0% | -test tests::test_print_compute_units_table ... ok +test tests::test_fast_fails ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/print_compute_units_table/test.txt b/examples/tree/artifacts/tests/fast_fails/test.txt similarity index 88% rename from examples/tree/artifacts/tests/print_compute_units_table/test.txt rename to examples/tree/artifacts/tests/fast_fails/test.txt index ff748bd7..bdd6e7b5 100644 --- a/examples/tree/artifacts/tests/print_compute_units_table/test.txt +++ b/examples/tree/artifacts/tests/fast_fails/test.txt @@ -1,6 +1,5 @@ #[test] -fn test_print_compute_units_table() { - println!("\n### :evergreen_tree: Parsing\n"); +fn test_fast_fails() { println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); println!("|------|-----------|------------|----------|------------|"); diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 668f7bd2..249b1507 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -201,8 +201,7 @@ fn test_rs_tree_duplicate() { // --- Compute unit comparison table --- #[test] -fn test_print_compute_units_table() { - println!("\n### :evergreen_tree: Parsing\n"); +fn test_fast_fails() { println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); println!("|------|-----------|------------|----------|------------|"); From 909104bd2f0483fd57571a47058b99b10ea3bc06 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:54:55 -0800 Subject: [PATCH 034/263] Include test MD --- docs/src/examples/tree.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 3049c649..28339676 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -9,6 +9,10 @@ This example implements a [red-black tree][wikipedia tree page] in both paths side-by-side for a comprehensive breakdown of assembly vs Rust performance. +## Input buffer checks + + + ## :white_check_mark: All tests ::: details `tests.rs` From 304f41db374bd76ebb4f2d171051ce565545af19 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:00:34 -0800 Subject: [PATCH 035/263] Tweak preliminary testing/includes --- docs/src/examples/tree.md | 12 +++++++++++- examples/tree/artifacts/tests/fast_fails/result.txt | 2 +- examples/tree/src/tests.rs | 11 +---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 28339676..28a6c8ea 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -11,7 +11,17 @@ performance. ## Input buffer checks - +::: code-group + +<<< ../../../examples/tree/src/tree/tree.s{asm} [Assembly] + +<<< ../../../examples/tree/src/program.rs [Rust] + +::: + + ## :white_check_mark: All tests diff --git a/examples/tree/artifacts/tests/fast_fails/result.txt b/examples/tree/artifacts/tests/fast_fails/result.txt index 85a36c93..87a093e3 100644 --- a/examples/tree/artifacts/tests/fast_fails/result.txt +++ b/examples/tree/artifacts/tests/fast_fails/result.txt @@ -2,7 +2,7 @@ |------|-----------|------------|----------|------------| | No accounts passed | 4 | 5 | +1 | +25.0% | | Too many accounts passed | 4 | 5 | +1 | +25.0% | -| User has non-zero data length | 6 | 10 | +4 | +66.7% | +| User has nonzero data length | 6 | 10 | +4 | +66.7% | | Tree account is duplicate | 8 | 16 | +8 | +100.0% | test tests::test_fast_fails ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 249b1507..0b20e697 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -39,8 +39,6 @@ fn happy_path_setup( (setup, instruction, accounts) } -// --- Test case definitions --- - #[derive(Clone, Copy)] enum Case { NoAccounts, @@ -61,7 +59,7 @@ impl Case { match self { Self::NoAccounts => "No accounts passed", Self::TooManyAccounts => "Too many accounts passed", - Self::UserDataLen => "User has non-zero data length", + Self::UserDataLen => "User has nonzero data length", Self::TreeDuplicate => "Tree account is duplicate", } } @@ -76,8 +74,6 @@ impl Case { } } -// --- Test runners that return CU consumption --- - fn run_no_accounts(lang: ProgramLanguage) -> u64 { let (setup, mut instruction, mut accounts) = happy_path_setup(lang); @@ -139,7 +135,6 @@ fn run_user_data_len(lang: ProgramLanguage) -> u64 { fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { let (setup, mut instruction, mut accounts) = happy_path_setup(lang); - // Make tree account a duplicate of user. instruction.accounts[AccountIndex::Tree as usize] = instruction.accounts[AccountIndex::User as usize].clone(); accounts[AccountIndex::Tree as usize] = accounts[AccountIndex::User as usize].clone(); @@ -156,8 +151,6 @@ fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { .compute_units_consumed } -// --- Individual tests for each case/implementation --- - #[test] fn test_asm_no_accounts() { run_no_accounts(ProgramLanguage::Assembly); @@ -198,8 +191,6 @@ fn test_rs_tree_duplicate() { run_tree_duplicate(ProgramLanguage::Rust); } -// --- Compute unit comparison table --- - #[test] fn test_fast_fails() { println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); From 0998858be26b85e0b008f42178a54557c3d23757 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:25:22 -0800 Subject: [PATCH 036/263] Add anchor support --- docs/src/examples/tree.md | 4 +- examples/tree/artifacts/dumps/rs.txt | 92 +++++++------- examples/tree/artifacts/rs-disassembly.s | 32 ++--- .../snippets/asm/check-input-buffer.txt | 9 ++ .../tree/artifacts/snippets/asm/constants.txt | 20 +++ .../snippets/rs/check-input-buffer.txt | 13 ++ examples/tree/build.rs | 120 +++++++++++++++++- examples/tree/src/program.rs | 6 +- examples/tree/src/tree/tree.s | 7 +- 9 files changed, 230 insertions(+), 73 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/check-input-buffer.txt create mode 100644 examples/tree/artifacts/snippets/asm/constants.txt create mode 100644 examples/tree/artifacts/snippets/rs/check-input-buffer.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 28a6c8ea..d53be418 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -13,9 +13,9 @@ performance. ::: code-group -<<< ../../../examples/tree/src/tree/tree.s{asm} [Assembly] +<<< ../../../examples/tree/artifacts/snippets/asm/check-input-buffer.txt{asm} [Assembly] -<<< ../../../examples/tree/src/program.rs [Rust] +<<< ../../../examples/tree/artifacts/snippets/rs/check-input-buffer.txt{rs} [Rust] ::: diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 0349fb13..a87bccc4 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -9,7 +9,7 @@ ELF Header Type DYN (Shared object file) Machine Solana Bytecode Format Version 0x1 - Entry point address 0x0 + Entry point address 0x40 Start of program headers 64 (bytes into file) Start of section headers 3296 (bytes into file) Flags 0x4 @@ -38,7 +38,7 @@ Key to Flags R (retain), p (processor specific) Elf file type is DYN (Shared object file) -Entry point 0x0 +Entry point 0x40 There are 4 program headers, starting at offset 64 Program Headers @@ -62,11 +62,11 @@ Symbol table '.symtab' contains 43 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 - 2 0000000100000028 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_1 - 3 0000000100000038 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_2 + 2 0000000100000028 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_3 + 3 0000000100000038 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_4 4 0000000100000000 18 OBJECT LOCAL DEFAULT 2 .L__unnamed_7 5 0000000100000012 22 OBJECT LOCAL DEFAULT 2 .L__unnamed_8 - 6 00000000000000f0 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind + 6 0000000000000000 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind 7 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl 8 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 9 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 @@ -102,53 +102,53 @@ Symbol table '.symtab' contains 43 entries 39 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 40 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 41 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 42 0000000000000000 240 FUNC GLOBAL DEFAULT 1 entrypoint + 42 0000000000000040 240 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf Disassembly of section .text -0000000000000000 - 0 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 10 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 18 55 02 0c 00 02 00 00 00 jne r2, 0x2, +0xc - 20 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] - 28 55 02 0b 00 ff 00 00 00 jne r2, 0xff, +0xb - 30 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 38 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 40 55 02 07 00 00 00 00 00 jne r2, 0x0, +0x7 - 48 0f 21 00 00 00 00 00 00 add64 r1, r2 - 50 07 01 00 00 6f 28 00 00 add64 r1, 0x286f - 58 57 01 00 00 f8 ff ff ff and64 r1, -0x8 - 60 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 68 2c 11 00 00 00 00 00 00 ldxb w1, [r1 + 0x0] - 70 55 01 01 00 ff 00 00 00 jne r1, 0xff, +0x1 - 78 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 80 9d 00 00 00 00 00 00 00 return - 88 b4 01 00 00 28 00 00 00 mov32 w1, 0x28 - 90 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - 98 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - a0 b4 02 00 00 38 00 00 00 mov32 w2, 0x38 - a8 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - b0 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 - b8 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 - c0 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 - c8 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 - d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - d8 07 01 00 00 10 00 00 00 add64 r1, 0x10 - e0 85 10 00 00 09 00 00 00 call 0x9 - e8 9d 00 00 00 00 00 00 00 return +0000000000000000 + 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 + 8 9c 13 08 00 00 00 00 00 ldxdw r3, [r1 + 0x8] + 10 8c 34 14 00 00 00 00 00 ldxw w4, [r3 + 0x14] + 18 9c 32 08 00 00 00 00 00 ldxdw r2, [r3 + 0x8] + 20 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] + 28 8c 33 10 00 00 00 00 00 ldxw w3, [r3 + 0x10] + 30 95 00 00 00 bb 93 60 68 syscall 0x686093bb + 38 9d 00 00 00 00 00 00 00 return -00000000000000f0 - f0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - f8 9c 13 08 00 00 00 00 00 ldxdw r3, [r1 + 0x8] - 100 8c 34 14 00 00 00 00 00 ldxw w4, [r3 + 0x14] - 108 9c 32 08 00 00 00 00 00 ldxdw r2, [r3 + 0x8] - 110 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] - 118 8c 33 10 00 00 00 00 00 ldxw w3, [r3 + 0x10] - 120 95 00 00 00 bb 93 60 68 syscall 0x686093bb +0000000000000040 + 40 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 48 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 50 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 58 55 02 0c 00 02 00 00 00 jne r2, 0x2, +0xc + 60 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] + 68 55 02 0b 00 ff 00 00 00 jne r2, 0xff, +0xb + 70 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 78 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 80 55 02 07 00 00 00 00 00 jne r2, 0x0, +0x7 + 88 0f 21 00 00 00 00 00 00 add64 r1, r2 + 90 07 01 00 00 6f 28 00 00 add64 r1, 0x286f + 98 57 01 00 00 f8 ff ff ff and64 r1, -0x8 + a0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + a8 2c 11 00 00 00 00 00 00 ldxb w1, [r1 + 0x0] + b0 55 01 01 00 ff 00 00 00 jne r1, 0xff, +0x1 + b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + c0 9d 00 00 00 00 00 00 00 return + c8 b4 01 00 00 28 00 00 00 mov32 w1, 0x28 + d0 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + d8 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + e0 b4 02 00 00 38 00 00 00 mov32 w2, 0x38 + e8 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + f0 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 + f8 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 + 100 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 + 108 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 + 110 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 118 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 120 85 10 00 00 01 00 00 00 call 0x1 128 9d 00 00 00 00 00 00 00 return 0000000000000130 @@ -158,5 +158,5 @@ Disassembly of section .text 148 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 150 bf a1 00 00 00 00 00 00 mov64 r1, r10 158 07 01 00 00 28 00 00 00 add64 r1, 0x28 - 160 85 10 00 00 f1 ff ff ff call -0xf + 160 85 10 00 00 d3 ff ff ff call -0x2d 168 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 94afb64f..279d89a6 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,27 +1,36 @@ .globl entrypoint +fn_0000: + ldxdw r2, [r1+8] + ldxw r4, [r2+20] + ldxw r3, [r2+16] + ldxdw r1, [r2+0] + ldxdw r2, [r2+8] + add64 r2, -1 + call sol_panic_ + entrypoint: add64 r10, -64 mov64 r0, 1 ldxdw r2, [r1+0] - jne r2, 2, jmp_0080 + jne r2, 2, jmp_00b8 ldxb r2, [r1+8] - jne r2, 255, jmp_0088 + jne r2, 255, jmp_00c0 mov64 r0, 2 ldxdw r2, [r1+88] - jne r2, 0, jmp_0080 + jne r2, 0, jmp_00b8 add64 r1, r2 add64 r1, 10351 and64 r1, -8 mov64 r0, 3 ldxb r1, [r1+0] - jne r1, 255, jmp_0080 + jne r1, 255, jmp_00b8 mov64 r0, 0 -jmp_0080: +jmp_00b8: exit -jmp_0088: +jmp_00c0: mov32 r1, 680 hor64 r1, 0 stxdw [r10+16], r1 @@ -35,15 +44,6 @@ jmp_0088: add64 r1, 16 call fn_0120 -fn_00e8: - ldxdw r2, [r1+8] - ldxw r4, [r2+20] - ldxw r3, [r2+16] - ldxdw r1, [r2+0] - ldxdw r2, [r2+8] - add64 r2, -1 - call sol_panic_ - fn_0120: add64 r10, -64 stxdw [r10+48], r2 @@ -51,7 +51,7 @@ fn_0120: sth [r10+56], 1 mov64 r1, r10 add64 r1, 40 - call fn_00e8 + call fn_0000 .rodata data_0000: .byte 0x73, 0x72, 0x63, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2f, 0x6c, 0x61, 0x7a, 0x79, 0x2e, 0x72, 0x73, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74 diff --git a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt new file mode 100644 index 00000000..afa3ca3a --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt @@ -0,0 +1,9 @@ +.globl entrypoint + +entrypoint: + ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. + ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. + jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. + ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt new file mode 100644 index 00000000..25a487f3 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -0,0 +1,20 @@ +# Error codes. +# ------------ +.equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. +.equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. +.equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. + +# Input buffer layout. +# -------------------- +.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_DATA_LEN_OFF, 88 # User data length field. +.equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. +.equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. +.equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. + +# Miscellaneous constants. +# ------------------------ +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/check-input-buffer.txt b/examples/tree/artifacts/snippets/rs/check-input-buffer.txt new file mode 100644 index 00000000..ac62a2c5 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/check-input-buffer.txt @@ -0,0 +1,13 @@ +lazy_program_entrypoint!(process_instruction); + +pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { + // Verify the input memory map: user has no data, tree is not duplicate. + if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); + // SAFETY: number of accounts has been checked. + let user = unsafe { context.next_account_unchecked().assume_account() }; + if_err!(!user.is_data_empty(), USER_DATA_LEN); + // SAFETY: number of accounts has been checked. + let _tree = match unsafe { context.next_account_unchecked() } { + MaybeAccount::Account(account) => account, + MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), + }; \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index c6fbf78a..9a507f51 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,7 +1,8 @@ use interface::*; use std::{collections::HashSet, fs, path::Path}; -const ENTRYPOINT_START: &str = ".globl entrypoint"; +const CONSTANTS_ANCHOR_START: &str = "# ANCHOR: constants"; +const CONSTANTS_ANCHOR_END: &str = "# ANCHOR_END: constants"; macro_rules! asm_groups { ($($group:ident),* $(,)?) => { @@ -10,11 +11,23 @@ macro_rules! asm_groups { } fn main() { - // Read in the assembly file and find the entrypoint marker. + // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let asm_path = Path::new(manifest_dir).join("src/tree/tree.s"); + let manifest_path = Path::new(manifest_dir); + let asm_path = manifest_path.join("src/tree/tree.s"); let content = fs::read_to_string(&asm_path).unwrap(); - let marker_pos = content.find(ENTRYPOINT_START).unwrap(); + + // Find the constants anchor region. + let anchor_start = content + .find(CONSTANTS_ANCHOR_START) + .expect("missing '# ANCHOR: constants' in assembly file"); + let anchor_end = content + .find(CONSTANTS_ANCHOR_END) + .expect("missing '# ANCHOR_END: constants' in assembly file"); + assert!( + anchor_start < anchor_end, + "ANCHOR: constants must come before ANCHOR_END: constants" + ); // Collect all constant groups. let groups = asm_groups![error_codes, input_buffer, misc]; @@ -33,10 +46,103 @@ fn main() { } } - // Generate the constants and insert them before the entrypoint marker. + // Generate the constants and insert inside the anchor region. let constants = groups.join("\n"); - let new_content = format!("{}\n{}", constants, &content[marker_pos..]); + let constants = constants.trim(); + let before_anchor = &content[..anchor_start + CONSTANTS_ANCHOR_START.len()]; + let after_anchor = &content[anchor_end..]; + let new_content = format!("{}\n{}\n{}", before_anchor, constants, after_anchor); if new_content != content { - fs::write(&asm_path, new_content).unwrap(); + fs::write(&asm_path, &new_content).unwrap(); + } + + // Extract ANCHOR snippets from source files (use new_content for asm since it's canonical). + extract_snippets(&new_content, manifest_path, "asm"); + + let rs_path = manifest_path.join("src/program.rs"); + let rs_content = fs::read_to_string(&rs_path).unwrap(); + extract_snippets(&rs_content, manifest_path, "rs"); +} + +/// Extract ANCHOR snippets from source content and write to artifacts/snippets/{kind}/. +fn extract_snippets(content: &str, manifest_dir: &Path, kind: &str) { + let snippets_dir = manifest_dir.join(format!("artifacts/snippets/{}", kind)); + + // Wipe existing snippets directory. + if snippets_dir.exists() { + fs::remove_dir_all(&snippets_dir).unwrap(); + } + + let mut current_anchor: Option = None; + let mut current_lines: Vec<&str> = Vec::new(); + let mut snippets: Vec<(String, String)> = Vec::new(); + let mut seen_names: HashSet = HashSet::new(); + + for line in content.lines() { + let trimmed = line.trim(); + + // Check for ANCHOR: start tag (supports # or // comments). + if let Some(rest) = trimmed + .strip_prefix("# ANCHOR:") + .or(trimmed.strip_prefix("// ANCHOR:")) + { + let name = rest.trim().to_string(); + assert!( + current_anchor.is_none(), + "Nested ANCHOR not allowed: found '{}' while inside '{}'", + name, + current_anchor.unwrap() + ); + assert!( + seen_names.insert(name.clone()), + "Duplicate ANCHOR name: '{}'", + name + ); + current_anchor = Some(name); + current_lines.clear(); + continue; + } + + // Check for ANCHOR_END: end tag. + if let Some(rest) = trimmed + .strip_prefix("# ANCHOR_END:") + .or(trimmed.strip_prefix("// ANCHOR_END:")) + { + let name = rest.trim(); + if let Some(ref anchor_name) = current_anchor { + assert_eq!( + anchor_name, name, + "ANCHOR_END mismatch: expected '{}', found '{}'", + anchor_name, name + ); + let snippet_content = current_lines.join("\n"); + snippets.push((anchor_name.clone(), snippet_content)); + current_anchor = None; + current_lines.clear(); + } else { + panic!("ANCHOR_END '{}' without matching ANCHOR", name); + } + continue; + } + + // Collect lines inside an anchor. + if current_anchor.is_some() { + current_lines.push(line); + } + } + + assert!( + current_anchor.is_none(), + "Unclosed ANCHOR: '{}'", + current_anchor.unwrap() + ); + + // Write snippets to files. + if !snippets.is_empty() { + fs::create_dir_all(&snippets_dir).unwrap(); + for (name, content) in snippets { + let snippet_path = snippets_dir.join(format!("{}.txt", name)); + fs::write(&snippet_path, content).unwrap(); + } } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index d39706bf..7b914443 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -21,10 +21,12 @@ macro_rules! err { }; } -lazy_program_entrypoint!(process_instruction); nostd_panic_handler!(); no_allocator!(); +// ANCHOR: check-input-buffer +lazy_program_entrypoint!(process_instruction); + pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { // Verify the input memory map: user has no data, tree is not duplicate. if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); @@ -36,6 +38,8 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; + // ANCHOR_END: check-input-buffer + // SAFETY: all accounts have been read. let _instruction_data = unsafe { context.instruction_data_unchecked() }; let _program_id = unsafe { context.program_id_unchecked() }; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 96d45535..a4564883 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1,3 +1,4 @@ +# ANCHOR: constants # Error codes. # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. @@ -18,7 +19,9 @@ .equ DATA_LEN_ZERO, 0 # Data length of zero. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +# ANCHOR_END: constants +# ANCHOR: check-input-buffer .globl entrypoint entrypoint: @@ -28,6 +31,8 @@ entrypoint: jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. + # ANCHOR_END: check-input-buffer + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. @@ -43,4 +48,4 @@ e_user_data_len: e_tree_duplicate: mov64 r0, E_TREE_DUPLICATE - exit \ No newline at end of file + exit From 95b62f3e8b05da02d06466baf2f676ee72826e59 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:35:41 -0800 Subject: [PATCH 037/263] Update algorithm parity stub --- docs/src/examples/tree.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index d53be418..874479c8 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -13,15 +13,17 @@ performance. ::: code-group + + <<< ../../../examples/tree/artifacts/snippets/asm/check-input-buffer.txt{asm} [Assembly] <<< ../../../examples/tree/artifacts/snippets/rs/check-input-buffer.txt{rs} [Rust] ::: - + + + ## :white_check_mark: All tests From 6df28c01ac96f023992d69667d57ca6dd257ae3c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:49:12 -0800 Subject: [PATCH 038/263] Try setting return data --- examples/tree/artifacts/dumps/asm.txt | 95 +++++++++++++------ .../tree/artifacts/snippets/asm/constants.txt | 1 + examples/tree/interface/src/asm.rs | 2 + examples/tree/src/tree/tree.s | 9 ++ 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index f85e1d1f..07802f4a 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -9,56 +9,95 @@ ELF Header Type DYN (Shared object file) Machine EM_BPF Version 0x1 - Entry point address 0x40 + Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 208 (bytes into file) + Start of section headers 720 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) - Number of program headers 0 + Number of program headers 3 Size of section headers 64 (bytes) - Number of section headers 3 - Section header string table index 2 -There are 3 section headers, starting at offset 0xd0 + Number of section headers 7 + Section header string table index 6 +There are 7 section headers, starting at offset 0x2d0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000040 000040 000080 00 AX 0 0 4 - [ 2] .s STRTAB 0000000000000000 0000c0 00000a 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0000a0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000188 000188 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000228 000228 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000270 000270 000020 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000290 000290 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0002a0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), R (retain), p (processor specific) -There are no program headers in this file. +Elf file type is DYN (Shared object file) +Entry point 0xe8 +There are 3 program headers, starting at offset 64 + +Program Headers + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0000a0 0x0000a0 R E 0x1000 + LOAD 0x000228 0x0000000000000228 0x0000000000000228 0x000078 0x000078 R 0x1000 + DYNAMIC 0x000188 0x0000000000000188 0x0000000000000188 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... - None .text .s + 00 .text + 01 .dynsym .dynstr .rel.dyn + 02 .dynamic + None .s +Dynamic section at offset 0x188 contains 10 entries + Tag Type Name/Value + 0x000000000000001e (FLAGS) TEXTREL + 0x0000000000000011 (REL) 0x290 + 0x0000000000000012 (RELSZ) 16 (bytes) + 0x0000000000000013 (RELENT) 16 (bytes) + 0x0000000000000006 (SYMTAB) 0x228 + 0x000000000000000b (SYMENT) 24 (bytes) + 0x0000000000000005 (STRTAB) 0x270 + 0x000000000000000a (STRSZ) 32 (bytes) + 0x0000000000000016 (TEXTREL) 0x0 + 0x0000000000000000 (NULL) 0x0 + +Relocation section '.rel.dyn' at offset 0x290 contains 1 entries + Offset Info Type Symbol's Value Symbol's Name +0000000000000140 000000020000000a R_BPF_64_32 0000000000000000 sol_set_return_data -There are no relocations in this file. +Symbol table '.dynsym' contains 3 entries + Num Value Size Type Bind Vis Ndx Name + 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1 00000000000000e8 0 NOTYPE GLOBAL DEFAULT 1 entrypoint + 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_set_return_data There are no section groups in this file. tree.so file format elf64-bpf Disassembly of section .text -0000000000000040 <.text> - 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) - 9 55 02 08 00 02 00 00 00 if r2 != 0x2 goto +0x8 <.text+0x50> - 10 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 11 55 02 08 00 00 00 00 00 if r2 != 0x0 goto +0x8 <.text+0x60> - 12 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 13 55 02 08 00 ff 00 00 00 if r2 != 0xff goto +0x8 <.text+0x70> - 14 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 15 07 02 00 00 07 00 00 00 r2 += 0x7 - 16 57 02 00 00 f8 ff ff ff r2 &= -0x8 - 17 95 00 00 00 00 00 00 00 exit - 18 b7 00 00 00 01 00 00 00 r0 = 0x1 - 19 95 00 00 00 00 00 00 00 exit - 20 b7 00 00 00 02 00 00 00 r0 = 0x2 - 21 95 00 00 00 00 00 00 00 exit - 22 b7 00 00 00 03 00 00 00 r0 = 0x3 - 23 95 00 00 00 00 00 00 00 exit \ No newline at end of file +00000000000000e8 + 29 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) + 30 55 02 0c 00 02 00 00 00 if r2 != 0x2 goto +0xc + 31 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 32 55 02 0c 00 00 00 00 00 if r2 != 0x0 goto +0xc + 33 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 34 55 02 0c 00 ff 00 00 00 if r2 != 0xff goto +0xc + 35 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 36 07 02 00 00 07 00 00 00 r2 += 0x7 + 37 57 02 00 00 f8 ff ff ff r2 &= -0x8 + 38 07 01 00 00 10 00 00 00 r1 += 0x10 + 39 b7 02 00 00 20 00 00 00 r2 = 0x20 + 40 85 10 00 00 ff ff ff ff call -0x1 + 41 b7 00 00 00 00 00 00 00 r0 = 0x0 + 42 95 00 00 00 00 00 00 00 exit + 43 b7 00 00 00 01 00 00 00 r0 = 0x1 + 44 95 00 00 00 00 00 00 00 exit + 45 b7 00 00 00 02 00 00 00 r0 = 0x2 + 46 95 00 00 00 00 00 00 00 exit + 47 b7 00 00 00 03 00 00 00 r0 = 0x3 + 48 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 25a487f3..85ba95ec 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -8,6 +8,7 @@ # -------------------- .equ IB_N_ACCOUNTS, 2 # Expected number of accounts. .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index bc0df7aa..d17fb51c 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -10,6 +10,8 @@ extend_constant_group!(input_buffer { prefix = "IB", /// Number of accounts field. offset!(N_ACCOUNTS, InputBuffer.n_accounts), + /// User address field. + offset!(USER_ADDRESS, InputBuffer.user.header.address), /// User data length field. offset!(USER_DATA_LEN, InputBuffer.user.header.data_len), /// Non-duplicate marker value. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a4564883..a686b117 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,6 +9,7 @@ # -------------------- .equ IB_N_ACCOUNTS, 2 # Expected number of accounts. .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. @@ -36,6 +37,14 @@ entrypoint: ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. + + # Test setting return data. + add64 r1, IB_USER_ADDRESS_OFF + mov64 r2, 32 + call sol_set_return_data + + mov64 r0, 0 + exit e_n_accounts: From 63af4849ca127e597531cd768a7605ac985eea96 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:10:11 -0800 Subject: [PATCH 039/263] Beging instruction layout --- examples/tree/artifacts/dumps/asm.txt | 95 ++++++------------- .../tests/asm_no_accounts/result.txt | 29 ++++++ .../tests/asm_return_data/result.txt | 29 ++++++ .../artifacts/tests/asm_return_data/test.txt | 15 +++ .../tests/asm_too_many_accounts/result.txt | 29 ++++++ .../tests/asm_tree_duplicate/result.txt | 29 ++++++ .../tests/asm_user_data_len/result.txt | 29 ++++++ .../artifacts/tests/fast_fails/result.txt | 29 ++++++ .../artifacts/tests/rs_no_accounts/result.txt | 29 ++++++ .../tests/rs_too_many_accounts/result.txt | 29 ++++++ .../tests/rs_tree_duplicate/result.txt | 29 ++++++ .../tests/rs_user_data_len/result.txt | 29 ++++++ examples/tree/interface/src/common.rs | 24 +++++ examples/tree/src/tree/tree.s | 8 -- 14 files changed, 357 insertions(+), 75 deletions(-) create mode 100644 examples/tree/artifacts/tests/asm_return_data/result.txt create mode 100644 examples/tree/artifacts/tests/asm_return_data/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 07802f4a..f85e1d1f 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -9,95 +9,56 @@ ELF Header Type DYN (Shared object file) Machine EM_BPF Version 0x1 - Entry point address 0xE8 + Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 720 (bytes into file) + Start of section headers 208 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) - Number of program headers 3 + Number of program headers 0 Size of section headers 64 (bytes) - Number of section headers 7 - Section header string table index 6 -There are 7 section headers, starting at offset 0x2d0 + Number of section headers 3 + Section header string table index 2 +There are 3 section headers, starting at offset 0xd0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0000a0 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000188 000188 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000228 000228 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000270 000270 000020 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000290 000290 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0002a0 00002c 00 0 0 1 + [ 1] .text PROGBITS 0000000000000040 000040 000080 00 AX 0 0 4 + [ 2] .s STRTAB 0000000000000000 0000c0 00000a 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), R (retain), p (processor specific) -Elf file type is DYN (Shared object file) -Entry point 0xe8 -There are 3 program headers, starting at offset 64 - -Program Headers - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0000a0 0x0000a0 R E 0x1000 - LOAD 0x000228 0x0000000000000228 0x0000000000000228 0x000078 0x000078 R 0x1000 - DYNAMIC 0x000188 0x0000000000000188 0x0000000000000188 0x0000a0 0x0000a0 RW 0x8 +There are no program headers in this file. Section to Segment mapping Segment Sections... - 00 .text - 01 .dynsym .dynstr .rel.dyn - 02 .dynamic - None .s -Dynamic section at offset 0x188 contains 10 entries - Tag Type Name/Value - 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x290 - 0x0000000000000012 (RELSZ) 16 (bytes) - 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x228 - 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x270 - 0x000000000000000a (STRSZ) 32 (bytes) - 0x0000000000000016 (TEXTREL) 0x0 - 0x0000000000000000 (NULL) 0x0 - -Relocation section '.rel.dyn' at offset 0x290 contains 1 entries - Offset Info Type Symbol's Value Symbol's Name -0000000000000140 000000020000000a R_BPF_64_32 0000000000000000 sol_set_return_data + None .text .s -Symbol table '.dynsym' contains 3 entries - Num Value Size Type Bind Vis Ndx Name - 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 00000000000000e8 0 NOTYPE GLOBAL DEFAULT 1 entrypoint - 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_set_return_data +There are no relocations in this file. There are no section groups in this file. tree.so file format elf64-bpf Disassembly of section .text -00000000000000e8 - 29 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) - 30 55 02 0c 00 02 00 00 00 if r2 != 0x2 goto +0xc - 31 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 32 55 02 0c 00 00 00 00 00 if r2 != 0x0 goto +0xc - 33 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 34 55 02 0c 00 ff 00 00 00 if r2 != 0xff goto +0xc - 35 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 36 07 02 00 00 07 00 00 00 r2 += 0x7 - 37 57 02 00 00 f8 ff ff ff r2 &= -0x8 - 38 07 01 00 00 10 00 00 00 r1 += 0x10 - 39 b7 02 00 00 20 00 00 00 r2 = 0x20 - 40 85 10 00 00 ff ff ff ff call -0x1 - 41 b7 00 00 00 00 00 00 00 r0 = 0x0 - 42 95 00 00 00 00 00 00 00 exit - 43 b7 00 00 00 01 00 00 00 r0 = 0x1 - 44 95 00 00 00 00 00 00 00 exit - 45 b7 00 00 00 02 00 00 00 r0 = 0x2 - 46 95 00 00 00 00 00 00 00 exit - 47 b7 00 00 00 03 00 00 00 r0 = 0x3 - 48 95 00 00 00 00 00 00 00 exit \ No newline at end of file +0000000000000040 <.text> + 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) + 9 55 02 08 00 02 00 00 00 if r2 != 0x2 goto +0x8 <.text+0x50> + 10 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 11 55 02 08 00 00 00 00 00 if r2 != 0x0 goto +0x8 <.text+0x60> + 12 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 13 55 02 08 00 ff 00 00 00 if r2 != 0xff goto +0x8 <.text+0x70> + 14 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 15 07 02 00 00 07 00 00 00 r2 += 0x7 + 16 57 02 00 00 f8 ff ff ff r2 &= -0x8 + 17 95 00 00 00 00 00 00 00 exit + 18 b7 00 00 00 01 00 00 00 r0 = 0x1 + 19 95 00 00 00 00 00 00 00 exit + 20 b7 00 00 00 02 00 00 00 r0 = 0x2 + 21 95 00 00 00 00 00 00 00 exit + 22 b7 00 00 00 03 00 00 00 r0 = 0x3 + 23 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_no_accounts/result.txt b/examples/tree/artifacts/tests/asm_no_accounts/result.txt index 56e16bab..fb19672e 100644 --- a/examples/tree/artifacts/tests/asm_no_accounts/result.txt +++ b/examples/tree/artifacts/tests/asm_no_accounts/result.txt @@ -1,4 +1,33 @@ test tests::test_asm_no_accounts ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_return_data/result.txt b/examples/tree/artifacts/tests/asm_return_data/result.txt new file mode 100644 index 00000000..45c65ca2 --- /dev/null +++ b/examples/tree/artifacts/tests/asm_return_data/result.txt @@ -0,0 +1,29 @@ +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_return_data/test.txt b/examples/tree/artifacts/tests/asm_return_data/test.txt new file mode 100644 index 00000000..107f5caf --- /dev/null +++ b/examples/tree/artifacts/tests/asm_return_data/test.txt @@ -0,0 +1,15 @@ +#[test] +fn test_asm_return_data() { + let (setup, instruction, accounts) = happy_path_setup(ProgramLanguage::Assembly); + let user_pubkey = instruction.accounts[AccountIndex::User as usize].pubkey; + + let result = setup + .mollusk + .process_and_validate_instruction(&instruction, &accounts, &[Check::success()]); + + assert_eq!( + result.return_data, + user_pubkey.to_bytes(), + "return data should be user pubkey" + ); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt index c1de1a92..e8ed8786 100644 --- a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt +++ b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt @@ -1,4 +1,33 @@ test tests::test_asm_too_many_accounts ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt b/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt index 6cf41176..f81391b7 100644 --- a/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt +++ b/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt @@ -1,4 +1,33 @@ test tests::test_asm_tree_duplicate ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_user_data_len/result.txt b/examples/tree/artifacts/tests/asm_user_data_len/result.txt index edd5c6a9..fed22ab3 100644 --- a/examples/tree/artifacts/tests/asm_user_data_len/result.txt +++ b/examples/tree/artifacts/tests/asm_user_data_len/result.txt @@ -1,4 +1,33 @@ test tests::test_asm_user_data_len ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/fast_fails/result.txt b/examples/tree/artifacts/tests/fast_fails/result.txt index 87a093e3..f79a3df7 100644 --- a/examples/tree/artifacts/tests/fast_fails/result.txt +++ b/examples/tree/artifacts/tests/fast_fails/result.txt @@ -5,6 +5,35 @@ | User has nonzero data length | 6 | 10 | +4 | +66.7% | | Tree account is duplicate | 8 | 16 | +8 | +100.0% | test tests::test_fast_fails ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/rs_no_accounts/result.txt b/examples/tree/artifacts/tests/rs_no_accounts/result.txt index 45fd880e..9e6ba6e6 100644 --- a/examples/tree/artifacts/tests/rs_no_accounts/result.txt +++ b/examples/tree/artifacts/tests/rs_no_accounts/result.txt @@ -1,4 +1,33 @@ test tests::test_rs_no_accounts ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt b/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt index 3730a4ad..511c887b 100644 --- a/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt +++ b/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt @@ -1,4 +1,33 @@ test tests::test_rs_too_many_accounts ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt b/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt index abe3ac71..79e01f75 100644 --- a/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt +++ b/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt @@ -1,4 +1,33 @@ test tests::test_rs_tree_duplicate ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_user_data_len/result.txt b/examples/tree/artifacts/tests/rs_user_data_len/result.txt index 15421030..36bb311d 100644 --- a/examples/tree/artifacts/tests/rs_user_data_len/result.txt +++ b/examples/tree/artifacts/tests/rs_user_data_len/result.txt @@ -1,4 +1,33 @@ test tests::test_rs_user_data_len ... ok +warning: struct `InitInstructionData` is never constructed + --> tree/interface/src/common.rs:20:8 + | +20 | struct InitInstructionData {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: struct `GetInstructionData` is never constructed + --> tree/interface/src/common.rs:22:8 + | +22 | struct GetInstructionData { + | ^^^^^^^^^^^^^^^^^^ +warning: struct `InsertInstructionData` is never constructed + --> tree/interface/src/common.rs:26:8 + | +26 | struct InsertInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `RemoveInstructionData` is never constructed + --> tree/interface/src/common.rs:31:8 + | +31 | struct RemoveInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: `interface` (lib) generated 5 warnings +warning: `interface` (lib) generated 5 warnings (5 duplicates) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 2e0acae4..5077a77e 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -16,3 +16,27 @@ constant_group! { N_ACCOUNTS: u64 = 2, } } + +struct InitInstructionData {} + +struct GetInstructionData { + key: u16, +} + +struct InsertInstructionData { + key: u16, + value: u16, +} + +struct RemoveInstructionData { + key: u16, +} + +/// Value in r0. +#[repr(C, packed)] +struct Return { + /// If a value is removed from the tree, it's placed here. + maybe_value: u16, + /// 0 for success, nonzero for error. + status: u16, +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a686b117..56b7e903 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -37,14 +37,6 @@ entrypoint: ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. - - # Test setting return data. - add64 r1, IB_USER_ADDRESS_OFF - mov64 r2, 32 - call sol_set_return_data - - mov64 r0, 0 - exit e_n_accounts: From 37afbbeb0bc1f86fdae2ae96f32d491054102e99 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:22:55 -0800 Subject: [PATCH 040/263] Add tree data length checks --- examples/tree/artifacts/snippets/asm/constants.txt | 2 ++ .../artifacts/snippets/asm/tree-data-length.txt | 4 ++++ examples/tree/interface/src/asm.rs | 14 ++++++++++++++ examples/tree/src/tree/tree.s | 9 +++++++++ 4 files changed, 29 insertions(+) create mode 100644 examples/tree/artifacts/snippets/asm/tree-data-length.txt diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 85ba95ec..36beca10 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -13,6 +13,8 @@ .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. +# Instruction data length field for empty tree account. +.equ IB_INSTRUCTION_DATA_LEN_OFF, 20680 # Miscellaneous constants. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/tree-data-length.txt b/examples/tree/artifacts/snippets/asm/tree-data-length.txt new file mode 100644 index 00000000..6cc1c03c --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/tree-data-length.txt @@ -0,0 +1,4 @@ + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. + and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. + add64 r2, r1 # Get input buffer pointer shifted for tree data. \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index d17fb51c..1a156f83 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,6 +4,7 @@ use macros::{asm_constant_group, extend_constant_group}; use pinocchio::{ account::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE}, entrypoint::NON_DUP_MARKER, + Address, }; extend_constant_group!(input_buffer { @@ -20,6 +21,8 @@ extend_constant_group!(input_buffer { offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.borrow_state), /// Tree data length field. offset!(TREE_DATA_LEN, InputBuffer.tree_header.data_len), + /// Instruction data length field for empty tree account. + offset!(INSTRUCTION_DATA_LEN, PackedInputBuffer.instruction_data_len), }); asm_constant_group! { @@ -47,3 +50,14 @@ struct InputBuffer { user: EmptyRuntimeAccount, tree_header: RuntimeAccount, } + +#[repr(C, packed)] +/// Input buffer for empty tree account and no instruction data (during initialization). +struct PackedInputBuffer { + n_accounts: u64, + user: EmptyRuntimeAccount, + tree: EmptyRuntimeAccount, + instruction_data_len: u64, + instruction_data: [u8; 0], + program_id: Address, +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 56b7e903..a2892871 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -14,6 +14,8 @@ .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. +# Instruction data length field for empty tree account. +.equ IB_INSTRUCTION_DATA_LEN_OFF, 20680 # Miscellaneous constants. # ------------------------ @@ -34,9 +36,16 @@ entrypoint: jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. # ANCHOR_END: check-input-buffer + # ANCHOR: tree-data-length ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. + add64 r2, r1 # Get input buffer pointer shifted for tree data. + # ANCHOR_END: tree-data-length + + # Get instruction data length. + ldxw r0, [r2 + IB_INSTRUCTION_DATA_LEN_OFF] + exit e_n_accounts: From 6f10a5c21345ad4ef5ea1017971a355ec4226d86 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:37:44 -0800 Subject: [PATCH 041/263] Add input buffer tail parsing --- .../tree/artifacts/snippets/asm/constants.txt | 4 +++- ...-length.txt => parse-input-buffer-tail.txt} | 4 +++- examples/tree/interface/src/asm.rs | 4 +++- examples/tree/src/tree/tree.s | 18 +++++++++++++----- 4 files changed, 22 insertions(+), 8 deletions(-) rename examples/tree/artifacts/snippets/asm/{tree-data-length.txt => parse-input-buffer-tail.txt} (75%) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 36beca10..c9dcf757 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -14,7 +14,9 @@ .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. -.equ IB_INSTRUCTION_DATA_LEN_OFF, 20680 +.equ IB_PACKED_INSTRUCTION_DATA_LEN_OFF, 20680 +# Program ID field for empty tree account. +.equ IB_PACKED_PROGRAM_ID_OFF, 20688 # Miscellaneous constants. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/tree-data-length.txt b/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt similarity index 75% rename from examples/tree/artifacts/snippets/asm/tree-data-length.txt rename to examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt index 6cc1c03c..cb463612 100644 --- a/examples/tree/artifacts/snippets/asm/tree-data-length.txt +++ b/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt @@ -1,4 +1,6 @@ ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. - add64 r2, r1 # Get input buffer pointer shifted for tree data. \ No newline at end of file + add64 r2, r1 # Get input buffer pointer shifted for tree data. + # Get instruction data length. + ldxdw r3, [r2 + IB_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 1a156f83..8bab4c50 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -22,7 +22,9 @@ extend_constant_group!(input_buffer { /// Tree data length field. offset!(TREE_DATA_LEN, InputBuffer.tree_header.data_len), /// Instruction data length field for empty tree account. - offset!(INSTRUCTION_DATA_LEN, PackedInputBuffer.instruction_data_len), + offset!(PACKED_INSTRUCTION_DATA_LEN, PackedInputBuffer.instruction_data_len), + /// Program ID field for empty tree account. + offset!(PACKED_PROGRAM_ID, PackedInputBuffer.program_id), }); asm_constant_group! { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a2892871..273a8654 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -15,7 +15,9 @@ .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. -.equ IB_INSTRUCTION_DATA_LEN_OFF, 20680 +.equ IB_PACKED_INSTRUCTION_DATA_LEN_OFF, 20680 +# Program ID field for empty tree account. +.equ IB_PACKED_PROGRAM_ID_OFF, 20688 # Miscellaneous constants. # ------------------------ @@ -36,16 +38,22 @@ entrypoint: jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. # ANCHOR_END: check-input-buffer - # ANCHOR: tree-data-length + # ANCHOR: parse-input-buffer-tail ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. add64 r2, r1 # Get input buffer pointer shifted for tree data. - # ANCHOR_END: tree-data-length - # Get instruction data length. - ldxw r0, [r2 + IB_INSTRUCTION_DATA_LEN_OFF] + ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] + # ANCHOR_END: parse-input-buffer-tail + + jeq r3, DATA_LEN_ZERO, initialize # Initialize if no instruction data. + + add64 r3, r2 # Add instruction data length to padded tree data length. + + exit +initialize: exit e_n_accounts: From ce3a49616405f8d02ba7697527d2b6eaa5c404b6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:50:35 -0800 Subject: [PATCH 042/263] Begin adding CPI interface bindings --- .../tree/artifacts/snippets/asm/constants.txt | 4 + .../snippets/asm/parse-input-buffer-tail.txt | 2 +- examples/tree/build.rs | 6 +- examples/tree/interface/src/asm.rs | 26 +++++++ examples/tree/interface/src/bindings.rs | 74 +++++++++++++++++++ examples/tree/interface/src/lib.rs | 1 + examples/tree/src/tree/tree.s | 5 ++ 7 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 examples/tree/interface/src/bindings.rs diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index c9dcf757..307c5263 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -18,6 +18,10 @@ # Program ID field for empty tree account. .equ IB_PACKED_PROGRAM_ID_OFF, 20688 +# CPI-related constants. +# ---------------------- +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign. + # Miscellaneous constants. # ------------------------ .equ DATA_LEN_ZERO, 0 # Data length of zero. diff --git a/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt b/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt index cb463612..6895056a 100644 --- a/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt +++ b/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt @@ -3,4 +3,4 @@ and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. add64 r2, r1 # Get input buffer pointer shifted for tree data. # Get instruction data length. - ldxdw r3, [r2 + IB_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file + ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 9a507f51..db79e7eb 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -11,6 +11,9 @@ macro_rules! asm_groups { } fn main() { + // Collect all constant groups. + let groups = asm_groups![error_codes, input_buffer, cpi, misc]; + // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); let manifest_path = Path::new(manifest_dir); @@ -29,9 +32,6 @@ fn main() { "ANCHOR: constants must come before ANCHOR_END: constants" ); - // Collect all constant groups. - let groups = asm_groups![error_codes, input_buffer, misc]; - // Check for duplicate constant names. let mut seen = HashSet::new(); for group in &groups { diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 8bab4c50..be95de41 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,9 +1,11 @@ extern crate alloc; +use crate::bindings::*; use macros::{asm_constant_group, extend_constant_group}; use pinocchio::{ account::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE}, entrypoint::NON_DUP_MARKER, + sysvars::rent::Rent, Address, }; @@ -63,3 +65,27 @@ struct PackedInputBuffer { instruction_data: [u8; 0], program_id: Address, } + +/// User and tree accounts must sign CPI. +const CPI_N_ACCOUNTS: usize = 2; +/// The tree account is a PDA. +const CPI_N_PDA_SIGNERS: usize = 1; +/// The bump seed is required for tree PDA signer. +const CPI_N_SEEDS: usize = 1; + +// Instead of hard-coding the number of accounts, derive it from createaccountinstruction data. +#[repr(C)] +struct InitStackFrame { + /// Zero-initialized on stack. + system_program_address: Address, + instruction: SolInstruction, + account_metas: [SolAccountMeta; CPI_N_ACCOUNTS], + /// Like CreateAccountInstructionData. + instruction_data: u8, + account_infos: [SolAccountInfo; CPI_N_ACCOUNTS], + pda: Address, + rent: Rent, + signers_seeds: [SolSignerSeeds; CPI_N_PDA_SIGNERS], + signer_seeds: [SolSignerSeed; CPI_N_SEEDS], + bump_seed: u8, +} diff --git a/examples/tree/interface/src/bindings.rs b/examples/tree/interface/src/bindings.rs new file mode 100644 index 00000000..bd651a68 --- /dev/null +++ b/examples/tree/interface/src/bindings.rs @@ -0,0 +1,74 @@ +/// Generated from Agave using bindgen. +use pinocchio::Address; + +/// SolInstruction from cpi.h +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SolInstruction { + /// Pubkey of the instruction processor that executes this instruction. + pub program_id: *mut Address, + /// Metadata for what accounts should be passed to the instruction processor. + pub accounts: *mut SolAccountMeta, + /// Number of SolAccountMetas. + pub account_len: u64, + /// Opaque data passed to the instruction processor. + pub data: *mut u8, + /// Length of the data in bytes. + pub data_len: u64, +} + +/// SolAccountMeta from cpi.h +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SolAccountMeta { + /// An account's public key. + pub pubkey: *mut Address, + /// True if the `pubkey` can be loaded as a read-write account. + pub is_writable: bool, + /// True if an Instruction requires a Transaction signature matching `pubkey`. + pub is_signer: bool, +} + +/// SolAccountInfo from entrypoint.h +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SolAccountInfo { + /// Public key of the account. + pub key: *mut Address, + /// Number of lamports owned by this account. + pub lamports: *mut u64, + /// Length of data in bytes. + pub data_len: u64, + /// On-chain data within this account. + pub data: *mut u8, + /// Program that owns this account. + pub owner: *mut Address, + /// The epoch at which this account will next owe rent. + pub rent_epoch: u64, + /// Transaction was signed by this account's key? + pub is_signer: bool, + /// Is the account writable? + pub is_writable: bool, + /// This account's data contains a loaded program (and is now read-only). + pub executable: bool, +} + +/// SolSignerSeed from pubkey.h +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SolSignerSeed { + /// Seed bytes. + pub addr: *const u8, + /// Length of the seed bytes. + pub len: u64, +} + +/// SolSignerSeeds from pubkey.h +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SolSignerSeeds { + /// An array of a signer's seeds. + pub addr: *const SolSignerSeed, + /// Number of seeds. + pub len: u64, +} diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index f85c0603..31b1e5ed 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -3,6 +3,7 @@ extern crate alloc; mod asm; +mod bindings; mod common; pub use asm::*; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 273a8654..dda1d8f3 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -19,6 +19,10 @@ # Program ID field for empty tree account. .equ IB_PACKED_PROGRAM_ID_OFF, 20688 +# CPI-related constants. +# ---------------------- +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign. + # Miscellaneous constants. # ------------------------ .equ DATA_LEN_ZERO, 0 # Data length of zero. @@ -54,6 +58,7 @@ entrypoint: exit initialize: + # Program ID at r2 + IB_PACKED_PROGRAM_ID_OFF exit e_n_accounts: From 63914c30c6181435c23cf36841e407085bfb0f27 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:58:16 -0800 Subject: [PATCH 043/263] Add bindings/stack layout --- examples/tree/interface/src/asm.rs | 9 ++++---- examples/tree/interface/src/bindings.rs | 10 ++++----- examples/tree/interface/src/common.rs | 29 ++++++++++--------------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index be95de41..13d34d0c 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,6 +1,7 @@ extern crate alloc; use crate::bindings::*; +use crate::common::*; use macros::{asm_constant_group, extend_constant_group}; use pinocchio::{ account::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE}, @@ -73,19 +74,17 @@ const CPI_N_PDA_SIGNERS: usize = 1; /// The bump seed is required for tree PDA signer. const CPI_N_SEEDS: usize = 1; -// Instead of hard-coding the number of accounts, derive it from createaccountinstruction data. #[repr(C)] struct InitStackFrame { /// Zero-initialized on stack. system_program_address: Address, instruction: SolInstruction, account_metas: [SolAccountMeta; CPI_N_ACCOUNTS], - /// Like CreateAccountInstructionData. - instruction_data: u8, account_infos: [SolAccountInfo; CPI_N_ACCOUNTS], - pda: Address, - rent: Rent, signers_seeds: [SolSignerSeeds; CPI_N_PDA_SIGNERS], signer_seeds: [SolSignerSeed; CPI_N_SEEDS], + pda: Address, + rent: Rent, + instruction_data: CreateAccountInstructionData, bump_seed: u8, } diff --git a/examples/tree/interface/src/bindings.rs b/examples/tree/interface/src/bindings.rs index bd651a68..68481dc4 100644 --- a/examples/tree/interface/src/bindings.rs +++ b/examples/tree/interface/src/bindings.rs @@ -1,7 +1,7 @@ /// Generated from Agave using bindgen. use pinocchio::Address; -/// SolInstruction from cpi.h +/// SolInstruction from cpi.h. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SolInstruction { @@ -17,7 +17,7 @@ pub struct SolInstruction { pub data_len: u64, } -/// SolAccountMeta from cpi.h +/// SolAccountMeta from cpi.h. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SolAccountMeta { @@ -29,7 +29,7 @@ pub struct SolAccountMeta { pub is_signer: bool, } -/// SolAccountInfo from entrypoint.h +/// SolAccountInfo from entrypoint.h. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SolAccountInfo { @@ -53,7 +53,7 @@ pub struct SolAccountInfo { pub executable: bool, } -/// SolSignerSeed from pubkey.h +/// SolSignerSeed from pubkey.h. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SolSignerSeed { @@ -63,7 +63,7 @@ pub struct SolSignerSeed { pub len: u64, } -/// SolSignerSeeds from pubkey.h +/// SolSignerSeeds from pubkey.h. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SolSignerSeeds { diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 5077a77e..dc7304cc 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,4 +1,5 @@ use macros::{constant_group, error_codes}; +use pinocchio::Address; error_codes! { /// An invalid number of accounts were passed. @@ -17,26 +18,20 @@ constant_group! { } } -struct InitInstructionData {} - -struct GetInstructionData { - key: u16, -} - -struct InsertInstructionData { - key: u16, - value: u16, -} - -struct RemoveInstructionData { - key: u16, -} - /// Value in r0. #[repr(C, packed)] struct Return { - /// If a value is removed from the tree, it's placed here. + /// If a value is retrieved from the tree, it's encoded in high bits. maybe_value: u16, - /// 0 for success, nonzero for error. + /// Nonzero iff error. status: u16, } + +#[repr(C, packed)] +/// For CPI to create tree account. +pub struct CreateAccountInstructionData { + instruction_tag: u32, + lamports: u64, + space: u64, + owner: Address, +} From 5698d2f104d47311817c21c0805380804617c804 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:09:31 -0800 Subject: [PATCH 044/263] Start adding PDA checks --- .../snippets/asm/check-input-buffer.txt | 13 ++++++++++++- .../tree/artifacts/snippets/asm/constants.txt | 6 ++---- .../snippets/asm/parse-input-buffer-tail.txt | 6 ------ .../snippets/rs/check-input-buffer.txt | 7 +++++-- .../artifacts/snippets/rs/initialize-tree.txt | 3 +++ examples/tree/build.rs | 2 +- examples/tree/interface/src/common.rs | 2 ++ examples/tree/src/program.rs | 19 ++++++++++++++----- examples/tree/src/tree/tree.s | 14 +++++++------- 9 files changed, 46 insertions(+), 26 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt create mode 100644 examples/tree/artifacts/snippets/rs/initialize-tree.txt diff --git a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt index afa3ca3a..42db178e 100644 --- a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt +++ b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt @@ -1,9 +1,20 @@ .globl entrypoint entrypoint: + # Check input buffer accounts. + # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. \ No newline at end of file + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. + + # Parse input buffer tail. + # ------------------------ + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. + and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. + add64 r2, r1 # Get input buffer pointer shifted for tree data. + # Get instruction data length. + ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 307c5263..594e774a 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -3,6 +3,8 @@ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. .equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. .equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. +# The passed PDA does not match the expected address. +.equ E_PDA_MISMATCH, 4 # Input buffer layout. # -------------------- @@ -18,10 +20,6 @@ # Program ID field for empty tree account. .equ IB_PACKED_PROGRAM_ID_OFF, 20688 -# CPI-related constants. -# ---------------------- -.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign. - # Miscellaneous constants. # ------------------------ .equ DATA_LEN_ZERO, 0 # Data length of zero. diff --git a/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt b/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt deleted file mode 100644 index 6895056a..00000000 --- a/examples/tree/artifacts/snippets/asm/parse-input-buffer-tail.txt +++ /dev/null @@ -1,6 +0,0 @@ - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. - add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. - and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. - add64 r2, r1 # Get input buffer pointer shifted for tree data. - # Get instruction data length. - ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/check-input-buffer.txt b/examples/tree/artifacts/snippets/rs/check-input-buffer.txt index ac62a2c5..91778464 100644 --- a/examples/tree/artifacts/snippets/rs/check-input-buffer.txt +++ b/examples/tree/artifacts/snippets/rs/check-input-buffer.txt @@ -7,7 +7,10 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { let user = unsafe { context.next_account_unchecked().assume_account() }; if_err!(!user.is_data_empty(), USER_DATA_LEN); // SAFETY: number of accounts has been checked. - let _tree = match unsafe { context.next_account_unchecked() } { + let tree = match unsafe { context.next_account_unchecked() } { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), - }; \ No newline at end of file + }; + // SAFETY: all accounts have been read. + let instruction_data = unsafe { context.instruction_data_unchecked() }; + let program_id = unsafe { context.program_id_unchecked() }; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-tree.txt b/examples/tree/artifacts/snippets/rs/initialize-tree.txt new file mode 100644 index 00000000..5f3efed3 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/initialize-tree.txt @@ -0,0 +1,3 @@ + if instruction_data.is_empty() { + let (expected_pda, bump) = Address::find_program_address(&[], program_id); + if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index db79e7eb..e329cd9f 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -12,7 +12,7 @@ macro_rules! asm_groups { fn main() { // Collect all constant groups. - let groups = asm_groups![error_codes, input_buffer, cpi, misc]; + let groups = asm_groups![error_codes, input_buffer, misc]; // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index dc7304cc..cc187fcc 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -8,6 +8,8 @@ error_codes! { USER_DATA_LEN, /// The tree account is a duplicate. TREE_DUPLICATE, + /// The passed PDA does not match the expected address. + PDA_MISMATCH, } constant_group! { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 7b914443..2f5f1c4c 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,8 +1,9 @@ use interface::*; use pinocchio::{ + address::address_eq, entrypoint::{InstructionContext, MaybeAccount}, error::ProgramError, - lazy_program_entrypoint, no_allocator, nostd_panic_handler, ProgramResult, + lazy_program_entrypoint, no_allocator, nostd_panic_handler, Address, ProgramResult, }; /// If condition is true, return the given error. @@ -34,14 +35,22 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { let user = unsafe { context.next_account_unchecked().assume_account() }; if_err!(!user.is_data_empty(), USER_DATA_LEN); // SAFETY: number of accounts has been checked. - let _tree = match unsafe { context.next_account_unchecked() } { + let tree = match unsafe { context.next_account_unchecked() } { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; + // SAFETY: all accounts have been read. + let instruction_data = unsafe { context.instruction_data_unchecked() }; + let program_id = unsafe { context.program_id_unchecked() }; // ANCHOR_END: check-input-buffer - // SAFETY: all accounts have been read. - let _instruction_data = unsafe { context.instruction_data_unchecked() }; - let _program_id = unsafe { context.program_id_unchecked() }; + // ANCHOR: initialize-tree + if instruction_data.is_empty() { + let (expected_pda, bump) = Address::find_program_address(&[], program_id); + if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); + // ANCHOR_END: initialize-tree + } else { + // Other instruction logic here... + }; Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index dda1d8f3..ae2e7902 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -4,6 +4,8 @@ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. .equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. .equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. +# The passed PDA does not match the expected address. +.equ E_PDA_MISMATCH, 4 # Input buffer layout. # -------------------- @@ -19,10 +21,6 @@ # Program ID field for empty tree account. .equ IB_PACKED_PROGRAM_ID_OFF, 20688 -# CPI-related constants. -# ---------------------- -.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign. - # Miscellaneous constants. # ------------------------ .equ DATA_LEN_ZERO, 0 # Data length of zero. @@ -34,22 +32,24 @@ .globl entrypoint entrypoint: + # Check input buffer accounts. + # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. - # ANCHOR_END: check-input-buffer - # ANCHOR: parse-input-buffer-tail + # Parse input buffer tail. + # ------------------------ ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. add64 r2, r1 # Get input buffer pointer shifted for tree data. # Get instruction data length. ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] - # ANCHOR_END: parse-input-buffer-tail + # ANCHOR_END: check-input-buffer jeq r3, DATA_LEN_ZERO, initialize # Initialize if no instruction data. From 56961f851ed9547741cf3b61dc488cbf1b0b9d6b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:18:19 -0800 Subject: [PATCH 045/263] Add preliminary init fail tests --- examples/tree/src/tests.rs | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 0b20e697..2d0d0d72 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -215,3 +215,101 @@ fn test_fast_fails() { ); } } + +// ============================================================================ +// Initialize operation tests +// ============================================================================ + +/// Setup for initialize instruction (empty instruction data, correct PDA). +fn init_setup( + program_language: ProgramLanguage, +) -> (test_utils::TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + // Derive the correct PDA for the tree account. + let (tree_pda, _bump) = Pubkey::find_program_address(&[], &setup.program_id); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], // Empty instruction data triggers initialize path + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pda, false), + ], + ); + + let accounts = vec![ + (user_pubkey, Account::new(1_000_000, 0, &system_program)), + (tree_pda, Account::new(0, 0, &system_program)), + ]; + + (setup, instruction, accounts) +} + +#[derive(Clone, Copy)] +enum InitCase { + PdaMismatch, +} + +impl InitCase { + const CASES: &'static [InitCase] = &[InitCase::PdaMismatch]; + + const fn name(&self) -> &'static str { + match self { + Self::PdaMismatch => "PDA mismatch", + } + } + + fn run(&self, lang: ProgramLanguage) -> u64 { + match self { + Self::PdaMismatch => run_init_pda_mismatch(lang), + } + } +} + +fn run_init_pda_mismatch(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, mut accounts) = init_setup(lang); + let (system_program, _) = program::keyed_account_for_system_program(); + + // Replace tree PDA with a random pubkey (not the correct PDA). + let wrong_tree_pubkey = Pubkey::new_unique(); + instruction.accounts[AccountIndex::Tree as usize] = AccountMeta::new(wrong_tree_pubkey, false); + accounts[AccountIndex::Tree as usize] = + (wrong_tree_pubkey, Account::new(0, 0, &system_program)); + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::PDA_MISMATCH.into(), + ))], + ) + .compute_units_consumed +} + +#[test] +fn test_rs_init_pda_mismatch() { + run_init_pda_mismatch(ProgramLanguage::Rust); +} + +#[test] +#[should_panic] // ASM doesn't have PDA check yet +fn test_asm_init_pda_mismatch() { + run_init_pda_mismatch(ProgramLanguage::Assembly); +} + +#[test] +fn test_init_fails() { + println!("\n| Init Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|-----------|-----------|------------|----------|------------|"); + + for case in InitCase::CASES { + // Only run Rust for now since ASM doesn't have init logic yet. + let rs_cu = case.run(ProgramLanguage::Rust); + println!("| {} | N/A | {} | N/A | N/A |", case.name(), rs_cu); + } +} From 137e34d761343a3c0f2998647cc211d3f5c00ca4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:17:23 -0800 Subject: [PATCH 046/263] Update init logic --- examples/tree/artifacts/dumps/asm.txt | 43 ++-- examples/tree/artifacts/dumps/rs.txt | 230 +++++++++++------- examples/tree/artifacts/rs-disassembly.s | 85 +++++-- .../snippets/asm/check-input-buffer.txt | 18 +- .../tree/artifacts/snippets/asm/constants.txt | 18 +- .../snippets/rs/check-input-buffer.txt | 16 -- .../snippets/rs/entrypoint-branch.txt | 9 + .../artifacts/snippets/rs/initialize-tree.txt | 3 - .../tests/asm_no_accounts/result.txt | 80 ++++-- .../tests/asm_too_many_accounts/result.txt | 80 ++++-- examples/tree/interface/src/common.rs | 16 +- examples/tree/macros/src/lib.rs | 121 +++++++-- examples/tree/src/program.rs | 44 ++-- examples/tree/src/tree/tree.s | 47 ++-- 14 files changed, 536 insertions(+), 274 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/rs/check-input-buffer.txt create mode 100644 examples/tree/artifacts/snippets/rs/entrypoint-branch.txt delete mode 100644 examples/tree/artifacts/snippets/rs/initialize-tree.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index f85e1d1f..cf380905 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 208 (bytes into file) + Start of section headers 248 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,13 +19,13 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 3 Section header string table index 2 -There are 3 section headers, starting at offset 0xd0 +There are 3 section headers, starting at offset 0xf8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000040 000040 000080 00 AX 0 0 4 - [ 2] .s STRTAB 0000000000000000 0000c0 00000a 00 0 0 1 + [ 1] .text PROGBITS 0000000000000040 000040 0000a8 00 AX 0 0 4 + [ 2] .s STRTAB 0000000000000000 0000e8 00000a 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -47,18 +47,23 @@ Disassembly of section .text 0000000000000040 <.text> 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) - 9 55 02 08 00 02 00 00 00 if r2 != 0x2 goto +0x8 <.text+0x50> - 10 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 11 55 02 08 00 00 00 00 00 if r2 != 0x0 goto +0x8 <.text+0x60> - 12 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 13 55 02 08 00 ff 00 00 00 if r2 != 0xff goto +0x8 <.text+0x70> - 14 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 15 07 02 00 00 07 00 00 00 r2 += 0x7 - 16 57 02 00 00 f8 ff ff ff r2 &= -0x8 - 17 95 00 00 00 00 00 00 00 exit - 18 b7 00 00 00 01 00 00 00 r0 = 0x1 - 19 95 00 00 00 00 00 00 00 exit - 20 b7 00 00 00 02 00 00 00 r0 = 0x2 - 21 95 00 00 00 00 00 00 00 exit - 22 b7 00 00 00 03 00 00 00 r0 = 0x3 - 23 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 9 15 02 03 00 02 00 00 00 if r2 == 0x2 goto +0x3 <.text+0x28> + 10 15 03 08 00 03 00 00 00 if r3 == 0x3 goto +0x8 <.text+0x58> + 11 b7 00 00 00 01 00 00 00 r0 = 0x1 + 12 95 00 00 00 00 00 00 00 exit + 13 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 14 07 02 00 00 07 00 00 00 r2 += 0x7 + 15 57 02 00 00 f8 ff ff ff r2 &= -0x8 + 16 0f 12 00 00 00 00 00 00 r2 += r1 + 17 79 23 c8 50 00 00 00 00 r3 = *(u64 *)(r2 + 0x50c8) + 18 95 00 00 00 00 00 00 00 exit + 19 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 20 55 02 04 00 00 00 00 00 if r2 != 0x0 goto +0x4 <.text+0x88> + 21 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 22 55 02 04 00 ff 00 00 00 if r2 != 0xff goto +0x4 <.text+0x98> + 23 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 24 95 00 00 00 00 00 00 00 exit + 25 b7 00 00 00 02 00 00 00 r0 = 0x2 + 26 95 00 00 00 00 00 00 00 exit + 27 b7 00 00 00 03 00 00 00 r0 = 0x3 + 28 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index a87bccc4..0ed391c0 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 3296 (bytes into file) + Start of section headers 3872 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xce0 +There are 8 section headers, starting at offset 0xf20 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000170 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000290 000058 00 WA 0 0 8 - [ 3] .bss.stack NOBITS 0000000200000000 0002e8 001000 00 WA 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 0002e8 001000 00 WA 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 0002e8 000408 18 7 42 8 - [ 6] .shstrtab STRTAB 0000000000000000 0006f0 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00072e 0005ac 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0002b0 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 0003d0 0000c0 00 WA 0 0 8 + [ 3] .bss.stack NOBITS 0000000200000000 000490 001000 00 WA 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000490 001000 00 WA 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000490 000468 18 7 46 8 + [ 6] .shstrtab STRTAB 0000000000000000 0008f8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000936 0005e6 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000170 0x000170 E 0x8 - LOAD 0x000290 0x0000000100000000 0x0000000100000000 0x000058 0x000058 R 0x8 - LOAD 0x0002e8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x0002e8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0002b0 0x0002b0 E 0x8 + LOAD 0x0003d0 0x0000000100000000 0x0000000100000000 0x0000c0 0x0000c0 R 0x8 + LOAD 0x000490 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000490 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -58,51 +58,55 @@ Program Headers There are no relocations in this file. -Symbol table '.symtab' contains 43 entries +Symbol table '.symtab' contains 47 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 - 2 0000000100000028 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_3 - 3 0000000100000038 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_4 - 4 0000000100000000 18 OBJECT LOCAL DEFAULT 2 .L__unnamed_7 - 5 0000000100000012 22 OBJECT LOCAL DEFAULT 2 .L__unnamed_8 - 6 0000000000000000 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind - 7 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl - 8 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 - 9 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 - 10 0000000000000130 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt - 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 - 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 - 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 - 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 - 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 - 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 - 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 - 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 - 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 - 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 - 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 - 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 - 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 - 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 - 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 - 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 - 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 - 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 - 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 - 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 - 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 - 32 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 - 33 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 - 34 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 - 35 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 - 36 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 - 37 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 - 38 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start - 39 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end - 40 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start - 41 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 42 0000000000000040 240 FUNC GLOBAL DEFAULT 1 entrypoint + 2 0000000100000068 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_3 + 3 0000000100000078 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_4 + 4 0000000100000090 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_5 + 5 00000001000000a0 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_6 + 6 0000000100000000 49 OBJECT LOCAL DEFAULT 2 .L__unnamed_7 + 7 0000000100000031 15 OBJECT LOCAL DEFAULT 2 .L__unnamed_8 + 8 0000000100000040 18 OBJECT LOCAL DEFAULT 2 .L__unnamed_11 + 9 0000000100000052 22 OBJECT LOCAL DEFAULT 2 .L__unnamed_12 + 10 0000000000000000 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 + 14 0000000000000270 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 + 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 + 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 + 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 + 32 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 + 33 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 + 34 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 + 35 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 + 36 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 + 37 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 + 38 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 + 39 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 + 40 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 + 41 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 + 42 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start + 43 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end + 44 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start + 45 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end + 46 0000000000000040 560 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -121,42 +125,82 @@ Disassembly of section .text 0000000000000040 40 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 48 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 50 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 58 55 02 0c 00 02 00 00 00 jne r2, 0x2, +0xc - 60 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] - 68 55 02 0b 00 ff 00 00 00 jne r2, 0xff, +0xb - 70 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 78 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 80 55 02 07 00 00 00 00 00 jne r2, 0x0, +0x7 - 88 0f 21 00 00 00 00 00 00 add64 r1, r2 - 90 07 01 00 00 6f 28 00 00 add64 r1, 0x286f - 98 57 01 00 00 f8 ff ff ff and64 r1, -0x8 - a0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - a8 2c 11 00 00 00 00 00 00 ldxb w1, [r1 + 0x0] - b0 55 01 01 00 ff 00 00 00 jne r1, 0xff, +0x1 - b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - c0 9d 00 00 00 00 00 00 00 return - c8 b4 01 00 00 28 00 00 00 mov32 w1, 0x28 - d0 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - d8 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - e0 b4 02 00 00 38 00 00 00 mov32 w2, 0x38 - e8 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - f0 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 - f8 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 - 100 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 - 108 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 - 110 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 118 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 120 85 10 00 00 01 00 00 00 call 0x1 - 128 9d 00 00 00 00 00 00 00 return + 48 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] + 50 15 03 2f 00 02 00 00 00 jeq r3, 0x2, +0x2f + 58 b7 02 00 00 01 00 00 00 mov64 r2, 0x1 + 60 55 03 2b 00 03 00 00 00 jne r3, 0x3, +0x2b + 68 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] + 70 55 02 39 00 ff 00 00 00 jne r2, 0xff, +0x39 + 78 b7 02 00 00 02 00 00 00 mov64 r2, 0x2 + 80 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 88 55 03 26 00 00 00 00 00 jne r3, 0x0, +0x26 + 90 0f 31 00 00 00 00 00 00 add64 r1, r3 + 98 07 01 00 00 6f 28 00 00 add64 r1, 0x286f + a0 57 01 00 00 f8 ff ff ff and64 r1, -0x8 + a8 b7 02 00 00 03 00 00 00 mov64 r2, 0x3 + b0 2c 13 00 00 00 00 00 00 ldxb w3, [r1 + 0x0] + b8 55 03 20 00 ff 00 00 00 jne r3, 0xff, +0x20 + c0 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] + c8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + d0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + d8 0f 23 00 00 00 00 00 00 add64 r3, r2 + e0 07 03 00 00 67 28 00 00 add64 r3, 0x2867 + e8 57 03 00 00 f8 ff ff ff and64 r3, -0x8 + f0 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] + f8 0f 13 00 00 00 00 00 00 add64 r3, r1 + 100 07 03 00 00 08 00 00 00 add64 r3, 0x8 + 108 27 0a 0f 00 ff 00 00 00 stb [r10 + 0xf], 0xff + 110 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 118 07 04 00 00 10 00 00 00 add64 r4, 0x10 + 120 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 128 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 130 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 + 138 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 140 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 148 55 00 12 00 00 00 00 00 jne r0, 0x0, +0x12 + 150 b7 02 00 00 04 00 00 00 mov64 r2, 0x4 + 158 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] + 160 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 168 5d 13 0a 00 00 00 00 00 jne r3, r1, +0xa + 170 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 178 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 180 5d 13 07 00 00 00 00 00 jne r3, r1, +0x7 + 188 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 190 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 198 5d 13 04 00 00 00 00 00 jne r3, r1, +0x4 + 1a0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 1a8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1b0 9c 63 20 00 00 00 00 00 ldxdw r3, [r6 + 0x20] + 1b8 1d 13 03 00 00 00 00 00 jeq r3, r1, +0x3 + 1c0 bf 20 00 00 00 00 00 00 mov64 r0, r2 + 1c8 05 00 01 00 00 00 00 00 ja +0x1 + 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1d8 9d 00 00 00 00 00 00 00 return + 1e0 b4 01 00 00 68 00 00 00 mov32 w1, 0x68 + 1e8 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + 1f0 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + 1f8 b4 02 00 00 78 00 00 00 mov32 w2, 0x78 + 200 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + 208 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 + 210 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 + 218 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 + 220 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 + 228 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 230 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 238 85 10 00 00 06 00 00 00 call 0x6 + 240 b4 01 00 00 90 00 00 00 mov32 w1, 0x90 + 248 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + 250 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + 258 b4 02 00 00 a0 00 00 00 mov32 w2, 0xa0 + 260 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + 268 05 00 f3 ff 00 00 00 00 ja -0xd -0000000000000130 - 130 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 138 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 - 140 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 - 148 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 - 150 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 158 07 01 00 00 28 00 00 00 add64 r1, 0x28 - 160 85 10 00 00 d3 ff ff ff call -0x2d - 168 9d 00 00 00 00 00 00 00 return \ No newline at end of file +0000000000000270 + 270 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 278 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 + 280 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 + 288 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 + 290 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 298 07 01 00 00 28 00 00 00 add64 r1, 0x28 + 2a0 85 10 00 00 ab ff ff ff call -0x55 + 2a8 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 279d89a6..3a565747 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -11,40 +11,89 @@ fn_0000: entrypoint: add64 r10, -64 - mov64 r0, 1 - ldxdw r2, [r1+0] - jne r2, 2, jmp_00b8 + ldxdw r3, [r1+0] + jeq r3, 2, jmp_01c8 + mov64 r2, 1 + jne r3, 3, jmp_01b8 ldxb r2, [r1+8] - jne r2, 255, jmp_00c0 - mov64 r0, 2 - ldxdw r2, [r1+88] - jne r2, 0, jmp_00b8 - add64 r1, r2 + jne r2, 255, jmp_0238 + mov64 r2, 2 + ldxdw r3, [r1+88] + jne r3, 0, jmp_01b8 + add64 r1, r3 add64 r1, 10351 and64 r1, -8 - mov64 r0, 3 - ldxb r1, [r1+0] - jne r1, 255, jmp_00b8 + mov64 r2, 3 + ldxb r3, [r1+0] + jne r3, 255, jmp_01b8 + ldxdw r2, [r1+80] + mov64 r6, r1 + mov64 r3, r1 + add64 r3, r2 + add64 r3, 10343 + and64 r3, -8 + ldxdw r1, [r3+0] + add64 r3, r1 + add64 r3, 8 + stb [r10+15], 255 + mov64 r4, r10 + add64 r4, 16 + mov64 r5, r10 + add64 r5, 15 + mov64 r1, 8 + mov64 r2, 0 + call sol_try_find_program_address + jne r0, 0, jmp_01d8 + mov64 r2, 4 + ldxdw r1, [r10+16] + ldxdw r3, [r6+8] + jne r3, r1, jmp_01b8 + ldxdw r1, [r10+24] + ldxdw r3, [r6+16] + jne r3, r1, jmp_01b8 + ldxdw r1, [r10+32] + ldxdw r3, [r6+24] + jne r3, r1, jmp_01b8 + ldxdw r1, [r10+40] mov64 r0, 0 + ldxdw r3, [r6+32] + jeq r3, r1, jmp_01d0 -jmp_00b8: +jmp_01b8: + mov64 r0, r2 + ja jmp_01d0 + +jmp_01c8: + mov64 r0, 0 + +jmp_01d0: exit -jmp_00c0: - mov32 r1, 680 +jmp_01d8: + mov32 r1, 1072 hor64 r1, 0 stxdw [r10+16], r1 - mov32 r2, 696 + mov32 r2, 1088 hor64 r2, 0 + +jmp_0200: stdw [r10+48], 0 stdw [r10+24], 1 stdw [r10+40], 0 stdw [r10+32], 8 mov64 r1, r10 add64 r1, 16 - call fn_0120 + call fn_0268 + +jmp_0238: + mov32 r1, 1112 + hor64 r1, 0 + stxdw [r10+16], r1 + mov32 r2, 1128 + hor64 r2, 0 + ja jmp_0200 -fn_0120: +fn_0268: add64 r10, -64 stxdw [r10+48], r2 stxdw [r10+40], r1 @@ -54,4 +103,4 @@ fn_0120: call fn_0000 .rodata - data_0000: .byte 0x73, 0x72, 0x63, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2f, 0x6c, 0x61, 0x7a, 0x79, 0x2e, 0x72, 0x73, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74 + data_0000: .byte 0x55, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x76, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, 0x75, 0x6d, 0x70, 0x20, 0x73, 0x65, 0x65, 0x64, 0x73, 0x72, 0x63, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2f, 0x6c, 0x61, 0x7a, 0x79, 0x2e, 0x72, 0x73, 0x00, 0x73, 0x72, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x2e, 0x72, 0x73, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74 diff --git a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt index 42db178e..17dede7c 100644 --- a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt +++ b/examples/tree/artifacts/snippets/asm/check-input-buffer.txt @@ -4,17 +4,7 @@ entrypoint: # Check input buffer accounts. # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. - ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. - jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. - ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. - - # Parse input buffer tail. - # ------------------------ - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. - add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. - and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. - add64 r2, r1 # Get input buffer pointer shifted for tree data. - # Get instruction data length. - ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] \ No newline at end of file + jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. + jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + mov64 r0, E_N_ACCOUNTS # Else fail. + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 594e774a..e0e8832f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -1,14 +1,24 @@ # Error codes. # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. -.equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. -.equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. +.equ E_USER_DATA_LEN, 2 # The user account has invalid data length. +.equ E_TREE_DATA_LEN, 3 # The tree account has invalid data length. +# The System Program account has invalid data length. +.equ E_SYSTEM_PROGRAM_DATA_LEN, 4 +.equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. +# The System Program account is a duplicate. +.equ E_SYSTEM_PROGRAM_DUPLICATE, 6 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 4 +.equ E_PDA_MISMATCH, 7 # Input buffer layout. # -------------------- -.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. +# Expected number of accounts for general instructions. +.equ IB_N_ACCOUNTS_GENERAL, 2 +# Expected number of accounts for tree initialization. +.equ IB_N_ACCOUNTS_INIT, 3 +# Expected data length of system program account. +.equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. diff --git a/examples/tree/artifacts/snippets/rs/check-input-buffer.txt b/examples/tree/artifacts/snippets/rs/check-input-buffer.txt deleted file mode 100644 index 91778464..00000000 --- a/examples/tree/artifacts/snippets/rs/check-input-buffer.txt +++ /dev/null @@ -1,16 +0,0 @@ -lazy_program_entrypoint!(process_instruction); - -pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - // Verify the input memory map: user has no data, tree is not duplicate. - if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); - // SAFETY: number of accounts has been checked. - let user = unsafe { context.next_account_unchecked().assume_account() }; - if_err!(!user.is_data_empty(), USER_DATA_LEN); - // SAFETY: number of accounts has been checked. - let tree = match unsafe { context.next_account_unchecked() } { - MaybeAccount::Account(account) => account, - MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), - }; - // SAFETY: all accounts have been read. - let instruction_data = unsafe { context.instruction_data_unchecked() }; - let program_id = unsafe { context.program_id_unchecked() }; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt new file mode 100644 index 00000000..0786ae83 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt @@ -0,0 +1,9 @@ +lazy_program_entrypoint!(process_instruction); + +pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { + match context.remaining() { + input_buffer::N_ACCOUNTS_GENERAL => Ok(()), + input_buffer::N_ACCOUNTS_INIT => initialize(context), + _ => err!(N_ACCOUNTS), + } +} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-tree.txt b/examples/tree/artifacts/snippets/rs/initialize-tree.txt deleted file mode 100644 index 5f3efed3..00000000 --- a/examples/tree/artifacts/snippets/rs/initialize-tree.txt +++ /dev/null @@ -1,3 +0,0 @@ - if instruction_data.is_empty() { - let (expected_pda, bump) = Address::find_program_address(&[], program_id); - if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_no_accounts/result.txt b/examples/tree/artifacts/tests/asm_no_accounts/result.txt index fb19672e..1047725e 100644 --- a/examples/tree/artifacts/tests/asm_no_accounts/result.txt +++ b/examples/tree/artifacts/tests/asm_no_accounts/result.txt @@ -1,33 +1,71 @@ test tests::test_asm_no_accounts ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 +warning: constant `CPI_N_ACCOUNTS` is never used + --> tree/interface/src/asm.rs:71:7 | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ +71 | const CPI_N_ACCOUNTS: usize = 2; + | ^^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 +warning: constant `CPI_N_PDA_SIGNERS` is never used + --> tree/interface/src/asm.rs:73:7 | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 +73 | const CPI_N_PDA_SIGNERS: usize = 1; + | ^^^^^^^^^^^^^^^^^ +warning: constant `CPI_N_SEEDS` is never used + --> tree/interface/src/asm.rs:75:7 | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 +75 | const CPI_N_SEEDS: usize = 1; + | ^^^^^^^^^^^ +warning: struct `InitStackFrame` is never constructed + --> tree/interface/src/asm.rs:78:8 | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ +78 | struct InitStackFrame { + | ^^^^^^^^^^^^^^ +warning: struct `SolInstruction` is never constructed + --> tree/interface/src/bindings.rs:7:12 + | +7 | pub struct SolInstruction { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountMeta` is never constructed + --> tree/interface/src/bindings.rs:23:12 + | +23 | pub struct SolAccountMeta { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountInfo` is never constructed + --> tree/interface/src/bindings.rs:35:12 + | +35 | pub struct SolAccountInfo { + | ^^^^^^^^^^^^^^ +warning: struct `SolSignerSeed` is never constructed + --> tree/interface/src/bindings.rs:59:12 + | +59 | pub struct SolSignerSeed { + | ^^^^^^^^^^^^^ +warning: struct `SolSignerSeeds` is never constructed + --> tree/interface/src/bindings.rs:69:12 + | +69 | pub struct SolSignerSeeds { + | ^^^^^^^^^^^^^^ warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 + --> tree/interface/src/common.rs:27:8 | -37 | struct Return { +27 | struct Return { | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) +warning: struct `CreateAccountInstructionData` is never constructed + --> tree/interface/src/common.rs:36:12 + | +36 | pub struct CreateAccountInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `interface` (lib) generated 11 warnings +warning: `interface` (lib) generated 11 warnings (11 duplicates) +warning: unused variable: `bump` + --> tree/src/program.rs:45:32 + | +45 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt index e8ed8786..b52aa1ec 100644 --- a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt +++ b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt @@ -1,33 +1,71 @@ test tests::test_asm_too_many_accounts ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 +warning: constant `CPI_N_ACCOUNTS` is never used + --> tree/interface/src/asm.rs:71:7 | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ +71 | const CPI_N_ACCOUNTS: usize = 2; + | ^^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 +warning: constant `CPI_N_PDA_SIGNERS` is never used + --> tree/interface/src/asm.rs:73:7 | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 +73 | const CPI_N_PDA_SIGNERS: usize = 1; + | ^^^^^^^^^^^^^^^^^ +warning: constant `CPI_N_SEEDS` is never used + --> tree/interface/src/asm.rs:75:7 | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 +75 | const CPI_N_SEEDS: usize = 1; + | ^^^^^^^^^^^ +warning: struct `InitStackFrame` is never constructed + --> tree/interface/src/asm.rs:78:8 | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ +78 | struct InitStackFrame { + | ^^^^^^^^^^^^^^ +warning: struct `SolInstruction` is never constructed + --> tree/interface/src/bindings.rs:7:12 + | +7 | pub struct SolInstruction { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountMeta` is never constructed + --> tree/interface/src/bindings.rs:23:12 + | +23 | pub struct SolAccountMeta { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountInfo` is never constructed + --> tree/interface/src/bindings.rs:35:12 + | +35 | pub struct SolAccountInfo { + | ^^^^^^^^^^^^^^ +warning: struct `SolSignerSeed` is never constructed + --> tree/interface/src/bindings.rs:59:12 + | +59 | pub struct SolSignerSeed { + | ^^^^^^^^^^^^^ +warning: struct `SolSignerSeeds` is never constructed + --> tree/interface/src/bindings.rs:69:12 + | +69 | pub struct SolSignerSeeds { + | ^^^^^^^^^^^^^^ warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 + --> tree/interface/src/common.rs:27:8 | -37 | struct Return { +27 | struct Return { | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) +warning: struct `CreateAccountInstructionData` is never constructed + --> tree/interface/src/common.rs:36:12 + | +36 | pub struct CreateAccountInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `interface` (lib) generated 11 warnings +warning: `interface` (lib) generated 11 warnings (11 duplicates) +warning: unused variable: `bump` + --> tree/src/program.rs:45:32 + | +45 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index cc187fcc..0554ef14 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -4,10 +4,16 @@ use pinocchio::Address; error_codes! { /// An invalid number of accounts were passed. N_ACCOUNTS, - /// The user account has nonzero data length. + /// The user account has invalid data length. USER_DATA_LEN, + /// The tree account has invalid data length. + TREE_DATA_LEN, + /// The System Program account has invalid data length. + SYSTEM_PROGRAM_DATA_LEN, /// The tree account is a duplicate. TREE_DUPLICATE, + /// The System Program account is a duplicate. + SYSTEM_PROGRAM_DUPLICATE, /// The passed PDA does not match the expected address. PDA_MISMATCH, } @@ -15,8 +21,12 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { - /// Expected number of accounts. - N_ACCOUNTS: u64 = 2, + /// Expected number of accounts for general instructions. + N_ACCOUNTS_GENERAL: u64 = 2, + /// Expected number of accounts for tree initialization. + N_ACCOUNTS_INIT: u64 = 3, + /// Expected data length of system program account. + SYSTEM_PROGRAM_DATA_LEN: usize = b"system_program".len(), } } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index ce4d5812..05b7b42f 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -175,7 +175,9 @@ struct ConstantDef { doc: String, name: Ident, ty: syn::Type, - value: LitInt, + value: syn::Expr, + /// Original literal string for ASM output (preserves hex/binary). + literal_repr: Option, } struct ConstantGroup { @@ -216,10 +218,43 @@ impl Parse for ConstantGroup { } let const_name: Ident = content.parse()?; - content.parse::()?; - let const_ty: syn::Type = content.parse()?; - content.parse::()?; - let const_value: LitInt = content.parse()?; + + // Support both `NAME: type = value` and `NAME = expr` forms. + let (const_ty, const_value, literal_repr) = if content.peek(Token![:]) { + // NAME: type = value + content.parse::()?; + let ty: syn::Type = content.parse()?; + content.parse::()?; + + // Try literal first to preserve hex/binary representation. + let fork = content.fork(); + if let Ok(lit) = fork.parse::() { + content.advance_to(&fork); + let repr = lit.to_string(); + let expr = syn::Expr::Lit(syn::ExprLit { + attrs: vec![], + lit: Lit::Int(lit), + }); + (ty, expr, Some(repr)) + } else { + let expr: syn::Expr = content.parse()?; + (ty, expr, None) + } + } else { + // NAME = expr (type inferred from `as Type` cast). + content.parse::()?; + let expr: syn::Expr = content.parse()?; + + let ty = if let syn::Expr::Cast(cast) = &expr { + (*cast.ty).clone() + } else { + return Err(content.error( + "Expression must include `as Type` when type annotation is omitted", + )); + }; + + (ty, expr, None) + }; // Optional trailing comma. let _ = content.parse::(); @@ -229,6 +264,7 @@ impl Parse for ConstantGroup { name: const_name, ty: const_ty, value: const_value, + literal_repr, }); } @@ -249,9 +285,12 @@ impl Parse for ConstantGroup { /// Macro for defining groups of constants shared between Rust and ASM. /// -/// Constants must specify their Rust type. Values are validated at compile time -/// to fit within i32 range (sBPF immediate constraint). The prefix is automatically -/// joined with an underscore. +/// Values are validated at compile time to fit within i32 range (sBPF immediate constraint). +/// The prefix is automatically joined with an underscore. +/// +/// Two syntaxes are supported: +/// - `NAME: type = value` — explicit type, literal values preserve hex/binary in ASM. +/// - `NAME = expr as Type` — type inferred from `as` cast, value computed at build time. /// /// # Example /// ```ignore @@ -260,9 +299,10 @@ impl Parse for ConstantGroup { /// input_buffer { /// /// Number of accounts expected. /// N_ACCOUNTS: u64 = 2, +/// /// Expected data length of system program account. +/// SYSTEM_PROGRAM_DATA_LEN = b"system_program".len() as u64, /// } /// } -/// // Usage: input_buffer::to_asm("IB") -> ".equ IB_N_ACCOUNTS, 2 # ..." /// ``` /// /// To extend a group with ASM-only constants, use `extend_constant_group!`. @@ -275,30 +315,55 @@ pub fn constant_group(input: TokenStream) -> TokenStream { let header = asm_header(&group.doc); // Generate Rust constants with i32 bounds checking for ASM compatibility. - let const_defs = group.constants.iter().map(|c| { + let mut const_defs = Vec::new(); + let mut const_value_strs: Vec> = Vec::new(); + + for c in &group.constants { let name = &c.name; let ty = &c.ty; let value = &c.value; let doc = &c.doc; let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); - quote! { - #[doc = #doc] - pub const #name: #ty = #value; - const #assert_name: () = assert!( - (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); + const_value_strs.push(c.literal_repr.clone()); + + if c.literal_repr.is_some() { + // Literal value - no scope wrapper needed. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: #ty = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } else { + // Expression value - use super::* for scope access. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: #ty = { use super::*; #value }; + + const #assert_name: () = assert!( + ({ use super::*; #value } as i64) >= (i32::MIN as i64) + && ({ use super::*; #value } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); } - }); + } let const_names: Vec = group.constants.iter().map(|c| c.name.to_string()).collect(); - let const_values: Vec = group - .constants + let const_idents: Vec<&Ident> = group.constants.iter().map(|c| &c.name).collect(); + let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); + + let value_str_opts: Vec<_> = const_value_strs .iter() - .map(|c| c.value.to_string()) + .map(|opt| match opt { + Some(s) => quote! { Some(#s) }, + None => quote! { None }, + }) .collect(); - let const_docs: Vec = group.constants.iter().map(|c| c.doc.clone()).collect(); let expanded = quote! { pub mod #mod_name { @@ -314,16 +379,22 @@ pub fn constant_group(input: TokenStream) -> TokenStream { result.push('\n'); let names = [#(#const_names),*]; - let values = [#(#const_values),*]; + let computed_values: &[i64] = &[#(#const_idents as i64),*]; + let literal_values: &[Option<&str>] = &[#(#value_str_opts),*]; let docs = [#(#const_docs),*]; for i in 0..names.len() { let full_name = format!("{}_{}", prefix, names[i]); - let inline = format!(".equ {}, {} # {}", full_name, values[i], docs[i]); + // Use original literal if available, otherwise use computed value. + let value_str = match literal_values[i] { + Some(lit) => String::from(lit), + None => format!("{}", computed_values[i]), + }; + let inline = format!(".equ {}, {} # {}", full_name, value_str, docs[i]); if inline.len() <= #max_line_len { result.push_str(&inline); } else { - result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, values[i])); + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, value_str)); } result.push('\n'); } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2f5f1c4c..659255a6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -25,32 +25,46 @@ macro_rules! err { nostd_panic_handler!(); no_allocator!(); -// ANCHOR: check-input-buffer +// ANCHOR: entrypoint-branch lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - // Verify the input memory map: user has no data, tree is not duplicate. - if_err!(context.remaining() != input_buffer::N_ACCOUNTS, N_ACCOUNTS); + match context.remaining() { + input_buffer::N_ACCOUNTS_GENERAL => Ok(()), + input_buffer::N_ACCOUNTS_INIT => initialize(context), + _ => err!(N_ACCOUNTS), + } +} +// ANCHOR_END: entrypoint-branch + +#[inline(always)] +fn initialize(mut context: InstructionContext) -> ProgramResult { + // Verify user has no data. // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; if_err!(!user.is_data_empty(), USER_DATA_LEN); + + // Verify tree is non-duplicate and has no data. // SAFETY: number of accounts has been checked. let tree = match unsafe { context.next_account_unchecked() } { MaybeAccount::Account(account) => account, MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), }; - // SAFETY: all accounts have been read. - let instruction_data = unsafe { context.instruction_data_unchecked() }; - let program_id = unsafe { context.program_id_unchecked() }; - // ANCHOR_END: check-input-buffer - - // ANCHOR: initialize-tree - if instruction_data.is_empty() { - let (expected_pda, bump) = Address::find_program_address(&[], program_id); - if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); - // ANCHOR_END: initialize-tree - } else { - // Other instruction logic here... + if_err!(!tree.is_data_empty(), TREE_DATA_LEN); + + // Verify system program is non-duplicate and has expected data length. + let system_program = match unsafe { context.next_account_unchecked() } { + MaybeAccount::Account(account) => account, + MaybeAccount::Duplicated(_) => err!(SYSTEM_PROGRAM_DUPLICATE), }; + if_err!( + system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, + SYSTEM_PROGRAM_DATA_LEN + ); + + // Verify tree PDA. + let program_id = unsafe { context.program_id_unchecked() }; + let (expected_pda, bump) = Address::find_program_address(&[], program_id); + if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); Ok(()) } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index ae2e7902..d431a0ac 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -2,14 +2,24 @@ # Error codes. # ------------ .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. -.equ E_USER_DATA_LEN, 2 # The user account has nonzero data length. -.equ E_TREE_DUPLICATE, 3 # The tree account is a duplicate. +.equ E_USER_DATA_LEN, 2 # The user account has invalid data length. +.equ E_TREE_DATA_LEN, 3 # The tree account has invalid data length. +# The System Program account has invalid data length. +.equ E_SYSTEM_PROGRAM_DATA_LEN, 4 +.equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. +# The System Program account is a duplicate. +.equ E_SYSTEM_PROGRAM_DUPLICATE, 6 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 4 +.equ E_PDA_MISMATCH, 7 # Input buffer layout. # -------------------- -.equ IB_N_ACCOUNTS, 2 # Expected number of accounts. +# Expected number of accounts for general instructions. +.equ IB_N_ACCOUNTS_GENERAL, 2 +# Expected number of accounts for tree initialization. +.equ IB_N_ACCOUNTS_INIT, 3 +# Expected data length of system program account. +.equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. @@ -35,34 +45,27 @@ entrypoint: # Check input buffer accounts. # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jne r2, IB_N_ACCOUNTS, e_n_accounts # Error if invalid number. - ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. - jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. - ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. + jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. + jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + mov64 r0, E_N_ACCOUNTS # Else fail. + exit + # ANCHOR_END: check-input-buffer - # Parse input buffer tail. - # ------------------------ +general: ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. add64 r2, r1 # Get input buffer pointer shifted for tree data. # Get instruction data length. ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] - # ANCHOR_END: check-input-buffer - - jeq r3, DATA_LEN_ZERO, initialize # Initialize if no instruction data. - - add64 r3, r2 # Add instruction data length to padded tree data length. - exit initialize: - # Program ID at r2 + IB_PACKED_PROGRAM_ID_OFF - exit - -e_n_accounts: - mov64 r0, E_N_ACCOUNTS + ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. + jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. + ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. exit e_user_data_len: From f89017cda569ae612f650a7d2c0c72b9e951d667 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:39:39 -0800 Subject: [PATCH 047/263] Abstract helpers --- .../snippets/rs/entrypoint-branch.txt | 7 +- examples/tree/src/program.rs | 85 +++++++++++-------- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt index 0786ae83..153cfb2d 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt @@ -1,9 +1,12 @@ +nostd_panic_handler!(); +no_allocator!(); lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => initialize(context), - _ => err!(N_ACCOUNTS), + // SAFETY: number of accounts has been checked. + input_buffer::N_ACCOUNTS_INIT => unsafe { initialize(context) }, + _ => err(error::N_ACCOUNTS), } } \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 659255a6..2831365c 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,70 +1,87 @@ -use interface::*; +use interface::{error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, entrypoint::{InstructionContext, MaybeAccount}, error::ProgramError, - lazy_program_entrypoint, no_allocator, nostd_panic_handler, Address, ProgramResult, + lazy_program_entrypoint, no_allocator, nostd_panic_handler, AccountView, Address, + ProgramResult, }; -/// If condition is true, return the given error. -macro_rules! if_err { - ($cond:expr, $variant:ident) => { - if $cond { - err!($variant); - } - }; +#[inline(always)] +/// Return an error code for early return at call site. +fn err(error_code: error) -> Result<(), ProgramError> { + Err(ProgramError::Custom(error_code.into())) } -/// Return the given error. -macro_rules! err { - ($variant:ident) => { - return Err(ProgramError::Custom(error_codes::error::$variant.into())) - }; +#[inline(always)] +/// Ensure a condition is met else return error code for early return at call site. +fn ensure(condition: bool, error_code: error) -> Result<(), ProgramError> { + if condition { + Ok(()) + } else { + err(error_code) + } } -nostd_panic_handler!(); -no_allocator!(); +#[inline(always)] +/// Ensure an account has empty data else return error code for early return at call site. +fn ensure_is_data_empty(account: &AccountView, error_code: error) -> Result<(), ProgramError> { + ensure(account.is_data_empty(), error_code) +} + +#[inline(always)] +unsafe fn next_account_non_duplicate( + context: &mut InstructionContext, + error_code: error, +) -> Result { + match unsafe { context.next_account_unchecked() } { + MaybeAccount::Account(account) => Ok(account), + MaybeAccount::Duplicated(_) => err(error_code), + } +} // ANCHOR: entrypoint-branch +nostd_panic_handler!(); +no_allocator!(); lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => initialize(context), - _ => err!(N_ACCOUNTS), + // SAFETY: number of accounts has been checked. + input_buffer::N_ACCOUNTS_INIT => unsafe { initialize(context) }, + _ => err(error::N_ACCOUNTS), } } // ANCHOR_END: entrypoint-branch #[inline(always)] -fn initialize(mut context: InstructionContext) -> ProgramResult { +unsafe fn initialize(mut context: InstructionContext) -> ProgramResult { // Verify user has no data. // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; - if_err!(!user.is_data_empty(), USER_DATA_LEN); + ensure_is_data_empty(&user, error::USER_DATA_LEN)?; // Verify tree is non-duplicate and has no data. // SAFETY: number of accounts has been checked. - let tree = match unsafe { context.next_account_unchecked() } { - MaybeAccount::Account(account) => account, - MaybeAccount::Duplicated(_) => err!(TREE_DUPLICATE), - }; - if_err!(!tree.is_data_empty(), TREE_DATA_LEN); + let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; + ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; // Verify system program is non-duplicate and has expected data length. - let system_program = match unsafe { context.next_account_unchecked() } { - MaybeAccount::Account(account) => account, - MaybeAccount::Duplicated(_) => err!(SYSTEM_PROGRAM_DUPLICATE), - }; - if_err!( - system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, - SYSTEM_PROGRAM_DATA_LEN - ); + // SAFETY: number of accounts has been checked. + let system_program = + unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; + ensure( + system_program.data_len() == input_buffer::SYSTEM_PROGRAM_DATA_LEN, + error::SYSTEM_PROGRAM_DATA_LEN, + )?; // Verify tree PDA. let program_id = unsafe { context.program_id_unchecked() }; let (expected_pda, bump) = Address::find_program_address(&[], program_id); - if_err!(!address_eq(tree.address(), &expected_pda), PDA_MISMATCH); + ensure( + address_eq(tree.address(), &expected_pda), + error::PDA_MISMATCH, + )?; Ok(()) } From cf7272bb63fbeee53c60b52007250d6690b9d943 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:42:02 -0800 Subject: [PATCH 048/263] Make helper generic --- examples/tree/src/program.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2831365c..acfa3225 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,7 +9,7 @@ use pinocchio::{ #[inline(always)] /// Return an error code for early return at call site. -fn err(error_code: error) -> Result<(), ProgramError> { +fn err(error_code: error) -> Result { Err(ProgramError::Custom(error_code.into())) } From 9664c2bfb513046442b4fd89d35fce10d2f25c29 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:14:30 -0800 Subject: [PATCH 049/263] Clean up ASM defs --- .../tree/artifacts/snippets/asm/constants.txt | 6 +-- ...input-buffer.txt => entrypoint-branch.txt} | 0 examples/tree/interface/src/asm.rs | 53 ++++++++++++------- examples/tree/src/tree/tree.s | 10 ++-- 4 files changed, 42 insertions(+), 27 deletions(-) rename examples/tree/artifacts/snippets/asm/{check-input-buffer.txt => entrypoint-branch.txt} (100%) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index e0e8832f..859302dd 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -26,9 +26,9 @@ .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. -.equ IB_PACKED_INSTRUCTION_DATA_LEN_OFF, 20680 -# Program ID field for empty tree account. -.equ IB_PACKED_PROGRAM_ID_OFF, 20688 +.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 +# Program ID field for initialize instruction. +.equ IB_INIT_PROGRAM_ID_OFF, 31040 # Miscellaneous constants. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/check-input-buffer.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branch.txt similarity index 100% rename from examples/tree/artifacts/snippets/asm/check-input-buffer.txt rename to examples/tree/artifacts/snippets/asm/entrypoint-branch.txt diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 13d34d0c..29037fa3 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,10 +1,13 @@ extern crate alloc; -use crate::bindings::*; -use crate::common::*; +use crate::bindings; +use crate::common; +use crate::common::CreateAccountInstructionData; +use core::char::MAX; +use core::mem::size_of; use macros::{asm_constant_group, extend_constant_group}; use pinocchio::{ - account::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE}, + account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address, @@ -25,9 +28,10 @@ extend_constant_group!(input_buffer { /// Tree data length field. offset!(TREE_DATA_LEN, InputBuffer.tree_header.data_len), /// Instruction data length field for empty tree account. - offset!(PACKED_INSTRUCTION_DATA_LEN, PackedInputBuffer.instruction_data_len), - /// Program ID field for empty tree account. - offset!(PACKED_PROGRAM_ID, PackedInputBuffer.program_id), + offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBuffer.instruction_data_len), + /// Program ID field for initialize instruction. + offset!(INIT_PROGRAM_ID, InitInputBuffer.program_id), + }); asm_constant_group! { @@ -42,28 +46,39 @@ asm_constant_group! { } } -#[repr(C, packed)] -struct EmptyRuntimeAccount { - header: RuntimeAccount, - data: [u8; MAX_PERMITTED_DATA_INCREASE], +/// Compute the data buffer size for a runtime account with the given data length. +const fn runtime_data_size(data_len: i64) -> usize { + MAX_PERMITTED_DATA_INCREASE + + (((data_len + misc::MAX_DATA_PAD) & misc::DATA_LEN_AND_MASK) as usize) +} + +#[repr(C)] +struct RuntimeAccount { + header: RuntimeAccountHeader, + data: [u8; DATA_SIZE], rent_epoch: u64, } +type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO) }>; +type SystemProgramRuntimeAccount = + RuntimeAccount<{ runtime_data_size(common::input_buffer::SYSTEM_PROGRAM_DATA_LEN as i64) }>; + #[repr(C, packed)] struct InputBuffer { n_accounts: u64, user: EmptyRuntimeAccount, - tree_header: RuntimeAccount, + tree_header: RuntimeAccountHeader, } #[repr(C, packed)] -/// Input buffer for empty tree account and no instruction data (during initialization). -struct PackedInputBuffer { +/// Input buffer for tree initialization instruction. +struct InitInputBuffer { n_accounts: u64, user: EmptyRuntimeAccount, tree: EmptyRuntimeAccount, + system_program: SystemProgramRuntimeAccount, + /// No actual instruction data follows. instruction_data_len: u64, - instruction_data: [u8; 0], program_id: Address, } @@ -78,11 +93,11 @@ const CPI_N_SEEDS: usize = 1; struct InitStackFrame { /// Zero-initialized on stack. system_program_address: Address, - instruction: SolInstruction, - account_metas: [SolAccountMeta; CPI_N_ACCOUNTS], - account_infos: [SolAccountInfo; CPI_N_ACCOUNTS], - signers_seeds: [SolSignerSeeds; CPI_N_PDA_SIGNERS], - signer_seeds: [SolSignerSeed; CPI_N_SEEDS], + instruction: bindings::SolInstruction, + account_metas: [bindings::SolAccountMeta; CPI_N_ACCOUNTS], + account_infos: [bindings::SolAccountInfo; CPI_N_ACCOUNTS], + signers_seeds: [bindings::SolSignerSeeds; CPI_N_PDA_SIGNERS], + signer_seeds: [bindings::SolSignerSeed; CPI_N_SEEDS], pda: Address, rent: Rent, instruction_data: CreateAccountInstructionData, diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d431a0ac..23e463aa 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -27,9 +27,9 @@ .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. -.equ IB_PACKED_INSTRUCTION_DATA_LEN_OFF, 20680 -# Program ID field for empty tree account. -.equ IB_PACKED_PROGRAM_ID_OFF, 20688 +.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 +# Program ID field for initialize instruction. +.equ IB_INIT_PROGRAM_ID_OFF, 31040 # Miscellaneous constants. # ------------------------ @@ -38,7 +38,7 @@ .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. # ANCHOR_END: constants -# ANCHOR: check-input-buffer +# ANCHOR: entrypoint-branch .globl entrypoint entrypoint: @@ -49,7 +49,7 @@ entrypoint: jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit - # ANCHOR_END: check-input-buffer + # ANCHOR_END: entrypoint-branch general: ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. From fd05cbd66a19fed744770e309c7ba8cfb2ab3ba1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:17:28 -0800 Subject: [PATCH 050/263] Tidy up ASM checks --- examples/tree/interface/src/asm.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 29037fa3..019d9cc4 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,8 +3,6 @@ extern crate alloc; use crate::bindings; use crate::common; use crate::common::CreateAccountInstructionData; -use core::char::MAX; -use core::mem::size_of; use macros::{asm_constant_group, extend_constant_group}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, @@ -16,17 +14,17 @@ use pinocchio::{ extend_constant_group!(input_buffer { prefix = "IB", /// Number of accounts field. - offset!(N_ACCOUNTS, InputBuffer.n_accounts), + offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User address field. - offset!(USER_ADDRESS, InputBuffer.user.header.address), + offset!(USER_ADDRESS, InputBufferHeader.user.header.address), /// User data length field. - offset!(USER_DATA_LEN, InputBuffer.user.header.data_len), + offset!(USER_DATA_LEN, InputBufferHeader.user.header.data_len), /// Non-duplicate marker value. NON_DUP_MARKER = NON_DUP_MARKER, /// Tree non-duplicate marker field. - offset!(TREE_NON_DUP_MARKER, InputBuffer.tree_header.borrow_state), + offset!(TREE_NON_DUP_MARKER, InputBufferHeader.tree_header.borrow_state), /// Tree data length field. - offset!(TREE_DATA_LEN, InputBuffer.tree_header.data_len), + offset!(TREE_DATA_LEN, InputBufferHeader.tree_header.data_len), /// Instruction data length field for empty tree account. offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBuffer.instruction_data_len), /// Program ID field for initialize instruction. @@ -64,7 +62,8 @@ type SystemProgramRuntimeAccount = RuntimeAccount<{ runtime_data_size(common::input_buffer::SYSTEM_PROGRAM_DATA_LEN as i64) }>; #[repr(C, packed)] -struct InputBuffer { +/// Input buffer header for all instructions. +struct InputBufferHeader { n_accounts: u64, user: EmptyRuntimeAccount, tree_header: RuntimeAccountHeader, From 4c2cb986766b7ea359b132b91e5d573542c7f842 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:30:13 -0800 Subject: [PATCH 051/263] Update init parse logic --- .../tree/artifacts/snippets/asm/constants.txt | 4 ++ examples/tree/interface/src/asm.rs | 5 +- examples/tree/interface/src/common.rs | 1 + examples/tree/src/tree/tree.s | 48 +++++++++++++++---- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 859302dd..455b0372 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -29,6 +29,10 @@ .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF, 31040 +# System Program non-duplicate marker field. +.equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 +# System Program data length field. +.equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 # Miscellaneous constants. # ------------------------ diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 019d9cc4..74a423fa 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -12,7 +12,6 @@ use pinocchio::{ }; extend_constant_group!(input_buffer { - prefix = "IB", /// Number of accounts field. offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User address field. @@ -29,6 +28,10 @@ extend_constant_group!(input_buffer { offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBuffer.instruction_data_len), /// Program ID field for initialize instruction. offset!(INIT_PROGRAM_ID, InitInputBuffer.program_id), + /// System Program non-duplicate marker field. + offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.system_program.header.borrow_state), + /// System Program data length field. + offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0554ef14..b775d183 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -21,6 +21,7 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { + prefix = "IB", /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 23e463aa..8f62c448 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -30,6 +30,10 @@ .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF, 31040 +# System Program non-duplicate marker field. +.equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 +# System Program data length field. +.equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 # Miscellaneous constants. # ------------------------ @@ -56,22 +60,48 @@ general: add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. add64 r2, r1 # Get input buffer pointer shifted for tree data. - # Get instruction data length. - ldxdw r3, [r2 + IB_PACKED_INSTRUCTION_DATA_LEN_OFF] exit initialize: - ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] # Get user data length. - jne r2, DATA_LEN_ZERO, e_user_data_len # Error if user has data. - ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] # Load tree non-dup marker. - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate # Error if duplicate. - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + + # Error if user has data. + # ----------------------- + ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate or has data. + # --------------------------------------- + ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_tree_data_len + + # Error if System Program is duplicate or has invalid data length. + # ---------------------------------------------------------------- + ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN] + jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + + # Error if has instruction data exit -e_user_data_len: - mov64 r0, E_USER_DATA_LEN +e_system_program_data_len: + mov64 r0, E_SYSTEM_PROGRAM_DATA_LEN + exit + +e_system_program_duplicate: + mov64 r0, E_SYSTEM_PROGRAM_DUPLICATE + exit + +e_tree_data_len: + mov64 r0, E_TREE_DATA_LEN exit e_tree_duplicate: mov64 r0, E_TREE_DUPLICATE exit + +e_user_data_len: + mov64 r0, E_USER_DATA_LEN + exit From fa46e97309e691db2617bd47ac592dad477f2044 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:31:41 -0800 Subject: [PATCH 052/263] Put prefix in ASM defs --- examples/tree/interface/src/asm.rs | 2 +- examples/tree/interface/src/common.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 74a423fa..25eb19f0 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -12,6 +12,7 @@ use pinocchio::{ }; extend_constant_group!(input_buffer { + prefix = "IB", /// Number of accounts field. offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User address field. @@ -32,7 +33,6 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.system_program.header.borrow_state), /// System Program data length field. offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), - }); asm_constant_group! { diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index b775d183..0554ef14 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -21,7 +21,6 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { - prefix = "IB", /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. From e07c0b061ab4fb01f128cebe3fb5f1273026ff9d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:36:20 -0800 Subject: [PATCH 053/263] Update initialize logic --- examples/tree/artifacts/snippets/asm/constants.txt | 4 +++- examples/tree/interface/src/common.rs | 2 ++ examples/tree/src/program.rs | 9 ++++++++- examples/tree/src/tree/tree.s | 14 ++++++++++++-- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 455b0372..04f71f72 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -8,8 +8,10 @@ .equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 +# Instruction data provided during initialization instruction. +.equ E_INSTRUCTION_DATA, 7 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 7 +.equ E_PDA_MISMATCH, 8 # Input buffer layout. # -------------------- diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0554ef14..838634e4 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -14,6 +14,8 @@ error_codes! { TREE_DUPLICATE, /// The System Program account is a duplicate. SYSTEM_PROGRAM_DUPLICATE, + /// Instruction data provided during initialization instruction. + INSTRUCTION_DATA, /// The passed PDA does not match the expected address. PDA_MISMATCH, } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index acfa3225..12111426 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -56,7 +56,7 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { // ANCHOR_END: entrypoint-branch #[inline(always)] -unsafe fn initialize(mut context: InstructionContext) -> ProgramResult { +fn initialize(mut context: InstructionContext) -> ProgramResult { // Verify user has no data. // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; @@ -76,6 +76,13 @@ unsafe fn initialize(mut context: InstructionContext) -> ProgramResult { error::SYSTEM_PROGRAM_DATA_LEN, )?; + // Verify no instruction data provided. + // SAFETY: all accounts have been consumed. + ensure( + unsafe { context.instruction_data_unchecked().is_empty() }, + error::INSTRUCTION_DATA, + )?; + // Verify tree PDA. let program_id = unsafe { context.program_id_unchecked() }; let (expected_pda, bump) = Address::find_program_address(&[], program_id); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 8f62c448..f7b96206 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,8 +9,10 @@ .equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 +# Instruction data provided during initialization instruction. +.equ E_INSTRUCTION_DATA, 7 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 7 +.equ E_PDA_MISMATCH, 8 # Input buffer layout. # -------------------- @@ -83,7 +85,15 @@ initialize: ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN] jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len - # Error if has instruction data + # Error if instruction data provided. + # ----------------------------------- + ldxdw r2, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_instruction_data + + exit + +e_instruction_data: + mov64 r0, E_INSTRUCTION_DATA exit e_system_program_data_len: From 74535b4b3cba0b5464a0700c97f06058dee42615 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:39:33 -0800 Subject: [PATCH 054/263] Implement initialize check parity --- ...nt-branch.txt => entrypoint-branching.txt} | 0 .../snippets/asm/initialize-input-checks.txt | 25 +++++++++++++++++ ...nt-branch.txt => entrypoint-branching.txt} | 3 +-- .../snippets/rs/initialize-input-checks.txt | 27 +++++++++++++++++++ examples/tree/src/program.rs | 9 ++++--- examples/tree/src/tree/tree.s | 6 +++-- 6 files changed, 62 insertions(+), 8 deletions(-) rename examples/tree/artifacts/snippets/asm/{entrypoint-branch.txt => entrypoint-branching.txt} (100%) create mode 100644 examples/tree/artifacts/snippets/asm/initialize-input-checks.txt rename examples/tree/artifacts/snippets/rs/{entrypoint-branch.txt => entrypoint-branching.txt} (69%) create mode 100644 examples/tree/artifacts/snippets/rs/initialize-input-checks.txt diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branch.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt similarity index 100% rename from examples/tree/artifacts/snippets/asm/entrypoint-branch.txt rename to examples/tree/artifacts/snippets/asm/entrypoint-branching.txt diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt new file mode 100644 index 00000000..1d4a56ab --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -0,0 +1,25 @@ +initialize: + + # Error if user has data. + # ----------------------- + ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate or has data. + # --------------------------------------- + ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r2, IB_NON_DUP_MARKER, e_tree_duplicate + ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_tree_data_len + + # Error if System Program is duplicate or has invalid data length. + # ---------------------------------------------------------------- + ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN] + jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + + # Error if instruction data provided. + # ----------------------------------- + ldxdw r2, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] + jne r2, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt similarity index 69% rename from examples/tree/artifacts/snippets/rs/entrypoint-branch.txt rename to examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 153cfb2d..5e2a7d68 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branch.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -5,8 +5,7 @@ lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - // SAFETY: number of accounts has been checked. - input_buffer::N_ACCOUNTS_INIT => unsafe { initialize(context) }, + input_buffer::N_ACCOUNTS_INIT => initialize(context), _ => err(error::N_ACCOUNTS), } } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt new file mode 100644 index 00000000..0ac0e6de --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -0,0 +1,27 @@ +#[inline(always)] +fn initialize(mut context: InstructionContext) -> ProgramResult { + // Verify user has no data. + // SAFETY: number of accounts has been checked. + let user = unsafe { context.next_account_unchecked().assume_account() }; + ensure_is_data_empty(&user, error::USER_DATA_LEN)?; + + // Verify tree is non-duplicate and has no data. + // SAFETY: number of accounts has been checked. + let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; + ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; + + // Verify system program is non-duplicate and has expected data length. + // SAFETY: number of accounts has been checked. + let system_program = + unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; + ensure( + system_program.data_len() == input_buffer::SYSTEM_PROGRAM_DATA_LEN, + error::SYSTEM_PROGRAM_DATA_LEN, + )?; + + // Verify no instruction data provided. + // SAFETY: all accounts have been consumed. + ensure( + unsafe { context.instruction_data_unchecked().is_empty() }, + error::INSTRUCTION_DATA, + )?; \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 12111426..d1803d08 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -40,7 +40,7 @@ unsafe fn next_account_non_duplicate( } } -// ANCHOR: entrypoint-branch +// ANCHOR: entrypoint-branching nostd_panic_handler!(); no_allocator!(); lazy_program_entrypoint!(process_instruction); @@ -48,13 +48,13 @@ lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - // SAFETY: number of accounts has been checked. - input_buffer::N_ACCOUNTS_INIT => unsafe { initialize(context) }, + input_buffer::N_ACCOUNTS_INIT => initialize(context), _ => err(error::N_ACCOUNTS), } } -// ANCHOR_END: entrypoint-branch +// ANCHOR_END: entrypoint-branching +// ANCHOR: initialize-input-checks #[inline(always)] fn initialize(mut context: InstructionContext) -> ProgramResult { // Verify user has no data. @@ -82,6 +82,7 @@ fn initialize(mut context: InstructionContext) -> ProgramResult { unsafe { context.instruction_data_unchecked().is_empty() }, error::INSTRUCTION_DATA, )?; + // ANCHOR_END: initialize-input-checks // Verify tree PDA. let program_id = unsafe { context.program_id_unchecked() }; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index f7b96206..0d1c62dd 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -44,7 +44,7 @@ .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. # ANCHOR_END: constants -# ANCHOR: entrypoint-branch +# ANCHOR: entrypoint-branching .globl entrypoint entrypoint: @@ -55,7 +55,7 @@ entrypoint: jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit - # ANCHOR_END: entrypoint-branch + # ANCHOR_END: entrypoint-branching general: ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. @@ -64,6 +64,7 @@ general: add64 r2, r1 # Get input buffer pointer shifted for tree data. exit +# ANCHOR: initialize-input-checks initialize: # Error if user has data. @@ -89,6 +90,7 @@ initialize: # ----------------------------------- ldxdw r2, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] jne r2, DATA_LEN_ZERO, e_instruction_data + # ANCHOR_END: initialize-input-checks exit From 2932f9dc7d91c5eaacdf6368df950e948f762249 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:44:57 -0800 Subject: [PATCH 055/263] Enforce comment parity --- .../artifacts/snippets/rs/initialize-input-checks.txt | 9 +++++---- examples/tree/src/program.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 0ac0e6de..181c5232 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,16 +1,17 @@ #[inline(always)] +/// SAFETY: Called by entrypoint after verifying the right number of accounts for initialization. fn initialize(mut context: InstructionContext) -> ProgramResult { - // Verify user has no data. + // Error if user has data. // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; ensure_is_data_empty(&user, error::USER_DATA_LEN)?; - // Verify tree is non-duplicate and has no data. + // Error if tree is duplicate or has data. // SAFETY: number of accounts has been checked. let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; - // Verify system program is non-duplicate and has expected data length. + // Error if System Program is duplicate or has invalid data length. // SAFETY: number of accounts has been checked. let system_program = unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; @@ -19,7 +20,7 @@ fn initialize(mut context: InstructionContext) -> ProgramResult { error::SYSTEM_PROGRAM_DATA_LEN, )?; - // Verify no instruction data provided. + // Error if instruction data provided. // SAFETY: all accounts have been consumed. ensure( unsafe { context.instruction_data_unchecked().is_empty() }, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index d1803d08..2e74fd04 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -56,18 +56,19 @@ pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { // ANCHOR: initialize-input-checks #[inline(always)] +/// SAFETY: Called by entrypoint after verifying the right number of accounts for initialization. fn initialize(mut context: InstructionContext) -> ProgramResult { - // Verify user has no data. + // Error if user has data. // SAFETY: number of accounts has been checked. let user = unsafe { context.next_account_unchecked().assume_account() }; ensure_is_data_empty(&user, error::USER_DATA_LEN)?; - // Verify tree is non-duplicate and has no data. + // Error if tree is duplicate or has data. // SAFETY: number of accounts has been checked. let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; - // Verify system program is non-duplicate and has expected data length. + // Error if System Program is duplicate or has invalid data length. // SAFETY: number of accounts has been checked. let system_program = unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; @@ -76,7 +77,7 @@ fn initialize(mut context: InstructionContext) -> ProgramResult { error::SYSTEM_PROGRAM_DATA_LEN, )?; - // Verify no instruction data provided. + // Error if instruction data provided. // SAFETY: all accounts have been consumed. ensure( unsafe { context.instruction_data_unchecked().is_empty() }, From 64820dd64ee5c35f48169646c6a8b7117e959f6c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:55:03 -0800 Subject: [PATCH 056/263] Make tests into groups --- .../snippets/asm/entrypoint-branching.txt | 2 +- .../snippets/asm/initialize-input-checks.txt | 2 +- examples/tree/src/tests.rs | 388 +++++++++++------- examples/tree/src/tree/tree.s | 4 +- 4 files changed, 233 insertions(+), 163 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt index 17dede7c..a48ee1cc 100644 --- a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt @@ -5,6 +5,6 @@ entrypoint: # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + jeq r2, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 1d4a56ab..bfd6c8e6 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -16,7 +16,7 @@ initialize: # ---------------------------------------------------------------- ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN] + ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if instruction data provided. diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 2d0d0d72..d249a06b 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -11,133 +11,60 @@ use test_utils::{setup_test, ProgramLanguage}; enum AccountIndex { User = 0, Tree = 1, + SystemProgram = 2, } -fn happy_path_setup( - program_language: ProgramLanguage, -) -> (test_utils::TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(program_language); - let (system_program, _) = program::keyed_account_for_system_program(); - - let user_pubkey = Pubkey::new_unique(); - let tree_pubkey = Pubkey::new_unique(); - - let instruction = Instruction::new_with_bytes( - setup.program_id, - &[], - vec![ - AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pubkey, false), - ], - ); - - let accounts = vec![ - (user_pubkey, Account::new(1_000_000, 0, &system_program)), - (tree_pubkey, Account::new(0, 0, &system_program)), - ]; - - (setup, instruction, accounts) -} +// ============================================================================ +// Entrypoint branching +// ============================================================================ #[derive(Clone, Copy)] -enum Case { +enum EntrypointCase { NoAccounts, - TooManyAccounts, - UserDataLen, - TreeDuplicate, + OneAccount, + FourAccounts, } -impl Case { - const PARSING_CASES: &'static [Case] = &[ - Case::NoAccounts, - Case::TooManyAccounts, - Case::UserDataLen, - Case::TreeDuplicate, +impl EntrypointCase { + const CASES: &'static [Self] = &[ + Self::NoAccounts, + Self::OneAccount, + Self::FourAccounts, ]; const fn name(&self) -> &'static str { match self { - Self::NoAccounts => "No accounts passed", - Self::TooManyAccounts => "Too many accounts passed", - Self::UserDataLen => "User has nonzero data length", - Self::TreeDuplicate => "Tree account is duplicate", + Self::NoAccounts => "No accounts", + Self::OneAccount => "One account", + Self::FourAccounts => "Four accounts", } } - fn run(&self, lang: ProgramLanguage) -> u64 { + const fn n_accounts(&self) -> usize { match self { - Self::NoAccounts => run_no_accounts(lang), - Self::TooManyAccounts => run_too_many_accounts(lang), - Self::UserDataLen => run_user_data_len(lang), - Self::TreeDuplicate => run_tree_duplicate(lang), + Self::NoAccounts => 0, + Self::OneAccount => 1, + Self::FourAccounts => 4, } } -} - -fn run_no_accounts(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, mut accounts) = happy_path_setup(lang); - instruction.accounts.clear(); - accounts.clear(); - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::N_ACCOUNTS.into(), - ))], - ) - .compute_units_consumed -} - -fn run_too_many_accounts(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, mut accounts) = happy_path_setup(lang); - - instruction - .accounts - .push(AccountMeta::new_readonly(Pubkey::new_unique(), false)); - accounts.push(( - instruction.accounts.last().unwrap().pubkey, - Account::default(), - )); - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::N_ACCOUNTS.into(), - ))], - ) - .compute_units_consumed + fn run(&self, lang: ProgramLanguage) -> u64 { + run_entrypoint(lang, self.n_accounts()) + } } -fn run_user_data_len(lang: ProgramLanguage) -> u64 { - let (setup, instruction, mut accounts) = happy_path_setup(lang); - - accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; +fn run_entrypoint(lang: ProgramLanguage, n_accounts: usize) -> u64 { + let setup = setup_test(lang); - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::USER_DATA_LEN.into(), - ))], - ) - .compute_units_consumed -} + let account_metas: Vec = (0..n_accounts) + .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) + .collect(); + let accounts: Vec<(Pubkey, Account)> = account_metas + .iter() + .map(|meta| (meta.pubkey, Account::default())) + .collect(); -fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, mut accounts) = happy_path_setup(lang); - - instruction.accounts[AccountIndex::Tree as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::Tree as usize] = accounts[AccountIndex::User as usize].clone(); + let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); setup .mollusk @@ -145,7 +72,7 @@ fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { &instruction, &accounts, &[Check::err(ProgramError::Custom( - error_codes::error::TREE_DUPLICATE.into(), + error_codes::error::N_ACCOUNTS.into(), ))], ) .compute_units_consumed @@ -153,50 +80,40 @@ fn run_tree_duplicate(lang: ProgramLanguage) -> u64 { #[test] fn test_asm_no_accounts() { - run_no_accounts(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_too_many_accounts() { - run_too_many_accounts(ProgramLanguage::Assembly); + EntrypointCase::NoAccounts.run(ProgramLanguage::Assembly); } #[test] -fn test_asm_user_data_len() { - run_user_data_len(ProgramLanguage::Assembly); +fn test_asm_one_account() { + EntrypointCase::OneAccount.run(ProgramLanguage::Assembly); } #[test] -fn test_asm_tree_duplicate() { - run_tree_duplicate(ProgramLanguage::Assembly); +fn test_asm_four_accounts() { + EntrypointCase::FourAccounts.run(ProgramLanguage::Assembly); } #[test] fn test_rs_no_accounts() { - run_no_accounts(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_too_many_accounts() { - run_too_many_accounts(ProgramLanguage::Rust); + EntrypointCase::NoAccounts.run(ProgramLanguage::Rust); } #[test] -fn test_rs_user_data_len() { - run_user_data_len(ProgramLanguage::Rust); +fn test_rs_one_account() { + EntrypointCase::OneAccount.run(ProgramLanguage::Rust); } #[test] -fn test_rs_tree_duplicate() { - run_tree_duplicate(ProgramLanguage::Rust); +fn test_rs_four_accounts() { + EntrypointCase::FourAccounts.run(ProgramLanguage::Rust); } #[test] -fn test_fast_fails() { +fn test_entrypoint_branching() { println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); println!("|------|-----------|------------|----------|------------|"); - for case in Case::PARSING_CASES { + for case in EntrypointCase::CASES { let asm_cu = case.run(ProgramLanguage::Assembly); let rs_cu = case.run(ProgramLanguage::Rust); let overhead = rs_cu as i64 - asm_cu as i64; @@ -217,32 +134,36 @@ fn test_fast_fails() { } // ============================================================================ -// Initialize operation tests +// Initialize input checks // ============================================================================ -/// Setup for initialize instruction (empty instruction data, correct PDA). fn init_setup( program_language: ProgramLanguage, ) -> (test_utils::TestSetup, Instruction, Vec<(Pubkey, Account)>) { let setup = setup_test(program_language); - let (system_program, _) = program::keyed_account_for_system_program(); + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); let user_pubkey = Pubkey::new_unique(); - // Derive the correct PDA for the tree account. - let (tree_pda, _bump) = Pubkey::find_program_address(&[], &setup.program_id); + let tree_pubkey = Pubkey::new_unique(); let instruction = Instruction::new_with_bytes( setup.program_id, - &[], // Empty instruction data triggers initialize path + &[], vec![ AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pda, false), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), ], ); let accounts = vec![ - (user_pubkey, Account::new(1_000_000, 0, &system_program)), - (tree_pda, Account::new(0, 0, &system_program)), + ( + user_pubkey, + Account::new(1_000_000, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), + (system_program_pubkey, system_program_account), ]; (setup, instruction, accounts) @@ -250,34 +171,84 @@ fn init_setup( #[derive(Clone, Copy)] enum InitCase { - PdaMismatch, + UserDataLen, + TreeDuplicate, + TreeDataLen, + SystemProgramDuplicate, + SystemProgramDataLen, + InstructionData, } impl InitCase { - const CASES: &'static [InitCase] = &[InitCase::PdaMismatch]; + const CASES: &'static [Self] = &[ + Self::UserDataLen, + Self::TreeDuplicate, + Self::TreeDataLen, + Self::SystemProgramDuplicate, + Self::SystemProgramDataLen, + Self::InstructionData, + ]; const fn name(&self) -> &'static str { match self { - Self::PdaMismatch => "PDA mismatch", + Self::UserDataLen => "User has nonzero data length", + Self::TreeDuplicate => "Tree account is duplicate", + Self::TreeDataLen => "Tree has nonzero data length", + Self::SystemProgramDuplicate => "System program is duplicate", + Self::SystemProgramDataLen => "System program wrong data length", + Self::InstructionData => "Non-empty instruction data", } } fn run(&self, lang: ProgramLanguage) -> u64 { match self { - Self::PdaMismatch => run_init_pda_mismatch(lang), + Self::UserDataLen => run_init_user_data_len(lang), + Self::TreeDuplicate => run_init_tree_duplicate(lang), + Self::TreeDataLen => run_init_tree_data_len(lang), + Self::SystemProgramDuplicate => run_init_system_program_duplicate(lang), + Self::SystemProgramDataLen => run_init_system_program_data_len(lang), + Self::InstructionData => run_init_instruction_data(lang), } } } -fn run_init_pda_mismatch(lang: ProgramLanguage) -> u64 { +fn run_init_user_data_len(lang: ProgramLanguage) -> u64 { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::USER_DATA_LEN.into(), + ))], + ) + .compute_units_consumed +} + +fn run_init_tree_duplicate(lang: ProgramLanguage) -> u64 { let (setup, mut instruction, mut accounts) = init_setup(lang); - let (system_program, _) = program::keyed_account_for_system_program(); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = accounts[AccountIndex::User as usize].clone(); - // Replace tree PDA with a random pubkey (not the correct PDA). - let wrong_tree_pubkey = Pubkey::new_unique(); - instruction.accounts[AccountIndex::Tree as usize] = AccountMeta::new(wrong_tree_pubkey, false); - accounts[AccountIndex::Tree as usize] = - (wrong_tree_pubkey, Account::new(0, 0, &system_program)); + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::TREE_DUPLICATE.into(), + ))], + ) + .compute_units_consumed +} + +fn run_init_tree_data_len(lang: ProgramLanguage) -> u64 { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::Tree as usize].1.data = vec![1u8; 1]; setup .mollusk @@ -285,31 +256,130 @@ fn run_init_pda_mismatch(lang: ProgramLanguage) -> u64 { &instruction, &accounts, &[Check::err(ProgramError::Custom( - error_codes::error::PDA_MISMATCH.into(), + error_codes::error::TREE_DATA_LEN.into(), ))], ) .compute_units_consumed } +fn run_init_system_program_duplicate(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::SystemProgram as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::SystemProgram as usize] = + accounts[AccountIndex::User as usize].clone(); + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::SYSTEM_PROGRAM_DUPLICATE.into(), + ))], + ) + .compute_units_consumed +} + +fn run_init_system_program_data_len(lang: ProgramLanguage) -> u64 { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::SYSTEM_PROGRAM_DATA_LEN.into(), + ))], + ) + .compute_units_consumed +} + +fn run_init_instruction_data(lang: ProgramLanguage) -> u64 { + let (setup, mut instruction, accounts) = init_setup(lang); + instruction.data = vec![1u8; 1]; + + setup + .mollusk + .process_and_validate_instruction( + &instruction, + &accounts, + &[Check::err(ProgramError::Custom( + error_codes::error::INSTRUCTION_DATA.into(), + ))], + ) + .compute_units_consumed +} + +#[test] +fn test_rs_init_user_data_len() { + run_init_user_data_len(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_init_tree_duplicate() { + run_init_tree_duplicate(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_init_tree_data_len() { + run_init_tree_data_len(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_init_system_program_duplicate() { + run_init_system_program_duplicate(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_init_system_program_data_len() { + run_init_system_program_data_len(ProgramLanguage::Rust); +} + +#[test] +fn test_rs_init_instruction_data() { + run_init_instruction_data(ProgramLanguage::Rust); +} + +#[test] +fn test_asm_init_user_data_len() { + run_init_user_data_len(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_init_tree_duplicate() { + run_init_tree_duplicate(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_init_tree_data_len() { + run_init_tree_data_len(ProgramLanguage::Assembly); +} + +#[test] +fn test_asm_init_system_program_duplicate() { + run_init_system_program_duplicate(ProgramLanguage::Assembly); +} + #[test] -fn test_rs_init_pda_mismatch() { - run_init_pda_mismatch(ProgramLanguage::Rust); +fn test_asm_init_system_program_data_len() { + run_init_system_program_data_len(ProgramLanguage::Assembly); } #[test] -#[should_panic] // ASM doesn't have PDA check yet -fn test_asm_init_pda_mismatch() { - run_init_pda_mismatch(ProgramLanguage::Assembly); +fn test_asm_init_instruction_data() { + run_init_instruction_data(ProgramLanguage::Assembly); } #[test] -fn test_init_fails() { - println!("\n| Init Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|-----------|-----------|------------|----------|------------|"); +fn test_initialize_input_checks() { + println!("\n| Init Case | Rust (CUs) |"); + println!("|-----------|------------|"); for case in InitCase::CASES { - // Only run Rust for now since ASM doesn't have init logic yet. let rs_cu = case.run(ProgramLanguage::Rust); - println!("| {} | N/A | {} | N/A | N/A |", case.name(), rs_cu); + println!("| {} | {} |", case.name(), rs_cu); } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 0d1c62dd..877e96b1 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -52,7 +52,7 @@ entrypoint: # ---------------------------- ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r3, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + jeq r2, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit # ANCHOR_END: entrypoint-branching @@ -83,7 +83,7 @@ initialize: # ---------------------------------------------------------------- ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN] + ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if instruction data provided. From 5c14f453f5f87ed15deba15961f492d78d57e4f1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:59:35 -0800 Subject: [PATCH 057/263] Clean up tests --- examples/tree/src/tests.rs | 327 +++++++++++++++---------------------- 1 file changed, 136 insertions(+), 191 deletions(-) diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index d249a06b..faf166f6 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -6,7 +6,7 @@ use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::program_error::ProgramError; use solana_sdk::pubkey::Pubkey; use std::vec; -use test_utils::{setup_test, ProgramLanguage}; +use test_utils::{setup_test, ProgramLanguage, TestSetup}; enum AccountIndex { User = 0, @@ -14,9 +14,50 @@ enum AccountIndex { SystemProgram = 2, } -// ============================================================================ -// Entrypoint branching -// ============================================================================ +fn expect_error( + setup: &TestSetup, + instruction: &Instruction, + accounts: &[(Pubkey, Account)], + error_code: error_codes::error, +) -> u64 { + setup + .mollusk + .process_and_validate_instruction( + instruction, + accounts, + &[Check::err(ProgramError::Custom(error_code.into()))], + ) + .compute_units_consumed +} + +trait TestCase: Copy { + fn name(&self) -> &'static str; + fn run(&self, lang: ProgramLanguage) -> u64; +} + +fn print_comparison_table(cases: &[T]) { + println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|------|-----------|------------|----------|------------|"); + + for case in cases { + let asm_cu = case.run(ProgramLanguage::Assembly); + let rs_cu = case.run(ProgramLanguage::Rust); + let overhead = rs_cu as i64 - asm_cu as i64; + let overhead_pct = if asm_cu > 0 { + (overhead as f64 / asm_cu as f64) * 100.0 + } else { + 0.0 + }; + println!( + "| {} | {} | {} | {:+} | {:+.1}% |", + case.name(), + asm_cu, + rs_cu, + overhead, + overhead_pct + ); + } +} #[derive(Clone, Copy)] enum EntrypointCase { @@ -32,14 +73,6 @@ impl EntrypointCase { Self::FourAccounts, ]; - const fn name(&self) -> &'static str { - match self { - Self::NoAccounts => "No accounts", - Self::OneAccount => "One account", - Self::FourAccounts => "Four accounts", - } - } - const fn n_accounts(&self) -> usize { match self { Self::NoAccounts => 0, @@ -47,35 +80,31 @@ impl EntrypointCase { Self::FourAccounts => 4, } } - - fn run(&self, lang: ProgramLanguage) -> u64 { - run_entrypoint(lang, self.n_accounts()) - } } -fn run_entrypoint(lang: ProgramLanguage, n_accounts: usize) -> u64 { - let setup = setup_test(lang); - - let account_metas: Vec = (0..n_accounts) - .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) - .collect(); - let accounts: Vec<(Pubkey, Account)> = account_metas - .iter() - .map(|meta| (meta.pubkey, Account::default())) - .collect(); - - let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); +impl TestCase for EntrypointCase { + fn name(&self) -> &'static str { + match self { + Self::NoAccounts => "No accounts", + Self::OneAccount => "One account", + Self::FourAccounts => "Four accounts", + } + } - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::N_ACCOUNTS.into(), - ))], - ) - .compute_units_consumed + fn run(&self, lang: ProgramLanguage) -> u64 { + let setup = setup_test(lang); + + let account_metas: Vec = (0..self.n_accounts()) + .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) + .collect(); + let accounts: Vec<(Pubkey, Account)> = account_metas + .iter() + .map(|meta| (meta.pubkey, Account::default())) + .collect(); + + let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); + expect_error(&setup, &instruction, &accounts, error_codes::error::N_ACCOUNTS) + } } #[test] @@ -110,36 +139,12 @@ fn test_rs_four_accounts() { #[test] fn test_entrypoint_branching() { - println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|------|-----------|------------|----------|------------|"); - - for case in EntrypointCase::CASES { - let asm_cu = case.run(ProgramLanguage::Assembly); - let rs_cu = case.run(ProgramLanguage::Rust); - let overhead = rs_cu as i64 - asm_cu as i64; - let overhead_pct = if asm_cu > 0 { - (overhead as f64 / asm_cu as f64) * 100.0 - } else { - 0.0 - }; - println!( - "| {} | {} | {} | {:+} | {:+.1}% |", - case.name(), - asm_cu, - rs_cu, - overhead, - overhead_pct - ); - } + print_comparison_table(EntrypointCase::CASES); } -// ============================================================================ -// Initialize input checks -// ============================================================================ - fn init_setup( program_language: ProgramLanguage, -) -> (test_utils::TestSetup, Instruction, Vec<(Pubkey, Account)>) { +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { let setup = setup_test(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); @@ -188,8 +193,10 @@ impl InitCase { Self::SystemProgramDataLen, Self::InstructionData, ]; +} - const fn name(&self) -> &'static str { +impl TestCase for InitCase { + fn name(&self) -> &'static str { match self { Self::UserDataLen => "User has nonzero data length", Self::TreeDuplicate => "Tree account is duplicate", @@ -202,184 +209,122 @@ impl InitCase { fn run(&self, lang: ProgramLanguage) -> u64 { match self { - Self::UserDataLen => run_init_user_data_len(lang), - Self::TreeDuplicate => run_init_tree_duplicate(lang), - Self::TreeDataLen => run_init_tree_data_len(lang), - Self::SystemProgramDuplicate => run_init_system_program_duplicate(lang), - Self::SystemProgramDataLen => run_init_system_program_data_len(lang), - Self::InstructionData => run_init_instruction_data(lang), + Self::UserDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + expect_error(&setup, &instruction, &accounts, error_codes::error::USER_DATA_LEN) + } + Self::TreeDuplicate => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = + accounts[AccountIndex::User as usize].clone(); + expect_error(&setup, &instruction, &accounts, error_codes::error::TREE_DUPLICATE) + } + Self::TreeDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::Tree as usize].1.data = vec![1u8; 1]; + expect_error(&setup, &instruction, &accounts, error_codes::error::TREE_DATA_LEN) + } + Self::SystemProgramDuplicate => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::SystemProgram as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::SystemProgram as usize] = + accounts[AccountIndex::User as usize].clone(); + expect_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DUPLICATE, + ) + } + Self::SystemProgramDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; + expect_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DATA_LEN, + ) + } + Self::InstructionData => { + let (setup, mut instruction, accounts) = init_setup(lang); + instruction.data = vec![1u8; 1]; + expect_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA, + ) + } } } } -fn run_init_user_data_len(lang: ProgramLanguage) -> u64 { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::USER_DATA_LEN.into(), - ))], - ) - .compute_units_consumed -} - -fn run_init_tree_duplicate(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, mut accounts) = init_setup(lang); - instruction.accounts[AccountIndex::Tree as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::Tree as usize] = accounts[AccountIndex::User as usize].clone(); - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::TREE_DUPLICATE.into(), - ))], - ) - .compute_units_consumed -} - -fn run_init_tree_data_len(lang: ProgramLanguage) -> u64 { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::Tree as usize].1.data = vec![1u8; 1]; - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::TREE_DATA_LEN.into(), - ))], - ) - .compute_units_consumed -} - -fn run_init_system_program_duplicate(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, mut accounts) = init_setup(lang); - instruction.accounts[AccountIndex::SystemProgram as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::SystemProgram as usize] = - accounts[AccountIndex::User as usize].clone(); - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::SYSTEM_PROGRAM_DUPLICATE.into(), - ))], - ) - .compute_units_consumed -} - -fn run_init_system_program_data_len(lang: ProgramLanguage) -> u64 { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::SYSTEM_PROGRAM_DATA_LEN.into(), - ))], - ) - .compute_units_consumed -} - -fn run_init_instruction_data(lang: ProgramLanguage) -> u64 { - let (setup, mut instruction, accounts) = init_setup(lang); - instruction.data = vec![1u8; 1]; - - setup - .mollusk - .process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - error_codes::error::INSTRUCTION_DATA.into(), - ))], - ) - .compute_units_consumed -} - #[test] fn test_rs_init_user_data_len() { - run_init_user_data_len(ProgramLanguage::Rust); + InitCase::UserDataLen.run(ProgramLanguage::Rust); } #[test] fn test_rs_init_tree_duplicate() { - run_init_tree_duplicate(ProgramLanguage::Rust); + InitCase::TreeDuplicate.run(ProgramLanguage::Rust); } #[test] fn test_rs_init_tree_data_len() { - run_init_tree_data_len(ProgramLanguage::Rust); + InitCase::TreeDataLen.run(ProgramLanguage::Rust); } #[test] fn test_rs_init_system_program_duplicate() { - run_init_system_program_duplicate(ProgramLanguage::Rust); + InitCase::SystemProgramDuplicate.run(ProgramLanguage::Rust); } #[test] fn test_rs_init_system_program_data_len() { - run_init_system_program_data_len(ProgramLanguage::Rust); + InitCase::SystemProgramDataLen.run(ProgramLanguage::Rust); } #[test] fn test_rs_init_instruction_data() { - run_init_instruction_data(ProgramLanguage::Rust); + InitCase::InstructionData.run(ProgramLanguage::Rust); } #[test] fn test_asm_init_user_data_len() { - run_init_user_data_len(ProgramLanguage::Assembly); + InitCase::UserDataLen.run(ProgramLanguage::Assembly); } #[test] fn test_asm_init_tree_duplicate() { - run_init_tree_duplicate(ProgramLanguage::Assembly); + InitCase::TreeDuplicate.run(ProgramLanguage::Assembly); } #[test] fn test_asm_init_tree_data_len() { - run_init_tree_data_len(ProgramLanguage::Assembly); + InitCase::TreeDataLen.run(ProgramLanguage::Assembly); } #[test] fn test_asm_init_system_program_duplicate() { - run_init_system_program_duplicate(ProgramLanguage::Assembly); + InitCase::SystemProgramDuplicate.run(ProgramLanguage::Assembly); } #[test] fn test_asm_init_system_program_data_len() { - run_init_system_program_data_len(ProgramLanguage::Assembly); + InitCase::SystemProgramDataLen.run(ProgramLanguage::Assembly); } #[test] fn test_asm_init_instruction_data() { - run_init_instruction_data(ProgramLanguage::Assembly); + InitCase::InstructionData.run(ProgramLanguage::Assembly); } #[test] fn test_initialize_input_checks() { - println!("\n| Init Case | Rust (CUs) |"); - println!("|-----------|------------|"); - - for case in InitCase::CASES { - let rs_cu = case.run(ProgramLanguage::Rust); - println!("| {} | {} |", case.name(), rs_cu); - } + print_comparison_table(InitCase::CASES); } From 99aa22bada8fb2202eb3615babd107dac0f163b9 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:10:34 -0800 Subject: [PATCH 058/263] Update test harnessing --- examples/tree/src/tests.rs | 330 -------------------------- examples/tree/src/tests/entrypoint.rs | 56 +++++ examples/tree/src/tests/init.rs | 145 +++++++++++ examples/tree/src/tests/mod.rs | 87 +++++++ 4 files changed, 288 insertions(+), 330 deletions(-) delete mode 100644 examples/tree/src/tests.rs create mode 100644 examples/tree/src/tests/entrypoint.rs create mode 100644 examples/tree/src/tests/init.rs create mode 100644 examples/tree/src/tests/mod.rs diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs deleted file mode 100644 index faf166f6..00000000 --- a/examples/tree/src/tests.rs +++ /dev/null @@ -1,330 +0,0 @@ -use interface::error_codes; -use mollusk_svm::program; -use mollusk_svm::result::Check; -use solana_sdk::account::Account; -use solana_sdk::instruction::{AccountMeta, Instruction}; -use solana_sdk::program_error::ProgramError; -use solana_sdk::pubkey::Pubkey; -use std::vec; -use test_utils::{setup_test, ProgramLanguage, TestSetup}; - -enum AccountIndex { - User = 0, - Tree = 1, - SystemProgram = 2, -} - -fn expect_error( - setup: &TestSetup, - instruction: &Instruction, - accounts: &[(Pubkey, Account)], - error_code: error_codes::error, -) -> u64 { - setup - .mollusk - .process_and_validate_instruction( - instruction, - accounts, - &[Check::err(ProgramError::Custom(error_code.into()))], - ) - .compute_units_consumed -} - -trait TestCase: Copy { - fn name(&self) -> &'static str; - fn run(&self, lang: ProgramLanguage) -> u64; -} - -fn print_comparison_table(cases: &[T]) { - println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|------|-----------|------------|----------|------------|"); - - for case in cases { - let asm_cu = case.run(ProgramLanguage::Assembly); - let rs_cu = case.run(ProgramLanguage::Rust); - let overhead = rs_cu as i64 - asm_cu as i64; - let overhead_pct = if asm_cu > 0 { - (overhead as f64 / asm_cu as f64) * 100.0 - } else { - 0.0 - }; - println!( - "| {} | {} | {} | {:+} | {:+.1}% |", - case.name(), - asm_cu, - rs_cu, - overhead, - overhead_pct - ); - } -} - -#[derive(Clone, Copy)] -enum EntrypointCase { - NoAccounts, - OneAccount, - FourAccounts, -} - -impl EntrypointCase { - const CASES: &'static [Self] = &[ - Self::NoAccounts, - Self::OneAccount, - Self::FourAccounts, - ]; - - const fn n_accounts(&self) -> usize { - match self { - Self::NoAccounts => 0, - Self::OneAccount => 1, - Self::FourAccounts => 4, - } - } -} - -impl TestCase for EntrypointCase { - fn name(&self) -> &'static str { - match self { - Self::NoAccounts => "No accounts", - Self::OneAccount => "One account", - Self::FourAccounts => "Four accounts", - } - } - - fn run(&self, lang: ProgramLanguage) -> u64 { - let setup = setup_test(lang); - - let account_metas: Vec = (0..self.n_accounts()) - .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) - .collect(); - let accounts: Vec<(Pubkey, Account)> = account_metas - .iter() - .map(|meta| (meta.pubkey, Account::default())) - .collect(); - - let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); - expect_error(&setup, &instruction, &accounts, error_codes::error::N_ACCOUNTS) - } -} - -#[test] -fn test_asm_no_accounts() { - EntrypointCase::NoAccounts.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_one_account() { - EntrypointCase::OneAccount.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_four_accounts() { - EntrypointCase::FourAccounts.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_rs_no_accounts() { - EntrypointCase::NoAccounts.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_one_account() { - EntrypointCase::OneAccount.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_four_accounts() { - EntrypointCase::FourAccounts.run(ProgramLanguage::Rust); -} - -#[test] -fn test_entrypoint_branching() { - print_comparison_table(EntrypointCase::CASES); -} - -fn init_setup( - program_language: ProgramLanguage, -) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(program_language); - let (system_program_pubkey, system_program_account) = - program::keyed_account_for_system_program(); - - let user_pubkey = Pubkey::new_unique(); - let tree_pubkey = Pubkey::new_unique(); - - let instruction = Instruction::new_with_bytes( - setup.program_id, - &[], - vec![ - AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pubkey, false), - AccountMeta::new_readonly(system_program_pubkey, false), - ], - ); - - let accounts = vec![ - ( - user_pubkey, - Account::new(1_000_000, 0, &system_program_pubkey), - ), - (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), - (system_program_pubkey, system_program_account), - ]; - - (setup, instruction, accounts) -} - -#[derive(Clone, Copy)] -enum InitCase { - UserDataLen, - TreeDuplicate, - TreeDataLen, - SystemProgramDuplicate, - SystemProgramDataLen, - InstructionData, -} - -impl InitCase { - const CASES: &'static [Self] = &[ - Self::UserDataLen, - Self::TreeDuplicate, - Self::TreeDataLen, - Self::SystemProgramDuplicate, - Self::SystemProgramDataLen, - Self::InstructionData, - ]; -} - -impl TestCase for InitCase { - fn name(&self) -> &'static str { - match self { - Self::UserDataLen => "User has nonzero data length", - Self::TreeDuplicate => "Tree account is duplicate", - Self::TreeDataLen => "Tree has nonzero data length", - Self::SystemProgramDuplicate => "System program is duplicate", - Self::SystemProgramDataLen => "System program wrong data length", - Self::InstructionData => "Non-empty instruction data", - } - } - - fn run(&self, lang: ProgramLanguage) -> u64 { - match self { - Self::UserDataLen => { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; - expect_error(&setup, &instruction, &accounts, error_codes::error::USER_DATA_LEN) - } - Self::TreeDuplicate => { - let (setup, mut instruction, mut accounts) = init_setup(lang); - instruction.accounts[AccountIndex::Tree as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::Tree as usize] = - accounts[AccountIndex::User as usize].clone(); - expect_error(&setup, &instruction, &accounts, error_codes::error::TREE_DUPLICATE) - } - Self::TreeDataLen => { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::Tree as usize].1.data = vec![1u8; 1]; - expect_error(&setup, &instruction, &accounts, error_codes::error::TREE_DATA_LEN) - } - Self::SystemProgramDuplicate => { - let (setup, mut instruction, mut accounts) = init_setup(lang); - instruction.accounts[AccountIndex::SystemProgram as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::SystemProgram as usize] = - accounts[AccountIndex::User as usize].clone(); - expect_error( - &setup, - &instruction, - &accounts, - error_codes::error::SYSTEM_PROGRAM_DUPLICATE, - ) - } - Self::SystemProgramDataLen => { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; - expect_error( - &setup, - &instruction, - &accounts, - error_codes::error::SYSTEM_PROGRAM_DATA_LEN, - ) - } - Self::InstructionData => { - let (setup, mut instruction, accounts) = init_setup(lang); - instruction.data = vec![1u8; 1]; - expect_error( - &setup, - &instruction, - &accounts, - error_codes::error::INSTRUCTION_DATA, - ) - } - } - } -} - -#[test] -fn test_rs_init_user_data_len() { - InitCase::UserDataLen.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_init_tree_duplicate() { - InitCase::TreeDuplicate.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_init_tree_data_len() { - InitCase::TreeDataLen.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_init_system_program_duplicate() { - InitCase::SystemProgramDuplicate.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_init_system_program_data_len() { - InitCase::SystemProgramDataLen.run(ProgramLanguage::Rust); -} - -#[test] -fn test_rs_init_instruction_data() { - InitCase::InstructionData.run(ProgramLanguage::Rust); -} - -#[test] -fn test_asm_init_user_data_len() { - InitCase::UserDataLen.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_init_tree_duplicate() { - InitCase::TreeDuplicate.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_init_tree_data_len() { - InitCase::TreeDataLen.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_init_system_program_duplicate() { - InitCase::SystemProgramDuplicate.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_init_system_program_data_len() { - InitCase::SystemProgramDataLen.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_asm_init_instruction_data() { - InitCase::InstructionData.run(ProgramLanguage::Assembly); -} - -#[test] -fn test_initialize_input_checks() { - print_comparison_table(InitCase::CASES); -} diff --git a/examples/tree/src/tests/entrypoint.rs b/examples/tree/src/tests/entrypoint.rs new file mode 100644 index 00000000..c77e3f0e --- /dev/null +++ b/examples/tree/src/tests/entrypoint.rs @@ -0,0 +1,56 @@ +use super::*; +use solana_sdk::instruction::AccountMeta; + +#[derive(Clone, Copy)] +enum EntrypointCase { + NoAccounts, + OneAccount, + FourAccounts, +} + +impl EntrypointCase { + const CASES: &'static [Self] = &[Self::NoAccounts, Self::OneAccount, Self::FourAccounts]; + + const fn n_accounts(&self) -> usize { + match self { + Self::NoAccounts => 0, + Self::OneAccount => 1, + Self::FourAccounts => 4, + } + } +} + +impl TestCase for EntrypointCase { + fn name(&self) -> &'static str { + match self { + Self::NoAccounts => "No accounts", + Self::OneAccount => "One account", + Self::FourAccounts => "Four accounts", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + let setup = setup_test(lang); + + let account_metas: Vec = (0..self.n_accounts()) + .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) + .collect(); + let accounts: Vec<(Pubkey, Account)> = account_metas + .iter() + .map(|meta| (meta.pubkey, Account::default())) + .collect(); + + let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS, + ) + } +} + +#[test] +fn test_entrypoint_branching() { + print_comparison_table(EntrypointCase::CASES); +} diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs new file mode 100644 index 00000000..c7c51ab5 --- /dev/null +++ b/examples/tree/src/tests/init.rs @@ -0,0 +1,145 @@ +use super::*; +use mollusk_svm::program; +use solana_sdk::instruction::AccountMeta; + +fn init_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), + (system_program_pubkey, system_program_account), + ]; + + (setup, instruction, accounts) +} + +#[derive(Clone, Copy)] +enum InitCase { + UserDataLen, + TreeDuplicate, + TreeDataLen, + SystemProgramDuplicate, + SystemProgramDataLen, + InstructionData, +} + +impl InitCase { + const CASES: &'static [Self] = &[ + Self::UserDataLen, + Self::TreeDuplicate, + Self::TreeDataLen, + Self::SystemProgramDuplicate, + Self::SystemProgramDataLen, + Self::InstructionData, + ]; +} + +impl TestCase for InitCase { + fn name(&self) -> &'static str { + match self { + Self::UserDataLen => "User has nonzero data length", + Self::TreeDuplicate => "Tree account is duplicate", + Self::TreeDataLen => "Tree has nonzero data length", + Self::SystemProgramDuplicate => "System program is duplicate", + Self::SystemProgramDataLen => "System program wrong data length", + Self::InstructionData => "Non-empty instruction data", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + Self::UserDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::USER_DATA_LEN, + ) + } + Self::TreeDuplicate => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::TREE_DUPLICATE, + ) + } + Self::TreeDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::Tree as usize].1.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::TREE_DATA_LEN, + ) + } + Self::SystemProgramDuplicate => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::SystemProgram as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::SystemProgram as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DUPLICATE, + ) + } + Self::SystemProgramDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DATA_LEN, + ) + } + Self::InstructionData => { + let (setup, mut instruction, accounts) = init_setup(lang); + instruction.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA, + ) + } + } + } +} + +#[test] +fn test_initialize_input_checks() { + print_comparison_table(InitCase::CASES); +} diff --git a/examples/tree/src/tests/mod.rs b/examples/tree/src/tests/mod.rs new file mode 100644 index 00000000..c1f5405f --- /dev/null +++ b/examples/tree/src/tests/mod.rs @@ -0,0 +1,87 @@ +mod entrypoint; +mod init; + +use interface::error_codes; +use mollusk_svm::result::ProgramResult as MolluskResult; +use solana_sdk::account::Account; +use solana_sdk::instruction::Instruction; +use solana_sdk::program_error::ProgramError; +use solana_sdk::pubkey::Pubkey; +use test_utils::{setup_test, ProgramLanguage, TestSetup}; + +const USER_LAMPORTS: u64 = 1_000_000; + +enum AccountIndex { + User = 0, + Tree = 1, + SystemProgram = 2, +} + +struct CaseResult { + cu: u64, + error: Option, +} + +fn check_error( + setup: &TestSetup, + instruction: &Instruction, + accounts: &[(Pubkey, Account)], + expected_error: error_codes::error, +) -> CaseResult { + let result = setup.mollusk.process_instruction(instruction, accounts); + let expected = ProgramError::Custom(expected_error.into()); + match &result.program_result { + MolluskResult::Failure(err) if *err == expected => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), + }, + } +} + +trait TestCase: Copy { + fn name(&self) -> &'static str; + fn run(&self, lang: ProgramLanguage) -> CaseResult; +} + +fn print_comparison_table(cases: &[T]) { + let mut failures = Vec::new(); + + println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|------|-----------|------------|----------|------------|"); + + for case in cases { + let asm = case.run(ProgramLanguage::Assembly); + let rs = case.run(ProgramLanguage::Rust); + let overhead = rs.cu as i64 - asm.cu as i64; + let overhead_pct = if asm.cu > 0 { + (overhead as f64 / asm.cu as f64) * 100.0 + } else { + 0.0 + }; + println!( + "| {} | {} | {} | {:+} | {:+.1}% |", + case.name(), + asm.cu, + rs.cu, + overhead, + overhead_pct + ); + + if let Some(err) = &asm.error { + failures.push(format!(" ASM {}: {}", case.name(), err)); + } + if let Some(err) = &rs.error { + failures.push(format!(" Rust {}: {}", case.name(), err)); + } + } + + assert!( + failures.is_empty(), + "\nFailed cases:\n{}", + failures.join("\n") + ); +} From 91da722fb87be7ec4b3020d05d3a98dcd28995a4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:29:39 -0800 Subject: [PATCH 059/263] Refactor testing, include in docs --- docs/src/examples/tree.md | 22 +- examples/tree/artifacts/dumps/asm.txt | 48 +++-- examples/tree/artifacts/dumps/rs.txt | 195 ++++++++++-------- examples/tree/artifacts/rs-disassembly.s | 102 +++++---- .../snippets/rs/entrypoint-branching.txt | 2 +- .../tests/entrypoint_branching/result.txt | 100 +++++++++ .../tests/entrypoint_branching/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 121 +++++++++++ .../tests/initialize_input_checks/test.txt | 4 + examples/tree/src/{tests/mod.rs => tests.rs} | 10 + examples/tree/src/tests/entrypoint.rs | 10 +- examples/tree/src/tests/init.rs | 9 +- 12 files changed, 456 insertions(+), 171 deletions(-) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt rename examples/tree/src/{tests/mod.rs => tests.rs} (92%) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 874479c8..54f3d51f 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -9,19 +9,33 @@ This example implements a [red-black tree][wikipedia tree page] in both paths side-by-side for a comprehensive breakdown of assembly vs Rust performance. -## Input buffer checks +## Entrypoint branching ::: code-group -<<< ../../../examples/tree/artifacts/snippets/asm/check-input-buffer.txt{asm} [Assembly] +<<< ../../../examples/tree/artifacts/snippets/asm/entrypoint-branching.txt{asm} [Assembly] -<<< ../../../examples/tree/artifacts/snippets/rs/check-input-buffer.txt{rs} [Rust] +<<< ../../../examples/tree/artifacts/snippets/rs/entrypoint-branching.txt{rs} [Rust] ::: - + + +## Initialize input checks + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/initialize-input-checks.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/initialize-input-checks.txt{rs} [Rust] + +::: + + diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index cf380905..8c9ee848 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 248 (bytes into file) + Start of section headers 360 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,13 +19,13 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 3 Section header string table index 2 -There are 3 section headers, starting at offset 0xf8 +There are 3 section headers, starting at offset 0x168 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000040 000040 0000a8 00 AX 0 0 4 - [ 2] .s STRTAB 0000000000000000 0000e8 00000a 00 0 0 1 + [ 1] .text PROGBITS 0000000000000040 000040 000118 00 AX 0 0 4 + [ 2] .s STRTAB 0000000000000000 000158 00000a 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -48,22 +48,36 @@ Disassembly of section .text 0000000000000040 <.text> 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) 9 15 02 03 00 02 00 00 00 if r2 == 0x2 goto +0x3 <.text+0x28> - 10 15 03 08 00 03 00 00 00 if r3 == 0x3 goto +0x8 <.text+0x58> + 10 15 02 07 00 03 00 00 00 if r2 == 0x3 goto +0x7 <.text+0x50> 11 b7 00 00 00 01 00 00 00 r0 = 0x1 12 95 00 00 00 00 00 00 00 exit 13 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) 14 07 02 00 00 07 00 00 00 r2 += 0x7 15 57 02 00 00 f8 ff ff ff r2 &= -0x8 16 0f 12 00 00 00 00 00 00 r2 += r1 - 17 79 23 c8 50 00 00 00 00 r3 = *(u64 *)(r2 + 0x50c8) - 18 95 00 00 00 00 00 00 00 exit - 19 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 20 55 02 04 00 00 00 00 00 if r2 != 0x0 goto +0x4 <.text+0x88> - 21 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 22 55 02 04 00 ff 00 00 00 if r2 != 0xff goto +0x4 <.text+0x98> - 23 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 24 95 00 00 00 00 00 00 00 exit - 25 b7 00 00 00 02 00 00 00 r0 = 0x2 - 26 95 00 00 00 00 00 00 00 exit - 27 b7 00 00 00 03 00 00 00 r0 = 0x3 - 28 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 17 95 00 00 00 00 00 00 00 exit + 18 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 19 55 02 15 00 00 00 00 00 if r2 != 0x0 goto +0x15 <.text+0x108> + 20 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 21 55 02 11 00 ff 00 00 00 if r2 != 0xff goto +0x11 <.text+0xf8> + 22 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 23 55 02 0d 00 00 00 00 00 if r2 != 0x0 goto +0xd <.text+0xe8> + 24 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) + 25 55 02 09 00 ff 00 00 00 if r2 != 0xff goto +0x9 <.text+0xd8> + 26 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) + 27 55 02 05 00 0e 00 00 00 if r2 != 0xe goto +0x5 <.text+0xc8> + 28 79 12 38 79 00 00 00 00 r2 = *(u64 *)(r1 + 0x7938) + 29 55 02 01 00 00 00 00 00 if r2 != 0x0 goto +0x1 <.text+0xb8> + 30 95 00 00 00 00 00 00 00 exit + 31 b7 00 00 00 07 00 00 00 r0 = 0x7 + 32 95 00 00 00 00 00 00 00 exit + 33 b7 00 00 00 04 00 00 00 r0 = 0x4 + 34 95 00 00 00 00 00 00 00 exit + 35 b7 00 00 00 06 00 00 00 r0 = 0x6 + 36 95 00 00 00 00 00 00 00 exit + 37 b7 00 00 00 03 00 00 00 r0 = 0x3 + 38 95 00 00 00 00 00 00 00 exit + 39 b7 00 00 00 05 00 00 00 r0 = 0x5 + 40 95 00 00 00 00 00 00 00 exit + 41 b7 00 00 00 02 00 00 00 r0 = 0x2 + 42 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 0ed391c0..cfdd815a 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x40 Start of program headers 64 (bytes into file) - Start of section headers 3872 (bytes into file) + Start of section headers 3992 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf20 +There are 8 section headers, starting at offset 0xf98 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0002b0 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 0003d0 0000c0 00 WA 0 0 8 - [ 3] .bss.stack NOBITS 0000000200000000 000490 001000 00 WA 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000490 001000 00 WA 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000490 000468 18 7 46 8 - [ 6] .shstrtab STRTAB 0000000000000000 0008f8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000936 0005e6 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000328 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000448 0000c0 00 WA 0 0 8 + [ 3] .bss.stack NOBITS 0000000200000000 000508 001000 00 WA 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000508 001000 00 WA 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000508 000468 18 7 46 8 + [ 6] .shstrtab STRTAB 0000000000000000 000970 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0009ae 0005e6 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0002b0 0x0002b0 E 0x8 - LOAD 0x0003d0 0x0000000100000000 0x0000000100000000 0x0000c0 0x0000c0 R 0x8 - LOAD 0x000490 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000490 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000328 0x000328 E 0x8 + LOAD 0x000448 0x0000000100000000 0x0000000100000000 0x0000c0 0x0000c0 R 0x8 + LOAD 0x000508 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000508 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -74,7 +74,7 @@ Symbol table '.symtab' contains 47 entries 11 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl 12 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 13 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 - 14 0000000000000270 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt + 14 00000000000002e8 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 @@ -106,7 +106,7 @@ Symbol table '.symtab' contains 47 entries 43 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 44 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 45 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 46 0000000000000040 560 FUNC GLOBAL DEFAULT 1 entrypoint + 46 0000000000000040 680 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -125,82 +125,97 @@ Disassembly of section .text 0000000000000040 40 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 48 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 50 15 03 2f 00 02 00 00 00 jeq r3, 0x2, +0x2f - 58 b7 02 00 00 01 00 00 00 mov64 r2, 0x1 - 60 55 03 2b 00 03 00 00 00 jne r3, 0x3, +0x2b + 48 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 50 15 02 3d 00 02 00 00 00 jeq r2, 0x2, +0x3d + 58 b7 06 00 00 01 00 00 00 mov64 r6, 0x1 + 60 55 02 39 00 03 00 00 00 jne r2, 0x3, +0x39 68 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] - 70 55 02 39 00 ff 00 00 00 jne r2, 0xff, +0x39 - 78 b7 02 00 00 02 00 00 00 mov64 r2, 0x2 - 80 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 88 55 03 26 00 00 00 00 00 jne r3, 0x0, +0x26 - 90 0f 31 00 00 00 00 00 00 add64 r1, r3 + 70 55 02 41 00 ff 00 00 00 jne r2, 0xff, +0x41 + 78 b7 06 00 00 02 00 00 00 mov64 r6, 0x2 + 80 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 88 55 02 34 00 00 00 00 00 jne r2, 0x0, +0x34 + 90 0f 21 00 00 00 00 00 00 add64 r1, r2 98 07 01 00 00 6f 28 00 00 add64 r1, 0x286f a0 57 01 00 00 f8 ff ff ff and64 r1, -0x8 - a8 b7 02 00 00 03 00 00 00 mov64 r2, 0x3 - b0 2c 13 00 00 00 00 00 00 ldxb w3, [r1 + 0x0] - b8 55 03 20 00 ff 00 00 00 jne r3, 0xff, +0x20 - c0 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] - c8 bf 16 00 00 00 00 00 00 mov64 r6, r1 - d0 bf 13 00 00 00 00 00 00 mov64 r3, r1 - d8 0f 23 00 00 00 00 00 00 add64 r3, r2 - e0 07 03 00 00 67 28 00 00 add64 r3, 0x2867 - e8 57 03 00 00 f8 ff ff ff and64 r3, -0x8 - f0 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] - f8 0f 13 00 00 00 00 00 00 add64 r3, r1 - 100 07 03 00 00 08 00 00 00 add64 r3, 0x8 - 108 27 0a 0f 00 ff 00 00 00 stb [r10 + 0xf], 0xff - 110 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 118 07 04 00 00 10 00 00 00 add64 r4, 0x10 - 120 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 128 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 130 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 - 138 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 140 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 148 55 00 12 00 00 00 00 00 jne r0, 0x0, +0x12 - 150 b7 02 00 00 04 00 00 00 mov64 r2, 0x4 - 158 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] - 160 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 168 5d 13 0a 00 00 00 00 00 jne r3, r1, +0xa - 170 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 178 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 180 5d 13 07 00 00 00 00 00 jne r3, r1, +0x7 - 188 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 190 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 198 5d 13 04 00 00 00 00 00 jne r3, r1, +0x4 - 1a0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 1a8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1b0 9c 63 20 00 00 00 00 00 ldxdw r3, [r6 + 0x20] - 1b8 1d 13 03 00 00 00 00 00 jeq r3, r1, +0x3 - 1c0 bf 20 00 00 00 00 00 00 mov64 r0, r2 - 1c8 05 00 01 00 00 00 00 00 ja +0x1 - 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1d8 9d 00 00 00 00 00 00 00 return - 1e0 b4 01 00 00 68 00 00 00 mov32 w1, 0x68 - 1e8 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - 1f0 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - 1f8 b4 02 00 00 78 00 00 00 mov32 w2, 0x78 - 200 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - 208 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 - 210 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 - 218 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 - 220 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 - 228 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 230 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 238 85 10 00 00 06 00 00 00 call 0x6 - 240 b4 01 00 00 90 00 00 00 mov32 w1, 0x90 - 248 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - 250 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - 258 b4 02 00 00 a0 00 00 00 mov32 w2, 0xa0 - 260 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - 268 05 00 f3 ff 00 00 00 00 ja -0xd + a8 b7 06 00 00 05 00 00 00 mov64 r6, 0x5 + b0 2c 12 00 00 00 00 00 00 ldxb w2, [r1 + 0x0] + b8 55 02 2e 00 ff 00 00 00 jne r2, 0xff, +0x2e + c0 b7 06 00 00 03 00 00 00 mov64 r6, 0x3 + c8 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] + d0 55 02 2b 00 00 00 00 00 jne r2, 0x0, +0x2b + d8 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] + e0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + e8 0f 23 00 00 00 00 00 00 add64 r3, r2 + f0 07 03 00 00 67 28 00 00 add64 r3, 0x2867 + f8 57 03 00 00 f8 ff ff ff and64 r3, -0x8 + 100 b7 06 00 00 06 00 00 00 mov64 r6, 0x6 + 108 2c 32 00 00 00 00 00 00 ldxb w2, [r3 + 0x0] + 110 55 02 23 00 ff 00 00 00 jne r2, 0xff, +0x23 + 118 b7 06 00 00 04 00 00 00 mov64 r6, 0x4 + 120 9c 32 50 00 00 00 00 00 ldxdw r2, [r3 + 0x50] + 128 55 02 20 00 0e 00 00 00 jne r2, 0xe, +0x20 + 130 9c 32 50 00 00 00 00 00 ldxdw r2, [r3 + 0x50] + 138 0f 23 00 00 00 00 00 00 add64 r3, r2 + 140 07 03 00 00 67 28 00 00 add64 r3, 0x2867 + 148 57 03 00 00 f8 ff ff ff and64 r3, -0x8 + 150 b7 06 00 00 07 00 00 00 mov64 r6, 0x7 + 158 9c 32 00 00 00 00 00 00 ldxdw r2, [r3 + 0x0] + 160 55 02 19 00 00 00 00 00 jne r2, 0x0, +0x19 + 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 170 27 0a 0f 00 ff 00 00 00 stb [r10 + 0xf], 0xff + 178 07 03 00 00 08 00 00 00 add64 r3, 0x8 + 180 b7 06 00 00 08 00 00 00 mov64 r6, 0x8 + 188 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 190 07 04 00 00 10 00 00 00 add64 r4, 0x10 + 198 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 1a0 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 1a8 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 + 1b0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 1b8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 1c0 55 00 11 00 00 00 00 00 jne r0, 0x0, +0x11 + 1c8 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] + 1d0 9c 72 08 00 00 00 00 00 ldxdw r2, [r7 + 0x8] + 1d8 5d 12 0a 00 00 00 00 00 jne r2, r1, +0xa + 1e0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 1e8 9c 72 10 00 00 00 00 00 ldxdw r2, [r7 + 0x10] + 1f0 5d 12 07 00 00 00 00 00 jne r2, r1, +0x7 + 1f8 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 200 9c 72 18 00 00 00 00 00 ldxdw r2, [r7 + 0x18] + 208 5d 12 04 00 00 00 00 00 jne r2, r1, +0x4 + 210 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 218 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 220 9c 72 20 00 00 00 00 00 ldxdw r2, [r7 + 0x20] + 228 1d 12 03 00 00 00 00 00 jeq r2, r1, +0x3 + 230 bf 60 00 00 00 00 00 00 mov64 r0, r6 + 238 05 00 01 00 00 00 00 00 ja +0x1 + 240 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 248 9d 00 00 00 00 00 00 00 return + 250 b4 01 00 00 68 00 00 00 mov32 w1, 0x68 + 258 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + 260 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + 268 b4 02 00 00 78 00 00 00 mov32 w2, 0x78 + 270 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + 278 05 00 05 00 00 00 00 00 ja +0x5 + 280 b4 01 00 00 90 00 00 00 mov32 w1, 0x90 + 288 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 + 290 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + 298 b4 02 00 00 a0 00 00 00 mov32 w2, 0xa0 + 2a0 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 + 2a8 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 + 2b0 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 + 2b8 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 + 2c0 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 + 2c8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 2d0 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 2d8 85 10 00 00 01 00 00 00 call 0x1 + 2e0 9d 00 00 00 00 00 00 00 return -0000000000000270 - 270 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 278 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 - 280 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 - 288 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 - 290 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 298 07 01 00 00 28 00 00 00 add64 r1, 0x28 - 2a0 85 10 00 00 ab ff ff ff call -0x55 - 2a8 9d 00 00 00 00 00 00 00 return \ No newline at end of file +00000000000002e8 + 2e8 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 2f0 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 + 2f8 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 + 300 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 + 308 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 310 07 01 00 00 28 00 00 00 add64 r1, 0x28 + 318 85 10 00 00 9c ff ff ff call -0x64 + 320 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 3a565747..ea596327 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -11,31 +11,44 @@ fn_0000: entrypoint: add64 r10, -64 - ldxdw r3, [r1+0] - jeq r3, 2, jmp_01c8 - mov64 r2, 1 - jne r3, 3, jmp_01b8 + ldxdw r2, [r1+0] + jeq r2, 2, jmp_0228 + mov64 r6, 1 + jne r2, 3, jmp_0218 ldxb r2, [r1+8] - jne r2, 255, jmp_0238 - mov64 r2, 2 - ldxdw r3, [r1+88] - jne r3, 0, jmp_01b8 - add64 r1, r3 + jne r2, 255, jmp_0268 + mov64 r6, 2 + ldxdw r2, [r1+88] + jne r2, 0, jmp_0218 + add64 r1, r2 add64 r1, 10351 and64 r1, -8 - mov64 r2, 3 - ldxb r3, [r1+0] - jne r3, 255, jmp_01b8 + mov64 r6, 5 + ldxb r2, [r1+0] + jne r2, 255, jmp_0218 + mov64 r6, 3 ldxdw r2, [r1+80] - mov64 r6, r1 + jne r2, 0, jmp_0218 mov64 r3, r1 add64 r3, r2 add64 r3, 10343 and64 r3, -8 - ldxdw r1, [r3+0] - add64 r3, r1 - add64 r3, 8 + mov64 r6, 6 + ldxb r2, [r3+0] + jne r2, 255, jmp_0218 + mov64 r6, 4 + ldxdw r2, [r3+80] + jne r2, 14, jmp_0218 + add64 r3, r2 + add64 r3, 10343 + and64 r3, -8 + mov64 r6, 7 + ldxdw r2, [r3+0] + jne r2, 0, jmp_0218 + mov64 r7, r1 stb [r10+15], 255 + add64 r3, 8 + mov64 r6, 8 mov64 r4, r10 add64 r4, 16 mov64 r5, r10 @@ -43,57 +56,56 @@ entrypoint: mov64 r1, 8 mov64 r2, 0 call sol_try_find_program_address - jne r0, 0, jmp_01d8 - mov64 r2, 4 + jne r0, 0, jmp_0238 ldxdw r1, [r10+16] - ldxdw r3, [r6+8] - jne r3, r1, jmp_01b8 + ldxdw r2, [r7+8] + jne r2, r1, jmp_0218 ldxdw r1, [r10+24] - ldxdw r3, [r6+16] - jne r3, r1, jmp_01b8 + ldxdw r2, [r7+16] + jne r2, r1, jmp_0218 ldxdw r1, [r10+32] - ldxdw r3, [r6+24] - jne r3, r1, jmp_01b8 + ldxdw r2, [r7+24] + jne r2, r1, jmp_0218 ldxdw r1, [r10+40] mov64 r0, 0 - ldxdw r3, [r6+32] - jeq r3, r1, jmp_01d0 + ldxdw r2, [r7+32] + jeq r2, r1, jmp_0230 -jmp_01b8: - mov64 r0, r2 - ja jmp_01d0 +jmp_0218: + mov64 r0, r6 + ja jmp_0230 -jmp_01c8: +jmp_0228: mov64 r0, 0 -jmp_01d0: +jmp_0230: exit -jmp_01d8: - mov32 r1, 1072 +jmp_0238: + mov32 r1, 1168 hor64 r1, 0 stxdw [r10+16], r1 - mov32 r2, 1088 + mov32 r2, 1184 hor64 r2, 0 + ja jmp_0290 -jmp_0200: +jmp_0268: + mov32 r1, 1208 + hor64 r1, 0 + stxdw [r10+16], r1 + mov32 r2, 1224 + hor64 r2, 0 + +jmp_0290: stdw [r10+48], 0 stdw [r10+24], 1 stdw [r10+40], 0 stdw [r10+32], 8 mov64 r1, r10 add64 r1, 16 - call fn_0268 - -jmp_0238: - mov32 r1, 1112 - hor64 r1, 0 - stxdw [r10+16], r1 - mov32 r2, 1128 - hor64 r2, 0 - ja jmp_0200 + call fn_02c8 -fn_0268: +fn_02c8: add64 r10, -64 stxdw [r10+48], r2 stxdw [r10+40], r1 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 5e2a7d68..ad980494 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -5,7 +5,7 @@ lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => initialize(context), + input_buffer::N_ACCOUNTS_INIT => Ok(()), _ => err(error::N_ACCOUNTS), } } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..62d97a94 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,100 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 8 | +3 | +60.0% | +| One account | 5 | 8 | +3 | +60.0% | +| Four accounts | 5 | 8 | +3 | +60.0% | +test tests::test_entrypoint_branching ... ok +warning: constant `CPI_N_ACCOUNTS` is never used + --> tree/interface/src/asm.rs:88:7 + | +88 | const CPI_N_ACCOUNTS: usize = 2; + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: constant `CPI_N_PDA_SIGNERS` is never used + --> tree/interface/src/asm.rs:90:7 + | +90 | const CPI_N_PDA_SIGNERS: usize = 1; + | ^^^^^^^^^^^^^^^^^ +warning: constant `CPI_N_SEEDS` is never used + --> tree/interface/src/asm.rs:92:7 + | +92 | const CPI_N_SEEDS: usize = 1; + | ^^^^^^^^^^^ +warning: struct `InitStackFrame` is never constructed + --> tree/interface/src/asm.rs:95:8 + | +95 | struct InitStackFrame { + | ^^^^^^^^^^^^^^ +warning: struct `SolInstruction` is never constructed + --> tree/interface/src/bindings.rs:7:12 + | +7 | pub struct SolInstruction { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountMeta` is never constructed + --> tree/interface/src/bindings.rs:23:12 + | +23 | pub struct SolAccountMeta { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountInfo` is never constructed + --> tree/interface/src/bindings.rs:35:12 + | +35 | pub struct SolAccountInfo { + | ^^^^^^^^^^^^^^ +warning: struct `SolSignerSeed` is never constructed + --> tree/interface/src/bindings.rs:59:12 + | +59 | pub struct SolSignerSeed { + | ^^^^^^^^^^^^^ +warning: struct `SolSignerSeeds` is never constructed + --> tree/interface/src/bindings.rs:69:12 + | +69 | pub struct SolSignerSeeds { + | ^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: struct `CreateAccountInstructionData` is never constructed + --> tree/interface/src/common.rs:46:12 + | +46 | pub struct CreateAccountInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `interface` (lib) generated 11 warnings +warning: `interface` (lib) generated 11 warnings (11 duplicates) +warning: variable does not need to be mutable + --> tree/src/program.rs:48:28 + | +48 | pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { + | ----^^^^^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default +warning: unused variable: `bump` + --> tree/src/program.rs:90:24 + | +90 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 2 warnings (run `cargo fix --lib -p tree --tests` to apply 1 suggestion) +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/test.txt b/examples/tree/artifacts/tests/entrypoint_branching/test.txt new file mode 100644 index 00000000..6c056146 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_entrypoint_branching() { + print_comparison_table(entrypoint::EntrypointCase::CASES); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..2d4d89a3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,121 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 13 | +6 | +85.7% | +| Tree account is duplicate | 9 | 19 | +10 | +111.1% | +| Tree has nonzero data length | 11 | 22 | +11 | +100.0% | +| System program is duplicate | 13 | 30 | +17 | +130.8% | +| System program wrong data length | 15 | 33 | +18 | +120.0% | +| Non-empty instruction data | 17 | 40 | +23 | +135.3% | +test tests::test_initialize_input_checks ... ok +warning: constant `CPI_N_ACCOUNTS` is never used + --> tree/interface/src/asm.rs:88:7 + | +88 | const CPI_N_ACCOUNTS: usize = 2; + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: constant `CPI_N_PDA_SIGNERS` is never used + --> tree/interface/src/asm.rs:90:7 + | +90 | const CPI_N_PDA_SIGNERS: usize = 1; + | ^^^^^^^^^^^^^^^^^ +warning: constant `CPI_N_SEEDS` is never used + --> tree/interface/src/asm.rs:92:7 + | +92 | const CPI_N_SEEDS: usize = 1; + | ^^^^^^^^^^^ +warning: struct `InitStackFrame` is never constructed + --> tree/interface/src/asm.rs:95:8 + | +95 | struct InitStackFrame { + | ^^^^^^^^^^^^^^ +warning: struct `SolInstruction` is never constructed + --> tree/interface/src/bindings.rs:7:12 + | +7 | pub struct SolInstruction { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountMeta` is never constructed + --> tree/interface/src/bindings.rs:23:12 + | +23 | pub struct SolAccountMeta { + | ^^^^^^^^^^^^^^ +warning: struct `SolAccountInfo` is never constructed + --> tree/interface/src/bindings.rs:35:12 + | +35 | pub struct SolAccountInfo { + | ^^^^^^^^^^^^^^ +warning: struct `SolSignerSeed` is never constructed + --> tree/interface/src/bindings.rs:59:12 + | +59 | pub struct SolSignerSeed { + | ^^^^^^^^^^^^^ +warning: struct `SolSignerSeeds` is never constructed + --> tree/interface/src/bindings.rs:69:12 + | +69 | pub struct SolSignerSeeds { + | ^^^^^^^^^^^^^^ +warning: struct `Return` is never constructed + --> tree/interface/src/common.rs:37:8 + | +37 | struct Return { + | ^^^^^^ +warning: struct `CreateAccountInstructionData` is never constructed + --> tree/interface/src/common.rs:46:12 + | +46 | pub struct CreateAccountInstructionData { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `interface` (lib) generated 11 warnings +warning: `interface` (lib) generated 11 warnings (11 duplicates) +warning: variable does not need to be mutable + --> tree/src/program.rs:48:28 + | +48 | pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { + | ----^^^^^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default +warning: unused variable: `bump` + --> tree/src/program.rs:90:24 + | +90 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 2 warnings (run `cargo fix --lib -p tree --tests` to apply 1 suggestion) +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..d179220a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES); +} \ No newline at end of file diff --git a/examples/tree/src/tests/mod.rs b/examples/tree/src/tests.rs similarity index 92% rename from examples/tree/src/tests/mod.rs rename to examples/tree/src/tests.rs index c1f5405f..8cd1e665 100644 --- a/examples/tree/src/tests/mod.rs +++ b/examples/tree/src/tests.rs @@ -85,3 +85,13 @@ fn print_comparison_table(cases: &[T]) { failures.join("\n") ); } + +#[test] +fn test_entrypoint_branching() { + print_comparison_table(entrypoint::EntrypointCase::CASES); +} + +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES); +} diff --git a/examples/tree/src/tests/entrypoint.rs b/examples/tree/src/tests/entrypoint.rs index c77e3f0e..b2f5425f 100644 --- a/examples/tree/src/tests/entrypoint.rs +++ b/examples/tree/src/tests/entrypoint.rs @@ -2,14 +2,15 @@ use super::*; use solana_sdk::instruction::AccountMeta; #[derive(Clone, Copy)] -enum EntrypointCase { +pub(super) enum EntrypointCase { NoAccounts, OneAccount, FourAccounts, } impl EntrypointCase { - const CASES: &'static [Self] = &[Self::NoAccounts, Self::OneAccount, Self::FourAccounts]; + pub(super) const CASES: &'static [Self] = + &[Self::NoAccounts, Self::OneAccount, Self::FourAccounts]; const fn n_accounts(&self) -> usize { match self { @@ -49,8 +50,3 @@ impl TestCase for EntrypointCase { ) } } - -#[test] -fn test_entrypoint_branching() { - print_comparison_table(EntrypointCase::CASES); -} diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index c7c51ab5..809e816c 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -35,7 +35,7 @@ fn init_setup( } #[derive(Clone, Copy)] -enum InitCase { +pub(super) enum InitCase { UserDataLen, TreeDuplicate, TreeDataLen, @@ -45,7 +45,7 @@ enum InitCase { } impl InitCase { - const CASES: &'static [Self] = &[ + pub(super) const CASES: &'static [Self] = &[ Self::UserDataLen, Self::TreeDuplicate, Self::TreeDataLen, @@ -138,8 +138,3 @@ impl TestCase for InitCase { } } } - -#[test] -fn test_initialize_input_checks() { - print_comparison_table(InitCase::CASES); -} From 2b24bb7a1e399e12e7417396cf31aa1a297e5b22 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:30:46 -0800 Subject: [PATCH 060/263] Regen snippet --- examples/tree/artifacts/snippets/rs/entrypoint-branching.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index ad980494..5e2a7d68 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -5,7 +5,7 @@ lazy_program_entrypoint!(process_instruction); pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { match context.remaining() { input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => Ok(()), + input_buffer::N_ACCOUNTS_INIT => initialize(context), _ => err(error::N_ACCOUNTS), } } \ No newline at end of file From ffdc578385d81bd102f1f1e60ebf83e7d3f37798 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:54:11 -0800 Subject: [PATCH 061/263] Begin extern refactor --- examples/tree/artifacts/dumps/rs.txt | 220 +++++------------- examples/tree/artifacts/rs-disassembly.s | 113 --------- .../snippets/rs/entrypoint-branching.txt | 19 +- examples/tree/interface/src/asm.rs | 69 +----- examples/tree/interface/src/common.rs | 52 ++++- examples/tree/macros/src/lib.rs | 160 +++++++++---- examples/tree/src/program.rs | 24 +- 7 files changed, 260 insertions(+), 397 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index cfdd815a..6d08c3ad 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -9,9 +9,9 @@ ELF Header Type DYN (Shared object file) Machine Solana Bytecode Format Version 0x1 - Entry point address 0x40 + Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3992 (bytes into file) + Start of section headers 2600 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf98 +There are 8 section headers, starting at offset 0xa28 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000328 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000448 0000c0 00 WA 0 0 8 - [ 3] .bss.stack NOBITS 0000000200000000 000508 001000 00 WA 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000508 001000 00 WA 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000508 000468 18 7 46 8 - [ 6] .shstrtab STRTAB 0000000000000000 000970 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0009ae 0005e6 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000018 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000138 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000140 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000140 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000140 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0004b8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0004f6 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -38,15 +38,15 @@ Key to Flags R (retain), p (processor specific) Elf file type is DYN (Shared object file) -Entry point 0x40 +Entry point 0x0 There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000328 0x000328 E 0x8 - LOAD 0x000448 0x0000000100000000 0x0000000100000000 0x0000c0 0x0000c0 R 0x8 - LOAD 0x000508 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000508 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000018 0x000018 E 0x8 + LOAD 0x000138 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000140 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000140 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -58,164 +58,52 @@ Program Headers There are no relocations in this file. -Symbol table '.symtab' contains 47 entries +Symbol table '.symtab' contains 37 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 - 2 0000000100000068 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_3 - 3 0000000100000078 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_4 - 4 0000000100000090 16 OBJECT LOCAL DEFAULT 2 .L__unnamed_5 - 5 00000001000000a0 24 OBJECT LOCAL DEFAULT 2 .L__unnamed_6 - 6 0000000100000000 49 OBJECT LOCAL DEFAULT 2 .L__unnamed_7 - 7 0000000100000031 15 OBJECT LOCAL DEFAULT 2 .L__unnamed_8 - 8 0000000100000040 18 OBJECT LOCAL DEFAULT 2 .L__unnamed_11 - 9 0000000100000052 22 OBJECT LOCAL DEFAULT 2 .L__unnamed_12 - 10 0000000000000000 64 FUNC LOCAL HIDDEN 1 rust_begin_unwind - 11 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl - 12 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 - 13 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 - 14 00000000000002e8 64 FUNC LOCAL HIDDEN 1 core::panicking::panic_fmt - 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 - 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 - 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 - 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 - 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 - 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 - 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 - 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 - 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 - 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 - 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 - 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 - 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 - 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 - 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 - 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 - 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 - 32 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 - 33 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 - 34 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 - 35 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 - 36 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 - 37 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 - 38 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 - 39 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 - 40 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 - 41 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 - 42 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start - 43 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end - 44 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start - 45 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 46 0000000000000040 680 FUNC GLOBAL DEFAULT 1 entrypoint + 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl + 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 + 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 + 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 + 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 + 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 + 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 + 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 + 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 + 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 + 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 + 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 + 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 + 32 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start + 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end + 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start + 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end + 36 0000000000000000 24 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf Disassembly of section .text -0000000000000000 +0000000000000000 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - 8 9c 13 08 00 00 00 00 00 ldxdw r3, [r1 + 0x8] - 10 8c 34 14 00 00 00 00 00 ldxw w4, [r3 + 0x14] - 18 9c 32 08 00 00 00 00 00 ldxdw r2, [r3 + 0x8] - 20 9c 31 00 00 00 00 00 00 ldxdw r1, [r3 + 0x0] - 28 8c 33 10 00 00 00 00 00 ldxw w3, [r3 + 0x10] - 30 95 00 00 00 bb 93 60 68 syscall 0x686093bb - 38 9d 00 00 00 00 00 00 00 return - -0000000000000040 - 40 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 48 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 50 15 02 3d 00 02 00 00 00 jeq r2, 0x2, +0x3d - 58 b7 06 00 00 01 00 00 00 mov64 r6, 0x1 - 60 55 02 39 00 03 00 00 00 jne r2, 0x3, +0x39 - 68 2c 12 08 00 00 00 00 00 ldxb w2, [r1 + 0x8] - 70 55 02 41 00 ff 00 00 00 jne r2, 0xff, +0x41 - 78 b7 06 00 00 02 00 00 00 mov64 r6, 0x2 - 80 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 88 55 02 34 00 00 00 00 00 jne r2, 0x0, +0x34 - 90 0f 21 00 00 00 00 00 00 add64 r1, r2 - 98 07 01 00 00 6f 28 00 00 add64 r1, 0x286f - a0 57 01 00 00 f8 ff ff ff and64 r1, -0x8 - a8 b7 06 00 00 05 00 00 00 mov64 r6, 0x5 - b0 2c 12 00 00 00 00 00 00 ldxb w2, [r1 + 0x0] - b8 55 02 2e 00 ff 00 00 00 jne r2, 0xff, +0x2e - c0 b7 06 00 00 03 00 00 00 mov64 r6, 0x3 - c8 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] - d0 55 02 2b 00 00 00 00 00 jne r2, 0x0, +0x2b - d8 9c 12 50 00 00 00 00 00 ldxdw r2, [r1 + 0x50] - e0 bf 13 00 00 00 00 00 00 mov64 r3, r1 - e8 0f 23 00 00 00 00 00 00 add64 r3, r2 - f0 07 03 00 00 67 28 00 00 add64 r3, 0x2867 - f8 57 03 00 00 f8 ff ff ff and64 r3, -0x8 - 100 b7 06 00 00 06 00 00 00 mov64 r6, 0x6 - 108 2c 32 00 00 00 00 00 00 ldxb w2, [r3 + 0x0] - 110 55 02 23 00 ff 00 00 00 jne r2, 0xff, +0x23 - 118 b7 06 00 00 04 00 00 00 mov64 r6, 0x4 - 120 9c 32 50 00 00 00 00 00 ldxdw r2, [r3 + 0x50] - 128 55 02 20 00 0e 00 00 00 jne r2, 0xe, +0x20 - 130 9c 32 50 00 00 00 00 00 ldxdw r2, [r3 + 0x50] - 138 0f 23 00 00 00 00 00 00 add64 r3, r2 - 140 07 03 00 00 67 28 00 00 add64 r3, 0x2867 - 148 57 03 00 00 f8 ff ff ff and64 r3, -0x8 - 150 b7 06 00 00 07 00 00 00 mov64 r6, 0x7 - 158 9c 32 00 00 00 00 00 00 ldxdw r2, [r3 + 0x0] - 160 55 02 19 00 00 00 00 00 jne r2, 0x0, +0x19 - 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 170 27 0a 0f 00 ff 00 00 00 stb [r10 + 0xf], 0xff - 178 07 03 00 00 08 00 00 00 add64 r3, 0x8 - 180 b7 06 00 00 08 00 00 00 mov64 r6, 0x8 - 188 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 190 07 04 00 00 10 00 00 00 add64 r4, 0x10 - 198 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 1a0 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 1a8 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 - 1b0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 1b8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 1c0 55 00 11 00 00 00 00 00 jne r0, 0x0, +0x11 - 1c8 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] - 1d0 9c 72 08 00 00 00 00 00 ldxdw r2, [r7 + 0x8] - 1d8 5d 12 0a 00 00 00 00 00 jne r2, r1, +0xa - 1e0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 1e8 9c 72 10 00 00 00 00 00 ldxdw r2, [r7 + 0x10] - 1f0 5d 12 07 00 00 00 00 00 jne r2, r1, +0x7 - 1f8 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 200 9c 72 18 00 00 00 00 00 ldxdw r2, [r7 + 0x18] - 208 5d 12 04 00 00 00 00 00 jne r2, r1, +0x4 - 210 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 218 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 220 9c 72 20 00 00 00 00 00 ldxdw r2, [r7 + 0x20] - 228 1d 12 03 00 00 00 00 00 jeq r2, r1, +0x3 - 230 bf 60 00 00 00 00 00 00 mov64 r0, r6 - 238 05 00 01 00 00 00 00 00 ja +0x1 - 240 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 248 9d 00 00 00 00 00 00 00 return - 250 b4 01 00 00 68 00 00 00 mov32 w1, 0x68 - 258 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - 260 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - 268 b4 02 00 00 78 00 00 00 mov32 w2, 0x78 - 270 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - 278 05 00 05 00 00 00 00 00 ja +0x5 - 280 b4 01 00 00 90 00 00 00 mov32 w1, 0x90 - 288 f7 01 00 00 01 00 00 00 hor64 r1, 0x1 - 290 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - 298 b4 02 00 00 a0 00 00 00 mov32 w2, 0xa0 - 2a0 f7 02 00 00 01 00 00 00 hor64 r2, 0x1 - 2a8 97 0a 30 00 00 00 00 00 stdw [r10 + 0x30], 0x0 - 2b0 97 0a 18 00 01 00 00 00 stdw [r10 + 0x18], 0x1 - 2b8 97 0a 28 00 00 00 00 00 stdw [r10 + 0x28], 0x0 - 2c0 97 0a 20 00 08 00 00 00 stdw [r10 + 0x20], 0x8 - 2c8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 2d0 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 2d8 85 10 00 00 01 00 00 00 call 0x1 - 2e0 9d 00 00 00 00 00 00 00 return - -00000000000002e8 - 2e8 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 2f0 9f 2a 30 00 00 00 00 00 stxdw [r10 + 0x30], r2 - 2f8 9f 1a 28 00 00 00 00 00 stxdw [r10 + 0x28], r1 - 300 37 0a 38 00 01 00 00 00 sth [r10 + 0x38], 0x1 - 308 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 310 07 01 00 00 28 00 00 00 add64 r1, 0x28 - 318 85 10 00 00 9c ff ff ff call -0x64 - 320 9d 00 00 00 00 00 00 00 return \ No newline at end of file + 8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 10 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index ea596327..50457dc6 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,118 +1,5 @@ .globl entrypoint -fn_0000: - ldxdw r2, [r1+8] - ldxw r4, [r2+20] - ldxw r3, [r2+16] - ldxdw r1, [r2+0] - ldxdw r2, [r2+8] - add64 r2, -1 - call sol_panic_ - entrypoint: - add64 r10, -64 - ldxdw r2, [r1+0] - jeq r2, 2, jmp_0228 - mov64 r6, 1 - jne r2, 3, jmp_0218 - ldxb r2, [r1+8] - jne r2, 255, jmp_0268 - mov64 r6, 2 - ldxdw r2, [r1+88] - jne r2, 0, jmp_0218 - add64 r1, r2 - add64 r1, 10351 - and64 r1, -8 - mov64 r6, 5 - ldxb r2, [r1+0] - jne r2, 255, jmp_0218 - mov64 r6, 3 - ldxdw r2, [r1+80] - jne r2, 0, jmp_0218 - mov64 r3, r1 - add64 r3, r2 - add64 r3, 10343 - and64 r3, -8 - mov64 r6, 6 - ldxb r2, [r3+0] - jne r2, 255, jmp_0218 - mov64 r6, 4 - ldxdw r2, [r3+80] - jne r2, 14, jmp_0218 - add64 r3, r2 - add64 r3, 10343 - and64 r3, -8 - mov64 r6, 7 - ldxdw r2, [r3+0] - jne r2, 0, jmp_0218 - mov64 r7, r1 - stb [r10+15], 255 - add64 r3, 8 - mov64 r6, 8 - mov64 r4, r10 - add64 r4, 16 - mov64 r5, r10 - add64 r5, 15 - mov64 r1, 8 - mov64 r2, 0 - call sol_try_find_program_address - jne r0, 0, jmp_0238 - ldxdw r1, [r10+16] - ldxdw r2, [r7+8] - jne r2, r1, jmp_0218 - ldxdw r1, [r10+24] - ldxdw r2, [r7+16] - jne r2, r1, jmp_0218 - ldxdw r1, [r10+32] - ldxdw r2, [r7+24] - jne r2, r1, jmp_0218 - ldxdw r1, [r10+40] mov64 r0, 0 - ldxdw r2, [r7+32] - jeq r2, r1, jmp_0230 - -jmp_0218: - mov64 r0, r6 - ja jmp_0230 - -jmp_0228: - mov64 r0, 0 - -jmp_0230: exit - -jmp_0238: - mov32 r1, 1168 - hor64 r1, 0 - stxdw [r10+16], r1 - mov32 r2, 1184 - hor64 r2, 0 - ja jmp_0290 - -jmp_0268: - mov32 r1, 1208 - hor64 r1, 0 - stxdw [r10+16], r1 - mov32 r2, 1224 - hor64 r2, 0 - -jmp_0290: - stdw [r10+48], 0 - stdw [r10+24], 1 - stdw [r10+40], 0 - stdw [r10+32], 8 - mov64 r1, r10 - add64 r1, 16 - call fn_02c8 - -fn_02c8: - add64 r10, -64 - stxdw [r10+48], r2 - stxdw [r10+40], r1 - sth [r10+56], 1 - mov64 r1, r10 - add64 r1, 40 - call fn_0000 - -.rodata - data_0000: .byte 0x55, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x76, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, 0x75, 0x6d, 0x70, 0x20, 0x73, 0x65, 0x65, 0x64, 0x73, 0x72, 0x63, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2f, 0x6c, 0x61, 0x7a, 0x79, 0x2e, 0x72, 0x73, 0x00, 0x73, 0x72, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x2e, 0x72, 0x73, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 5e2a7d68..fe85aed2 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -1,11 +1,14 @@ -nostd_panic_handler!(); no_allocator!(); -lazy_program_entrypoint!(process_instruction); - -pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - match context.remaining() { - input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => initialize(context), - _ => err(error::N_ACCOUNTS), +nostd_panic_handler!(); +#[no_mangle] +pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { + match process_instruction(input) { + Ok(_) => SUCCESS, + Err(error) => error.into(), } +} + +#[inline(always)] +pub fn process_instruction(input: *mut u8) -> ProgramResult { + Ok(()) } \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 25eb19f0..379fc290 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,20 +1,12 @@ extern crate alloc; use crate::bindings; -use crate::common; -use crate::common::CreateAccountInstructionData; -use macros::{asm_constant_group, extend_constant_group}; -use pinocchio::{ - account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, - entrypoint::NON_DUP_MARKER, - sysvars::rent::Rent, - Address, -}; +use crate::common::{CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; +use macros::extend_constant_group; +use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; extend_constant_group!(input_buffer { prefix = "IB", - /// Number of accounts field. - offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User address field. offset!(USER_ADDRESS, InputBufferHeader.user.header.address), /// User data length field. @@ -35,54 +27,13 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), }); -asm_constant_group! { - /// Miscellaneous constants. - misc { - /// Data length of zero. - DATA_LEN_ZERO = 0, - /// And mask for data length alignment. - DATA_LEN_AND_MASK = -8, - /// Maximum possible data length padding. - MAX_DATA_PAD = 7, - } -} - -/// Compute the data buffer size for a runtime account with the given data length. -const fn runtime_data_size(data_len: i64) -> usize { - MAX_PERMITTED_DATA_INCREASE - + (((data_len + misc::MAX_DATA_PAD) & misc::DATA_LEN_AND_MASK) as usize) -} - -#[repr(C)] -struct RuntimeAccount { - header: RuntimeAccountHeader, - data: [u8; DATA_SIZE], - rent_epoch: u64, -} - -type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO) }>; -type SystemProgramRuntimeAccount = - RuntimeAccount<{ runtime_data_size(common::input_buffer::SYSTEM_PROGRAM_DATA_LEN as i64) }>; - -#[repr(C, packed)] -/// Input buffer header for all instructions. -struct InputBufferHeader { - n_accounts: u64, - user: EmptyRuntimeAccount, - tree_header: RuntimeAccountHeader, -} - -#[repr(C, packed)] -/// Input buffer for tree initialization instruction. -struct InitInputBuffer { - n_accounts: u64, - user: EmptyRuntimeAccount, - tree: EmptyRuntimeAccount, - system_program: SystemProgramRuntimeAccount, - /// No actual instruction data follows. - instruction_data_len: u64, - program_id: Address, -} +extend_constant_group!(misc { + prefix = "MISC", + /// And mask for data length alignment. + DATA_LEN_AND_MASK = -8, + /// Maximum possible data length padding. + MAX_DATA_PAD = 7, +}); /// User and tree accounts must sign CPI. const CPI_N_ACCOUNTS: usize = 2; diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 838634e4..4e857633 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,5 +1,8 @@ use macros::{constant_group, error_codes}; -use pinocchio::Address; +use pinocchio::{ + account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, + Address, +}; error_codes! { /// An invalid number of accounts were passed. @@ -23,6 +26,8 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { + /// Number of accounts field. + offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. @@ -32,6 +37,14 @@ constant_group! { } } +constant_group! { + /// Miscellaneous constants. + misc { + /// Data length of zero. + DATA_LEN_ZERO: usize = 0, + } +} + /// Value in r0. #[repr(C, packed)] struct Return { @@ -49,3 +62,40 @@ pub struct CreateAccountInstructionData { space: u64, owner: Address, } + +#[repr(C, packed)] +/// Input buffer header for all instructions. +pub struct InputBufferHeader { + pub n_accounts: u64, + pub user: EmptyRuntimeAccount, + pub tree_header: RuntimeAccountHeader, +} + +#[repr(C, packed)] +/// Input buffer for tree initialization instruction. +pub struct InitInputBuffer { + pub n_accounts: u64, + pub user: EmptyRuntimeAccount, + pub tree: EmptyRuntimeAccount, + pub system_program: SystemProgramRuntimeAccount, + /// No actual instruction data follows. + pub instruction_data_len: u64, + pub program_id: Address, +} + +#[repr(C)] +struct RuntimeAccount { + pub header: RuntimeAccountHeader, + pub data: [u8; DATA_SIZE], + pub rent_epoch: u64, +} + +type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO) }>; +type SystemProgramRuntimeAccount = + RuntimeAccount<{ runtime_data_size(input_buffer::SYSTEM_PROGRAM_DATA_LEN) }>; + +/// Compute the data buffer size for a runtime account with the given data length. +const fn runtime_data_size(data_len: usize) -> usize { + MAX_PERMITTED_DATA_INCREASE + + (((data_len + misc::MAX_DATA_PAD) & misc::DATA_LEN_AND_MASK) as usize) +} diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 05b7b42f..2871abe0 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -171,13 +171,26 @@ fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { } } +enum ConstantKind { + /// Regular constant with explicit type and value. + Value { + ty: syn::Type, + value: syn::Expr, + /// Original literal string for ASM output (preserves hex/binary). + literal_repr: Option, + }, + /// Offset derived from struct field path (i16 validated). + /// Name gets `_OFF` suffix appended. + Offset { + struct_name: Ident, + field_path: Vec, + }, +} + struct ConstantDef { doc: String, name: Ident, - ty: syn::Type, - value: syn::Expr, - /// Original literal string for ASM output (preserves hex/binary). - literal_repr: Option, + kind: ConstantKind, } struct ConstantGroup { @@ -217,10 +230,35 @@ impl Parse for ConstantGroup { return Err(content.error(e)); } - let const_name: Ident = content.parse()?; + let ident: Ident = content.parse()?; - // Support both `NAME: type = value` and `NAME = expr` forms. - let (const_ty, const_value, literal_repr) = if content.peek(Token![:]) { + // Support `offset!(NAME, Struct.field)`, `NAME: type = value`, + // and `NAME = expr as Type` forms. + let (const_name, kind) = if ident == "offset" { + // offset!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + ( + full_name, + ConstantKind::Offset { + struct_name, + field_path, + }, + ) + } else if content.peek(Token![:]) { // NAME: type = value content.parse::()?; let ty: syn::Type = content.parse()?; @@ -235,10 +273,24 @@ impl Parse for ConstantGroup { attrs: vec![], lit: Lit::Int(lit), }); - (ty, expr, Some(repr)) + ( + ident, + ConstantKind::Value { + ty, + value: expr, + literal_repr: Some(repr), + }, + ) } else { let expr: syn::Expr = content.parse()?; - (ty, expr, None) + ( + ident, + ConstantKind::Value { + ty, + value: expr, + literal_repr: None, + }, + ) } } else { // NAME = expr (type inferred from `as Type` cast). @@ -253,7 +305,14 @@ impl Parse for ConstantGroup { )); }; - (ty, expr, None) + ( + ident, + ConstantKind::Value { + ty, + value: expr, + literal_repr: None, + }, + ) }; // Optional trailing comma. @@ -262,9 +321,7 @@ impl Parse for ConstantGroup { constants.push(ConstantDef { doc: const_doc, name: const_name, - ty: const_ty, - value: const_value, - literal_repr, + kind, }); } @@ -320,36 +377,61 @@ pub fn constant_group(input: TokenStream) -> TokenStream { for c in &group.constants { let name = &c.name; - let ty = &c.ty; - let value = &c.value; let doc = &c.doc; - let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); - const_value_strs.push(c.literal_repr.clone()); + match &c.kind { + ConstantKind::Value { + ty, + value, + literal_repr, + } => { + let assert_name = + Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); + const_value_strs.push(literal_repr.clone()); + + if literal_repr.is_some() { + // Literal value - no scope wrapper needed. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: #ty = #value; + + const #assert_name: () = assert!( + (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } else { + // Expression value - use super::* for scope access. + const_defs.push(quote! { + #[doc = #doc] + pub const #name: #ty = { use super::*; #value }; + + const #assert_name: () = assert!( + ({ use super::*; #value } as i64) >= (i32::MIN as i64) + && ({ use super::*; #value } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + } + } + ConstantKind::Offset { + struct_name, + field_path, + } => { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + const_value_strs.push(None); - if c.literal_repr.is_some() { - // Literal value - no scope wrapper needed. - const_defs.push(quote! { - #[doc = #doc] - pub const #name: #ty = #value; + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; - const #assert_name: () = assert!( - (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); - }); - } else { - // Expression value - use super::* for scope access. - const_defs.push(quote! { - #[doc = #doc] - pub const #name: #ty = { use super::*; #value }; - - const #assert_name: () = assert!( - ({ use super::*; #value } as i64) >= (i32::MIN as i64) - && ({ use super::*; #value } as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); - }); + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), + "Offset must fit in i16 range" + ); + }); + } } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2e74fd04..42382591 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,10 +1,9 @@ use interface::{error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, - entrypoint::{InstructionContext, MaybeAccount}, + entrypoint::{lazy::InstructionContext, MaybeAccount}, error::ProgramError, - lazy_program_entrypoint, no_allocator, nostd_panic_handler, AccountView, Address, - ProgramResult, + no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, }; #[inline(always)] @@ -41,17 +40,20 @@ unsafe fn next_account_non_duplicate( } // ANCHOR: entrypoint-branching -nostd_panic_handler!(); no_allocator!(); -lazy_program_entrypoint!(process_instruction); - -pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - match context.remaining() { - input_buffer::N_ACCOUNTS_GENERAL => Ok(()), - input_buffer::N_ACCOUNTS_INIT => initialize(context), - _ => err(error::N_ACCOUNTS), +nostd_panic_handler!(); +#[no_mangle] +pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { + match process_instruction(input) { + Ok(_) => SUCCESS, + Err(error) => error.into(), } } + +#[inline(always)] +pub fn process_instruction(input: *mut u8) -> ProgramResult { + Ok(()) +} // ANCHOR_END: entrypoint-branching // ANCHOR: initialize-input-checks From 64fd118eab96f01a8d0ea419ceb748837928abb2 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:59:39 -0800 Subject: [PATCH 062/263] Make constants compile --- .../tree/artifacts/snippets/asm/constants.txt | 9 ++++--- examples/tree/interface/src/common.rs | 25 ++++++++++--------- examples/tree/src/tree/tree.s | 9 ++++--- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 04f71f72..8aba6aab 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -15,13 +15,13 @@ # Input buffer layout. # -------------------- +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 3 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 -.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -38,6 +38,7 @@ # Miscellaneous constants. # ------------------------ -.equ DATA_LEN_ZERO, 0 # Data length of zero. -.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file +.equ MISC_DATA_LEN_ZERO, 0 # Data length of zero. +.equ MISC_BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ MISC_DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MISC_MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 4e857633..567fa88a 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -42,6 +42,8 @@ constant_group! { misc { /// Data length of zero. DATA_LEN_ZERO: usize = 0, + /// Data alignment during runtime. + BPF_ALIGN_OF_U128: usize = 8, } } @@ -54,15 +56,6 @@ struct Return { status: u16, } -#[repr(C, packed)] -/// For CPI to create tree account. -pub struct CreateAccountInstructionData { - instruction_tag: u32, - lamports: u64, - space: u64, - owner: Address, -} - #[repr(C, packed)] /// Input buffer header for all instructions. pub struct InputBufferHeader { @@ -84,7 +77,7 @@ pub struct InitInputBuffer { } #[repr(C)] -struct RuntimeAccount { +pub struct RuntimeAccount { pub header: RuntimeAccountHeader, pub data: [u8; DATA_SIZE], pub rent_epoch: u64, @@ -96,6 +89,14 @@ type SystemProgramRuntimeAccount = /// Compute the data buffer size for a runtime account with the given data length. const fn runtime_data_size(data_len: usize) -> usize { - MAX_PERMITTED_DATA_INCREASE - + (((data_len + misc::MAX_DATA_PAD) & misc::DATA_LEN_AND_MASK) as usize) + MAX_PERMITTED_DATA_INCREASE + data_len.next_multiple_of(misc::BPF_ALIGN_OF_U128) +} + +#[repr(C, packed)] +/// For CPI to create tree account. +pub struct CreateAccountInstructionData { + instruction_tag: u32, + lamports: u64, + space: u64, + owner: Address, } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 877e96b1..b4e57e13 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -16,13 +16,13 @@ # Input buffer layout. # -------------------- +.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 3 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 -.equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -39,9 +39,10 @@ # Miscellaneous constants. # ------------------------ -.equ DATA_LEN_ZERO, 0 # Data length of zero. -.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ MISC_DATA_LEN_ZERO, 0 # Data length of zero. +.equ MISC_BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ MISC_DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MISC_MAX_DATA_PAD, 7 # Maximum possible data length padding. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 4ea7217279f72eafee06eccf48fec023e9fcb240 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:06:04 -0800 Subject: [PATCH 063/263] Clean interface --- examples/tree/interface/src/asm.rs | 28 +------------- examples/tree/interface/src/common.rs | 18 --------- examples/tree/macros/src/lib.rs | 53 ++++++++++++++++++--------- examples/tree/src/program.rs | 6 +-- examples/tree/src/tree/tree.s | 8 ++-- 5 files changed, 43 insertions(+), 70 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 379fc290..86e99333 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,9 +1,8 @@ extern crate alloc; -use crate::bindings; -use crate::common::{CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; +use crate::common::{InitInputBuffer, InputBufferHeader}; use macros::extend_constant_group; -use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; +use pinocchio::entrypoint::NON_DUP_MARKER; extend_constant_group!(input_buffer { prefix = "IB", @@ -28,31 +27,8 @@ extend_constant_group!(input_buffer { }); extend_constant_group!(misc { - prefix = "MISC", /// And mask for data length alignment. DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. MAX_DATA_PAD = 7, }); - -/// User and tree accounts must sign CPI. -const CPI_N_ACCOUNTS: usize = 2; -/// The tree account is a PDA. -const CPI_N_PDA_SIGNERS: usize = 1; -/// The bump seed is required for tree PDA signer. -const CPI_N_SEEDS: usize = 1; - -#[repr(C)] -struct InitStackFrame { - /// Zero-initialized on stack. - system_program_address: Address, - instruction: bindings::SolInstruction, - account_metas: [bindings::SolAccountMeta; CPI_N_ACCOUNTS], - account_infos: [bindings::SolAccountInfo; CPI_N_ACCOUNTS], - signers_seeds: [bindings::SolSignerSeeds; CPI_N_PDA_SIGNERS], - signer_seeds: [bindings::SolSignerSeed; CPI_N_SEEDS], - pda: Address, - rent: Rent, - instruction_data: CreateAccountInstructionData, - bump_seed: u8, -} diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 567fa88a..08dfd172 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -47,15 +47,6 @@ constant_group! { } } -/// Value in r0. -#[repr(C, packed)] -struct Return { - /// If a value is retrieved from the tree, it's encoded in high bits. - maybe_value: u16, - /// Nonzero iff error. - status: u16, -} - #[repr(C, packed)] /// Input buffer header for all instructions. pub struct InputBufferHeader { @@ -91,12 +82,3 @@ type SystemProgramRuntimeAccount = const fn runtime_data_size(data_len: usize) -> usize { MAX_PERMITTED_DATA_INCREASE + data_len.next_multiple_of(misc::BPF_ALIGN_OF_U128) } - -#[repr(C, packed)] -/// For CPI to create tree account. -pub struct CreateAccountInstructionData { - instruction_tag: u32, - lamports: u64, - space: u64, - owner: Address, -} diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 2871abe0..53f681fb 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -466,7 +466,11 @@ pub fn constant_group(input: TokenStream) -> TokenStream { let docs = [#(#const_docs),*]; for i in 0..names.len() { - let full_name = format!("{}_{}", prefix, names[i]); + let full_name = if prefix.is_empty() { + String::from(names[i]) + } else { + format!("{}_{}", prefix, names[i]) + }; // Use original literal if available, otherwise use computed value. let value_str = match literal_values[i] { Some(lit) => String::from(lit), @@ -801,7 +805,7 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { /// Input for extend_constant_group! macro. struct ExtendConstantGroupInput { name: Ident, - prefix: String, + prefix: Option, constants: Vec, } @@ -814,18 +818,22 @@ impl Parse for ExtendConstantGroupInput { let content; braced!(content in input); - // Parse prefix = "..." - let ident: Ident = content.parse()?; - if ident != "prefix" { - return Err(syn::Error::new( - ident.span(), - "First item must be 'prefix = \"...\"'", - )); - } - content.parse::()?; - let prefix_lit: syn::LitStr = content.parse()?; - let prefix = prefix_lit.value(); - content.parse::()?; + // Parse optional prefix = "..." + let prefix = if content.peek(Ident) { + let fork = content.fork(); + let ident: Ident = fork.parse()?; + if ident == "prefix" && fork.peek(Token![=]) { + content.parse::()?; + content.parse::()?; + let prefix_lit: syn::LitStr = content.parse()?; + content.parse::()?; + Some(prefix_lit.value()) + } else { + None + } + } else { + None + }; // Parse constants using shared parser. let constants = parse_asm_constants(&content)?; @@ -865,7 +873,6 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ExtendConstantGroupInput); let mod_name = &input.name; - let prefix = &input.prefix; let max_line_len = MAX_LINE_LEN; // Generate constant definitions and collect info for ASM. @@ -936,6 +943,16 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { // Collect const idents for ASM output. let const_idents: Vec<_> = input.constants.iter().map(|c| &c.name).collect(); + // Generate name formatting logic based on whether prefix is present. + let base_prefix = match &input.prefix { + Some(prefix) => quote! { #prefix }, + None => quote! { "" }, + }; + let name_format = match &input.prefix { + Some(prefix) => quote! { format!("{}_{}", #prefix, names[i]) }, + None => quote! { String::from(names[i]) }, + }; + // Generate value string options for preserving hex/binary literals. let value_str_opts: Vec<_> = const_value_strs .iter() @@ -955,10 +972,10 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { #(#const_defs)* - /// Generate combined ASM (base + extension) with prefix. + /// Generate combined ASM (base + extension). pub fn to_asm() -> String { // Base group adds header and its constants. - let mut result = crate::common::#mod_name::to_asm(#prefix); + let mut result = crate::common::#mod_name::to_asm(#base_prefix); // Add extension constants (no separate header). let names: &[&str] = &[#(#const_names),*]; @@ -967,7 +984,7 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { let docs: &[&str] = &[#(#const_docs),*]; for i in 0..names.len() { - let full_name = format!("{}_{}", #prefix, names[i]); + let full_name = #name_format; // Use original literal if available, otherwise use computed value. let value_str = match literal_values[i] { Some(lit) => String::from(lit), diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 42382591..724a47df 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -42,12 +42,10 @@ unsafe fn next_account_non_duplicate( // ANCHOR: entrypoint-branching no_allocator!(); nostd_panic_handler!(); + #[no_mangle] pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { - match process_instruction(input) { - Ok(_) => SUCCESS, - Err(error) => error.into(), - } + 0 } #[inline(always)] diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b4e57e13..d577bf54 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -39,10 +39,10 @@ # Miscellaneous constants. # ------------------------ -.equ MISC_DATA_LEN_ZERO, 0 # Data length of zero. -.equ MISC_BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. -.equ MISC_DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MISC_MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 6a6a725a2bc224f45b49d9b86507de76db00c36a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:35:54 -0800 Subject: [PATCH 064/263] Pin impl --- examples/tree/artifacts/dumps/rs.txt | 35 ++++++++++--------- examples/tree/artifacts/rs-disassembly.s | 7 +++- .../tree/artifacts/snippets/asm/constants.txt | 8 ++--- .../snippets/rs/entrypoint-branching.txt | 17 +++++---- examples/tree/interface/src/bindings.rs | 1 + examples/tree/macros/src/lib.rs | 6 ++++ examples/tree/src/lib.rs | 1 + examples/tree/src/program.rs | 16 +++++---- examples/tree/src/tests.rs | 2 ++ 9 files changed, 56 insertions(+), 37 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 6d08c3ad..3759e075 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2600 (bytes into file) + Start of section headers 2624 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xa28 +There are 8 section headers, starting at offset 0xa40 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000018 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000138 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000140 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000140 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000140 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0004b8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0004f6 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000030 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000150 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000158 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000158 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000158 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0004d0 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00050e 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000018 0x000018 E 0x8 - LOAD 0x000138 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000140 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000140 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000030 0x000030 E 0x8 + LOAD 0x000150 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000158 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000158 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 24 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 48 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -105,5 +105,8 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - 8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 10 9d 00 00 00 00 00 00 00 return \ No newline at end of file + 8 9c 11 00 00 00 00 00 00 ldxdw r1, [r1 + 0x0] + 10 b4 00 00 00 01 00 00 00 mov32 w0, 0x1 + 18 55 01 01 00 03 00 00 00 jne r1, 0x3, +0x1 + 20 b4 00 00 00 00 00 00 00 mov32 w0, 0x0 + 28 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 50457dc6..ac38fb9a 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,5 +1,10 @@ .globl entrypoint entrypoint: - mov64 r0, 0 + ldxdw r1, [r1+0] + mov32 r0, 1 + jne r1, 3, jmp_0020 + mov32 r0, 0 + +jmp_0020: exit diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 8aba6aab..318ad1b8 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -38,7 +38,7 @@ # Miscellaneous constants. # ------------------------ -.equ MISC_DATA_LEN_ZERO, 0 # Data length of zero. -.equ MISC_BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. -.equ MISC_DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MISC_MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index fe85aed2..907f3c72 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -1,14 +1,13 @@ no_allocator!(); nostd_panic_handler!(); + #[no_mangle] -pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { - match process_instruction(input) { - Ok(_) => SUCCESS, - Err(error) => error.into(), +pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { + match *transmute::<*mut u8, *const u64>( + input_buffer_ptr.add(input_buffer::N_ACCOUNTS_OFF as usize), + ) { + input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, + input_buffer::N_ACCOUNTS_INIT => SUCCESS, + _ => error::N_ACCOUNTS.into(), } -} - -#[inline(always)] -pub fn process_instruction(input: *mut u8) -> ProgramResult { - Ok(()) } \ No newline at end of file diff --git a/examples/tree/interface/src/bindings.rs b/examples/tree/interface/src/bindings.rs index 68481dc4..a4dfa338 100644 --- a/examples/tree/interface/src/bindings.rs +++ b/examples/tree/interface/src/bindings.rs @@ -1,3 +1,4 @@ +#![allow(warnings)] /// Generated from Agave using bindgen. use pinocchio::Address; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 53f681fb..738efb01 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -105,6 +105,12 @@ pub fn error_codes(input: TokenStream) -> TokenStream { } } + impl From for u64 { + fn from(e: error) -> u64 { + e as u64 + } + } + /// Generate ASM constants for error codes. pub fn to_asm() -> alloc::string::String { alloc::format!("{}\n{}\n", #header, #body) diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs index 569ef2f5..d17a169b 100644 --- a/examples/tree/src/lib.rs +++ b/examples/tree/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(warnings)] #![cfg_attr(not(test), no_std)] mod program; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 724a47df..6bc8e7ae 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,3 +1,4 @@ +use core::mem::transmute; use interface::{error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, @@ -44,13 +45,14 @@ no_allocator!(); nostd_panic_handler!(); #[no_mangle] -pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { - 0 -} - -#[inline(always)] -pub fn process_instruction(input: *mut u8) -> ProgramResult { - Ok(()) +pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { + match *transmute::<*mut u8, *const u64>( + input_buffer_ptr.add(input_buffer::N_ACCOUNTS_OFF as usize), + ) { + input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, + input_buffer::N_ACCOUNTS_INIT => SUCCESS, + _ => error::N_ACCOUNTS.into(), + } } // ANCHOR_END: entrypoint-branching diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 8cd1e665..e04e462a 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -91,7 +91,9 @@ fn test_entrypoint_branching() { print_comparison_table(entrypoint::EntrypointCase::CASES); } +/* #[test] fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES); } + */ From 76a9874ab6a0589c8621b9852dfc75c79640f408 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:03:12 -0800 Subject: [PATCH 065/263] Pin program --- examples/tree/src/program.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 6bc8e7ae..fa92dd06 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -56,6 +56,16 @@ pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { } // ANCHOR_END: entrypoint-branching +#[inline(always)] +fn general_branch() -> u64 { + 10 +} + +#[inline(always)] +fn initialize_branch() -> u64 { + 5 +} + // ANCHOR: initialize-input-checks #[inline(always)] /// SAFETY: Called by entrypoint after verifying the right number of accounts for initialization. From d508f0cbea4e825060e64b45ad7f87786616bb37 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:03:36 -0800 Subject: [PATCH 066/263] Pin disassembly --- examples/tree/artifacts/rs-disassembly.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index ac38fb9a..0f1a2888 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,9 +2,10 @@ entrypoint: ldxdw r1, [r1+0] + and64 r1, -2 mov32 r0, 1 - jne r1, 3, jmp_0020 + jne r1, 2, jmp_0028 mov32 r0, 0 -jmp_0020: +jmp_0028: exit From fa368ec2ff0cf3badacf247dd447c8ffb6c6a42b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:31:03 -0800 Subject: [PATCH 067/263] Pin impl --- examples/tree/artifacts/dumps/rs.txt | 59 +++++++---- examples/tree/artifacts/rs-disassembly.s | 34 ++++-- .../snippets/rs/entrypoint-branching.txt | 14 ++- .../snippets/rs/initialize-input-checks.txt | 49 +++++---- .../tests/entrypoint_branching/result.txt | 88 ++------------- .../tests/initialize_input_checks/result.txt | 100 +++--------------- examples/tree/interface/src/common.rs | 4 +- examples/tree/src/program.rs | 83 ++++++++------- examples/tree/src/tests.rs | 2 - 9 files changed, 170 insertions(+), 263 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 3759e075..d3a8d47d 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2624 (bytes into file) + Start of section headers 2792 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xa40 +There are 8 section headers, starting at offset 0xae8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000030 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000150 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000158 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000158 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000158 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0004d0 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00050e 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0000d8 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 0001f8 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000200 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000200 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000200 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000578 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0005b6 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000030 0x000030 E 0x8 - LOAD 0x000150 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000158 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000158 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0000d8 0x0000d8 E 0x8 + LOAD 0x0001f8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000200 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000200 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 48 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 216 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -105,8 +105,29 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - 8 9c 11 00 00 00 00 00 00 ldxdw r1, [r1 + 0x0] - 10 b4 00 00 00 01 00 00 00 mov32 w0, 0x1 - 18 55 01 01 00 03 00 00 00 jne r1, 0x3, +0x1 - 20 b4 00 00 00 00 00 00 00 mov32 w0, 0x0 - 28 9d 00 00 00 00 00 00 00 return \ No newline at end of file + 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 10 15 02 04 00 03 00 00 00 jeq r2, 0x3, +0x4 + 18 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 20 55 02 15 00 02 00 00 00 jne r2, 0x2, +0x15 + 28 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 30 05 00 13 00 00 00 00 00 ja +0x13 + 38 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 40 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 48 55 02 10 00 00 00 00 00 jne r2, 0x0, +0x10 + 50 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 60 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 68 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 70 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 78 55 02 0a 00 00 00 00 00 jne r2, 0x0, +0xa + 80 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 88 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 90 55 02 07 00 ff 00 00 00 jne r2, 0xff, +0x7 + 98 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + a0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + a8 55 02 04 00 0e 00 00 00 jne r2, 0xe, +0x4 + b0 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] + b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + c0 15 01 01 00 00 00 00 00 jeq r1, 0x0, +0x1 + c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + d0 9d 00 00 00 00 00 00 00 return \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 0f1a2888..23e9bd64 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,11 +1,33 @@ .globl entrypoint entrypoint: - ldxdw r1, [r1+0] - and64 r1, -2 - mov32 r0, 1 - jne r1, 2, jmp_0028 - mov32 r0, 0 + ldxdw r2, [r1+0] + jeq r2, 3, jmp_0030 + mov64 r0, 1 + jne r2, 2, jmp_00c8 + mov64 r0, 0 + ja jmp_00c8 -jmp_0028: +jmp_0030: + mov64 r0, 2 + ldxdw r2, [r1+88] + jne r2, 0, jmp_00c8 + mov64 r0, 5 + ldxb r2, [r1+10344] + jne r2, 255, jmp_00c8 + mov64 r0, 3 + ldxdw r2, [r1+10424] + jne r2, 0, jmp_00c8 + mov64 r0, 6 + ldxb r2, [r1+20680] + jne r2, 255, jmp_00c8 + mov64 r0, 4 + ldxdw r2, [r1+20760] + jne r2, 14, jmp_00c8 + ldxdw r1, [r1+31032] + mov64 r0, 0 + jeq r1, 0, jmp_00c8 + mov64 r0, 7 + +jmp_00c8: exit diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 907f3c72..e9e6d544 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -1,13 +1,19 @@ no_allocator!(); nostd_panic_handler!(); +unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { + *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) +} + +unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { + *ptr.add(offset as usize) +} + #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match *transmute::<*mut u8, *const u64>( - input_buffer_ptr.add(input_buffer::N_ACCOUNTS_OFF as usize), - ) { + match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, - input_buffer::N_ACCOUNTS_INIT => SUCCESS, + input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), _ => error::N_ACCOUNTS.into(), } } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 181c5232..3ff48878 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,28 +1,37 @@ #[inline(always)] -/// SAFETY: Called by entrypoint after verifying the right number of accounts for initialization. -fn initialize(mut context: InstructionContext) -> ProgramResult { +unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - // SAFETY: number of accounts has been checked. - let user = unsafe { context.next_account_unchecked().assume_account() }; - ensure_is_data_empty(&user, error::USER_DATA_LEN)?; + if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + return error::USER_DATA_LEN.into(); + } // Error if tree is duplicate or has data. - // SAFETY: number of accounts has been checked. - let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; - ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; + if ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER { + return error::TREE_DUPLICATE.into(); + } + if ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + return error::TREE_DATA_LEN.into(); + } // Error if System Program is duplicate or has invalid data length. - // SAFETY: number of accounts has been checked. - let system_program = - unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; - ensure( - system_program.data_len() == input_buffer::SYSTEM_PROGRAM_DATA_LEN, - error::SYSTEM_PROGRAM_DATA_LEN, - )?; + if ldxb( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + ) != NON_DUP_MARKER + { + return error::SYSTEM_PROGRAM_DUPLICATE.into(); + } + if ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) + != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64 + { + return error::SYSTEM_PROGRAM_DATA_LEN.into(); + } // Error if instruction data provided. - // SAFETY: all accounts have been consumed. - ensure( - unsafe { context.instruction_data_unchecked().is_empty() }, - error::INSTRUCTION_DATA, - )?; \ No newline at end of file + if ldxdw( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + ) != misc::DATA_LEN_ZERO + { + return error::INSTRUCTION_DATA.into(); + } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 62d97a94..337304d4 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,100 +1,24 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| No accounts | 5 | 8 | +3 | +60.0% | -| One account | 5 | 8 | +3 | +60.0% | -| Four accounts | 5 | 8 | +3 | +60.0% | +| No accounts | 5 | 6 | +1 | +20.0% | +| One account | 5 | 6 | +1 | +20.0% | +| Four accounts | 5 | 6 | +1 | +20.0% | test tests::test_entrypoint_branching ... ok -warning: constant `CPI_N_ACCOUNTS` is never used - --> tree/interface/src/asm.rs:88:7 - | -88 | const CPI_N_ACCOUNTS: usize = 2; - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: constant `CPI_N_PDA_SIGNERS` is never used - --> tree/interface/src/asm.rs:90:7 - | -90 | const CPI_N_PDA_SIGNERS: usize = 1; - | ^^^^^^^^^^^^^^^^^ -warning: constant `CPI_N_SEEDS` is never used - --> tree/interface/src/asm.rs:92:7 - | -92 | const CPI_N_SEEDS: usize = 1; - | ^^^^^^^^^^^ -warning: struct `InitStackFrame` is never constructed - --> tree/interface/src/asm.rs:95:8 - | -95 | struct InitStackFrame { - | ^^^^^^^^^^^^^^ -warning: struct `SolInstruction` is never constructed - --> tree/interface/src/bindings.rs:7:12 - | -7 | pub struct SolInstruction { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountMeta` is never constructed - --> tree/interface/src/bindings.rs:23:12 - | -23 | pub struct SolAccountMeta { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountInfo` is never constructed - --> tree/interface/src/bindings.rs:35:12 - | -35 | pub struct SolAccountInfo { - | ^^^^^^^^^^^^^^ -warning: struct `SolSignerSeed` is never constructed - --> tree/interface/src/bindings.rs:59:12 - | -59 | pub struct SolSignerSeed { - | ^^^^^^^^^^^^^ -warning: struct `SolSignerSeeds` is never constructed - --> tree/interface/src/bindings.rs:69:12 - | -69 | pub struct SolSignerSeeds { - | ^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: struct `CreateAccountInstructionData` is never constructed - --> tree/interface/src/common.rs:46:12 - | -46 | pub struct CreateAccountInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `interface` (lib) generated 11 warnings -warning: `interface` (lib) generated 11 warnings (11 duplicates) -warning: variable does not need to be mutable - --> tree/src/program.rs:48:28 - | -48 | pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - | ----^^^^^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default -warning: unused variable: `bump` - --> tree/src/program.rs:90:24 - | -90 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 2 warnings (run `cargo fix --lib -p tree --tests` to apply 1 suggestion) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 2d4d89a3..5cf68e1f 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,121 +1,45 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 13 | +6 | +85.7% | -| Tree account is duplicate | 9 | 19 | +10 | +111.1% | -| Tree has nonzero data length | 11 | 22 | +11 | +100.0% | -| System program is duplicate | 13 | 30 | +17 | +130.8% | -| System program wrong data length | 15 | 33 | +18 | +120.0% | -| Non-empty instruction data | 17 | 40 | +23 | +135.3% | +| User has nonzero data length | 7 | 7 | +0 | +0.0% | +| Tree account is duplicate | 9 | 10 | +1 | +11.1% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 16 | +3 | +23.1% | +| System program wrong data length | 15 | 19 | +4 | +26.7% | +| Non-empty instruction data | 17 | 23 | +6 | +35.3% | test tests::test_initialize_input_checks ... ok -warning: constant `CPI_N_ACCOUNTS` is never used - --> tree/interface/src/asm.rs:88:7 - | -88 | const CPI_N_ACCOUNTS: usize = 2; - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: constant `CPI_N_PDA_SIGNERS` is never used - --> tree/interface/src/asm.rs:90:7 - | -90 | const CPI_N_PDA_SIGNERS: usize = 1; - | ^^^^^^^^^^^^^^^^^ -warning: constant `CPI_N_SEEDS` is never used - --> tree/interface/src/asm.rs:92:7 - | -92 | const CPI_N_SEEDS: usize = 1; - | ^^^^^^^^^^^ -warning: struct `InitStackFrame` is never constructed - --> tree/interface/src/asm.rs:95:8 - | -95 | struct InitStackFrame { - | ^^^^^^^^^^^^^^ -warning: struct `SolInstruction` is never constructed - --> tree/interface/src/bindings.rs:7:12 - | -7 | pub struct SolInstruction { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountMeta` is never constructed - --> tree/interface/src/bindings.rs:23:12 - | -23 | pub struct SolAccountMeta { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountInfo` is never constructed - --> tree/interface/src/bindings.rs:35:12 - | -35 | pub struct SolAccountInfo { - | ^^^^^^^^^^^^^^ -warning: struct `SolSignerSeed` is never constructed - --> tree/interface/src/bindings.rs:59:12 - | -59 | pub struct SolSignerSeed { - | ^^^^^^^^^^^^^ -warning: struct `SolSignerSeeds` is never constructed - --> tree/interface/src/bindings.rs:69:12 - | -69 | pub struct SolSignerSeeds { - | ^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: struct `CreateAccountInstructionData` is never constructed - --> tree/interface/src/common.rs:46:12 - | -46 | pub struct CreateAccountInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `interface` (lib) generated 11 warnings -warning: `interface` (lib) generated 11 warnings (11 duplicates) -warning: variable does not need to be mutable - --> tree/src/program.rs:48:28 - | -48 | pub fn process_instruction(mut context: InstructionContext) -> ProgramResult { - | ----^^^^^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default -warning: unused variable: `bump` - --> tree/src/program.rs:90:24 - | -90 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 2 warnings (run `cargo fix --lib -p tree --tests` to apply 1 suggestion) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 08dfd172..c1084e01 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -41,7 +41,7 @@ constant_group! { /// Miscellaneous constants. misc { /// Data length of zero. - DATA_LEN_ZERO: usize = 0, + DATA_LEN_ZERO: u64 = 0, /// Data alignment during runtime. BPF_ALIGN_OF_U128: usize = 8, } @@ -74,7 +74,7 @@ pub struct RuntimeAccount { pub rent_epoch: u64, } -type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO) }>; +type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO as usize) }>; type SystemProgramRuntimeAccount = RuntimeAccount<{ runtime_data_size(input_buffer::SYSTEM_PROGRAM_DATA_LEN) }>; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index fa92dd06..a7d48190 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,8 +1,8 @@ use core::mem::transmute; -use interface::{error_codes::error, input_buffer}; +use interface::{error_codes::error, input_buffer, misc}; use pinocchio::{ address::address_eq, - entrypoint::{lazy::InstructionContext, MaybeAccount}, + entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, error::ProgramError, no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, }; @@ -44,13 +44,19 @@ unsafe fn next_account_non_duplicate( no_allocator!(); nostd_panic_handler!(); +unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { + *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) +} + +unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { + *ptr.add(offset as usize) +} + #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match *transmute::<*mut u8, *const u64>( - input_buffer_ptr.add(input_buffer::N_ACCOUNTS_OFF as usize), - ) { + match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, - input_buffer::N_ACCOUNTS_INIT => SUCCESS, + input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), _ => error::N_ACCOUNTS.into(), } } @@ -58,51 +64,48 @@ pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { #[inline(always)] fn general_branch() -> u64 { - 10 -} - -#[inline(always)] -fn initialize_branch() -> u64 { - 5 + SUCCESS } // ANCHOR: initialize-input-checks #[inline(always)] -/// SAFETY: Called by entrypoint after verifying the right number of accounts for initialization. -fn initialize(mut context: InstructionContext) -> ProgramResult { +unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - // SAFETY: number of accounts has been checked. - let user = unsafe { context.next_account_unchecked().assume_account() }; - ensure_is_data_empty(&user, error::USER_DATA_LEN)?; + if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + return error::USER_DATA_LEN.into(); + } // Error if tree is duplicate or has data. - // SAFETY: number of accounts has been checked. - let tree = unsafe { next_account_non_duplicate(&mut context, error::TREE_DUPLICATE) }?; - ensure_is_data_empty(&tree, error::TREE_DATA_LEN)?; + if ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER { + return error::TREE_DUPLICATE.into(); + } + if ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + return error::TREE_DATA_LEN.into(); + } // Error if System Program is duplicate or has invalid data length. - // SAFETY: number of accounts has been checked. - let system_program = - unsafe { next_account_non_duplicate(&mut context, error::SYSTEM_PROGRAM_DUPLICATE) }?; - ensure( - system_program.data_len() == input_buffer::SYSTEM_PROGRAM_DATA_LEN, - error::SYSTEM_PROGRAM_DATA_LEN, - )?; + if ldxb( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + ) != NON_DUP_MARKER + { + return error::SYSTEM_PROGRAM_DUPLICATE.into(); + } + if ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) + != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64 + { + return error::SYSTEM_PROGRAM_DATA_LEN.into(); + } // Error if instruction data provided. - // SAFETY: all accounts have been consumed. - ensure( - unsafe { context.instruction_data_unchecked().is_empty() }, - error::INSTRUCTION_DATA, - )?; + if ldxdw( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + ) != misc::DATA_LEN_ZERO + { + return error::INSTRUCTION_DATA.into(); + } // ANCHOR_END: initialize-input-checks - // Verify tree PDA. - let program_id = unsafe { context.program_id_unchecked() }; - let (expected_pda, bump) = Address::find_program_address(&[], program_id); - ensure( - address_eq(tree.address(), &expected_pda), - error::PDA_MISMATCH, - )?; - Ok(()) + SUCCESS } diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index e04e462a..8cd1e665 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -91,9 +91,7 @@ fn test_entrypoint_branching() { print_comparison_table(entrypoint::EntrypointCase::CASES); } -/* #[test] fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES); } - */ From 5d2b0710fad0334d0dd78fcffd0dddf177479ba8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:39:59 -0800 Subject: [PATCH 068/263] Rebuild with v2 --- examples/tree/artifacts/dumps/asm.txt | 4 +- examples/tree/artifacts/dumps/rs.txt | 186 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 26 +-- .../snippets/rs/entrypoint-branching.txt | 2 +- .../tests/entrypoint_branching/result.txt | 12 +- .../tests/initialize_input_checks/result.txt | 24 +-- examples/tree/src/program.rs | 10 +- 7 files changed, 139 insertions(+), 125 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 8c9ee848..fc9bd914 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -58,11 +58,11 @@ Disassembly of section .text 17 95 00 00 00 00 00 00 00 exit 18 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) 19 55 02 15 00 00 00 00 00 if r2 != 0x0 goto +0x15 <.text+0x108> - 20 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 20 71 12 68 28 00 00 00 00 w2 = *(u8 *)(r1 + 0x2868) 21 55 02 11 00 ff 00 00 00 if r2 != 0xff goto +0x11 <.text+0xf8> 22 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) 23 55 02 0d 00 00 00 00 00 if r2 != 0x0 goto +0xd <.text+0xe8> - 24 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) + 24 71 12 c8 50 00 00 00 00 w2 = *(u8 *)(r1 + 0x50c8) 25 55 02 09 00 ff 00 00 00 if r2 != 0xff goto +0x9 <.text+0xd8> 26 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) 27 55 02 05 00 0e 00 00 00 if r2 != 0xe goto +0x5 <.text+0xc8> diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index d3a8d47d..75d5f432 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -9,28 +9,29 @@ ELF Header Type DYN (Shared object file) Machine Solana Bytecode Format Version 0x1 - Entry point address 0x0 + Entry point address 0x120 Start of program headers 64 (bytes into file) - Start of section headers 2792 (bytes into file) - Flags 0x4 + Start of section headers 2768 (bytes into file) + Flags 0x2 Size of this header 64 (bytes) Size of program headers 56 (bytes) - Number of program headers 4 + Number of program headers 3 Size of section headers 64 (bytes) - Number of section headers 8 - Section header string table index 6 -There are 8 section headers, starting at offset 0xae8 + Number of section headers 9 + Section header string table index 7 +There are 9 section headers, starting at offset 0xad0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0000d8 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 0001f8 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000200 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000200 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000200 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000578 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0005b6 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000120 000120 0000e0 00 AX 0 0 8 + [ 2] .dynamic DYNAMIC 0000000000000200 000200 000070 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000270 000270 000030 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000002a0 0002a0 00000c 00 A 0 0 1 + [ 5] .comment PROGBITS 0000000000000000 0002ac 00006b 01 MS 0 0 1 + [ 6] .symtab SYMTAB 0000000000000000 000318 0002e8 18 8 30 8 + [ 7] .shstrtab STRTAB 0000000000000000 000600 000043 00 0 0 1 + [ 8] .strtab STRTAB 0000000000000000 000643 00048b 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -38,96 +39,103 @@ Key to Flags R (retain), p (processor specific) Elf file type is DYN (Shared object file) -Entry point 0x0 -There are 4 program headers, starting at offset 64 +Entry point 0x120 +There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0000d8 0x0000d8 E 0x8 - LOAD 0x0001f8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000200 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000200 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000120 0x0000000000000120 0x0000e0 0x0000e0 R E 0x1000 + LOAD 0x000270 0x0000000000000270 0x0000000000000270 0x00003c 0x00003c R 0x1000 + DYNAMIC 0x000200 0x0000000000000200 0x0000000000000200 0x000070 0x000070 RW 0x8 Section to Segment mapping Segment Sections... 00 .text - 01 .rodata - 02 .bss.stack - 03 .bss.heap - None .symtab .shstrtab .strtab + 01 .dynsym .dynstr + 02 .dynamic + None .comment .symtab .shstrtab .strtab +Dynamic section at offset 0x200 contains 7 entries + Tag Type Name/Value + 0x000000000000001e (FLAGS) TEXTREL + 0x0000000000000006 (SYMTAB) 0x270 + 0x000000000000000b (SYMENT) 24 (bytes) + 0x0000000000000005 (STRTAB) 0x2a0 + 0x000000000000000a (STRSZ) 12 (bytes) + 0x0000000000000016 (TEXTREL) 0x0 + 0x0000000000000000 (NULL) 0x0 There are no relocations in this file. -Symbol table '.symtab' contains 37 entries +Symbol table '.dynsym' contains 2 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 - 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl - 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 - 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 - 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 - 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 - 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 - 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 - 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 - 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 - 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 - 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 - 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 - 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 - 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 - 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 - 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 - 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 - 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 - 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 - 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 - 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 - 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 - 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 - 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 - 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 - 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 - 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 - 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 - 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 - 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 - 32 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start - 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end - 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start - 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 216 FUNC GLOBAL DEFAULT 1 entrypoint + 1 0000000000000120 224 FUNC GLOBAL DEFAULT 1 entrypoint + +Symbol table '.symtab' contains 31 entries + Num Value Size Type Bind Vis Ndx Name + 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.d0c49d1e43105785-cgu.0 + 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 80ibksluagh4kwnjvjamobpuj + 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.7fa3ac0a27424a8-cgu.0 + 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.1777bc652cbba5b9-cgu.0 + 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.114 + 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.164 + 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.016 + 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.167 + 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.199 + 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.200 + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.215 + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.218 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.227 + 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.238 + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.251 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.259 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.000 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.247 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.272 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.273 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.303 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.318 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.004 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.325 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.328 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.336 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.347 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.012 + 29 0000000000000200 0 NOTYPE LOCAL HIDDEN 2 _DYNAMIC + 30 0000000000000120 224 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf Disassembly of section .text -0000000000000000 - 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 - 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 10 15 02 04 00 03 00 00 00 jeq r2, 0x3, +0x4 - 18 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 20 55 02 15 00 02 00 00 00 jne r2, 0x2, +0x15 - 28 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 30 05 00 13 00 00 00 00 00 ja +0x13 - 38 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 40 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 48 55 02 10 00 00 00 00 00 jne r2, 0x0, +0x10 - 50 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 60 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd - 68 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 70 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 78 55 02 0a 00 00 00 00 00 jne r2, 0x0, +0xa - 80 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 88 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 90 55 02 07 00 ff 00 00 00 jne r2, 0xff, +0x7 - 98 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - a0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - a8 55 02 04 00 0e 00 00 00 jne r2, 0xe, +0x4 - b0 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - c0 15 01 01 00 00 00 00 00 jeq r1, 0x0, +0x1 - c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - d0 9d 00 00 00 00 00 00 00 return \ No newline at end of file +0000000000000120 + 120 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 128 15 02 06 00 03 00 00 00 jeq r2, 0x3, +0x6 + 130 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 138 55 02 17 00 02 00 00 00 jne r2, 0x2, +0x17 + 140 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] + 148 15 01 15 00 05 00 00 00 jeq r1, 0x5, +0x15 + 150 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 158 05 00 13 00 00 00 00 00 ja +0x13 + 160 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 168 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 170 55 02 10 00 00 00 00 00 jne r2, 0x0, +0x10 + 178 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 180 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 188 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 190 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 198 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 1a0 55 02 0a 00 00 00 00 00 jne r2, 0x0, +0xa + 1a8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1b0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 1b8 55 02 07 00 ff 00 00 00 jne r2, 0xff, +0x7 + 1c0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 1c8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 1d0 55 02 04 00 0e 00 00 00 jne r2, 0xe, +0x4 + 1d8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] + 1e0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1e8 15 01 01 00 00 00 00 00 jeq r1, 0x0, +0x1 + 1f0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1f8 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 23e9bd64..e49cede8 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,32 +2,34 @@ entrypoint: ldxdw r2, [r1+0] - jeq r2, 3, jmp_0030 + jeq r2, 3, jmp_0040 mov64 r0, 1 - jne r2, 2, jmp_00c8 - mov64 r0, 0 - ja jmp_00c8 + jne r2, 2, jmp_00d8 + ldxdw r1, [r1+88] + jeq r1, 5, jmp_00d8 + mov64 r0, 3 + ja jmp_00d8 -jmp_0030: +jmp_0040: mov64 r0, 2 ldxdw r2, [r1+88] - jne r2, 0, jmp_00c8 + jne r2, 0, jmp_00d8 mov64 r0, 5 ldxb r2, [r1+10344] - jne r2, 255, jmp_00c8 + jne r2, 255, jmp_00d8 mov64 r0, 3 ldxdw r2, [r1+10424] - jne r2, 0, jmp_00c8 + jne r2, 0, jmp_00d8 mov64 r0, 6 ldxb r2, [r1+20680] - jne r2, 255, jmp_00c8 + jne r2, 255, jmp_00d8 mov64 r0, 4 ldxdw r2, [r1+20760] - jne r2, 14, jmp_00c8 + jne r2, 14, jmp_00d8 ldxdw r1, [r1+31032] mov64 r0, 0 - jeq r1, 0, jmp_00c8 + jeq r1, 0, jmp_00d8 mov64 r0, 7 -jmp_00c8: +jmp_00d8: exit diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index e9e6d544..c17f057f 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -12,7 +12,7 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, + input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), _ => error::N_ACCOUNTS.into(), } diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 337304d4..42c498f1 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,24 +1,24 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| No accounts | 5 | 6 | +1 | +20.0% | -| One account | 5 | 6 | +1 | +20.0% | -| Four accounts | 5 | 6 | +1 | +20.0% | +| No accounts | 5 | 5 | +0 | +0.0% | +| One account | 5 | 5 | +0 | +0.0% | +| Four accounts | 5 | 5 | +0 | +0.0% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 5cf68e1f..52c64997 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,45 +1,45 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 7 | +0 | +0.0% | -| Tree account is duplicate | 9 | 10 | +1 | +11.1% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 16 | +3 | +23.1% | -| System program wrong data length | 15 | 19 | +4 | +26.7% | -| Non-empty instruction data | 17 | 23 | +6 | +35.3% | +| User has nonzero data length | 7 | 6 | -1 | -14.3% | +| Tree account is duplicate | 9 | 9 | +0 | +0.0% | +| Tree has nonzero data length | 11 | 12 | +1 | +9.1% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 18 | +3 | +20.0% | +| Non-empty instruction data | 17 | 22 | +5 | +29.4% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a7d48190..e7649939 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -55,7 +55,7 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => SUCCESS, + input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), _ => error::N_ACCOUNTS.into(), } @@ -63,8 +63,12 @@ pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { // ANCHOR_END: entrypoint-branching #[inline(always)] -fn general_branch() -> u64 { - SUCCESS +unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { + if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) == 5 { + 1 + } else { + 3 + } } // ANCHOR: initialize-input-checks From e5f4a88b883db72c553e14f0236e741633195935 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:04:50 -0800 Subject: [PATCH 069/263] Pin impl with cold paths --- examples/tree/artifacts/dumps/rs.txt | 95 ++++++++++--------- examples/tree/artifacts/rs-disassembly.s | 57 +++++++---- .../snippets/rs/entrypoint-branching.txt | 11 ++- .../snippets/rs/initialize-input-checks.txt | 36 +++---- .../tests/initialize_input_checks/result.txt | 20 ++-- examples/tree/src/program.rs | 54 ++++++----- 6 files changed, 157 insertions(+), 116 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 75d5f432..f2018886 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x120 Start of program headers 64 (bytes into file) - Start of section headers 2768 (bytes into file) + Start of section headers 2824 (bytes into file) Flags 0x2 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,19 +19,19 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 9 Section header string table index 7 -There are 9 section headers, starting at offset 0xad0 +There are 9 section headers, starting at offset 0xb08 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000120 000120 0000e0 00 AX 0 0 8 - [ 2] .dynamic DYNAMIC 0000000000000200 000200 000070 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000270 000270 000030 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000002a0 0002a0 00000c 00 A 0 0 1 - [ 5] .comment PROGBITS 0000000000000000 0002ac 00006b 01 MS 0 0 1 - [ 6] .symtab SYMTAB 0000000000000000 000318 0002e8 18 8 30 8 - [ 7] .shstrtab STRTAB 0000000000000000 000600 000043 00 0 0 1 - [ 8] .strtab STRTAB 0000000000000000 000643 00048b 00 0 0 1 + [ 1] .text PROGBITS 0000000000000120 000120 000118 00 AX 0 0 8 + [ 2] .dynamic DYNAMIC 0000000000000238 000238 000070 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000002a8 0002a8 000030 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000002d8 0002d8 00000c 00 A 0 0 1 + [ 5] .comment PROGBITS 0000000000000000 0002e4 00006b 01 MS 0 0 1 + [ 6] .symtab SYMTAB 0000000000000000 000350 0002e8 18 8 30 8 + [ 7] .shstrtab STRTAB 0000000000000000 000638 000043 00 0 0 1 + [ 8] .strtab STRTAB 0000000000000000 00067b 00048b 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -44,9 +44,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000120 0x0000000000000120 0x0000e0 0x0000e0 R E 0x1000 - LOAD 0x000270 0x0000000000000270 0x0000000000000270 0x00003c 0x00003c R 0x1000 - DYNAMIC 0x000200 0x0000000000000200 0x0000000000000200 0x000070 0x000070 RW 0x8 + LOAD 0x000120 0x0000000000000120 0x0000000000000120 0x000118 0x000118 R E 0x1000 + LOAD 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00003c 0x00003c R 0x1000 + DYNAMIC 0x000238 0x0000000000000238 0x0000000000000238 0x000070 0x000070 RW 0x8 Section to Segment mapping Segment Sections... @@ -54,12 +54,12 @@ Program Headers 01 .dynsym .dynstr 02 .dynamic None .comment .symtab .shstrtab .strtab -Dynamic section at offset 0x200 contains 7 entries +Dynamic section at offset 0x238 contains 7 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000006 (SYMTAB) 0x270 + 0x0000000000000006 (SYMTAB) 0x2a8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x2a0 + 0x0000000000000005 (STRTAB) 0x2d8 0x000000000000000a (STRSZ) 12 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 @@ -69,7 +69,7 @@ There are no relocations in this file. Symbol table '.dynsym' contains 2 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000120 224 FUNC GLOBAL DEFAULT 1 entrypoint + 1 0000000000000120 280 FUNC GLOBAL DEFAULT 1 entrypoint Symbol table '.symtab' contains 31 entries Num Value Size Type Bind Vis Ndx Name @@ -102,8 +102,8 @@ Symbol table '.symtab' contains 31 entries 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.336 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.347 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.012 - 29 0000000000000200 0 NOTYPE LOCAL HIDDEN 2 _DYNAMIC - 30 0000000000000120 224 FUNC GLOBAL DEFAULT 1 entrypoint + 29 0000000000000238 0 NOTYPE LOCAL HIDDEN 2 _DYNAMIC + 30 0000000000000120 280 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,30 +112,37 @@ Disassembly of section .text 0000000000000120 120 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 128 15 02 06 00 03 00 00 00 jeq r2, 0x3, +0x6 - 130 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 138 55 02 17 00 02 00 00 00 jne r2, 0x2, +0x17 - 140 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] - 148 15 01 15 00 05 00 00 00 jeq r1, 0x5, +0x15 - 150 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 158 05 00 13 00 00 00 00 00 ja +0x13 - 160 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 168 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 170 55 02 10 00 00 00 00 00 jne r2, 0x0, +0x10 - 178 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 128 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 + 130 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] + 138 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 + 140 15 01 04 00 43 00 00 00 jeq r1, 0x43, +0x4 + 148 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 + 150 05 00 02 00 00 00 00 00 ja +0x2 + 158 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 160 15 02 01 00 03 00 00 00 jeq r2, 0x3, +0x1 + 168 95 00 00 00 00 00 00 00 exit + 170 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 178 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd 180 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] 188 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd - 190 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 198 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 1a0 55 02 0a 00 00 00 00 00 jne r2, 0x0, +0xa - 1a8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 1b0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 1b8 55 02 07 00 ff 00 00 00 jne r2, 0xff, +0x7 - 1c0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1c8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 1d0 55 02 04 00 0e 00 00 00 jne r2, 0xe, +0x4 - 1d8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - 1e0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1e8 15 01 01 00 00 00 00 00 jeq r1, 0x0, +0x1 - 1f0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1f8 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 190 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 198 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 1a0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 1a8 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 1b0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 1b8 55 02 0d 00 0e 00 00 00 jne r2, 0xe, +0xd + 1c0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1c8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] + 1d0 15 01 f2 ff 00 00 00 00 jeq r1, 0x0, -0xe + 1d8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1e0 05 00 f0 ff 00 00 00 00 ja -0x10 + 1e8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 1f0 05 00 ee ff 00 00 00 00 ja -0x12 + 1f8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 200 05 00 ec ff 00 00 00 00 ja -0x14 + 208 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 210 05 00 ea ff 00 00 00 00 ja -0x16 + 218 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 220 05 00 e8 ff 00 00 00 00 ja -0x18 + 228 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 230 05 00 e6 ff 00 00 00 00 ja -0x1a \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index e49cede8..291edc16 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,34 +2,53 @@ entrypoint: ldxdw r2, [r1+0] - jeq r2, 3, jmp_0040 - mov64 r0, 1 - jne r2, 2, jmp_00d8 + jne r2, 2, jmp_0038 ldxdw r1, [r1+88] - jeq r1, 5, jmp_00d8 - mov64 r0, 3 - ja jmp_00d8 + mov64 r0, 6677 + jeq r1, 67, jmp_0048 + mov64 r0, 666777 + ja jmp_0048 -jmp_0040: - mov64 r0, 2 +jmp_0038: + mov64 r0, 1 + jeq r2, 3, jmp_0050 + +jmp_0048: + exit + +jmp_0050: ldxdw r2, [r1+88] - jne r2, 0, jmp_00d8 - mov64 r0, 5 + jne r2, 0, jmp_00c8 ldxb r2, [r1+10344] jne r2, 255, jmp_00d8 - mov64 r0, 3 ldxdw r2, [r1+10424] - jne r2, 0, jmp_00d8 - mov64 r0, 6 + jne r2, 0, jmp_00e8 ldxb r2, [r1+20680] - jne r2, 255, jmp_00d8 - mov64 r0, 4 + jne r2, 255, jmp_00f8 ldxdw r2, [r1+20760] - jne r2, 14, jmp_00d8 - ldxdw r1, [r1+31032] + jne r2, 14, jmp_0108 mov64 r0, 0 - jeq r1, 0, jmp_00d8 + ldxdw r1, [r1+31032] + jeq r1, 0, jmp_0048 mov64 r0, 7 + ja jmp_0048 + +jmp_00c8: + mov64 r0, 2 + ja jmp_0048 jmp_00d8: - exit + mov64 r0, 5 + ja jmp_0048 + +jmp_00e8: + mov64 r0, 3 + ja jmp_0048 + +jmp_00f8: + mov64 r0, 6 + ja jmp_0048 + +jmp_0108: + mov64 r0, 4 + ja jmp_0048 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index c17f057f..f9cb66c7 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -11,9 +11,12 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), - input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), - _ => error::N_ACCOUNTS.into(), + let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + if n_accounts == input_buffer::N_ACCOUNTS_GENERAL { + general(input_buffer_ptr) + } else if n_accounts == input_buffer::N_ACCOUNTS_INIT { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() } } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 3ff48878..08c8ee0a 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,37 +1,41 @@ #[inline(always)] +#[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + if unlikely(ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { return error::USER_DATA_LEN.into(); } // Error if tree is duplicate or has data. - if ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER { + if unlikely(ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER) { return error::TREE_DUPLICATE.into(); } - if ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + if unlikely(ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { return error::TREE_DATA_LEN.into(); } // Error if System Program is duplicate or has invalid data length. - if ldxb( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - ) != NON_DUP_MARKER - { + if unlikely( + ldxb( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + ) != NON_DUP_MARKER, + ) { return error::SYSTEM_PROGRAM_DUPLICATE.into(); } - if ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) - != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64 - { + if unlikely( + ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) + != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + ) { return error::SYSTEM_PROGRAM_DATA_LEN.into(); } // Error if instruction data provided. - if ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ) != misc::DATA_LEN_ZERO - { + if unlikely( + ldxdw( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + ) != misc::DATA_LEN_ZERO, + ) { return error::INSTRUCTION_DATA.into(); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 52c64997..769058c4 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,29 +1,29 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 6 | -1 | -14.3% | -| Tree account is duplicate | 9 | 9 | +0 | +0.0% | -| Tree has nonzero data length | 11 | 12 | +1 | +9.1% | +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | | System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 18 | +3 | +20.0% | -| Non-empty instruction data | 17 | 22 | +5 | +29.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Non-empty instruction data | 17 | 20 | +3 | +17.6% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units @@ -35,11 +35,11 @@ test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index e7649939..a28b71a8 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -4,6 +4,7 @@ use pinocchio::{ address::address_eq, entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, error::ProgramError, + hint::unlikely, no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, }; @@ -54,59 +55,66 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), - input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr).into(), - _ => error::N_ACCOUNTS.into(), + let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + if n_accounts == input_buffer::N_ACCOUNTS_GENERAL { + general(input_buffer_ptr) + } else if n_accounts == input_buffer::N_ACCOUNTS_INIT { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() } } // ANCHOR_END: entrypoint-branching #[inline(always)] unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { - if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) == 5 { - 1 + if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) == 67 { + 6677 } else { - 3 + 666777 } } // ANCHOR: initialize-input-checks #[inline(always)] +#[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + if unlikely(ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { return error::USER_DATA_LEN.into(); } // Error if tree is duplicate or has data. - if ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER { + if unlikely(ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER) { return error::TREE_DUPLICATE.into(); } - if ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO { + if unlikely(ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { return error::TREE_DATA_LEN.into(); } // Error if System Program is duplicate or has invalid data length. - if ldxb( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - ) != NON_DUP_MARKER - { + if unlikely( + ldxb( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + ) != NON_DUP_MARKER, + ) { return error::SYSTEM_PROGRAM_DUPLICATE.into(); } - if ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) - != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64 - { + if unlikely( + ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) + != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + ) { return error::SYSTEM_PROGRAM_DATA_LEN.into(); } // Error if instruction data provided. - if ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ) != misc::DATA_LEN_ZERO - { + if unlikely( + ldxdw( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + ) != misc::DATA_LEN_ZERO, + ) { return error::INSTRUCTION_DATA.into(); } // ANCHOR_END: initialize-input-checks From 8f409de3b006b3efc373bfa21faae93c71888f4a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:33:58 -0800 Subject: [PATCH 070/263] Add hints --- examples/tree/artifacts/dumps/asm.txt | 4 +- examples/tree/artifacts/dumps/rs.txt | 201 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 47 ++-- .../snippets/rs/entrypoint-branching.txt | 16 +- .../tests/entrypoint_branching/result.txt | 12 +- .../tests/initialize_input_checks/result.txt | 24 +-- examples/tree/src/program.rs | 18 +- 7 files changed, 158 insertions(+), 164 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index fc9bd914..8c9ee848 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -58,11 +58,11 @@ Disassembly of section .text 17 95 00 00 00 00 00 00 00 exit 18 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) 19 55 02 15 00 00 00 00 00 if r2 != 0x0 goto +0x15 <.text+0x108> - 20 71 12 68 28 00 00 00 00 w2 = *(u8 *)(r1 + 0x2868) + 20 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) 21 55 02 11 00 ff 00 00 00 if r2 != 0xff goto +0x11 <.text+0xf8> 22 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) 23 55 02 0d 00 00 00 00 00 if r2 != 0x0 goto +0xd <.text+0xe8> - 24 71 12 c8 50 00 00 00 00 w2 = *(u8 *)(r1 + 0x50c8) + 24 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) 25 55 02 09 00 ff 00 00 00 if r2 != 0xff goto +0x9 <.text+0xd8> 26 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) 27 55 02 05 00 0e 00 00 00 if r2 != 0xe goto +0x5 <.text+0xc8> diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index f2018886..a065bbad 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -9,29 +9,28 @@ ELF Header Type DYN (Shared object file) Machine Solana Bytecode Format Version 0x1 - Entry point address 0x120 + Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2824 (bytes into file) - Flags 0x2 + Start of section headers 2856 (bytes into file) + Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) - Number of program headers 3 + Number of program headers 4 Size of section headers 64 (bytes) - Number of section headers 9 - Section header string table index 7 -There are 9 section headers, starting at offset 0xb08 + Number of section headers 8 + Section header string table index 6 +There are 8 section headers, starting at offset 0xb28 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000120 000120 000118 00 AX 0 0 8 - [ 2] .dynamic DYNAMIC 0000000000000238 000238 000070 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000002a8 0002a8 000030 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000002d8 0002d8 00000c 00 A 0 0 1 - [ 5] .comment PROGBITS 0000000000000000 0002e4 00006b 01 MS 0 0 1 - [ 6] .symtab SYMTAB 0000000000000000 000350 0002e8 18 8 30 8 - [ 7] .shstrtab STRTAB 0000000000000000 000638 000043 00 0 0 1 - [ 8] .strtab STRTAB 0000000000000000 00067b 00048b 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000118 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000238 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000240 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000240 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000240 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0005b8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0005f6 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -39,110 +38,104 @@ Key to Flags R (retain), p (processor specific) Elf file type is DYN (Shared object file) -Entry point 0x120 -There are 3 program headers, starting at offset 64 +Entry point 0x0 +There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000120 0x0000000000000120 0x000118 0x000118 R E 0x1000 - LOAD 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00003c 0x00003c R 0x1000 - DYNAMIC 0x000238 0x0000000000000238 0x0000000000000238 0x000070 0x000070 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000118 0x000118 E 0x8 + LOAD 0x000238 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000240 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000240 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... 00 .text - 01 .dynsym .dynstr - 02 .dynamic - None .comment .symtab .shstrtab .strtab -Dynamic section at offset 0x238 contains 7 entries - Tag Type Name/Value - 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000006 (SYMTAB) 0x2a8 - 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x2d8 - 0x000000000000000a (STRSZ) 12 (bytes) - 0x0000000000000016 (TEXTREL) 0x0 - 0x0000000000000000 (NULL) 0x0 + 01 .rodata + 02 .bss.stack + 03 .bss.heap + None .symtab .shstrtab .strtab There are no relocations in this file. -Symbol table '.dynsym' contains 2 entries +Symbol table '.symtab' contains 37 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000120 280 FUNC GLOBAL DEFAULT 1 entrypoint - -Symbol table '.symtab' contains 31 entries - Num Value Size Type Bind Vis Ndx Name - 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.d0c49d1e43105785-cgu.0 - 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 80ibksluagh4kwnjvjamobpuj - 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.7fa3ac0a27424a8-cgu.0 - 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.1777bc652cbba5b9-cgu.0 - 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.114 - 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.164 - 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.016 - 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.167 - 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.199 - 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.200 - 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.215 - 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.218 - 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.227 - 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.238 - 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.251 - 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.259 - 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.000 - 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.247 - 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.272 - 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.273 - 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.303 - 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.318 - 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.004 - 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.325 - 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.328 - 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.336 - 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.347 - 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.1ab262a76c8ace2a-cgu.012 - 29 0000000000000238 0 NOTYPE LOCAL HIDDEN 2 _DYNAMIC - 30 0000000000000120 280 FUNC GLOBAL DEFAULT 1 entrypoint + 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 + 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl + 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 + 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 + 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 + 6 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.115 + 7 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.000 + 8 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.015 + 9 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.121 + 10 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.012 + 11 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.132 + 12 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.009 + 13 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.138 + 14 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.142 + 15 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.005 + 16 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.146 + 17 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.148 + 18 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.151 + 19 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.163 + 20 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.176 + 21 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.182 + 22 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.021 + 23 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.189 + 24 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.219 + 25 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.248 + 26 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.013 + 27 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.256 + 28 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.263 + 29 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.276 + 30 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.282 + 31 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.291 + 32 0000000200000000 0 NOTYPE LOCAL DEFAULT 3 _stack_start + 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end + 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start + 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end + 36 0000000000000000 280 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf Disassembly of section .text -0000000000000120 - 120 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 128 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 - 130 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] - 138 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 - 140 15 01 04 00 43 00 00 00 jeq r1, 0x43, +0x4 - 148 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 - 150 05 00 02 00 00 00 00 00 ja +0x2 - 158 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 160 15 02 01 00 03 00 00 00 jeq r2, 0x3, +0x1 - 168 95 00 00 00 00 00 00 00 exit - 170 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 178 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd - 180 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 188 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd - 190 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 198 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd - 1a0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 1a8 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd - 1b0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 1b8 55 02 0d 00 0e 00 00 00 jne r2, 0xe, +0xd - 1c0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1c8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - 1d0 15 01 f2 ff 00 00 00 00 jeq r1, 0x0, -0xe - 1d8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1e0 05 00 f0 ff 00 00 00 00 ja -0x10 - 1e8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 1f0 05 00 ee ff 00 00 00 00 ja -0x12 - 1f8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 200 05 00 ec ff 00 00 00 00 ja -0x14 - 208 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 210 05 00 ea ff 00 00 00 00 ja -0x16 - 218 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 220 05 00 e8 ff 00 00 00 00 ja -0x18 - 228 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 230 05 00 e6 ff 00 00 00 00 ja -0x1a \ No newline at end of file +0000000000000000 + 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 + 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 10 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 + 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] + 20 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 + 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 + 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 + 38 9d 00 00 00 00 00 00 00 return + 40 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 48 55 02 fd ff 03 00 00 00 jne r2, 0x3, -0x3 + 50 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 58 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 60 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 68 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 70 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 78 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 80 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 88 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 90 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 98 55 02 0d 00 0e 00 00 00 jne r2, 0xe, +0xd + a0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + a8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] + b0 15 01 f0 ff 00 00 00 00 jeq r1, 0x0, -0x10 + b8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + c0 05 00 ee ff 00 00 00 00 ja -0x12 + c8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + d0 05 00 ec ff 00 00 00 00 ja -0x14 + d8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + e0 05 00 ea ff 00 00 00 00 ja -0x16 + e8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + f0 05 00 e8 ff 00 00 00 00 ja -0x18 + f8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 100 05 00 e6 ff 00 00 00 00 ja -0x1a + 108 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 110 05 00 e4 ff 00 00 00 00 ja -0x1c \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 291edc16..2bd7cac3 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -5,50 +5,47 @@ entrypoint: jne r2, 2, jmp_0038 ldxdw r1, [r1+88] mov64 r0, 6677 - jeq r1, 67, jmp_0048 + jeq r1, 67, jmp_0030 mov64 r0, 666777 - ja jmp_0048 -jmp_0038: - mov64 r0, 1 - jeq r2, 3, jmp_0050 - -jmp_0048: +jmp_0030: exit -jmp_0050: +jmp_0038: + mov64 r0, 1 + jne r2, 3, jmp_0030 ldxdw r2, [r1+88] - jne r2, 0, jmp_00c8 + jne r2, 0, jmp_00c0 ldxb r2, [r1+10344] - jne r2, 255, jmp_00d8 + jne r2, 255, jmp_00d0 ldxdw r2, [r1+10424] - jne r2, 0, jmp_00e8 + jne r2, 0, jmp_00e0 ldxb r2, [r1+20680] - jne r2, 255, jmp_00f8 + jne r2, 255, jmp_00f0 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0108 + jne r2, 14, jmp_0100 mov64 r0, 0 ldxdw r1, [r1+31032] - jeq r1, 0, jmp_0048 + jeq r1, 0, jmp_0030 mov64 r0, 7 - ja jmp_0048 + ja jmp_0030 -jmp_00c8: +jmp_00c0: mov64 r0, 2 - ja jmp_0048 + ja jmp_0030 -jmp_00d8: +jmp_00d0: mov64 r0, 5 - ja jmp_0048 + ja jmp_0030 -jmp_00e8: +jmp_00e0: mov64 r0, 3 - ja jmp_0048 + ja jmp_0030 -jmp_00f8: +jmp_00f0: mov64 r0, 6 - ja jmp_0048 + ja jmp_0030 -jmp_0108: +jmp_0100: mov64 r0, 4 - ja jmp_0048 + ja jmp_0030 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index f9cb66c7..a5b2fd76 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -1,10 +1,12 @@ no_allocator!(); nostd_panic_handler!(); +#[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) } +#[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { *ptr.add(offset as usize) } @@ -12,11 +14,11 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); - if n_accounts == input_buffer::N_ACCOUNTS_GENERAL { - general(input_buffer_ptr) - } else if n_accounts == input_buffer::N_ACCOUNTS_INIT { - initialize(input_buffer_ptr) - } else { - error::N_ACCOUNTS.into() - } + if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { + return general(input_buffer_ptr); + }; + if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + return initialize(input_buffer_ptr); + }; + error::N_ACCOUNTS.into() } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 42c498f1..337304d4 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,24 +1,24 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| No accounts | 5 | 5 | +0 | +0.0% | -| One account | 5 | 5 | +0 | +0.0% | -| Four accounts | 5 | 5 | +0 | +0.0% | +| No accounts | 5 | 6 | +1 | +20.0% | +| One account | 5 | 6 | +1 | +20.0% | +| Four accounts | 5 | 6 | +1 | +20.0% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 769058c4..9c6cfc6a 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,45 +1,45 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Non-empty instruction data | 17 | 20 | +3 | +17.6% | +| User has nonzero data length | 7 | 10 | +3 | +42.9% | +| Tree account is duplicate | 9 | 12 | +3 | +33.3% | +| Tree has nonzero data length | 11 | 14 | +3 | +27.3% | +| System program is duplicate | 13 | 16 | +3 | +23.1% | +| System program wrong data length | 15 | 18 | +3 | +20.0% | +| Non-empty instruction data | 17 | 21 | +4 | +23.5% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a28b71a8..1c506298 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -4,7 +4,7 @@ use pinocchio::{ address::address_eq, entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, error::ProgramError, - hint::unlikely, + hint::{likely, unlikely}, no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, }; @@ -45,10 +45,12 @@ unsafe fn next_account_non_duplicate( no_allocator!(); nostd_panic_handler!(); +#[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) } +#[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { *ptr.add(offset as usize) } @@ -56,13 +58,13 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); - if n_accounts == input_buffer::N_ACCOUNTS_GENERAL { - general(input_buffer_ptr) - } else if n_accounts == input_buffer::N_ACCOUNTS_INIT { - initialize(input_buffer_ptr) - } else { - error::N_ACCOUNTS.into() - } + if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { + return general(input_buffer_ptr); + }; + if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + return initialize(input_buffer_ptr); + }; + error::N_ACCOUNTS.into() } // ANCHOR_END: entrypoint-branching From a47909d885c5cd7711cf5d759f12b4d21e0dd334 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:44:42 -0800 Subject: [PATCH 071/263] Add macros --- .../snippets/rs/entrypoint-branching.txt | 10 -- .../snippets/rs/initialize-input-checks.txt | 67 +++++----- examples/tree/src/program.rs | 116 ++++++++---------- 3 files changed, 88 insertions(+), 105 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index a5b2fd76..a2be295a 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -1,16 +1,6 @@ no_allocator!(); nostd_panic_handler!(); -#[inline(always)] -unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { - *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) -} - -#[inline(always)] -unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { - *ptr.add(offset as usize) -} - #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 08c8ee0a..e349f5d7 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -2,40 +2,45 @@ #[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - if unlikely(ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { - return error::USER_DATA_LEN.into(); - } + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::USER_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::USER_DATA_LEN + ); // Error if tree is duplicate or has data. - if unlikely(ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER) { - return error::TREE_DUPLICATE.into(); - } - if unlikely(ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { - return error::TREE_DATA_LEN.into(); - } + ensure_ldxb!( + input_buffer_ptr, + input_buffer::TREE_NON_DUP_MARKER_OFF, + NON_DUP_MARKER, + error::TREE_DUPLICATE + ); + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::TREE_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::TREE_DATA_LEN + ); // Error if System Program is duplicate or has invalid data length. - if unlikely( - ldxb( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - ) != NON_DUP_MARKER, - ) { - return error::SYSTEM_PROGRAM_DUPLICATE.into(); - } - if unlikely( - ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) - != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, - ) { - return error::SYSTEM_PROGRAM_DATA_LEN.into(); - } + ensure_ldxb!( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + NON_DUP_MARKER, + error::SYSTEM_PROGRAM_DUPLICATE + ); + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF, + input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + error::SYSTEM_PROGRAM_DATA_LEN + ); // Error if instruction data provided. - if unlikely( - ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ) != misc::DATA_LEN_ZERO, - ) { - return error::INSTRUCTION_DATA.into(); - } \ No newline at end of file + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::INSTRUCTION_DATA + ); \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1c506298..2efafcbf 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,52 +9,35 @@ use pinocchio::{ }; #[inline(always)] -/// Return an error code for early return at call site. -fn err(error_code: error) -> Result { - Err(ProgramError::Custom(error_code.into())) +unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { + *ptr.add(offset as usize) } -#[inline(always)] -/// Ensure a condition is met else return error code for early return at call site. -fn ensure(condition: bool, error_code: error) -> Result<(), ProgramError> { - if condition { - Ok(()) - } else { - err(error_code) - } +macro_rules! ensure_ldxb { + ($ptr:expr, $offset:expr, $expected:expr, $error:expr) => { + if unlikely(ldxb($ptr, $offset) != $expected) { + return $error.into(); + } + }; } #[inline(always)] -/// Ensure an account has empty data else return error code for early return at call site. -fn ensure_is_data_empty(account: &AccountView, error_code: error) -> Result<(), ProgramError> { - ensure(account.is_data_empty(), error_code) +unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { + *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) } -#[inline(always)] -unsafe fn next_account_non_duplicate( - context: &mut InstructionContext, - error_code: error, -) -> Result { - match unsafe { context.next_account_unchecked() } { - MaybeAccount::Account(account) => Ok(account), - MaybeAccount::Duplicated(_) => err(error_code), - } +macro_rules! ensure_ldxdw { + ($ptr:expr, $offset:expr, $expected:expr, $error:expr) => { + if unlikely(ldxdw($ptr, $offset) != $expected) { + return $error.into(); + } + }; } // ANCHOR: entrypoint-branching no_allocator!(); nostd_panic_handler!(); -#[inline(always)] -unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { - *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) -} - -#[inline(always)] -unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { - *ptr.add(offset as usize) -} - #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); @@ -82,43 +65,48 @@ unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { #[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - if unlikely(ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { - return error::USER_DATA_LEN.into(); - } + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::USER_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::USER_DATA_LEN + ); // Error if tree is duplicate or has data. - if unlikely(ldxb(input_buffer_ptr, input_buffer::TREE_NON_DUP_MARKER_OFF) != NON_DUP_MARKER) { - return error::TREE_DUPLICATE.into(); - } - if unlikely(ldxdw(input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF) != misc::DATA_LEN_ZERO) { - return error::TREE_DATA_LEN.into(); - } + ensure_ldxb!( + input_buffer_ptr, + input_buffer::TREE_NON_DUP_MARKER_OFF, + NON_DUP_MARKER, + error::TREE_DUPLICATE + ); + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::TREE_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::TREE_DATA_LEN + ); // Error if System Program is duplicate or has invalid data length. - if unlikely( - ldxb( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - ) != NON_DUP_MARKER, - ) { - return error::SYSTEM_PROGRAM_DUPLICATE.into(); - } - if unlikely( - ldxdw(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF) - != input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, - ) { - return error::SYSTEM_PROGRAM_DATA_LEN.into(); - } + ensure_ldxb!( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, + NON_DUP_MARKER, + error::SYSTEM_PROGRAM_DUPLICATE + ); + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF, + input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + error::SYSTEM_PROGRAM_DATA_LEN + ); // Error if instruction data provided. - if unlikely( - ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ) != misc::DATA_LEN_ZERO, - ) { - return error::INSTRUCTION_DATA.into(); - } + ensure_ldxdw!( + input_buffer_ptr, + input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, + misc::DATA_LEN_ZERO, + error::INSTRUCTION_DATA + ); // ANCHOR_END: initialize-input-checks SUCCESS From 5d6f4bce4625a01444f6869c6e116b1db155cdcb Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:51:08 -0800 Subject: [PATCH 072/263] Pin match --- .../artifacts/snippets/rs/entrypoint-branching.txt | 10 +++++----- examples/tree/src/program.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index a2be295a..aa7afe8d 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -6,9 +6,9 @@ pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { return general(input_buffer_ptr); - }; - if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - return initialize(input_buffer_ptr); - }; - error::N_ACCOUNTS.into() + } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() + } } \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2efafcbf..f84901af 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -43,11 +43,11 @@ pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { return general(input_buffer_ptr); - }; - if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - return initialize(input_buffer_ptr); - }; - error::N_ACCOUNTS.into() + } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() + } } // ANCHOR_END: entrypoint-branching From f25eb80e7467583a7c2143b5913bd9d8a70fa817 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:55:30 -0800 Subject: [PATCH 073/263] Update match --- examples/tree/artifacts/dumps/rs.txt | 81 ++++++++++--------- examples/tree/artifacts/rs-disassembly.s | 36 ++++----- .../snippets/rs/entrypoint-branching.txt | 11 +-- .../tests/initialize_input_checks/result.txt | 24 +++--- examples/tree/src/program.rs | 11 +-- 5 files changed, 79 insertions(+), 84 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index a065bbad..20530db4 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2856 (bytes into file) + Start of section headers 2864 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xb28 +There are 8 section headers, starting at offset 0xb30 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000118 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000238 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000240 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000240 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000240 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0005b8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0005f6 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000120 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000240 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000248 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000248 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000248 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0005c0 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0005fe 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000118 0x000118 E 0x8 - LOAD 0x000238 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000240 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000240 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000120 0x000120 E 0x8 + LOAD 0x000240 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000248 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000248 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 280 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 288 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -106,36 +106,37 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 10 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 - 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] - 20 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 - 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 - 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 - 38 9d 00 00 00 00 00 00 00 return - 40 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 48 55 02 fd ff 03 00 00 00 jne r2, 0x3, -0x3 + 10 15 02 07 00 03 00 00 00 jeq r2, 0x3, +0x7 + 18 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 20 55 02 12 00 02 00 00 00 jne r2, 0x2, +0x12 + 28 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] + 30 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 + 38 15 01 0f 00 43 00 00 00 jeq r1, 0x43, +0xf + 40 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 + 48 05 00 0d 00 00 00 00 00 ja +0xd 50 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 58 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 58 55 02 0c 00 00 00 00 00 jne r2, 0x0, +0xc 60 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 68 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 68 55 02 0c 00 ff 00 00 00 jne r2, 0xff, +0xc 70 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 78 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 78 55 02 0c 00 00 00 00 00 jne r2, 0x0, +0xc 80 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 88 55 02 0d 00 ff 00 00 00 jne r2, 0xff, +0xd + 88 55 02 0c 00 ff 00 00 00 jne r2, 0xff, +0xc 90 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 98 55 02 0d 00 0e 00 00 00 jne r2, 0xe, +0xd + 98 55 02 0c 00 0e 00 00 00 jne r2, 0xe, +0xc a0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 a8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - b0 15 01 f0 ff 00 00 00 00 jeq r1, 0x0, -0x10 - b8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - c0 05 00 ee ff 00 00 00 00 ja -0x12 - c8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - d0 05 00 ec ff 00 00 00 00 ja -0x14 - d8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - e0 05 00 ea ff 00 00 00 00 ja -0x16 - e8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - f0 05 00 e8 ff 00 00 00 00 ja -0x18 - f8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 100 05 00 e6 ff 00 00 00 00 ja -0x1a - 108 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 110 05 00 e4 ff 00 00 00 00 ja -0x1c \ No newline at end of file + b0 55 01 0b 00 00 00 00 00 jne r1, 0x0, +0xb + b8 9d 00 00 00 00 00 00 00 return + c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + c8 05 00 fd ff 00 00 00 00 ja -0x3 + d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + d8 05 00 fb ff 00 00 00 00 ja -0x5 + e0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + e8 05 00 f9 ff 00 00 00 00 ja -0x7 + f0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + f8 05 00 f7 ff 00 00 00 00 ja -0x9 + 100 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 108 05 00 f5 ff 00 00 00 00 ja -0xb + 110 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 118 05 00 f3 ff 00 00 00 00 ja -0xd \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 2bd7cac3..ff1015b9 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,18 +2,9 @@ entrypoint: ldxdw r2, [r1+0] - jne r2, 2, jmp_0038 - ldxdw r1, [r1+88] - mov64 r0, 6677 - jeq r1, 67, jmp_0030 - mov64 r0, 666777 - -jmp_0030: - exit - -jmp_0038: + jeq r2, 2, jmp_0098 mov64 r0, 1 - jne r2, 3, jmp_0030 + jne r2, 3, jmp_00b8 ldxdw r2, [r1+88] jne r2, 0, jmp_00c0 ldxb r2, [r1+10344] @@ -26,26 +17,35 @@ jmp_0038: jne r2, 14, jmp_0100 mov64 r0, 0 ldxdw r1, [r1+31032] - jeq r1, 0, jmp_0030 + jeq r1, 0, jmp_00b8 mov64 r0, 7 - ja jmp_0030 + ja jmp_00b8 + +jmp_0098: + ldxdw r1, [r1+88] + mov64 r0, 6677 + jeq r1, 67, jmp_00b8 + mov64 r0, 666777 + +jmp_00b8: + exit jmp_00c0: mov64 r0, 2 - ja jmp_0030 + ja jmp_00b8 jmp_00d0: mov64 r0, 5 - ja jmp_0030 + ja jmp_00b8 jmp_00e0: mov64 r0, 3 - ja jmp_0030 + ja jmp_00b8 jmp_00f0: mov64 r0, 6 - ja jmp_0030 + ja jmp_00b8 jmp_0100: mov64 r0, 4 - ja jmp_0030 + ja jmp_00b8 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index aa7afe8d..82f53a4d 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -3,12 +3,9 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); - if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - return general(input_buffer_ptr); - } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr) - } else { - error::N_ACCOUNTS.into() + match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { + input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), + input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr), + _ => error::N_ACCOUNTS.into(), } } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 9c6cfc6a..e97fedbb 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,45 +1,45 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 10 | +3 | +42.9% | -| Tree account is duplicate | 9 | 12 | +3 | +33.3% | -| Tree has nonzero data length | 11 | 14 | +3 | +27.3% | -| System program is duplicate | 13 | 16 | +3 | +23.1% | -| System program wrong data length | 15 | 18 | +3 | +20.0% | -| Non-empty instruction data | 17 | 21 | +4 | +23.5% | +| User has nonzero data length | 7 | 8 | +1 | +14.3% | +| Tree account is duplicate | 9 | 10 | +1 | +11.1% | +| Tree has nonzero data length | 11 | 12 | +1 | +9.1% | +| System program is duplicate | 13 | 14 | +1 | +7.7% | +| System program wrong data length | 15 | 16 | +1 | +6.7% | +| Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index f84901af..50d44335 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -40,13 +40,10 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); - if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - return general(input_buffer_ptr); - } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr) - } else { - error::N_ACCOUNTS.into() + match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { + input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), + input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr), + _ => error::N_ACCOUNTS.into(), } } // ANCHOR_END: entrypoint-branching From adc4294a6b18b572de6ce7cb4b49e9329699fac5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 5 Feb 2026 18:20:46 -0800 Subject: [PATCH 074/263] Tie off versioning --- examples/tree/artifacts/dumps/rs.txt | 66 +++++++++---------- examples/tree/artifacts/rs-disassembly.s | 59 +++++++++-------- .../snippets/rs/entrypoint-branching.txt | 11 ++-- .../snippets/rs/initialize-input-checks.txt | 1 - .../tests/entrypoint_branching/result.txt | 12 ++-- .../tests/initialize_input_checks/result.txt | 24 +++---- examples/tree/src/program.rs | 12 ++-- 7 files changed, 96 insertions(+), 89 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 20530db4..164aeb65 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -106,37 +106,37 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 10 15 02 07 00 03 00 00 00 jeq r2, 0x3, +0x7 - 18 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 20 55 02 12 00 02 00 00 00 jne r2, 0x2, +0x12 - 28 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] - 30 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 - 38 15 01 0f 00 43 00 00 00 jeq r1, 0x43, +0xf - 40 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 - 48 05 00 0d 00 00 00 00 00 ja +0xd - 50 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 58 55 02 0c 00 00 00 00 00 jne r2, 0x0, +0xc - 60 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 68 55 02 0c 00 ff 00 00 00 jne r2, 0xff, +0xc - 70 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 78 55 02 0c 00 00 00 00 00 jne r2, 0x0, +0xc - 80 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 88 55 02 0c 00 ff 00 00 00 jne r2, 0xff, +0xc - 90 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 98 55 02 0c 00 0e 00 00 00 jne r2, 0xe, +0xc - a0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - a8 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - b0 55 01 0b 00 00 00 00 00 jne r1, 0x0, +0xb - b8 9d 00 00 00 00 00 00 00 return + 10 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 + 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] + 20 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 + 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 + 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 + 38 9d 00 00 00 00 00 00 00 return + 40 55 02 11 00 03 00 00 00 jne r2, 0x3, +0x11 + 48 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 50 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 60 55 02 0f 00 ff 00 00 00 jne r2, 0xff, +0xf + 68 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 70 55 02 0f 00 00 00 00 00 jne r2, 0x0, +0xf + 78 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 80 55 02 0f 00 ff 00 00 00 jne r2, 0xff, +0xf + 88 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 90 55 02 0f 00 0e 00 00 00 jne r2, 0xe, +0xf + 98 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + a0 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] + a8 15 01 f1 ff 00 00 00 00 jeq r1, 0x0, -0xf + b0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + b8 05 00 ef ff 00 00 00 00 ja -0x11 c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c8 05 00 fd ff 00 00 00 00 ja -0x3 - d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - d8 05 00 fb ff 00 00 00 00 ja -0x5 - e0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - e8 05 00 f9 ff 00 00 00 00 ja -0x7 - f0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - f8 05 00 f7 ff 00 00 00 00 ja -0x9 - 100 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 108 05 00 f5 ff 00 00 00 00 ja -0xb - 110 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 118 05 00 f3 ff 00 00 00 00 ja -0xd \ No newline at end of file + c8 05 00 ed ff 00 00 00 00 ja -0x13 + d0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + d8 05 00 eb ff 00 00 00 00 ja -0x15 + e0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + e8 05 00 e9 ff 00 00 00 00 ja -0x17 + f0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + f8 05 00 e7 ff 00 00 00 00 ja -0x19 + 100 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 108 05 00 e5 ff 00 00 00 00 ja -0x1b + 110 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 118 05 00 e3 ff 00 00 00 00 ja -0x1d \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index ff1015b9..98bafd5a 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,50 +2,53 @@ entrypoint: ldxdw r2, [r1+0] - jeq r2, 2, jmp_0098 - mov64 r0, 1 - jne r2, 3, jmp_00b8 + jne r2, 2, jmp_0038 + ldxdw r1, [r1+88] + mov64 r0, 6677 + jeq r1, 67, jmp_0030 + mov64 r0, 666777 + +jmp_0030: + exit + +jmp_0038: + jne r2, 3, jmp_00c8 ldxdw r2, [r1+88] - jne r2, 0, jmp_00c0 + jne r2, 0, jmp_00b8 ldxb r2, [r1+10344] - jne r2, 255, jmp_00d0 + jne r2, 255, jmp_00d8 ldxdw r2, [r1+10424] - jne r2, 0, jmp_00e0 + jne r2, 0, jmp_00e8 ldxb r2, [r1+20680] - jne r2, 255, jmp_00f0 + jne r2, 255, jmp_00f8 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0100 + jne r2, 14, jmp_0108 mov64 r0, 0 ldxdw r1, [r1+31032] - jeq r1, 0, jmp_00b8 + jeq r1, 0, jmp_0030 mov64 r0, 7 - ja jmp_00b8 - -jmp_0098: - ldxdw r1, [r1+88] - mov64 r0, 6677 - jeq r1, 67, jmp_00b8 - mov64 r0, 666777 + ja jmp_0030 jmp_00b8: - exit - -jmp_00c0: mov64 r0, 2 - ja jmp_00b8 + ja jmp_0030 + +jmp_00c8: + mov64 r0, 1 + ja jmp_0030 -jmp_00d0: +jmp_00d8: mov64 r0, 5 - ja jmp_00b8 + ja jmp_0030 -jmp_00e0: +jmp_00e8: mov64 r0, 3 - ja jmp_00b8 + ja jmp_0030 -jmp_00f0: +jmp_00f8: mov64 r0, 6 - ja jmp_00b8 + ja jmp_0030 -jmp_0100: +jmp_0108: mov64 r0, 4 - ja jmp_00b8 + ja jmp_0030 diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 82f53a4d..879dd8b5 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -3,9 +3,12 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), - input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr), - _ => error::N_ACCOUNTS.into(), + let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { + general(input_buffer_ptr) + } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() } } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index e349f5d7..0d778b00 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,5 +1,4 @@ #[inline(always)] -#[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. ensure_ldxdw!( diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 337304d4..b36b9ca3 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,24 +1,24 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| No accounts | 5 | 6 | +1 | +20.0% | -| One account | 5 | 6 | +1 | +20.0% | -| Four accounts | 5 | 6 | +1 | +20.0% | +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index e97fedbb..769058c4 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,45 +1,45 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 8 | +1 | +14.3% | -| Tree account is duplicate | 9 | 10 | +1 | +11.1% | -| Tree has nonzero data length | 11 | 12 | +1 | +9.1% | -| System program is duplicate | 13 | 14 | +1 | +7.7% | -| System program wrong data length | 15 | 16 | +1 | +6.7% | -| Non-empty instruction data | 17 | 19 | +2 | +11.8% | +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Non-empty instruction data | 17 | 20 | +3 | +17.6% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 50d44335..1cec5e0b 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -40,10 +40,13 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { - match ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF) { - input_buffer::N_ACCOUNTS_GENERAL => general(input_buffer_ptr), - input_buffer::N_ACCOUNTS_INIT => initialize(input_buffer_ptr), - _ => error::N_ACCOUNTS.into(), + let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { + general(input_buffer_ptr) + } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { + initialize(input_buffer_ptr) + } else { + error::N_ACCOUNTS.into() } } // ANCHOR_END: entrypoint-branching @@ -59,7 +62,6 @@ unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { // ANCHOR: initialize-input-checks #[inline(always)] -#[cold] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. ensure_ldxdw!( From c42e7206863a1ab0eddb774039870458732576ad Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:02:24 -0800 Subject: [PATCH 075/263] Begin stack frame layout --- examples/tree/interface/src/common.rs | 12 ++++++++++++ examples/tree/src/tree/tree.s | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index c1084e01..cd83490d 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -37,6 +37,18 @@ constant_group! { } } +constant_group! { + /// CPI-specific constants. + cpi { + /// User and tree accounts must sign CPI. + CPI_N_ACCOUNTS: usize = 2, + /// The tree account is a PDA. + CPI_N_PDA_SIGNERS: usize = 1, + /// The bump seed is required for tree PDA signer. + CPI_N_SEEDS: usize = 1, + } +} + constant_group! { /// Miscellaneous constants. misc { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d577bf54..caafda7a 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -93,6 +93,10 @@ initialize: jne r2, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks + # Initialize signer seed for PDA bump key. + # ---------------------------------------- + mov64 r2, r10 # Get stack frame pointer. + exit e_instruction_data: From c589a94d0e559f0d6a24a620731dd32ba9481fc3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:07:06 -0800 Subject: [PATCH 076/263] Add stack definitions --- examples/tree/interface/src/asm.rs | 20 ++++++++++++++++++-- examples/tree/interface/src/common.rs | 15 ++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 86e99333..df7d0826 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,8 +1,9 @@ extern crate alloc; -use crate::common::{InitInputBuffer, InputBufferHeader}; +use crate::bindings; +use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; use macros::extend_constant_group; -use pinocchio::entrypoint::NON_DUP_MARKER; +use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; extend_constant_group!(input_buffer { prefix = "IB", @@ -32,3 +33,18 @@ extend_constant_group!(misc { /// Maximum possible data length padding. MAX_DATA_PAD = 7, }); + +#[repr(C)] +struct InitStackFrame { + /// Zero-initialized on stack. + system_program_address: Address, + instruction: bindings::SolInstruction, + account_metas: [bindings::SolAccountMeta; cpi::N_ACCOUNTS], + account_infos: [bindings::SolAccountInfo; cpi::N_ACCOUNTS], + signers_seeds: [bindings::SolSignerSeeds; cpi::N_PDA_SIGNERS], + signer_seeds: [bindings::SolSignerSeed; cpi::N_SEEDS], + pda: Address, + rent: Rent, + instruction_data: CreateAccountInstructionData, + bump_seed: u8, +} diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index cd83490d..d8a52d8f 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -41,14 +41,23 @@ constant_group! { /// CPI-specific constants. cpi { /// User and tree accounts must sign CPI. - CPI_N_ACCOUNTS: usize = 2, + N_ACCOUNTS: usize = 2, /// The tree account is a PDA. - CPI_N_PDA_SIGNERS: usize = 1, + N_PDA_SIGNERS: usize = 1, /// The bump seed is required for tree PDA signer. - CPI_N_SEEDS: usize = 1, + N_SEEDS: usize = 1, } } +#[repr(C, packed)] +/// For CPI to create tree account. +pub struct CreateAccountInstructionData { + instruction_tag: u32, + lamports: u64, + space: u64, + owner: Address, +} + constant_group! { /// Miscellaneous constants. misc { From aa3a41697f305c1dc98ef39374c5edf9783573c3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:57:18 -0800 Subject: [PATCH 077/263] Add macros --- .../tree/artifacts/snippets/asm/constants.txt | 18 +- examples/tree/build.rs | 2 +- examples/tree/interface/src/asm.rs | 40 +- examples/tree/macros/src/lib.rs | 498 ++++++++++++++++-- examples/tree/src/tree/tree.s | 16 + 5 files changed, 536 insertions(+), 38 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 318ad1b8..fefc6869 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -41,4 +41,20 @@ .equ DATA_LEN_ZERO, 0 # Data length of zero. .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. \ No newline at end of file +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ SIZE_OF_U_8, 1 # Foo. + +# Init stack frame layout. +# ------------------------ +.equ SF_SYSTEM_PROGRAM_ADDRESS_OFF, -360 # System program address. +.equ SF_INSTRUCTION_OFF, -328 # CPI instruction. +.equ SF_ACCOUNT_META_0_OFF, -288 # First account meta. +.equ SF_ACCOUNT_META_1_OFF, -272 # Second account meta. +.equ SF_ACCOUNT_INFO_0_OFF, -256 # First account info. +.equ SF_ACCOUNT_INFO_1_OFF, -200 # Second account info. +.equ SF_SIGNERS_SEEDS_OFF, -144 # Signer seeds array. +.equ SF_SIGNER_SEEDS_OFF, -128 # Signer seed entry. +.equ SF_PDA_OFF, -112 # PDA address. +.equ SF_RENT_OFF, -80 # Rent sysvar. +.equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. +.equ SF_BUMP_SEED_OFF, -8 # Bump seed. \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index e329cd9f..401d8a2a 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -12,7 +12,7 @@ macro_rules! asm_groups { fn main() { // Collect all constant groups. - let groups = asm_groups![error_codes, input_buffer, misc]; + let groups = asm_groups![error_codes, input_buffer, misc, init_stack_frame]; // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index df7d0826..1058f5ae 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -2,7 +2,7 @@ extern crate alloc; use crate::bindings; use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::extend_constant_group; +use macros::{asm_constant_group, extend_constant_group, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; extend_constant_group!(input_buffer { @@ -32,9 +32,11 @@ extend_constant_group!(misc { DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. MAX_DATA_PAD = 7, + /// Foo. + size_of!(u8), }); -#[repr(C)] +#[stack_frame] struct InitStackFrame { /// Zero-initialized on stack. system_program_address: Address, @@ -46,5 +48,39 @@ struct InitStackFrame { pda: Address, rent: Rent, instruction_data: CreateAccountInstructionData, + /// Padding for alignment. + _pad: [u8; 4], bump_seed: u8, } + +asm_constant_group! { + /// Init stack frame layout. + init_stack_frame { + prefix = "SF", + align = misc::BPF_ALIGN_OF_U128, + /// System program address. + stack_frame_offset!(SYSTEM_PROGRAM_ADDRESS, InitStackFrame.system_program_address), + /// CPI instruction. + stack_frame_offset!(INSTRUCTION, InitStackFrame.instruction), + /// First account meta. + stack_frame_offset!(ACCOUNT_META_0, InitStackFrame.account_metas[0]), + /// Second account meta. + stack_frame_offset!(ACCOUNT_META_1, InitStackFrame.account_metas[1]), + /// First account info. + stack_frame_offset!(ACCOUNT_INFO_0, InitStackFrame.account_infos[0]), + /// Second account info. + stack_frame_offset!(ACCOUNT_INFO_1, InitStackFrame.account_infos[1]), + /// Signer seeds array. + stack_frame_offset!(SIGNERS_SEEDS, InitStackFrame.signers_seeds), + /// Signer seed entry. + stack_frame_offset!(SIGNER_SEEDS, InitStackFrame.signer_seeds), + /// PDA address. + stack_frame_offset!(PDA, InitStackFrame.pda), + /// Rent sysvar. + stack_frame_offset!(RENT, InitStackFrame.rent), + /// Instruction data. + stack_frame_offset!(INSTRUCTION_DATA, InitStackFrame.instruction_data), + /// Bump seed. + stack_frame_offset!(BUMP_SEED, InitStackFrame.bump_seed), + } +} diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 738efb01..8bec3161 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -1,7 +1,8 @@ +use convert_case::{Case, Casing}; use proc_macro::TokenStream; use quote::quote; use syn::{ - braced, + braced, bracketed, parse::{discouraged::Speculative, Parse, ParseStream}, parse_macro_input, Ident, Lit, LitInt, Meta, Token, }; @@ -191,6 +192,28 @@ enum ConstantKind { struct_name: Ident, field_path: Vec, }, + /// Negative offset from end of a stack frame struct (i16 validated). + /// Computed as `offset_of!(Struct, field) - size_of::()`. + /// Name gets `_OFF` suffix appended. + /// Array element types are resolved via the `___fields` companion module + /// generated by `#[stack_frame]`. + StackFrameOffset { + struct_name: Ident, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, + }, +} + +/// Array index info for stack frame offset computation. +/// Supports expression indices (e.g., `CpiAccountIndex::User`) and +/// optional inner field access (e.g., `.is_writable`). +struct ArrayIndexInfo { + /// The array field name on the struct (for type alias lookup). + array_field_name: Ident, + /// The index expression (e.g., `0`, `CpiAccountIndex::User`). + index_expr: syn::Expr, + /// Optional inner field path after the array index (e.g., `is_writable`). + inner_field_path: Option, } struct ConstantDef { @@ -264,6 +287,26 @@ impl Parse for ConstantGroup { field_path, }, ) + } else if ident == "stack_frame_offset" { + // stack_frame_offset!(NAME, Struct.field) + // stack_frame_offset!(NAME, Struct.field[expr]) + // stack_frame_offset!(NAME, Struct.field[expr].inner_field) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let parsed = parse_stack_frame_field_path(&inner)?; + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + ( + full_name, + ConstantKind::StackFrameOffset { + struct_name, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, + }, + ) } else if content.peek(Token![:]) { // NAME: type = value content.parse::()?; @@ -438,6 +481,22 @@ pub fn constant_group(input: TokenStream) -> TokenStream { ); }); } + ConstantKind::StackFrameOffset { + struct_name, + field_path_tokens, + array_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + &None, // constant_group! does not support align + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } } } @@ -519,6 +578,21 @@ enum AsmConstantKind { struct_name: Ident, field_path: Vec, }, + /// Negative offset from end of a stack frame struct (i16 validated). + /// Computed as `offset_of!(Struct, field) - size_of::()`. + /// Name gets `_OFF` suffix appended. + /// Array element types are resolved via the `___fields` companion module + /// generated by `#[stack_frame]`. + StackFrameOffset { + struct_name: Ident, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, + }, + /// Size of a type (i64, validated for i32 range). + /// Name is auto-generated as `SIZE_OF_`. + SizeOf { + type_path: syn::Type, + }, } /// Input for asm_constant_group! macro. @@ -526,9 +600,154 @@ struct AsmConstantGroupInput { doc: String, name: Ident, prefix: Option, + align: Option, constants: Vec, } +/// Parse a dot-separated field path for `offset_of!`. +/// +/// Expects tokens like `.field` or `.field1.field2.field3`. +/// Returns a `TokenStream` suitable for use inside `offset_of!(Type, )`. +fn parse_field_path(inner: ParseStream) -> syn::Result { + let mut tokens = proc_macro2::TokenStream::new(); + let mut has_field = false; + + while inner.peek(Token![.]) { + inner.parse::()?; + let field: Ident = inner.parse()?; + if has_field { + tokens.extend(quote! { . #field }); + } else { + tokens.extend(quote! { #field }); + has_field = true; + } + } + + if !has_field { + return Err(inner.error("Expected at least one field in path")); + } + + Ok(tokens) +} + +/// Result of parsing a stack frame field path. +struct StackFrameFieldPath { + /// Token stream for `offset_of!(Struct, )` (fields before any bracket). + field_path_tokens: proc_macro2::TokenStream, + /// Optional array index info (bracket expression, inner field access). + array_index: Option, +} + +/// Parse a stack frame field path with optional array indexing and inner field access. +/// +/// Supports: +/// - `Struct.field` → simple field access +/// - `Struct.field[expr]` → array element access +/// - `Struct.field[expr].inner` → array element + inner field access +/// - `Struct.a.b.c` → nested field access (no array) +/// +/// Array element types are resolved via `___fields::` type aliases +/// generated by `#[stack_frame]`, so the element type is not required in the syntax. +fn parse_stack_frame_field_path(inner: ParseStream) -> syn::Result { + let mut fields: Vec = Vec::new(); + let mut tokens = proc_macro2::TokenStream::new(); + + // Parse dot-separated field segments until we hit a bracket or end. + while inner.peek(Token![.]) { + inner.parse::()?; + let field: Ident = inner.parse()?; + + if !fields.is_empty() { + tokens.extend(quote! { . }); + } + tokens.extend(quote! { #field }); + fields.push(field); + + // Check for array index after this field. + if inner.peek(syn::token::Bracket) { + let bracket_content; + bracketed!(bracket_content in inner); + let index_expr: syn::Expr = bracket_content.parse()?; + + // Parse optional inner field path. + let inner_field_path = if inner.peek(Token![.]) { + Some(parse_field_path(inner)?) + } else { + None + }; + + let array_field_name = fields.last().unwrap().clone(); + + return Ok(StackFrameFieldPath { + field_path_tokens: tokens, + array_index: Some(ArrayIndexInfo { + array_field_name, + index_expr, + inner_field_path, + }), + }); + } + } + + if fields.is_empty() { + return Err(inner.error("Expected at least one field in path")); + } + + Ok(StackFrameFieldPath { + field_path_tokens: tokens, + array_index: None, + }) +} + +/// Extract the last path segment name from a type (for auto-generating constant names). +fn extract_type_name(ty: &syn::Type) -> Option { + if let syn::Type::Path(type_path) = ty { + type_path + .path + .segments + .last() + .map(|seg| seg.ident.to_string()) + } else { + None + } +} + +/// Parse optional `prefix = "..."` and `align = expr` group header parameters. +/// +/// Both are optional and can appear in any order before the first constant definition. +fn parse_group_params(content: ParseStream) -> syn::Result<(Option, Option)> { + let mut prefix = None; + let mut align = None; + + // Parse header parameters (prefix and align) before constants. + loop { + if !content.peek(Ident) { + break; + } + let fork = content.fork(); + let ident: Ident = fork.parse()?; + if (ident == "prefix" || ident == "align") && fork.peek(Token![=]) { + // Advance the actual stream. + content.parse::()?; + content.parse::()?; + + if ident == "prefix" { + let prefix_lit: syn::LitStr = content.parse()?; + prefix = Some(prefix_lit.value()); + } else { + let align_expr: syn::Expr = content.parse()?; + align = Some(align_expr); + } + + content.parse::()?; + } else { + break; + } + } + + Ok((prefix, align)) +} + /// Parse ASM constants (shared between asm_constant_group! and extend_constant_group!). fn parse_asm_constants(content: ParseStream) -> syn::Result> { let mut constants = Vec::new(); @@ -571,6 +790,39 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> field_path, }, ) + } else if ident == "stack_frame_offset" { + // stack_frame_offset!(NAME, Struct.field) + // stack_frame_offset!(NAME, Struct.field[expr]) + // stack_frame_offset!(NAME, Struct.field[expr].inner_field) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let parsed = parse_stack_frame_field_path(&inner)?; + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + ( + full_name, + AsmConstantKind::StackFrameOffset { + struct_name, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, + }, + ) + } else if ident == "size_of" { + // size_of!(Type) - auto-generates SIZE_OF_. + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let type_path: syn::Type = inner.parse()?; + + let type_name = extract_type_name(&type_path) + .ok_or_else(|| content.error("Expected a type path for size_of!"))?; + let screaming = type_name.to_case(Case::UpperSnake); + let const_name = + Ident::new(&format!("SIZE_OF_{}", screaming), ident.span()); + (const_name, AsmConstantKind::SizeOf { type_path }) } else { // Regular NAME = value syntax. content.parse::()?; @@ -619,23 +871,8 @@ impl Parse for AsmConstantGroupInput { let content; braced!(content in input); - // Parse optional prefix = "..." - let prefix = if content.peek(Ident) { - let fork = content.fork(); - let ident: Ident = fork.parse()?; - if ident == "prefix" && fork.peek(Token![=]) { - // Advance the actual stream. - content.parse::()?; - content.parse::()?; - let prefix_lit: syn::LitStr = content.parse()?; - content.parse::()?; - Some(prefix_lit.value()) - } else { - None - } - } else { - None - }; + // Parse optional header parameters: prefix = "...", align = expr + let (prefix, align) = parse_group_params(&content)?; // Parse constants. let constants = parse_asm_constants(&content)?; @@ -649,11 +886,104 @@ impl Parse for AsmConstantGroupInput { doc, name, prefix, + align, constants, }) } } +/// Generate code for a `stack_frame_offset!` constant. +/// +/// Returns `(const_def_tokens, literal_repr)` where literal_repr is always `None` +/// (offsets are always computed). +fn gen_stack_frame_offset_code( + name: &Ident, + doc: &str, + struct_name: &Ident, + field_path_tokens: &proc_macro2::TokenStream, + array_index: &Option, + align: &Option, +) -> (proc_macro2::TokenStream, Option) { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); + + let offset_expr = match array_index { + Some(info) => { + let array_field_name = &info.array_field_name; + let index_expr = &info.index_expr; + let inner_offset = match &info.inner_field_path { + Some(path) => quote! { + + core::mem::offset_of!(#fields_mod::#array_field_name, #path) as i64 + }, + None => quote! {}, + }; + quote! { + core::mem::offset_of!(#struct_name, #field_path_tokens) as i64 + + (#index_expr) as i64 * core::mem::size_of::<#fields_mod::#array_field_name>() as i64 + #inner_offset + } + } + None => quote! { + core::mem::offset_of!(#struct_name, #field_path_tokens) as i64 + }, + }; + + let align_assertion = match align { + Some(align_expr) => quote! { + assert!( + result % (#align_expr as i64) == 0, + "Stack frame offset must be aligned" + ); + }, + None => quote! {}, + }; + + let const_def = quote! { + #[doc = #doc] + pub const #name: i16 = { + use super::*; + (#offset_expr - core::mem::size_of::<#struct_name>() as i64) as i16 + }; + + const #assert_name: () = { + use super::*; + let result = #offset_expr - core::mem::size_of::<#struct_name>() as i64; + assert!( + result >= (i16::MIN as i64) && result <= (i16::MAX as i64), + "Stack frame offset must fit in i16" + ); + assert!(result < 0, "Stack frame offset must be negative"); + #align_assertion + }; + }; + + (const_def, None) +} + +/// Generate code for a `size_of!` constant. +/// +/// Returns `(const_def_tokens, literal_repr)` where literal_repr is always `None`. +fn gen_size_of_code( + name: &Ident, + doc: &str, + type_path: &syn::Type, +) -> (proc_macro2::TokenStream, Option) { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + + let const_def = quote! { + #[doc = #doc] + pub const #name: i64 = { use super::*; core::mem::size_of::<#type_path>() as i64 }; + + const #assert_name: () = assert!( + ({ use super::*; core::mem::size_of::<#type_path>() } as i64) >= (i32::MIN as i64) + && ({ use super::*; core::mem::size_of::<#type_path>() } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }; + + (const_def, None) +} + /// Macro for defining ASM-only constant groups. /// /// Constants don't need types - values are `i64`, offsets are `i16`. @@ -747,6 +1077,27 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { ); }); } + AsmConstantKind::StackFrameOffset { + struct_name, + field_path_tokens, + array_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + &input.align, + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } + AsmConstantKind::SizeOf { type_path } => { + let (const_def, literal_repr) = gen_size_of_code(name, doc, type_path); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } } } @@ -812,6 +1163,7 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { struct ExtendConstantGroupInput { name: Ident, prefix: Option, + align: Option, constants: Vec, } @@ -824,22 +1176,8 @@ impl Parse for ExtendConstantGroupInput { let content; braced!(content in input); - // Parse optional prefix = "..." - let prefix = if content.peek(Ident) { - let fork = content.fork(); - let ident: Ident = fork.parse()?; - if ident == "prefix" && fork.peek(Token![=]) { - content.parse::()?; - content.parse::()?; - let prefix_lit: syn::LitStr = content.parse()?; - content.parse::()?; - Some(prefix_lit.value()) - } else { - None - } - } else { - None - }; + // Parse optional header parameters: prefix = "...", align = expr + let (prefix, align) = parse_group_params(&content)?; // Parse constants using shared parser. let constants = parse_asm_constants(&content)?; @@ -847,6 +1185,7 @@ impl Parse for ExtendConstantGroupInput { Ok(ExtendConstantGroupInput { name, prefix, + align, constants, }) } @@ -943,6 +1282,27 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { ); }); } + AsmConstantKind::StackFrameOffset { + struct_name, + field_path_tokens, + array_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + &input.align, + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } + AsmConstantKind::SizeOf { type_path } => { + let (const_def, literal_repr) = gen_size_of_code(name, doc, type_path); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } } } @@ -1012,3 +1372,73 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +/// Attribute macro for stack frame structs. +/// +/// Adds `#[repr(C, align(8))]` to ensure C layout and 8-byte alignment. +/// Any existing `#[repr(...)]` attributes are removed. +/// +/// Also generates a companion module `___fields` containing type aliases +/// for each array field's element type. This allows `stack_frame_offset!` to resolve +/// element types without requiring them in the syntax. +/// +/// # Example +/// ```ignore +/// #[stack_frame] +/// struct InitStackFrame { +/// data: [u8; 32], +/// metas: [SolAccountMeta; 2], +/// } +/// ``` +/// +/// Generates: +/// ```ignore +/// #[repr(C, align(8))] +/// struct InitStackFrame { ... } +/// +/// mod __InitStackFrame_fields { +/// use super::*; +/// pub type metas = SolAccountMeta; +/// pub type data = u8; +/// } +/// ``` +#[proc_macro_attribute] +pub fn stack_frame(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(item as syn::ItemStruct); + + // Remove existing repr attributes to avoid conflicts. + input.attrs.retain(|attr| !attr.path().is_ident("repr")); + + let struct_name = &input.ident; + let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); + + // Extract array element types for each array field. + let mut type_aliases = Vec::new(); + if let syn::Fields::Named(ref fields) = input.fields { + for field in &fields.named { + if let Some(ref field_name) = field.ident { + if let syn::Type::Array(array_type) = &field.ty { + let elem_type = &*array_type.elem; + type_aliases.push(quote! { + #[allow(non_camel_case_types)] + pub type #field_name = #elem_type; + }); + } + } + } + } + + let expanded = quote! { + #[repr(C, align(8))] + #input + + #[doc(hidden)] + #[allow(non_snake_case)] + mod #fields_mod { + use super::*; + #(#type_aliases)* + } + }; + + TokenStream::from(expanded) +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index caafda7a..be096ba6 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -43,6 +43,22 @@ .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ SIZE_OF_U_8, 1 # Foo. + +# Init stack frame layout. +# ------------------------ +.equ SF_SYSTEM_PROGRAM_ADDRESS_OFF, -360 # System program address. +.equ SF_INSTRUCTION_OFF, -328 # CPI instruction. +.equ SF_ACCOUNT_META_0_OFF, -288 # First account meta. +.equ SF_ACCOUNT_META_1_OFF, -272 # Second account meta. +.equ SF_ACCOUNT_INFO_0_OFF, -256 # First account info. +.equ SF_ACCOUNT_INFO_1_OFF, -200 # Second account info. +.equ SF_SIGNERS_SEEDS_OFF, -144 # Signer seeds array. +.equ SF_SIGNER_SEEDS_OFF, -128 # Signer seed entry. +.equ SF_PDA_OFF, -112 # PDA address. +.equ SF_RENT_OFF, -80 # Rent sysvar. +.equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. +.equ SF_BUMP_SEED_OFF, -8 # Bump seed. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 4eb33803bfea44713ca47496bac533f404274c96 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:02:58 -0800 Subject: [PATCH 078/263] Update size_of macro --- .../tree/artifacts/snippets/asm/constants.txt | 15 +- examples/tree/build.rs | 2 +- examples/tree/interface/src/asm.rs | 15 +- examples/tree/macros/src/lib.rs | 169 ++++++++++++------ examples/tree/src/tree/tree.s | 13 +- 5 files changed, 155 insertions(+), 59 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index fefc6869..92ff1a50 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -42,7 +42,6 @@ .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. -.equ SIZE_OF_U_8, 1 # Foo. # Init stack frame layout. # ------------------------ @@ -57,4 +56,16 @@ .equ SF_PDA_OFF, -112 # PDA address. .equ SF_RENT_OFF, -80 # Rent sysvar. .equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. -.equ SF_BUMP_SEED_OFF, -8 # Bump seed. \ No newline at end of file +.equ SF_BUMP_SEED_OFF, -8 # Bump seed. + +# Type sizes. +# ----------- +.equ SIZE_OF_SOL_INSTRUCTION, 40 # Size of SolInstruction. +.equ SIZE_OF_SOL_ACCOUNT_META, 16 # Size of SolAccountMeta. +.equ SIZE_OF_SOL_ACCOUNT_INFO, 56 # Size of SolAccountInfo. +.equ SIZE_OF_SOL_SIGNER_SEED, 16 # Size of SolSignerSeed. +.equ SIZE_OF_SOL_SIGNER_SEEDS, 16 # Size of SolSignerSeeds. +# Size of CreateAccountInstructionData. +.equ SIZE_OF_CREATE_ACCOUNT_INSTRUCTION_DATA, 52 +.equ SIZE_OF_RENT, 16 # Size of Rent. +.equ SIZE_OF_ADDRESS, 32 # Size of Address. \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 401d8a2a..bcc77040 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -12,7 +12,7 @@ macro_rules! asm_groups { fn main() { // Collect all constant groups. - let groups = asm_groups![error_codes, input_buffer, misc, init_stack_frame]; + let groups = asm_groups![error_codes, input_buffer, misc, init_stack_frame, sizes]; // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 1058f5ae..394c476e 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -2,7 +2,7 @@ extern crate alloc; use crate::bindings; use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::{asm_constant_group, extend_constant_group, stack_frame}; +use macros::{asm_constant_group, extend_constant_group, size_of, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; extend_constant_group!(input_buffer { @@ -32,8 +32,6 @@ extend_constant_group!(misc { DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. MAX_DATA_PAD = 7, - /// Foo. - size_of!(u8), }); #[stack_frame] @@ -84,3 +82,14 @@ asm_constant_group! { stack_frame_offset!(BUMP_SEED, InitStackFrame.bump_seed), } } + +size_of! { + bindings::SolInstruction, + bindings::SolAccountMeta, + bindings::SolAccountInfo, + bindings::SolSignerSeed, + bindings::SolSignerSeeds, + CreateAccountInstructionData, + Rent, + Address, +} diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 8bec3161..d6142621 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -588,11 +588,6 @@ enum AsmConstantKind { field_path_tokens: proc_macro2::TokenStream, array_index: Option, }, - /// Size of a type (i64, validated for i32 range). - /// Name is auto-generated as `SIZE_OF_`. - SizeOf { - type_path: syn::Type, - }, } /// Input for asm_constant_group! macro. @@ -810,19 +805,6 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> array_index: parsed.array_index, }, ) - } else if ident == "size_of" { - // size_of!(Type) - auto-generates SIZE_OF_. - content.parse::()?; - let inner; - syn::parenthesized!(inner in content); - let type_path: syn::Type = inner.parse()?; - - let type_name = extract_type_name(&type_path) - .ok_or_else(|| content.error("Expected a type path for size_of!"))?; - let screaming = type_name.to_case(Case::UpperSnake); - let const_name = - Ident::new(&format!("SIZE_OF_{}", screaming), ident.span()); - (const_name, AsmConstantKind::SizeOf { type_path }) } else { // Regular NAME = value syntax. content.parse::()?; @@ -960,30 +942,6 @@ fn gen_stack_frame_offset_code( (const_def, None) } -/// Generate code for a `size_of!` constant. -/// -/// Returns `(const_def_tokens, literal_repr)` where literal_repr is always `None`. -fn gen_size_of_code( - name: &Ident, - doc: &str, - type_path: &syn::Type, -) -> (proc_macro2::TokenStream, Option) { - let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); - - let const_def = quote! { - #[doc = #doc] - pub const #name: i64 = { use super::*; core::mem::size_of::<#type_path>() as i64 }; - - const #assert_name: () = assert!( - ({ use super::*; core::mem::size_of::<#type_path>() } as i64) >= (i32::MIN as i64) - && ({ use super::*; core::mem::size_of::<#type_path>() } as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); - }; - - (const_def, None) -} - /// Macro for defining ASM-only constant groups. /// /// Constants don't need types - values are `i64`, offsets are `i16`. @@ -1093,11 +1051,6 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } - AsmConstantKind::SizeOf { type_path } => { - let (const_def, literal_repr) = gen_size_of_code(name, doc, type_path); - const_value_strs.push(literal_repr); - const_defs.push(const_def); - } } } @@ -1298,11 +1251,6 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } - AsmConstantKind::SizeOf { type_path } => { - let (const_def, literal_repr) = gen_size_of_code(name, doc, type_path); - const_value_strs.push(literal_repr); - const_defs.push(const_def); - } } } @@ -1373,6 +1321,123 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } +/// Input for size_of! macro. +struct SizeOfInput { + types: Vec, +} + +impl Parse for SizeOfInput { + fn parse(input: ParseStream) -> syn::Result { + let mut types = Vec::new(); + while !input.is_empty() { + let ty: syn::Type = input.parse()?; + types.push(ty); + // Optional trailing comma. + let _ = input.parse::(); + } + Ok(SizeOfInput { types }) + } +} + +/// Macro for generating type size constants for ASM. +/// +/// Takes a list of types and generates `SIZE_OF_` constants. +/// Creates a `sizes` module with a `to_asm()` function for build-time ASM generation. +/// +/// # Example +/// ```ignore +/// size_of! { +/// u8, +/// SolAccountMeta, +/// Rent, +/// } +/// ``` +/// +/// Generates ASM: +/// ```text +/// # Type sizes. +/// # ----------- +/// .equ SIZE_OF_U8, 1 # Size of u8. +/// .equ SIZE_OF_SOL_ACCOUNT_META, 24 # Size of SolAccountMeta. +/// .equ SIZE_OF_RENT, 17 # Size of Rent. +/// ``` +#[proc_macro] +pub fn size_of(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as SizeOfInput); + + let max_line_len = MAX_LINE_LEN; + let header = asm_header("Type sizes."); + + let mut const_defs = Vec::new(); + let mut const_name_strs = Vec::new(); + let mut const_doc_strs = Vec::new(); + + for ty in &input.types { + let type_name = extract_type_name(ty) + .unwrap_or_else(|| panic!("Expected a named type path in size_of!")); + let screaming = type_name.to_case(Case::UpperSnake); + let name_str = format!("SIZE_OF_{}", screaming); + let name = Ident::new(&name_str, proc_macro2::Span::call_site()); + let assert_name = Ident::new( + &format!("_ASSERT_{}_FITS", name_str), + proc_macro2::Span::call_site(), + ); + let doc = format!("Size of {}.", type_name); + + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i64 = { use super::*; core::mem::size_of::<#ty>() as i64 }; + + const #assert_name: () = assert!( + ({ use super::*; core::mem::size_of::<#ty>() } as i64) >= (i32::MIN as i64) + && ({ use super::*; core::mem::size_of::<#ty>() } as i64) <= (i32::MAX as i64), + "ASM immediate must fit in i32 range" + ); + }); + + const_name_strs.push(name_str); + const_doc_strs.push(doc); + } + + let const_idents: Vec<_> = const_name_strs + .iter() + .map(|n| Ident::new(n, proc_macro2::Span::call_site())) + .collect(); + + let expanded = quote! { + pub mod sizes { + use alloc::string::String; + use alloc::format; + + #(#const_defs)* + + /// Generate ASM constants for type sizes. + pub fn to_asm() -> String { + let mut result = String::from(#header); + result.push('\n'); + + let names: &[&str] = &[#(#const_name_strs),*]; + let values: &[i64] = &[#(#const_idents as i64),*]; + let docs: &[&str] = &[#(#const_doc_strs),*]; + + for i in 0..names.len() { + let inline = format!(".equ {}, {} # {}", names[i], values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], names[i], values[i])); + } + result.push('\n'); + } + + result + } + } + }; + + TokenStream::from(expanded) +} + /// Attribute macro for stack frame structs. /// /// Adds `#[repr(C, align(8))]` to ensure C layout and 8-byte alignment. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index be096ba6..cb989d73 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -43,7 +43,6 @@ .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. -.equ SIZE_OF_U_8, 1 # Foo. # Init stack frame layout. # ------------------------ @@ -59,6 +58,18 @@ .equ SF_RENT_OFF, -80 # Rent sysvar. .equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. .equ SF_BUMP_SEED_OFF, -8 # Bump seed. + +# Type sizes. +# ----------- +.equ SIZE_OF_SOL_INSTRUCTION, 40 # Size of SolInstruction. +.equ SIZE_OF_SOL_ACCOUNT_META, 16 # Size of SolAccountMeta. +.equ SIZE_OF_SOL_ACCOUNT_INFO, 56 # Size of SolAccountInfo. +.equ SIZE_OF_SOL_SIGNER_SEED, 16 # Size of SolSignerSeed. +.equ SIZE_OF_SOL_SIGNER_SEEDS, 16 # Size of SolSignerSeeds. +# Size of CreateAccountInstructionData. +.equ SIZE_OF_CREATE_ACCOUNT_INSTRUCTION_DATA, 52 +.equ SIZE_OF_RENT, 16 # Size of Rent. +.equ SIZE_OF_ADDRESS, 32 # Size of Address. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 6c53a53cc5a9012e62a42af8580dc84ec5076eb4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:08:26 -0800 Subject: [PATCH 079/263] Update sizes macro --- .../tree/artifacts/snippets/asm/constants.txt | 10 +---- examples/tree/interface/src/asm.rs | 31 ++++++--------- examples/tree/macros/src/lib.rs | 38 ++++++++++++++----- examples/tree/src/tree/tree.s | 10 +---- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 92ff1a50..400bd187 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -60,12 +60,4 @@ # Type sizes. # ----------- -.equ SIZE_OF_SOL_INSTRUCTION, 40 # Size of SolInstruction. -.equ SIZE_OF_SOL_ACCOUNT_META, 16 # Size of SolAccountMeta. -.equ SIZE_OF_SOL_ACCOUNT_INFO, 56 # Size of SolAccountInfo. -.equ SIZE_OF_SOL_SIGNER_SEED, 16 # Size of SolSignerSeed. -.equ SIZE_OF_SOL_SIGNER_SEEDS, 16 # Size of SolSignerSeeds. -# Size of CreateAccountInstructionData. -.equ SIZE_OF_CREATE_ACCOUNT_INSTRUCTION_DATA, 52 -.equ SIZE_OF_RENT, 16 # Size of Rent. -.equ SIZE_OF_ADDRESS, 32 # Size of Address. \ No newline at end of file +.equ SIZE_OF_U8, 1 # Size of u8. \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 394c476e..9f33df31 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -2,9 +2,20 @@ extern crate alloc; use crate::bindings; use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::{asm_constant_group, extend_constant_group, size_of, stack_frame}; +use macros::{asm_constant_group, extend_constant_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; +sizes! { + u8, +} + +extend_constant_group!(misc { + /// And mask for data length alignment. + DATA_LEN_AND_MASK = -8, + /// Maximum possible data length padding. + MAX_DATA_PAD = 7, +}); + extend_constant_group!(input_buffer { prefix = "IB", /// User address field. @@ -27,13 +38,6 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), }); -extend_constant_group!(misc { - /// And mask for data length alignment. - DATA_LEN_AND_MASK = -8, - /// Maximum possible data length padding. - MAX_DATA_PAD = 7, -}); - #[stack_frame] struct InitStackFrame { /// Zero-initialized on stack. @@ -82,14 +86,3 @@ asm_constant_group! { stack_frame_offset!(BUMP_SEED, InitStackFrame.bump_seed), } } - -size_of! { - bindings::SolInstruction, - bindings::SolAccountMeta, - bindings::SolAccountInfo, - bindings::SolSignerSeed, - bindings::SolSignerSeeds, - CreateAccountInstructionData, - Rent, - Address, -} diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index d6142621..d381e291 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -707,6 +707,24 @@ fn extract_type_name(ty: &syn::Type) -> Option { } } +/// Convert a type name to UPPER_SNAKE_CASE for ASM constants. +/// +/// Uses `convert_case` but fixes primitive types like `u8`, `i16` etc. +/// where the default conversion inserts an unwanted underscore (`U_8` → `U8`). +fn type_name_to_upper_snake(name: &str) -> String { + let s = name.to_case(Case::UpperSnake); + // Primitive types: single letter + digits (e.g. U_8, I_16, F_32). + // Remove the underscore between the letter and digits. + if s.starts_with(|c: char| c.is_ascii_uppercase()) + && s.as_bytes().get(1) == Some(&b'_') + && s[2..].chars().all(|c| c.is_ascii_digit()) + { + format!("{}{}", &s[..1], &s[2..]) + } else { + s + } +} + /// Parse optional `prefix = "..."` and `align = expr` group header parameters. /// /// Both are optional and can appear in any order before the first constant definition. @@ -1321,12 +1339,12 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } -/// Input for size_of! macro. -struct SizeOfInput { +/// Input for sizes! macro. +struct SizesInput { types: Vec, } -impl Parse for SizeOfInput { +impl Parse for SizesInput { fn parse(input: ParseStream) -> syn::Result { let mut types = Vec::new(); while !input.is_empty() { @@ -1335,18 +1353,18 @@ impl Parse for SizeOfInput { // Optional trailing comma. let _ = input.parse::(); } - Ok(SizeOfInput { types }) + Ok(SizesInput { types }) } } /// Macro for generating type size constants for ASM. /// -/// Takes a list of types and generates `SIZE_OF_` constants. +/// Takes a list of types and generates `SIZE_OF_` constants. /// Creates a `sizes` module with a `to_asm()` function for build-time ASM generation. /// /// # Example /// ```ignore -/// size_of! { +/// sizes! { /// u8, /// SolAccountMeta, /// Rent, @@ -1362,8 +1380,8 @@ impl Parse for SizeOfInput { /// .equ SIZE_OF_RENT, 17 # Size of Rent. /// ``` #[proc_macro] -pub fn size_of(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as SizeOfInput); +pub fn sizes(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as SizesInput); let max_line_len = MAX_LINE_LEN; let header = asm_header("Type sizes."); @@ -1374,8 +1392,8 @@ pub fn size_of(input: TokenStream) -> TokenStream { for ty in &input.types { let type_name = extract_type_name(ty) - .unwrap_or_else(|| panic!("Expected a named type path in size_of!")); - let screaming = type_name.to_case(Case::UpperSnake); + .unwrap_or_else(|| panic!("Expected a named type path in sizes!")); + let screaming = type_name_to_upper_snake(&type_name); let name_str = format!("SIZE_OF_{}", screaming); let name = Ident::new(&name_str, proc_macro2::Span::call_site()); let assert_name = Ident::new( diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index cb989d73..3f36509e 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -61,15 +61,7 @@ # Type sizes. # ----------- -.equ SIZE_OF_SOL_INSTRUCTION, 40 # Size of SolInstruction. -.equ SIZE_OF_SOL_ACCOUNT_META, 16 # Size of SolAccountMeta. -.equ SIZE_OF_SOL_ACCOUNT_INFO, 56 # Size of SolAccountInfo. -.equ SIZE_OF_SOL_SIGNER_SEED, 16 # Size of SolSignerSeed. -.equ SIZE_OF_SOL_SIGNER_SEEDS, 16 # Size of SolSignerSeeds. -# Size of CreateAccountInstructionData. -.equ SIZE_OF_CREATE_ACCOUNT_INSTRUCTION_DATA, 52 -.equ SIZE_OF_RENT, 16 # Size of Rent. -.equ SIZE_OF_ADDRESS, 32 # Size of Address. +.equ SIZE_OF_U8, 1 # Size of u8. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 87a2b9b911d912e544599bfa85f256e6097e7f57 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:18:05 -0800 Subject: [PATCH 080/263] Clean up size/stack frame offset macros --- .../tree/artifacts/snippets/asm/constants.txt | 13 +-- examples/tree/interface/src/asm.rs | 47 +++------ examples/tree/interface/src/common.rs | 6 ++ examples/tree/macros/src/lib.rs | 99 ++++++++----------- examples/tree/src/tree/tree.s | 13 +-- 5 files changed, 64 insertions(+), 114 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 400bd187..0ff9e872 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -45,18 +45,7 @@ # Init stack frame layout. # ------------------------ -.equ SF_SYSTEM_PROGRAM_ADDRESS_OFF, -360 # System program address. -.equ SF_INSTRUCTION_OFF, -328 # CPI instruction. -.equ SF_ACCOUNT_META_0_OFF, -288 # First account meta. -.equ SF_ACCOUNT_META_1_OFF, -272 # Second account meta. -.equ SF_ACCOUNT_INFO_0_OFF, -256 # First account info. -.equ SF_ACCOUNT_INFO_1_OFF, -200 # Second account info. -.equ SF_SIGNERS_SEEDS_OFF, -144 # Signer seeds array. -.equ SF_SIGNER_SEEDS_OFF, -128 # Signer seed entry. -.equ SF_PDA_OFF, -112 # PDA address. -.equ SF_RENT_OFF, -80 # Rent sysvar. -.equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. -.equ SF_BUMP_SEED_OFF, -8 # Bump seed. +.equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. # Type sizes. # ----------- diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 9f33df31..a6deee64 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -1,7 +1,11 @@ extern crate alloc; -use crate::bindings; -use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; +use crate::bindings::{ + SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, +}; +use crate::common::{ + cpi, CpiAccountIndex, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, +}; use macros::{asm_constant_group, extend_constant_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; @@ -41,47 +45,22 @@ extend_constant_group!(input_buffer { #[stack_frame] struct InitStackFrame { /// Zero-initialized on stack. + bump_seed: u8, system_program_address: Address, - instruction: bindings::SolInstruction, - account_metas: [bindings::SolAccountMeta; cpi::N_ACCOUNTS], - account_infos: [bindings::SolAccountInfo; cpi::N_ACCOUNTS], - signers_seeds: [bindings::SolSignerSeeds; cpi::N_PDA_SIGNERS], - signer_seeds: [bindings::SolSignerSeed; cpi::N_SEEDS], + instruction: SolInstruction, + account_metas: [SolAccountMeta; cpi::N_ACCOUNTS], + account_infos: [SolAccountInfo; cpi::N_ACCOUNTS], + signers_seeds: [SolSignerSeeds; cpi::N_PDA_SIGNERS], + signer_seeds: [SolSignerSeed; cpi::N_SEEDS], pda: Address, rent: Rent, instruction_data: CreateAccountInstructionData, - /// Padding for alignment. - _pad: [u8; 4], - bump_seed: u8, } asm_constant_group! { /// Init stack frame layout. init_stack_frame { - prefix = "SF", - align = misc::BPF_ALIGN_OF_U128, - /// System program address. - stack_frame_offset!(SYSTEM_PROGRAM_ADDRESS, InitStackFrame.system_program_address), - /// CPI instruction. - stack_frame_offset!(INSTRUCTION, InitStackFrame.instruction), - /// First account meta. - stack_frame_offset!(ACCOUNT_META_0, InitStackFrame.account_metas[0]), - /// Second account meta. - stack_frame_offset!(ACCOUNT_META_1, InitStackFrame.account_metas[1]), - /// First account info. - stack_frame_offset!(ACCOUNT_INFO_0, InitStackFrame.account_infos[0]), - /// Second account info. - stack_frame_offset!(ACCOUNT_INFO_1, InitStackFrame.account_infos[1]), - /// Signer seeds array. - stack_frame_offset!(SIGNERS_SEEDS, InitStackFrame.signers_seeds), - /// Signer seed entry. - stack_frame_offset!(SIGNER_SEEDS, InitStackFrame.signer_seeds), - /// PDA address. - stack_frame_offset!(PDA, InitStackFrame.pda), - /// Rent sysvar. - stack_frame_offset!(RENT, InitStackFrame.rent), - /// Instruction data. - stack_frame_offset!(INSTRUCTION_DATA, InitStackFrame.instruction_data), + prefix = "SF_INIT", /// Bump seed. stack_frame_offset!(BUMP_SEED, InitStackFrame.bump_seed), } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index d8a52d8f..5e8ef796 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -37,6 +37,12 @@ constant_group! { } } +#[repr(usize)] +pub enum CpiAccountIndex { + User, + Tree, +} + constant_group! { /// CPI-specific constants. cpi { diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index d381e291..85fe96cb 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -10,6 +10,9 @@ use syn::{ /// Maximum line length for ASM output. const MAX_LINE_LEN: usize = 75; +/// BPF alignment requirement (align_of::()). +const BPF_ALIGN: i64 = 8; + /// Maximum comment length (accounting for `# ` prefix). const MAX_COMMENT_LEN: usize = MAX_LINE_LEN - "# ".len(); @@ -194,13 +197,14 @@ enum ConstantKind { }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. - /// Name gets `_OFF` suffix appended. + /// Name gets `_OFF` suffix (aligned) or `_UOFF` suffix (unaligned). /// Array element types are resolved via the `___fields` companion module /// generated by `#[stack_frame]`. StackFrameOffset { struct_name: Ident, field_path_tokens: proc_macro2::TokenStream, array_index: Option, + aligned: bool, }, } @@ -287,10 +291,9 @@ impl Parse for ConstantGroup { field_path, }, ) - } else if ident == "stack_frame_offset" { - // stack_frame_offset!(NAME, Struct.field) - // stack_frame_offset!(NAME, Struct.field[expr]) - // stack_frame_offset!(NAME, Struct.field[expr].inner_field) + } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { + let aligned = ident == "stack_frame_offset"; + let suffix = if aligned { "_OFF" } else { "_UOFF" }; content.parse::()?; let inner; syn::parenthesized!(inner in content); @@ -298,13 +301,14 @@ impl Parse for ConstantGroup { inner.parse::()?; let struct_name: Ident = inner.parse()?; let parsed = parse_stack_frame_field_path(&inner)?; - let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); ( full_name, ConstantKind::StackFrameOffset { struct_name, field_path_tokens: parsed.field_path_tokens, array_index: parsed.array_index, + aligned, }, ) } else if content.peek(Token![:]) { @@ -485,6 +489,7 @@ pub fn constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, + aligned, } => { let (const_def, literal_repr) = gen_stack_frame_offset_code( name, @@ -492,7 +497,7 @@ pub fn constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, - &None, // constant_group! does not support align + *aligned, ); const_value_strs.push(literal_repr); const_defs.push(const_def); @@ -580,13 +585,14 @@ enum AsmConstantKind { }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. - /// Name gets `_OFF` suffix appended. + /// Name gets `_OFF` suffix (aligned) or `_UOFF` suffix (unaligned). /// Array element types are resolved via the `___fields` companion module /// generated by `#[stack_frame]`. StackFrameOffset { struct_name: Ident, field_path_tokens: proc_macro2::TokenStream, array_index: Option, + aligned: bool, }, } @@ -595,7 +601,6 @@ struct AsmConstantGroupInput { doc: String, name: Ident, prefix: Option, - align: Option, constants: Vec, } @@ -725,40 +730,21 @@ fn type_name_to_upper_snake(name: &str) -> String { } } -/// Parse optional `prefix = "..."` and `align = expr` group header parameters. -/// -/// Both are optional and can appear in any order before the first constant definition. -fn parse_group_params(content: ParseStream) -> syn::Result<(Option, Option)> { - let mut prefix = None; - let mut align = None; - - // Parse header parameters (prefix and align) before constants. - loop { - if !content.peek(Ident) { - break; - } +/// Parse optional `prefix = "..."` group header parameter. +fn parse_group_params(content: ParseStream) -> syn::Result> { + // Check for prefix = "..." before constants. + if content.peek(Ident) { let fork = content.fork(); let ident: Ident = fork.parse()?; - if (ident == "prefix" || ident == "align") && fork.peek(Token![=]) { - // Advance the actual stream. + if ident == "prefix" && fork.peek(Token![=]) { content.parse::()?; content.parse::()?; - - if ident == "prefix" { - let prefix_lit: syn::LitStr = content.parse()?; - prefix = Some(prefix_lit.value()); - } else { - let align_expr: syn::Expr = content.parse()?; - align = Some(align_expr); - } - + let prefix_lit: syn::LitStr = content.parse()?; content.parse::()?; - } else { - break; + return Ok(Some(prefix_lit.value())); } } - - Ok((prefix, align)) + Ok(None) } /// Parse ASM constants (shared between asm_constant_group! and extend_constant_group!). @@ -803,10 +789,9 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> field_path, }, ) - } else if ident == "stack_frame_offset" { - // stack_frame_offset!(NAME, Struct.field) - // stack_frame_offset!(NAME, Struct.field[expr]) - // stack_frame_offset!(NAME, Struct.field[expr].inner_field) + } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { + let aligned = ident == "stack_frame_offset"; + let suffix = if aligned { "_OFF" } else { "_UOFF" }; content.parse::()?; let inner; syn::parenthesized!(inner in content); @@ -814,13 +799,14 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> inner.parse::()?; let struct_name: Ident = inner.parse()?; let parsed = parse_stack_frame_field_path(&inner)?; - let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); ( full_name, AsmConstantKind::StackFrameOffset { struct_name, field_path_tokens: parsed.field_path_tokens, array_index: parsed.array_index, + aligned, }, ) } else { @@ -871,8 +857,8 @@ impl Parse for AsmConstantGroupInput { let content; braced!(content in input); - // Parse optional header parameters: prefix = "...", align = expr - let (prefix, align) = parse_group_params(&content)?; + // Parse optional header parameter: prefix = "..." + let prefix = parse_group_params(&content)?; // Parse constants. let constants = parse_asm_constants(&content)?; @@ -886,7 +872,6 @@ impl Parse for AsmConstantGroupInput { doc, name, prefix, - align, constants, }) } @@ -902,7 +887,7 @@ fn gen_stack_frame_offset_code( struct_name: &Ident, field_path_tokens: &proc_macro2::TokenStream, array_index: &Option, - align: &Option, + aligned: bool, ) -> (proc_macro2::TokenStream, Option) { let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); @@ -928,14 +913,16 @@ fn gen_stack_frame_offset_code( }, }; - let align_assertion = match align { - Some(align_expr) => quote! { + let align_assertion = if aligned { + let bpf_align = BPF_ALIGN; + quote! { assert!( - result % (#align_expr as i64) == 0, + result % #bpf_align == 0, "Stack frame offset must be aligned" ); - }, - None => quote! {}, + } + } else { + quote! {} }; let const_def = quote! { @@ -1057,6 +1044,7 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, + aligned, } => { let (const_def, literal_repr) = gen_stack_frame_offset_code( name, @@ -1064,7 +1052,7 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, - &input.align, + *aligned, ); const_value_strs.push(literal_repr); const_defs.push(const_def); @@ -1134,7 +1122,6 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { struct ExtendConstantGroupInput { name: Ident, prefix: Option, - align: Option, constants: Vec, } @@ -1147,8 +1134,8 @@ impl Parse for ExtendConstantGroupInput { let content; braced!(content in input); - // Parse optional header parameters: prefix = "...", align = expr - let (prefix, align) = parse_group_params(&content)?; + // Parse optional header parameter: prefix = "..." + let prefix = parse_group_params(&content)?; // Parse constants using shared parser. let constants = parse_asm_constants(&content)?; @@ -1156,7 +1143,6 @@ impl Parse for ExtendConstantGroupInput { Ok(ExtendConstantGroupInput { name, prefix, - align, constants, }) } @@ -1257,6 +1243,7 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, + aligned, } => { let (const_def, literal_repr) = gen_stack_frame_offset_code( name, @@ -1264,7 +1251,7 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { struct_name, field_path_tokens, array_index, - &input.align, + *aligned, ); const_value_strs.push(literal_repr); const_defs.push(const_def); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 3f36509e..646c461c 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -46,18 +46,7 @@ # Init stack frame layout. # ------------------------ -.equ SF_SYSTEM_PROGRAM_ADDRESS_OFF, -360 # System program address. -.equ SF_INSTRUCTION_OFF, -328 # CPI instruction. -.equ SF_ACCOUNT_META_0_OFF, -288 # First account meta. -.equ SF_ACCOUNT_META_1_OFF, -272 # Second account meta. -.equ SF_ACCOUNT_INFO_0_OFF, -256 # First account info. -.equ SF_ACCOUNT_INFO_1_OFF, -200 # Second account info. -.equ SF_SIGNERS_SEEDS_OFF, -144 # Signer seeds array. -.equ SF_SIGNER_SEEDS_OFF, -128 # Signer seed entry. -.equ SF_PDA_OFF, -112 # PDA address. -.equ SF_RENT_OFF, -80 # Rent sysvar. -.equ SF_INSTRUCTION_DATA_OFF, -64 # Instruction data. -.equ SF_BUMP_SEED_OFF, -8 # Bump seed. +.equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. # Type sizes. # ----------- From 8131a9199c9f9d0b3ec0c39dfedd035929f5f50c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:54:12 -0800 Subject: [PATCH 081/263] Add logic to check PDA --- .../tree/artifacts/snippets/asm/constants.txt | 39 +++++++--- .../snippets/rs/initialize-input-checks.txt | 6 +- examples/tree/build.rs | 10 ++- examples/tree/interface/src/asm.rs | 37 ++++++++- examples/tree/interface/src/common.rs | 8 +- examples/tree/src/program.rs | 8 +- examples/tree/src/tree/tree.s | 78 ++++++++++++++++--- 7 files changed, 149 insertions(+), 37 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 0ff9e872..a2df7b3c 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -13,6 +13,25 @@ # The passed PDA does not match the expected address. .equ E_PDA_MISMATCH, 8 +# Type sizes. +# ----------- +.equ SIZE_OF_U8, 1 # Size of u8. + +# Data layout constants. +# ---------------------- +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ OFFSET_ZERO, 0 # No offset. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. + +# Pubkey chunking offsets. +# ------------------------ +.equ PUBKEY_CHUNK_OFF_0, 0 # Offset for the first 8 bytes. +.equ PUBKEY_CHUNK_OFF_1, 8 # Offset for the second 8 bytes. +.equ PUBKEY_CHUNK_OFF_2, 16 # Offset for the third 8 bytes. +.equ PUBKEY_CHUNK_OFF_3, 24 # Offset for the fourth 8 bytes. + # Input buffer layout. # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. @@ -26,6 +45,7 @@ .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. +.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 @@ -36,17 +56,16 @@ # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 -# Miscellaneous constants. -# ------------------------ -.equ DATA_LEN_ZERO, 0 # Data length of zero. -.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. -.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. - # Init stack frame layout. # ------------------------ .equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. +.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. +.equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. +.equ SF_INIT_PDA_OFF, -104 # PDA address field. -# Type sizes. -# ----------- -.equ SIZE_OF_U8, 1 # Size of u8. \ No newline at end of file +# CPI-specific constants. +# ----------------------- +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign CPI. +.equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. +.equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. +.equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 0d778b00..1f70c2a4 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -4,7 +4,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::USER_DATA_LEN ); @@ -18,7 +18,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::TREE_DATA_LEN ); @@ -40,6 +40,6 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::INSTRUCTION_DATA ); \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index bcc77040..59badf3a 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -12,7 +12,15 @@ macro_rules! asm_groups { fn main() { // Collect all constant groups. - let groups = asm_groups![error_codes, input_buffer, misc, init_stack_frame, sizes]; + let groups = asm_groups![ + error_codes, + sizes, + data, + pubkey_chunk, + input_buffer, + init_stack_frame, + cpi + ]; // Read in the assembly file. let manifest_dir = env!("CARGO_MANIFEST_DIR"); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index a6deee64..259a8640 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,9 +3,7 @@ extern crate alloc; use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; -use crate::common::{ - cpi, CpiAccountIndex, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, -}; +use crate::common::{CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; use macros::{asm_constant_group, extend_constant_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; @@ -13,13 +11,30 @@ sizes! { u8, } -extend_constant_group!(misc { +extend_constant_group!(data { + /// No offset. + OFFSET_ZERO = 0, /// And mask for data length alignment. DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. MAX_DATA_PAD = 7, }); +asm_constant_group! { + /// Pubkey chunking offsets. + pubkey_chunk { + prefix = "PUBKEY_CHUNK", + /// Offset for the first 8 bytes. + OFF_0 = 0, + /// Offset for the second 8 bytes. + OFF_1 = 8, + /// Offset for the third 8 bytes. + OFF_2 = 16, + /// Offset for the fourth 8 bytes. + OFF_3 = 24, + } +} + extend_constant_group!(input_buffer { prefix = "IB", /// User address field. @@ -30,6 +45,8 @@ extend_constant_group!(input_buffer { NON_DUP_MARKER = NON_DUP_MARKER, /// Tree non-duplicate marker field. offset!(TREE_NON_DUP_MARKER, InputBufferHeader.tree_header.borrow_state), + /// Tree address field. + offset!(TREE_ADDRESS, InputBufferHeader.tree_header.address), /// Tree data length field. offset!(TREE_DATA_LEN, InputBufferHeader.tree_header.data_len), /// Instruction data length field for empty tree account. @@ -42,6 +59,12 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), }); +extend_constant_group!(cpi { + prefix = "CPI", + /// Number of seeds for PDA generation. + N_SEEDS_TRY_FIND_PDA = 0, +}); + #[stack_frame] struct InitStackFrame { /// Zero-initialized on stack. @@ -63,5 +86,11 @@ asm_constant_group! { prefix = "SF_INIT", /// Bump seed. stack_frame_offset!(BUMP_SEED, InitStackFrame.bump_seed), + /// Bump signer seed address field. + stack_frame_offset!(SIGNER_SEED_ADDR, InitStackFrame.signer_seeds[0].addr), + /// Bump signer seed length field. + stack_frame_offset!(SIGNER_SEED_LEN, InitStackFrame.signer_seeds[0].len), + /// PDA address field. + stack_frame_offset!(PDA, InitStackFrame.pda), } } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 5e8ef796..1568e063 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -65,8 +65,8 @@ pub struct CreateAccountInstructionData { } constant_group! { - /// Miscellaneous constants. - misc { + /// Data layout constants. + data { /// Data length of zero. DATA_LEN_ZERO: u64 = 0, /// Data alignment during runtime. @@ -101,11 +101,11 @@ pub struct RuntimeAccount { pub rent_epoch: u64, } -type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(misc::DATA_LEN_ZERO as usize) }>; +type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(data::DATA_LEN_ZERO as usize) }>; type SystemProgramRuntimeAccount = RuntimeAccount<{ runtime_data_size(input_buffer::SYSTEM_PROGRAM_DATA_LEN) }>; /// Compute the data buffer size for a runtime account with the given data length. const fn runtime_data_size(data_len: usize) -> usize { - MAX_PERMITTED_DATA_INCREASE + data_len.next_multiple_of(misc::BPF_ALIGN_OF_U128) + MAX_PERMITTED_DATA_INCREASE + data_len.next_multiple_of(data::BPF_ALIGN_OF_U128) } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1cec5e0b..fda123a1 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,5 +1,5 @@ use core::mem::transmute; -use interface::{error_codes::error, input_buffer, misc}; +use interface::{data, error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, @@ -67,7 +67,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::USER_DATA_LEN ); @@ -81,7 +81,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::TREE_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::TREE_DATA_LEN ); @@ -103,7 +103,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ensure_ldxdw!( input_buffer_ptr, input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - misc::DATA_LEN_ZERO, + data::DATA_LEN_ZERO, error::INSTRUCTION_DATA ); // ANCHOR_END: initialize-input-checks diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 646c461c..0afaf08b 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -14,6 +14,25 @@ # The passed PDA does not match the expected address. .equ E_PDA_MISMATCH, 8 +# Type sizes. +# ----------- +.equ SIZE_OF_U8, 1 # Size of u8. + +# Data layout constants. +# ---------------------- +.equ DATA_LEN_ZERO, 0 # Data length of zero. +.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. +.equ OFFSET_ZERO, 0 # No offset. +.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. +.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. + +# Pubkey chunking offsets. +# ------------------------ +.equ PUBKEY_CHUNK_OFF_0, 0 # Offset for the first 8 bytes. +.equ PUBKEY_CHUNK_OFF_1, 8 # Offset for the second 8 bytes. +.equ PUBKEY_CHUNK_OFF_2, 16 # Offset for the third 8 bytes. +.equ PUBKEY_CHUNK_OFF_3, 24 # Offset for the fourth 8 bytes. + # Input buffer layout. # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. @@ -27,6 +46,7 @@ .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. +.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 @@ -37,20 +57,19 @@ # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 -# Miscellaneous constants. -# ------------------------ -.equ DATA_LEN_ZERO, 0 # Data length of zero. -.equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. -.equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. -.equ MAX_DATA_PAD, 7 # Maximum possible data length padding. - # Init stack frame layout. # ------------------------ .equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. - -# Type sizes. -# ----------- -.equ SIZE_OF_U8, 1 # Size of u8. +.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. +.equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. +.equ SF_INIT_PDA_OFF, -104 # PDA address field. + +# CPI-specific constants. +# ----------------------- +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign CPI. +.equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. +.equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. +.equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -101,9 +120,42 @@ initialize: jne r2, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks + # ANCHOR: init-check-pda + # Compute PDA. + # ------------ + mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. + mov64 r4, r10 # Get stack frame pointer. + add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. + mov64 r5, r10 # Get stack frame pointer. + add64 r4, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. + call sol_try_find_program_address # Find PDA. + + # Compare computed PDA against passed account. + # -------------------------------------------- + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_TREE_ADDRESS_OFF # Point at tree address. + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_0] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_0] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_1] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_1] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_2] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_2] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] + jne r5, r6, e_pda_mismatch + # ANCHOR_END: init-check-pda + # Initialize signer seed for PDA bump key. # ---------------------------------------- mov64 r2, r10 # Get stack frame pointer. + add64 r2, SF_INIT_BUMP_SEED_OFF # Point at bump seed on stack. + stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r2 # Store in signer seed. + stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. exit @@ -111,6 +163,10 @@ e_instruction_data: mov64 r0, E_INSTRUCTION_DATA exit +e_pda_mismatch: + mov64 r0, E_PDA_MISMATCH + exit + e_system_program_data_len: mov64 r0, E_SYSTEM_PROGRAM_DATA_LEN exit From 5b57f73ee89783f20e4dc9f96de531d47b433017 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:55:44 -0800 Subject: [PATCH 082/263] Add anchor --- .../snippets/asm/initialize-check-pda.txt | 27 +++++++++++++++++++ examples/tree/src/tree/tree.s | 4 +-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/initialize-check-pda.txt diff --git a/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt b/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt new file mode 100644 index 00000000..6a088bdc --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt @@ -0,0 +1,27 @@ + # Compute PDA. + # ------------ + mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. + mov64 r4, r10 # Get stack frame pointer. + add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. + mov64 r5, r10 # Get stack frame pointer. + add64 r4, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. + call sol_try_find_program_address # Find PDA. + + # Compare computed PDA against passed account. + # -------------------------------------------- + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_TREE_ADDRESS_OFF # Point at tree address. + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_0] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_0] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_1] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_1] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_2] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_2] + jne r5, r6, e_pda_mismatch + ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] + ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] + jne r5, r6, e_pda_mismatch \ No newline at end of file diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 0afaf08b..7797c7e3 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -120,7 +120,7 @@ initialize: jne r2, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks - # ANCHOR: init-check-pda + # ANCHOR: initialize-check-pda # Compute PDA. # ------------ mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. @@ -148,7 +148,7 @@ initialize: ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] jne r5, r6, e_pda_mismatch - # ANCHOR_END: init-check-pda + # ANCHOR_END: initialize-check-pda # Initialize signer seed for PDA bump key. # ---------------------------------------- From 7733559128ae693ddcd3284dd09256ba20c09d4b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:59:42 -0800 Subject: [PATCH 083/263] Add pubkey chunk group --- examples/tree/interface/src/asm.rs | 19 +------ examples/tree/macros/src/lib.rs | 88 ++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 259a8640..4232f069 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,9 +4,11 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::{asm_constant_group, extend_constant_group, sizes, stack_frame}; +use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; +pubkey_chunk_group!(); + sizes! { u8, } @@ -20,21 +22,6 @@ extend_constant_group!(data { MAX_DATA_PAD = 7, }); -asm_constant_group! { - /// Pubkey chunking offsets. - pubkey_chunk { - prefix = "PUBKEY_CHUNK", - /// Offset for the first 8 bytes. - OFF_0 = 0, - /// Offset for the second 8 bytes. - OFF_1 = 8, - /// Offset for the third 8 bytes. - OFF_2 = 16, - /// Offset for the fourth 8 bytes. - OFF_3 = 24, - } -} - extend_constant_group!(input_buffer { prefix = "IB", /// User address field. diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 85fe96cb..df5ae207 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -1443,6 +1443,94 @@ pub fn sizes(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } +/// Macro for generating pubkey chunking offset constants. +/// +/// A pubkey (Address) is 32 bytes. For 8-byte register loads, it is +/// accessed in 4 chunks of 8 bytes each. This macro generates a +/// `pubkey_chunk` module with `OFF_0` through `OFF_3` constants +/// and a `to_asm()` function. +/// +/// # Example +/// ```ignore +/// pubkey_chunk_group!(); +/// ``` +/// +/// Generates ASM: +/// ```text +/// # Pubkey chunking offsets. +/// # ------------------------ +/// .equ PUBKEY_CHUNK_OFF_0, 0 # Offset for the first 8 bytes. +/// .equ PUBKEY_CHUNK_OFF_1, 8 # Offset for the second 8 bytes. +/// .equ PUBKEY_CHUNK_OFF_2, 16 # Offset for the third 8 bytes. +/// .equ PUBKEY_CHUNK_OFF_3, 24 # Offset for the fourth 8 bytes. +/// ``` +#[proc_macro] +pub fn pubkey_chunk_group(_input: TokenStream) -> TokenStream { + const PUBKEY_SIZE: usize = 32; + const CHUNK_SIZE: usize = BPF_ALIGN as usize; + const N_CHUNKS: usize = PUBKEY_SIZE / CHUNK_SIZE; + const ORDINALS: [&str; N_CHUNKS] = ["first", "second", "third", "fourth"]; + + let max_line_len = MAX_LINE_LEN; + let header = asm_header("Pubkey chunking offsets."); + + let mut const_defs = Vec::new(); + let mut const_name_strs = Vec::new(); + let mut const_doc_strs = Vec::new(); + + for i in 0..N_CHUNKS { + let offset = (i * CHUNK_SIZE) as i64; + let name_str = format!("PUBKEY_CHUNK_OFF_{}", i); + let name = Ident::new(&format!("OFF_{}", i), proc_macro2::Span::call_site()); + let doc = format!("Offset for the {} 8 bytes.", ORDINALS[i]); + + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i64 = #offset; + }); + + const_name_strs.push(name_str); + const_doc_strs.push(doc); + } + + let const_idents: Vec<_> = (0..N_CHUNKS) + .map(|i| Ident::new(&format!("OFF_{}", i), proc_macro2::Span::call_site())) + .collect(); + + let expanded = quote! { + pub mod pubkey_chunk { + use alloc::string::String; + use alloc::format; + + #(#const_defs)* + + /// Generate ASM constants for pubkey chunking offsets. + pub fn to_asm() -> String { + let mut result = String::from(#header); + result.push('\n'); + + let names: &[&str] = &[#(#const_name_strs),*]; + let values: &[i64] = &[#(#const_idents as i64),*]; + let docs: &[&str] = &[#(#const_doc_strs),*]; + + for i in 0..names.len() { + let inline = format!(".equ {}, {} # {}", names[i], values[i], docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], names[i], values[i])); + } + result.push('\n'); + } + + result + } + } + }; + + TokenStream::from(expanded) +} + /// Attribute macro for stack frame structs. /// /// Adds `#[repr(C, align(8))]` to ensure C layout and 8-byte alignment. From f9c7e7c5c6e56e6387b267c54db39afb68bb5f79 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:15:13 -0800 Subject: [PATCH 084/263] Add PDA mismatch testing --- .../snippets/asm/initialize-check-pda.txt | 2 +- examples/tree/interface/src/asm.rs | 2 +- examples/tree/src/program.rs | 5 +- examples/tree/src/tests.rs | 6 ++ examples/tree/src/tests/pda.rs | 67 +++++++++++++++++++ examples/tree/src/tree/tree.s | 2 +- 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 examples/tree/src/tests/pda.rs diff --git a/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt b/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt index 6a088bdc..d85ec106 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt @@ -6,7 +6,7 @@ mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. mov64 r5, r10 # Get stack frame pointer. - add64 r4, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. + add64 r5, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. call sol_try_find_program_address # Find PDA. # Compare computed PDA against passed account. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 4232f069..b289461e 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -54,8 +54,8 @@ extend_constant_group!(cpi { #[stack_frame] struct InitStackFrame { - /// Zero-initialized on stack. bump_seed: u8, + /// Zero-initialized on stack. system_program_address: Address, instruction: SolInstruction, account_metas: [SolAccountMeta; cpi::N_ACCOUNTS], diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index fda123a1..63c83d1d 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,4 @@ -use core::mem::transmute; +use core::mem::{transmute, MaybeUninit}; use interface::{data, error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, @@ -108,5 +108,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ); // ANCHOR_END: initialize-input-checks + let pda = MaybeUninit::
::uninit(); + let bump = MaybeUninit::::uninit(); + SUCCESS } diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 8cd1e665..5c4f5e52 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,5 +1,6 @@ mod entrypoint; mod init; +mod pda; use interface::error_codes; use mollusk_svm::result::ProgramResult as MolluskResult; @@ -95,3 +96,8 @@ fn test_entrypoint_branching() { fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES); } + +#[test] +fn test_initialize_pda_mismatch() { + pda::test_pda_mismatch_chunks(ProgramLanguage::Assembly); +} diff --git a/examples/tree/src/tests/pda.rs b/examples/tree/src/tests/pda.rs new file mode 100644 index 00000000..f10a0e26 --- /dev/null +++ b/examples/tree/src/tests/pda.rs @@ -0,0 +1,67 @@ +use super::*; +use mollusk_svm::program; +use solana_sdk::instruction::AccountMeta; + +fn pda_init_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + // Derive PDA with no seeds (matching CPI_N_SEEDS_TRY_FIND_PDA = 0). + let (tree_pubkey, _bump) = Pubkey::find_program_address(&[], &setup.program_id); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), + (system_program_pubkey, system_program_account), + ]; + + (setup, instruction, accounts) +} + +/// Test PDA mismatch detection in each 8-byte chunk of the 32-byte pubkey. +pub(super) fn test_pda_mismatch_chunks(lang: ProgramLanguage) { + const FINAL_BIT: usize = size_of::() - 1; + + let (setup, instruction, accounts) = pda_init_setup(lang); + + for chunk in 0..size_of::() / size_of::() { + let mut instruction = instruction.clone(); + let mut accounts = accounts.clone(); + + // Flip the last bit of the chunk to create a mismatch. + let flip_index = (chunk * size_of::()) + FINAL_BIT; + accounts[AccountIndex::Tree as usize].0.as_mut()[flip_index] ^= 1; + instruction.accounts[AccountIndex::Tree as usize].pubkey = + accounts[AccountIndex::Tree as usize].0; + + let result = check_error( + &setup, + &instruction, + &accounts, + error_codes::error::PDA_MISMATCH, + ); + assert!( + result.error.is_none(), + "PDA mismatch chunk {}: {}", + chunk, + result.error.unwrap() + ); + } +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 7797c7e3..edeac2f0 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -129,7 +129,7 @@ initialize: mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. mov64 r5, r10 # Get stack frame pointer. - add64 r4, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. + add64 r5, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. call sol_try_find_program_address # Find PDA. # Compare computed PDA against passed account. From a7b3fac8c6bab914faaa9e209a98f01e35e9ae11 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:32:30 -0800 Subject: [PATCH 085/263] Clean up PDA chunk test --- examples/tree/src/tests.rs | 3 +- examples/tree/src/tests/init.rs | 69 +++++++++++++++++++++++++++++++++ examples/tree/src/tests/pda.rs | 67 -------------------------------- 3 files changed, 70 insertions(+), 69 deletions(-) delete mode 100644 examples/tree/src/tests/pda.rs diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 5c4f5e52..3cee17f7 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,6 +1,5 @@ mod entrypoint; mod init; -mod pda; use interface::error_codes; use mollusk_svm::result::ProgramResult as MolluskResult; @@ -99,5 +98,5 @@ fn test_initialize_input_checks() { #[test] fn test_initialize_pda_mismatch() { - pda::test_pda_mismatch_chunks(ProgramLanguage::Assembly); + print_comparison_table(init::InitCase::PDA_CASES); } diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 809e816c..b34cab0e 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -34,6 +34,56 @@ fn init_setup( (setup, instruction, accounts) } +fn pda_init_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, _bump) = Pubkey::find_program_address(&[], &setup.program_id); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), + (system_program_pubkey, system_program_account), + ]; + + (setup, instruction, accounts) +} + +fn run_pda_mismatch_chunk(lang: ProgramLanguage, chunk: usize) -> CaseResult { + const FINAL_BIT: usize = size_of::() - 1; + + let (setup, mut instruction, mut accounts) = pda_init_setup(lang); + + let flip_index = (chunk * size_of::()) + FINAL_BIT; + accounts[AccountIndex::Tree as usize].0.as_mut()[flip_index] ^= 1; + instruction.accounts[AccountIndex::Tree as usize].pubkey = + accounts[AccountIndex::Tree as usize].0; + + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::PDA_MISMATCH, + ) +} + #[derive(Clone, Copy)] pub(super) enum InitCase { UserDataLen, @@ -42,6 +92,10 @@ pub(super) enum InitCase { SystemProgramDuplicate, SystemProgramDataLen, InstructionData, + PdaMismatchChunk0, + PdaMismatchChunk1, + PdaMismatchChunk2, + PdaMismatchChunk3, } impl InitCase { @@ -53,6 +107,13 @@ impl InitCase { Self::SystemProgramDataLen, Self::InstructionData, ]; + + pub(super) const PDA_CASES: &'static [Self] = &[ + Self::PdaMismatchChunk0, + Self::PdaMismatchChunk1, + Self::PdaMismatchChunk2, + Self::PdaMismatchChunk3, + ]; } impl TestCase for InitCase { @@ -64,6 +125,10 @@ impl TestCase for InitCase { Self::SystemProgramDuplicate => "System program is duplicate", Self::SystemProgramDataLen => "System program wrong data length", Self::InstructionData => "Non-empty instruction data", + Self::PdaMismatchChunk0 => "PDA mismatch chunk 0", + Self::PdaMismatchChunk1 => "PDA mismatch chunk 1", + Self::PdaMismatchChunk2 => "PDA mismatch chunk 2", + Self::PdaMismatchChunk3 => "PDA mismatch chunk 3", } } @@ -135,6 +200,10 @@ impl TestCase for InitCase { error_codes::error::INSTRUCTION_DATA, ) } + Self::PdaMismatchChunk0 => run_pda_mismatch_chunk(lang, 0), + Self::PdaMismatchChunk1 => run_pda_mismatch_chunk(lang, 1), + Self::PdaMismatchChunk2 => run_pda_mismatch_chunk(lang, 2), + Self::PdaMismatchChunk3 => run_pda_mismatch_chunk(lang, 3), } } } diff --git a/examples/tree/src/tests/pda.rs b/examples/tree/src/tests/pda.rs deleted file mode 100644 index f10a0e26..00000000 --- a/examples/tree/src/tests/pda.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::*; -use mollusk_svm::program; -use solana_sdk::instruction::AccountMeta; - -fn pda_init_setup( - program_language: ProgramLanguage, -) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(program_language); - let (system_program_pubkey, system_program_account) = - program::keyed_account_for_system_program(); - - let user_pubkey = Pubkey::new_unique(); - // Derive PDA with no seeds (matching CPI_N_SEEDS_TRY_FIND_PDA = 0). - let (tree_pubkey, _bump) = Pubkey::find_program_address(&[], &setup.program_id); - - let instruction = Instruction::new_with_bytes( - setup.program_id, - &[], - vec![ - AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pubkey, false), - AccountMeta::new_readonly(system_program_pubkey, false), - ], - ); - - let accounts = vec![ - ( - user_pubkey, - Account::new(USER_LAMPORTS, 0, &system_program_pubkey), - ), - (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), - (system_program_pubkey, system_program_account), - ]; - - (setup, instruction, accounts) -} - -/// Test PDA mismatch detection in each 8-byte chunk of the 32-byte pubkey. -pub(super) fn test_pda_mismatch_chunks(lang: ProgramLanguage) { - const FINAL_BIT: usize = size_of::() - 1; - - let (setup, instruction, accounts) = pda_init_setup(lang); - - for chunk in 0..size_of::() / size_of::() { - let mut instruction = instruction.clone(); - let mut accounts = accounts.clone(); - - // Flip the last bit of the chunk to create a mismatch. - let flip_index = (chunk * size_of::()) + FINAL_BIT; - accounts[AccountIndex::Tree as usize].0.as_mut()[flip_index] ^= 1; - instruction.accounts[AccountIndex::Tree as usize].pubkey = - accounts[AccountIndex::Tree as usize].0; - - let result = check_error( - &setup, - &instruction, - &accounts, - error_codes::error::PDA_MISMATCH, - ); - assert!( - result.error.is_none(), - "PDA mismatch chunk {}: {}", - chunk, - result.error.unwrap() - ); - } -} From bb9b745997b6772a15dd4c3656be0a7fda9b93aa Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:11:15 -0800 Subject: [PATCH 086/263] Implement address check in RS --- .../snippets/rs/initialize-check-pda.txt | 22 ++++++++ examples/tree/interface/src/asm.rs | 8 +-- examples/tree/interface/src/common.rs | 3 ++ examples/tree/interface/src/lib.rs | 1 + examples/tree/macros/src/lib.rs | 53 +++++++++++++++++-- examples/tree/src/program.rs | 34 ++++++++++-- 6 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/initialize-check-pda.txt diff --git a/examples/tree/artifacts/snippets/rs/initialize-check-pda.txt b/examples/tree/artifacts/snippets/rs/initialize-check-pda.txt new file mode 100644 index 00000000..15419eed --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/initialize-check-pda.txt @@ -0,0 +1,22 @@ + // Invoke syscall. + let mut pda = MaybeUninit::
::uninit(); + let mut bump = MaybeUninit::::uninit(); + sol_try_find_program_address( + null(), + cpi::N_SEEDS_TRY_FIND_PDA, + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + pda.as_mut_ptr().cast(), + bump.as_mut_ptr(), + ); + let pda = pda.assume_init(); + let bump = bump.assume_init(); + + // Compare result with passed PDA. + if !address_eq( + &pda, + transmute::<*const u8, &Address>( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), + ), + ) { + return error::PDA_MISMATCH.into(); + } \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index b289461e..735f563a 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,7 +3,7 @@ extern crate alloc; use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; -use crate::common::{CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; +use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; @@ -46,12 +46,6 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), }); -extend_constant_group!(cpi { - prefix = "CPI", - /// Number of seeds for PDA generation. - N_SEEDS_TRY_FIND_PDA = 0, -}); - #[stack_frame] struct InitStackFrame { bump_seed: u8, diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1568e063..9af528b2 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -46,12 +46,15 @@ pub enum CpiAccountIndex { constant_group! { /// CPI-specific constants. cpi { + prefix = "CPI", /// User and tree accounts must sign CPI. N_ACCOUNTS: usize = 2, /// The tree account is a PDA. N_PDA_SIGNERS: usize = 1, /// The bump seed is required for tree PDA signer. N_SEEDS: usize = 1, + /// Number of seeds for PDA generation. + N_SEEDS_TRY_FIND_PDA: u64 = 0, } } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 31b1e5ed..5bda0316 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -7,4 +7,5 @@ mod bindings; mod common; pub use asm::*; +pub use common::cpi; pub use common::error_codes; diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index df5ae207..605bf2bc 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -229,6 +229,7 @@ struct ConstantDef { struct ConstantGroup { doc: String, name: Ident, + prefix: Option, constants: Vec, } @@ -251,6 +252,9 @@ impl Parse for ConstantGroup { let content; braced!(content in input); + // Parse optional header parameter: prefix = "..." + let prefix = parse_group_params(&content)?; + // Parse constants. let mut constants = Vec::new(); while !content.is_empty() { @@ -388,6 +392,7 @@ impl Parse for ConstantGroup { Ok(ConstantGroup { doc, name, + prefix, constants, }) } @@ -517,10 +522,43 @@ pub fn constant_group(input: TokenStream) -> TokenStream { }) .collect(); - let expanded = quote! { - pub mod #mod_name { - #(#const_defs)* + // Generate to_asm function signature based on whether prefix is baked in. + let to_asm_fn = if let Some(ref prefix) = group.prefix { + let name_format = quote! { format!("{}_{}", #prefix, names[i]) }; + quote! { + /// Generate ASM constants for this module. + pub fn to_asm() -> alloc::string::String { + use alloc::string::String; + use alloc::format; + + let mut result = String::from(#header); + result.push('\n'); + + let names = [#(#const_names),*]; + let computed_values: &[i64] = &[#(#const_idents as i64),*]; + let literal_values: &[Option<&str>] = &[#(#value_str_opts),*]; + let docs = [#(#const_docs),*]; + + for i in 0..names.len() { + let full_name = #name_format; + let value_str = match literal_values[i] { + Some(lit) => String::from(lit), + None => format!("{}", computed_values[i]), + }; + let inline = format!(".equ {}, {} # {}", full_name, value_str, docs[i]); + if inline.len() <= #max_line_len { + result.push_str(&inline); + } else { + result.push_str(&format!("# {}\n.equ {}, {}", docs[i], full_name, value_str)); + } + result.push('\n'); + } + result + } + } + } else { + quote! { /// Generate ASM constants for this module with the given prefix. /// Prefix is automatically joined with underscore (e.g., "IB" -> "IB_NAME"). pub fn to_asm(prefix: &str) -> alloc::string::String { @@ -541,7 +579,6 @@ pub fn constant_group(input: TokenStream) -> TokenStream { } else { format!("{}_{}", prefix, names[i]) }; - // Use original literal if available, otherwise use computed value. let value_str = match literal_values[i] { Some(lit) => String::from(lit), None => format!("{}", computed_values[i]), @@ -560,6 +597,14 @@ pub fn constant_group(input: TokenStream) -> TokenStream { } }; + let expanded = quote! { + pub mod #mod_name { + #(#const_defs)* + + #to_asm_fn + } + }; + TokenStream::from(expanded) } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 63c83d1d..89f82456 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,5 +1,9 @@ -use core::mem::{transmute, MaybeUninit}; -use interface::{data, error_codes::error, input_buffer}; +use core::{ + mem::{transmute, MaybeUninit}, + ptr::null, +}; +use interface::{cpi, data, error_codes::error, input_buffer}; +use pinocchio::syscalls::sol_try_find_program_address; use pinocchio::{ address::address_eq, entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, @@ -108,8 +112,30 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ); // ANCHOR_END: initialize-input-checks - let pda = MaybeUninit::
::uninit(); - let bump = MaybeUninit::::uninit(); + // ANCHOR: initialize-check-pda + // Invoke syscall. + let mut pda = MaybeUninit::
::uninit(); + let mut bump = MaybeUninit::::uninit(); + sol_try_find_program_address( + null(), + cpi::N_SEEDS_TRY_FIND_PDA, + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + pda.as_mut_ptr().cast(), + bump.as_mut_ptr(), + ); + let pda = pda.assume_init(); + let bump = bump.assume_init(); + + // Compare result with passed PDA. + if !address_eq( + &pda, + transmute::<*const u8, &Address>( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), + ), + ) { + return error::PDA_MISMATCH.into(); + } + // ANCHOR_END: initialize-check-pda SUCCESS } From 99ca0ade06fa799f6faeb3512772ebbcdca0aef9 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:22:55 -0800 Subject: [PATCH 087/263] Pin RS vs ASM tests for PDA --- docs/src/examples/tree.md | 16 ++ examples/tree/artifacts/dumps/asm.txt | 155 ++++++++++++------ examples/tree/artifacts/dumps/rs.txt | 103 +++++++----- examples/tree/artifacts/rs-disassembly.s | 84 +++++++--- ...heck-pda.txt => initialize-pda-checks.txt} | 0 ...heck-pda.txt => initialize-pda-checks.txt} | 1 + .../tests/asm_no_accounts/result.txt | 71 -------- .../artifacts/tests/asm_no_accounts/test.txt | 4 - .../tests/asm_return_data/result.txt | 29 ---- .../artifacts/tests/asm_return_data/test.txt | 15 -- .../tests/asm_too_many_accounts/result.txt | 71 -------- .../tests/asm_too_many_accounts/test.txt | 4 - .../tests/asm_tree_duplicate/result.txt | 33 ---- .../tests/asm_tree_duplicate/test.txt | 4 - .../tests/asm_user_data_len/result.txt | 33 ---- .../tests/asm_user_data_len/test.txt | 4 - .../tests/entrypoint_branching/result.txt | 9 + .../artifacts/tests/fast_fails/result.txt | 60 ------- .../tree/artifacts/tests/fast_fails/test.txt | 24 --- .../tests/initialize_input_checks/result.txt | 13 +- .../tests/initialize_pda_checks/result.txt | 40 +++++ .../tests/initialize_pda_checks/test.txt | 4 + .../artifacts/tests/rs_no_accounts/result.txt | 33 ---- .../artifacts/tests/rs_no_accounts/test.txt | 4 - .../tests/rs_too_many_accounts/result.txt | 33 ---- .../tests/rs_too_many_accounts/test.txt | 4 - .../tests/rs_tree_duplicate/result.txt | 33 ---- .../tests/rs_tree_duplicate/test.txt | 4 - .../tests/rs_user_data_len/result.txt | 33 ---- .../artifacts/tests/rs_user_data_len/test.txt | 4 - examples/tree/src/program.rs | 6 +- examples/tree/src/tests.rs | 2 +- examples/tree/src/tests/init.rs | 8 +- examples/tree/src/tree/tree.s | 4 +- 34 files changed, 324 insertions(+), 621 deletions(-) rename examples/tree/artifacts/snippets/asm/{initialize-check-pda.txt => initialize-pda-checks.txt} (100%) rename examples/tree/artifacts/snippets/rs/{initialize-check-pda.txt => initialize-pda-checks.txt} (95%) delete mode 100644 examples/tree/artifacts/tests/asm_no_accounts/result.txt delete mode 100644 examples/tree/artifacts/tests/asm_no_accounts/test.txt delete mode 100644 examples/tree/artifacts/tests/asm_return_data/result.txt delete mode 100644 examples/tree/artifacts/tests/asm_return_data/test.txt delete mode 100644 examples/tree/artifacts/tests/asm_too_many_accounts/result.txt delete mode 100644 examples/tree/artifacts/tests/asm_too_many_accounts/test.txt delete mode 100644 examples/tree/artifacts/tests/asm_tree_duplicate/result.txt delete mode 100644 examples/tree/artifacts/tests/asm_tree_duplicate/test.txt delete mode 100644 examples/tree/artifacts/tests/asm_user_data_len/result.txt delete mode 100644 examples/tree/artifacts/tests/asm_user_data_len/test.txt delete mode 100644 examples/tree/artifacts/tests/fast_fails/result.txt delete mode 100644 examples/tree/artifacts/tests/fast_fails/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/rs_no_accounts/result.txt delete mode 100644 examples/tree/artifacts/tests/rs_no_accounts/test.txt delete mode 100644 examples/tree/artifacts/tests/rs_too_many_accounts/result.txt delete mode 100644 examples/tree/artifacts/tests/rs_too_many_accounts/test.txt delete mode 100644 examples/tree/artifacts/tests/rs_tree_duplicate/result.txt delete mode 100644 examples/tree/artifacts/tests/rs_tree_duplicate/test.txt delete mode 100644 examples/tree/artifacts/tests/rs_user_data_len/result.txt delete mode 100644 examples/tree/artifacts/tests/rs_user_data_len/test.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 54f3d51f..bb2e8d79 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -39,6 +39,22 @@ performance. +## Initialize PDA checks + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt{rs} [Rust] + +::: + + + + + ## :white_check_mark: All tests ::: details `tests.rs` diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 8c9ee848..e9f6aed2 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -9,75 +9,138 @@ ELF Header Type DYN (Shared object file) Machine EM_BPF Version 0x1 - Entry point address 0x40 + Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 360 (bytes into file) + Start of section headers 1080 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) - Number of program headers 0 + Number of program headers 3 Size of section headers 64 (bytes) - Number of section headers 3 - Section header string table index 2 -There are 3 section headers, starting at offset 0x168 + Number of section headers 7 + Section header string table index 6 +There are 7 section headers, starting at offset 0x438 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000040 000040 000118 00 AX 0 0 4 - [ 2] .s STRTAB 0000000000000000 000158 00000a 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0001f8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000002e0 0002e0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000380 000380 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003c8 0003c8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000003f8 0003f8 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000408 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), R (retain), p (processor specific) -There are no program headers in this file. +Elf file type is DYN (Shared object file) +Entry point 0xe8 +There are 3 program headers, starting at offset 64 + +Program Headers + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001f8 0x0001f8 R E 0x1000 + LOAD 0x000380 0x0000000000000380 0x0000000000000380 0x000088 0x000088 R 0x1000 + DYNAMIC 0x0002e0 0x00000000000002e0 0x00000000000002e0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... - None .text .s + 00 .text + 01 .dynsym .dynstr .rel.dyn + 02 .dynamic + None .s +Dynamic section at offset 0x2e0 contains 10 entries + Tag Type Name/Value + 0x000000000000001e (FLAGS) TEXTREL + 0x0000000000000011 (REL) 0x3f8 + 0x0000000000000012 (RELSZ) 16 (bytes) + 0x0000000000000013 (RELENT) 16 (bytes) + 0x0000000000000006 (SYMTAB) 0x380 + 0x000000000000000b (SYMENT) 24 (bytes) + 0x0000000000000005 (STRTAB) 0x3c8 + 0x000000000000000a (STRSZ) 48 (bytes) + 0x0000000000000016 (TEXTREL) 0x0 + 0x0000000000000000 (NULL) 0x0 + +Relocation section '.rel.dyn' at offset 0x3f8 contains 1 entries + Offset Info Type Symbol's Value Symbol's Name +00000000000001d0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -There are no relocations in this file. +Symbol table '.dynsym' contains 3 entries + Num Value Size Type Bind Vis Ndx Name + 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1 00000000000000e8 0 NOTYPE GLOBAL DEFAULT 1 entrypoint + 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_try_find_program_address There are no section groups in this file. tree.so file format elf64-bpf Disassembly of section .text -0000000000000040 <.text> - 8 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) - 9 15 02 03 00 02 00 00 00 if r2 == 0x2 goto +0x3 <.text+0x28> - 10 15 02 07 00 03 00 00 00 if r2 == 0x3 goto +0x7 <.text+0x50> - 11 b7 00 00 00 01 00 00 00 r0 = 0x1 - 12 95 00 00 00 00 00 00 00 exit - 13 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 14 07 02 00 00 07 00 00 00 r2 += 0x7 - 15 57 02 00 00 f8 ff ff ff r2 &= -0x8 - 16 0f 12 00 00 00 00 00 00 r2 += r1 - 17 95 00 00 00 00 00 00 00 exit - 18 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 19 55 02 15 00 00 00 00 00 if r2 != 0x0 goto +0x15 <.text+0x108> - 20 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 21 55 02 11 00 ff 00 00 00 if r2 != 0xff goto +0x11 <.text+0xf8> - 22 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 23 55 02 0d 00 00 00 00 00 if r2 != 0x0 goto +0xd <.text+0xe8> - 24 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) - 25 55 02 09 00 ff 00 00 00 if r2 != 0xff goto +0x9 <.text+0xd8> - 26 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) - 27 55 02 05 00 0e 00 00 00 if r2 != 0xe goto +0x5 <.text+0xc8> - 28 79 12 38 79 00 00 00 00 r2 = *(u64 *)(r1 + 0x7938) - 29 55 02 01 00 00 00 00 00 if r2 != 0x0 goto +0x1 <.text+0xb8> - 30 95 00 00 00 00 00 00 00 exit - 31 b7 00 00 00 07 00 00 00 r0 = 0x7 - 32 95 00 00 00 00 00 00 00 exit - 33 b7 00 00 00 04 00 00 00 r0 = 0x4 - 34 95 00 00 00 00 00 00 00 exit - 35 b7 00 00 00 06 00 00 00 r0 = 0x6 - 36 95 00 00 00 00 00 00 00 exit - 37 b7 00 00 00 03 00 00 00 r0 = 0x3 +00000000000000e8 + 29 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) + 30 15 02 03 00 02 00 00 00 if r2 == 0x2 goto +0x3 + 31 15 02 07 00 03 00 00 00 if r2 == 0x3 goto +0x7 + 32 b7 00 00 00 01 00 00 00 r0 = 0x1 + 33 95 00 00 00 00 00 00 00 exit + 34 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 35 07 02 00 00 07 00 00 00 r2 += 0x7 + 36 57 02 00 00 f8 ff ff ff r2 &= -0x8 + 37 0f 12 00 00 00 00 00 00 r2 += r1 38 95 00 00 00 00 00 00 00 exit - 39 b7 00 00 00 05 00 00 00 r0 = 0x5 - 40 95 00 00 00 00 00 00 00 exit - 41 b7 00 00 00 02 00 00 00 r0 = 0x2 - 42 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 39 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) + 40 55 02 31 00 00 00 00 00 if r2 != 0x0 goto +0x31 + 41 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) + 42 55 02 2d 00 ff 00 00 00 if r2 != 0xff goto +0x2d + 43 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) + 44 55 02 29 00 00 00 00 00 if r2 != 0x0 goto +0x29 + 45 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) + 46 55 02 25 00 ff 00 00 00 if r2 != 0xff goto +0x25 + 47 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) + 48 55 02 21 00 0e 00 00 00 if r2 != 0xe goto +0x21 + 49 79 12 38 79 00 00 00 00 r2 = *(u64 *)(r1 + 0x7938) + 50 55 02 1b 00 00 00 00 00 if r2 != 0x0 goto +0x1b + 51 b7 02 00 00 00 00 00 00 r2 = 0x0 + 52 bf 13 00 00 00 00 00 00 r3 = r1 + 53 07 03 00 00 40 79 00 00 r3 += 0x7940 + 54 bf a4 00 00 00 00 00 00 r4 = r10 + 55 07 04 00 00 98 ff ff ff r4 += -0x68 + 56 bf a5 00 00 00 00 00 00 r5 = r10 + 57 07 05 00 00 98 fe ff ff r5 += -0x168 + 58 85 10 00 00 ff ff ff ff call -0x1 + 59 bf 13 00 00 00 00 00 00 r3 = r1 + 60 07 03 00 00 70 28 00 00 r3 += 0x2870 + 61 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 62 79 46 00 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x0) + 63 5d 65 10 00 00 00 00 00 if r5 != r6 goto +0x10 + 64 79 35 08 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x8) + 65 79 46 08 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x8) + 66 5d 65 0d 00 00 00 00 00 if r5 != r6 goto +0xd + 67 79 35 10 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x10) + 68 79 46 10 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x10) + 69 5d 65 0a 00 00 00 00 00 if r5 != r6 goto +0xa + 70 79 35 18 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x18) + 71 79 46 18 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x18) + 72 5d 65 07 00 00 00 00 00 if r5 != r6 goto +0x7 + 73 bf a2 00 00 00 00 00 00 r2 = r10 + 74 07 02 00 00 98 fe ff ff r2 += -0x168 + 75 7b 2a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r2 + 76 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 77 95 00 00 00 00 00 00 00 exit + 78 b7 00 00 00 07 00 00 00 r0 = 0x7 + 79 95 00 00 00 00 00 00 00 exit + 80 b7 00 00 00 08 00 00 00 r0 = 0x8 + 81 95 00 00 00 00 00 00 00 exit + 82 b7 00 00 00 04 00 00 00 r0 = 0x4 + 83 95 00 00 00 00 00 00 00 exit + 84 b7 00 00 00 06 00 00 00 r0 = 0x6 + 85 95 00 00 00 00 00 00 00 exit + 86 b7 00 00 00 03 00 00 00 r0 = 0x3 + 87 95 00 00 00 00 00 00 00 exit + 88 b7 00 00 00 05 00 00 00 r0 = 0x5 + 89 95 00 00 00 00 00 00 00 exit + 90 b7 00 00 00 02 00 00 00 r0 = 0x2 + 91 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 164aeb65..cd53f420 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 2864 (bytes into file) + Start of section headers 3080 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xb30 +There are 8 section headers, starting at offset 0xc08 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000120 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000240 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000248 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000248 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000248 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0005c0 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0005fe 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0001f8 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000318 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000320 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000320 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000320 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000698 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006d6 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000120 0x000120 E 0x8 - LOAD 0x000240 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000248 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000248 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001f8 0x0001f8 E 0x8 + LOAD 0x000318 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000320 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000320 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 288 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 504 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,7 +104,7 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 00 00 00 00 add64 r10, 0x0 + 0 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] 10 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] @@ -112,31 +112,58 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 02 11 00 03 00 00 00 jne r2, 0x3, +0x11 + 40 55 02 2a 00 03 00 00 00 jne r2, 0x3, +0x2a 48 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 50 55 02 0d 00 00 00 00 00 jne r2, 0x0, +0xd + 50 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 60 55 02 0f 00 ff 00 00 00 jne r2, 0xff, +0xf + 60 55 02 28 00 ff 00 00 00 jne r2, 0xff, +0x28 68 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 70 55 02 0f 00 00 00 00 00 jne r2, 0x0, +0xf + 70 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 78 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 80 55 02 0f 00 ff 00 00 00 jne r2, 0xff, +0xf + 80 55 02 28 00 ff 00 00 00 jne r2, 0xff, +0x28 88 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 90 55 02 0f 00 0e 00 00 00 jne r2, 0xe, +0xf - 98 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - a0 9c 11 38 79 00 00 00 00 ldxdw r1, [r1 + 0x7938] - a8 15 01 f1 ff 00 00 00 00 jeq r1, 0x0, -0xf - b0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - b8 05 00 ef ff 00 00 00 00 ja -0x11 - c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c8 05 00 ed ff 00 00 00 00 ja -0x13 - d0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - d8 05 00 eb ff 00 00 00 00 ja -0x15 - e0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - e8 05 00 e9 ff 00 00 00 00 ja -0x17 - f0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - f8 05 00 e7 ff 00 00 00 00 ja -0x19 - 100 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 108 05 00 e5 ff 00 00 00 00 ja -0x1b - 110 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 118 05 00 e3 ff 00 00 00 00 ja -0x1d \ No newline at end of file + 90 55 02 28 00 0e 00 00 00 jne r2, 0xe, +0x28 + 98 9c 12 38 79 00 00 00 00 ldxdw r2, [r1 + 0x7938] + a0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 + a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + b0 07 03 00 00 40 79 00 00 add64 r3, 0x7940 + b8 bf a4 00 00 00 00 00 00 mov64 r4, r10 + c0 07 04 00 00 18 00 00 00 add64 r4, 0x18 + c8 bf a5 00 00 00 00 00 00 mov64 r5, r10 + d0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f + d8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + e0 b7 01 00 00 00 00 00 00 mov64 r1, 0x0 + e8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + f0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + f8 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 100 9c 12 70 28 00 00 00 00 ldxdw r2, [r1 + 0x2870] + 108 9c a3 18 00 00 00 00 00 ldxdw r3, [r10 + 0x18] + 110 5d 23 0c 00 00 00 00 00 jne r3, r2, +0xc + 118 9c 12 78 28 00 00 00 00 ldxdw r2, [r1 + 0x2878] + 120 9c a3 20 00 00 00 00 00 ldxdw r3, [r10 + 0x20] + 128 5d 23 09 00 00 00 00 00 jne r3, r2, +0x9 + 130 9c a2 28 00 00 00 00 00 ldxdw r2, [r10 + 0x28] + 138 9c 13 80 28 00 00 00 00 ldxdw r3, [r1 + 0x2880] + 140 5d 32 06 00 00 00 00 00 jne r2, r3, +0x6 + 148 9c a2 30 00 00 00 00 00 ldxdw r2, [r10 + 0x30] + 150 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 158 9c 11 88 28 00 00 00 00 ldxdw r1, [r1 + 0x2888] + 160 5d 12 da ff 00 00 00 00 jne r2, r1, -0x26 + 168 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 170 05 00 d8 ff 00 00 00 00 ja -0x28 + 178 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 180 05 00 d6 ff 00 00 00 00 ja -0x2a + 188 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 190 05 00 d4 ff 00 00 00 00 ja -0x2c + 198 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e + 1a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 + 1b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1c0 05 00 ce ff 00 00 00 00 ja -0x32 + 1c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1d0 05 00 cc ff 00 00 00 00 ja -0x34 + 1d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 1e0 05 00 ca ff 00 00 00 00 ja -0x36 + 1e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 98bafd5a..303dd100 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,54 +1,86 @@ .globl entrypoint entrypoint: + add64 r10, -64 ldxdw r2, [r1+0] - jne r2, 2, jmp_0038 + jne r2, 2, jmp_0040 ldxdw r1, [r1+88] mov64 r0, 6677 - jeq r1, 67, jmp_0030 + jeq r1, 67, jmp_0038 mov64 r0, 666777 -jmp_0030: +jmp_0038: exit -jmp_0038: - jne r2, 3, jmp_00c8 +jmp_0040: + jne r2, 3, jmp_0198 ldxdw r2, [r1+88] - jne r2, 0, jmp_00b8 + jne r2, 0, jmp_0188 ldxb r2, [r1+10344] - jne r2, 255, jmp_00d8 + jne r2, 255, jmp_01a8 ldxdw r2, [r1+10424] - jne r2, 0, jmp_00e8 + jne r2, 0, jmp_01b8 ldxb r2, [r1+20680] - jne r2, 255, jmp_00f8 + jne r2, 255, jmp_01c8 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0108 + jne r2, 14, jmp_01d8 + ldxdw r2, [r1+31032] + jne r2, 0, jmp_01e8 + mov64 r3, r1 + add64 r3, 31040 + mov64 r4, r10 + add64 r4, 24 + mov64 r5, r10 + add64 r5, 63 + mov64 r6, r1 + mov64 r1, 0 + mov64 r2, 0 + call sol_try_find_program_address + mov64 r1, r6 + ldxdw r2, [r1+10352] + ldxdw r3, [r10+24] + jne r3, r2, jmp_0178 + ldxdw r2, [r1+10360] + ldxdw r3, [r10+32] + jne r3, r2, jmp_0178 + ldxdw r2, [r10+40] + ldxdw r3, [r1+10368] + jne r2, r3, jmp_0178 + ldxdw r2, [r10+48] + mov64 r0, 8 + ldxdw r1, [r1+10376] + jne r2, r1, jmp_0038 mov64 r0, 0 - ldxdw r1, [r1+31032] - jeq r1, 0, jmp_0030 - mov64 r0, 7 - ja jmp_0030 + ja jmp_0038 -jmp_00b8: +jmp_0178: + mov64 r0, 8 + ja jmp_0038 + +jmp_0188: mov64 r0, 2 - ja jmp_0030 + ja jmp_0038 -jmp_00c8: +jmp_0198: mov64 r0, 1 - ja jmp_0030 + ja jmp_0038 -jmp_00d8: +jmp_01a8: mov64 r0, 5 - ja jmp_0030 + ja jmp_0038 -jmp_00e8: +jmp_01b8: mov64 r0, 3 - ja jmp_0030 + ja jmp_0038 -jmp_00f8: +jmp_01c8: mov64 r0, 6 - ja jmp_0030 + ja jmp_0038 -jmp_0108: +jmp_01d8: mov64 r0, 4 - ja jmp_0030 + ja jmp_0038 + +jmp_01e8: + mov64 r0, 7 + ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/initialize-check-pda.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt similarity index 100% rename from examples/tree/artifacts/snippets/asm/initialize-check-pda.txt rename to examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt diff --git a/examples/tree/artifacts/snippets/rs/initialize-check-pda.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt similarity index 95% rename from examples/tree/artifacts/snippets/rs/initialize-check-pda.txt rename to examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 15419eed..a6afe48b 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-check-pda.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -1,6 +1,7 @@ // Invoke syscall. let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); + #[cfg(target_os = "solana")] sol_try_find_program_address( null(), cpi::N_SEEDS_TRY_FIND_PDA, diff --git a/examples/tree/artifacts/tests/asm_no_accounts/result.txt b/examples/tree/artifacts/tests/asm_no_accounts/result.txt deleted file mode 100644 index 1047725e..00000000 --- a/examples/tree/artifacts/tests/asm_no_accounts/result.txt +++ /dev/null @@ -1,71 +0,0 @@ -test tests::test_asm_no_accounts ... ok -warning: constant `CPI_N_ACCOUNTS` is never used - --> tree/interface/src/asm.rs:71:7 - | -71 | const CPI_N_ACCOUNTS: usize = 2; - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: constant `CPI_N_PDA_SIGNERS` is never used - --> tree/interface/src/asm.rs:73:7 - | -73 | const CPI_N_PDA_SIGNERS: usize = 1; - | ^^^^^^^^^^^^^^^^^ -warning: constant `CPI_N_SEEDS` is never used - --> tree/interface/src/asm.rs:75:7 - | -75 | const CPI_N_SEEDS: usize = 1; - | ^^^^^^^^^^^ -warning: struct `InitStackFrame` is never constructed - --> tree/interface/src/asm.rs:78:8 - | -78 | struct InitStackFrame { - | ^^^^^^^^^^^^^^ -warning: struct `SolInstruction` is never constructed - --> tree/interface/src/bindings.rs:7:12 - | -7 | pub struct SolInstruction { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountMeta` is never constructed - --> tree/interface/src/bindings.rs:23:12 - | -23 | pub struct SolAccountMeta { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountInfo` is never constructed - --> tree/interface/src/bindings.rs:35:12 - | -35 | pub struct SolAccountInfo { - | ^^^^^^^^^^^^^^ -warning: struct `SolSignerSeed` is never constructed - --> tree/interface/src/bindings.rs:59:12 - | -59 | pub struct SolSignerSeed { - | ^^^^^^^^^^^^^ -warning: struct `SolSignerSeeds` is never constructed - --> tree/interface/src/bindings.rs:69:12 - | -69 | pub struct SolSignerSeeds { - | ^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:27:8 - | -27 | struct Return { - | ^^^^^^ -warning: struct `CreateAccountInstructionData` is never constructed - --> tree/interface/src/common.rs:36:12 - | -36 | pub struct CreateAccountInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `interface` (lib) generated 11 warnings -warning: `interface` (lib) generated 11 warnings (11 duplicates) -warning: unused variable: `bump` - --> tree/src/program.rs:45:32 - | -45 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 1 warning -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_no_accounts/test.txt b/examples/tree/artifacts/tests/asm_no_accounts/test.txt deleted file mode 100644 index 81c7c702..00000000 --- a/examples/tree/artifacts/tests/asm_no_accounts/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_asm_no_accounts() { - run_no_accounts(ProgramLanguage::Assembly); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_return_data/result.txt b/examples/tree/artifacts/tests/asm_return_data/result.txt deleted file mode 100644 index 45c65ca2..00000000 --- a/examples/tree/artifacts/tests/asm_return_data/result.txt +++ /dev/null @@ -1,29 +0,0 @@ -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_return_data/test.txt b/examples/tree/artifacts/tests/asm_return_data/test.txt deleted file mode 100644 index 107f5caf..00000000 --- a/examples/tree/artifacts/tests/asm_return_data/test.txt +++ /dev/null @@ -1,15 +0,0 @@ -#[test] -fn test_asm_return_data() { - let (setup, instruction, accounts) = happy_path_setup(ProgramLanguage::Assembly); - let user_pubkey = instruction.accounts[AccountIndex::User as usize].pubkey; - - let result = setup - .mollusk - .process_and_validate_instruction(&instruction, &accounts, &[Check::success()]); - - assert_eq!( - result.return_data, - user_pubkey.to_bytes(), - "return data should be user pubkey" - ); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt deleted file mode 100644 index b52aa1ec..00000000 --- a/examples/tree/artifacts/tests/asm_too_many_accounts/result.txt +++ /dev/null @@ -1,71 +0,0 @@ -test tests::test_asm_too_many_accounts ... ok -warning: constant `CPI_N_ACCOUNTS` is never used - --> tree/interface/src/asm.rs:71:7 - | -71 | const CPI_N_ACCOUNTS: usize = 2; - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: constant `CPI_N_PDA_SIGNERS` is never used - --> tree/interface/src/asm.rs:73:7 - | -73 | const CPI_N_PDA_SIGNERS: usize = 1; - | ^^^^^^^^^^^^^^^^^ -warning: constant `CPI_N_SEEDS` is never used - --> tree/interface/src/asm.rs:75:7 - | -75 | const CPI_N_SEEDS: usize = 1; - | ^^^^^^^^^^^ -warning: struct `InitStackFrame` is never constructed - --> tree/interface/src/asm.rs:78:8 - | -78 | struct InitStackFrame { - | ^^^^^^^^^^^^^^ -warning: struct `SolInstruction` is never constructed - --> tree/interface/src/bindings.rs:7:12 - | -7 | pub struct SolInstruction { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountMeta` is never constructed - --> tree/interface/src/bindings.rs:23:12 - | -23 | pub struct SolAccountMeta { - | ^^^^^^^^^^^^^^ -warning: struct `SolAccountInfo` is never constructed - --> tree/interface/src/bindings.rs:35:12 - | -35 | pub struct SolAccountInfo { - | ^^^^^^^^^^^^^^ -warning: struct `SolSignerSeed` is never constructed - --> tree/interface/src/bindings.rs:59:12 - | -59 | pub struct SolSignerSeed { - | ^^^^^^^^^^^^^ -warning: struct `SolSignerSeeds` is never constructed - --> tree/interface/src/bindings.rs:69:12 - | -69 | pub struct SolSignerSeeds { - | ^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:27:8 - | -27 | struct Return { - | ^^^^^^ -warning: struct `CreateAccountInstructionData` is never constructed - --> tree/interface/src/common.rs:36:12 - | -36 | pub struct CreateAccountInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `interface` (lib) generated 11 warnings -warning: `interface` (lib) generated 11 warnings (11 duplicates) -warning: unused variable: `bump` - --> tree/src/program.rs:45:32 - | -45 | let (expected_pda, bump) = Address::find_program_address(&[], program_id); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 1 warning -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt b/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt deleted file mode 100644 index 34851030..00000000 --- a/examples/tree/artifacts/tests/asm_too_many_accounts/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_asm_too_many_accounts() { - run_too_many_accounts(ProgramLanguage::Assembly); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt b/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt deleted file mode 100644 index f81391b7..00000000 --- a/examples/tree/artifacts/tests/asm_tree_duplicate/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_asm_tree_duplicate ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt b/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt deleted file mode 100644 index 795d0a06..00000000 --- a/examples/tree/artifacts/tests/asm_tree_duplicate/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_asm_tree_duplicate() { - run_tree_duplicate(ProgramLanguage::Assembly); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_user_data_len/result.txt b/examples/tree/artifacts/tests/asm_user_data_len/result.txt deleted file mode 100644 index fed22ab3..00000000 --- a/examples/tree/artifacts/tests/asm_user_data_len/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_asm_user_data_len ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/asm_user_data_len/test.txt b/examples/tree/artifacts/tests/asm_user_data_len/test.txt deleted file mode 100644 index 90ee3df2..00000000 --- a/examples/tree/artifacts/tests/asm_user_data_len/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_asm_user_data_len() { - run_user_data_len(ProgramLanguage::Assembly); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index b36b9ca3..e26681ce 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -4,6 +4,15 @@ | One account | 5 | 7 | +2 | +40.0% | | Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok +warning: enum `CpiAccountIndex` is never used + --> tree/interface/src/common.rs:41:10 + | +41 | pub enum CpiAccountIndex { + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `interface` (lib) generated 1 warning +warning: `interface` (lib) generated 1 warning (1 duplicate) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/fast_fails/result.txt b/examples/tree/artifacts/tests/fast_fails/result.txt deleted file mode 100644 index f79a3df7..00000000 --- a/examples/tree/artifacts/tests/fast_fails/result.txt +++ /dev/null @@ -1,60 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts passed | 4 | 5 | +1 | +25.0% | -| Too many accounts passed | 4 | 5 | +1 | +25.0% | -| User has nonzero data length | 6 | 10 | +4 | +66.7% | -| Tree account is duplicate | 8 | 16 | +8 | +100.0% | -test tests::test_fast_fails ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/fast_fails/test.txt b/examples/tree/artifacts/tests/fast_fails/test.txt deleted file mode 100644 index bdd6e7b5..00000000 --- a/examples/tree/artifacts/tests/fast_fails/test.txt +++ /dev/null @@ -1,24 +0,0 @@ -#[test] -fn test_fast_fails() { - println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|------|-----------|------------|----------|------------|"); - - for case in Case::PARSING_CASES { - let asm_cu = case.run(ProgramLanguage::Assembly); - let rs_cu = case.run(ProgramLanguage::Rust); - let overhead = rs_cu as i64 - asm_cu as i64; - let overhead_pct = if asm_cu > 0 { - (overhead as f64 / asm_cu as f64) * 100.0 - } else { - 0.0 - }; - println!( - "| {} | {} | {} | {:+} | {:+.1}% |", - case.name(), - asm_cu, - rs_cu, - overhead, - overhead_pct - ); - } -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 769058c4..354eee1d 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -5,8 +5,17 @@ | Tree has nonzero data length | 11 | 13 | +2 | +18.2% | | System program is duplicate | 13 | 15 | +2 | +15.4% | | System program wrong data length | 15 | 17 | +2 | +13.3% | -| Non-empty instruction data | 17 | 20 | +3 | +17.6% | +| Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok +warning: enum `CpiAccountIndex` is never used + --> tree/interface/src/common.rs:41:10 + | +41 | pub enum CpiAccountIndex { + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `interface` (lib) generated 1 warning +warning: `interface` (lib) generated 1 warning (1 duplicate) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 @@ -41,5 +50,5 @@ test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..cbfd932a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,40 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1530 | 1533 | +3 | +0.2% | +| PDA mismatch chunk 2 | 1533 | 1536 | +3 | +0.2% | +| PDA mismatch chunk 3 | 1536 | 1539 | +3 | +0.2% | +| PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | +test tests::test_initialize_pda_checks ... ok +warning: enum `CpiAccountIndex` is never used + --> tree/interface/src/common.rs:41:10 + | +41 | pub enum CpiAccountIndex { + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `interface` (lib) generated 1 warning +warning: `interface` (lib) generated 1 warning (1 duplicate) +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..5bd90196 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_no_accounts/result.txt b/examples/tree/artifacts/tests/rs_no_accounts/result.txt deleted file mode 100644 index 9e6ba6e6..00000000 --- a/examples/tree/artifacts/tests/rs_no_accounts/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_rs_no_accounts ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_no_accounts/test.txt b/examples/tree/artifacts/tests/rs_no_accounts/test.txt deleted file mode 100644 index e1a69a29..00000000 --- a/examples/tree/artifacts/tests/rs_no_accounts/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_rs_no_accounts() { - run_no_accounts(ProgramLanguage::Rust); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt b/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt deleted file mode 100644 index 511c887b..00000000 --- a/examples/tree/artifacts/tests/rs_too_many_accounts/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_rs_too_many_accounts ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt b/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt deleted file mode 100644 index 0b789239..00000000 --- a/examples/tree/artifacts/tests/rs_too_many_accounts/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_rs_too_many_accounts() { - run_too_many_accounts(ProgramLanguage::Rust); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt b/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt deleted file mode 100644 index 79e01f75..00000000 --- a/examples/tree/artifacts/tests/rs_tree_duplicate/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_rs_tree_duplicate ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt b/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt deleted file mode 100644 index 7f272336..00000000 --- a/examples/tree/artifacts/tests/rs_tree_duplicate/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_rs_tree_duplicate() { - run_tree_duplicate(ProgramLanguage::Rust); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_user_data_len/result.txt b/examples/tree/artifacts/tests/rs_user_data_len/result.txt deleted file mode 100644 index 36bb311d..00000000 --- a/examples/tree/artifacts/tests/rs_user_data_len/result.txt +++ /dev/null @@ -1,33 +0,0 @@ -test tests::test_rs_user_data_len ... ok -warning: struct `InitInstructionData` is never constructed - --> tree/interface/src/common.rs:20:8 - | -20 | struct InitInstructionData {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: struct `GetInstructionData` is never constructed - --> tree/interface/src/common.rs:22:8 - | -22 | struct GetInstructionData { - | ^^^^^^^^^^^^^^^^^^ -warning: struct `InsertInstructionData` is never constructed - --> tree/interface/src/common.rs:26:8 - | -26 | struct InsertInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `RemoveInstructionData` is never constructed - --> tree/interface/src/common.rs:31:8 - | -31 | struct RemoveInstructionData { - | ^^^^^^^^^^^^^^^^^^^^^ -warning: struct `Return` is never constructed - --> tree/interface/src/common.rs:37:8 - | -37 | struct Return { - | ^^^^^^ -warning: `interface` (lib) generated 5 warnings -warning: `interface` (lib) generated 5 warnings (5 duplicates) -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/rs_user_data_len/test.txt b/examples/tree/artifacts/tests/rs_user_data_len/test.txt deleted file mode 100644 index e2c49a6a..00000000 --- a/examples/tree/artifacts/tests/rs_user_data_len/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_rs_user_data_len() { - run_user_data_len(ProgramLanguage::Rust); -} \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 89f82456..88a9618d 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -3,6 +3,7 @@ use core::{ ptr::null, }; use interface::{cpi, data, error_codes::error, input_buffer}; +#[cfg(target_os = "solana")] use pinocchio::syscalls::sol_try_find_program_address; use pinocchio::{ address::address_eq, @@ -112,10 +113,11 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ); // ANCHOR_END: initialize-input-checks - // ANCHOR: initialize-check-pda + // ANCHOR: initialize-pda-checks // Invoke syscall. let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); + #[cfg(target_os = "solana")] sol_try_find_program_address( null(), cpi::N_SEEDS_TRY_FIND_PDA, @@ -135,7 +137,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ) { return error::PDA_MISMATCH.into(); } - // ANCHOR_END: initialize-check-pda + // ANCHOR_END: initialize-pda-checks SUCCESS } diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 3cee17f7..68589a65 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -97,6 +97,6 @@ fn test_initialize_input_checks() { } #[test] -fn test_initialize_pda_mismatch() { +fn test_initialize_pda_checks() { print_comparison_table(init::InitCase::PDA_CASES); } diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index b34cab0e..6d512ee6 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -125,10 +125,10 @@ impl TestCase for InitCase { Self::SystemProgramDuplicate => "System program is duplicate", Self::SystemProgramDataLen => "System program wrong data length", Self::InstructionData => "Non-empty instruction data", - Self::PdaMismatchChunk0 => "PDA mismatch chunk 0", - Self::PdaMismatchChunk1 => "PDA mismatch chunk 1", - Self::PdaMismatchChunk2 => "PDA mismatch chunk 2", - Self::PdaMismatchChunk3 => "PDA mismatch chunk 3", + Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", + Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", + Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", + Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index edeac2f0..1d46e927 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -120,7 +120,7 @@ initialize: jne r2, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks - # ANCHOR: initialize-check-pda + # ANCHOR: initialize-pda-checks # Compute PDA. # ------------ mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. @@ -148,7 +148,7 @@ initialize: ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] jne r5, r6, e_pda_mismatch - # ANCHOR_END: initialize-check-pda + # ANCHOR_END: initialize-pda-checks # Initialize signer seed for PDA bump key. # ---------------------------------------- From 44f3b2600e7d3b78ee13b3b45248cb7bd82db392 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:24:46 -0800 Subject: [PATCH 088/263] Silence warning --- .../tree/artifacts/tests/entrypoint_branching/result.txt | 9 --------- .../artifacts/tests/initialize_input_checks/result.txt | 9 --------- .../artifacts/tests/initialize_pda_checks/result.txt | 9 --------- examples/tree/interface/src/common.rs | 6 ------ 4 files changed, 33 deletions(-) diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index e26681ce..b36b9ca3 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -4,15 +4,6 @@ | One account | 5 | 7 | +2 | +40.0% | | Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok -warning: enum `CpiAccountIndex` is never used - --> tree/interface/src/common.rs:41:10 - | -41 | pub enum CpiAccountIndex { - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `interface` (lib) generated 1 warning -warning: `interface` (lib) generated 1 warning (1 duplicate) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 354eee1d..1bcf1d9b 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -7,15 +7,6 @@ | System program wrong data length | 15 | 17 | +2 | +13.3% | | Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok -warning: enum `CpiAccountIndex` is never used - --> tree/interface/src/common.rs:41:10 - | -41 | pub enum CpiAccountIndex { - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `interface` (lib) generated 1 warning -warning: `interface` (lib) generated 1 warning (1 duplicate) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index cbfd932a..444c18e6 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -5,15 +5,6 @@ | PDA mismatch chunk 3 | 1536 | 1539 | +3 | +0.2% | | PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | test tests::test_initialize_pda_checks ... ok -warning: enum `CpiAccountIndex` is never used - --> tree/interface/src/common.rs:41:10 - | -41 | pub enum CpiAccountIndex { - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `interface` (lib) generated 1 warning -warning: `interface` (lib) generated 1 warning (1 duplicate) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 9af528b2..e1667c53 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -37,12 +37,6 @@ constant_group! { } } -#[repr(usize)] -pub enum CpiAccountIndex { - User, - Tree, -} - constant_group! { /// CPI-specific constants. cpi { From 5d3a345d2e06ed52718737443c4367ad9685cb2c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:26:19 -0800 Subject: [PATCH 089/263] Disallow warnings --- .../tests/entrypoint_branching/result.txt | 46 ++++++++++++++++++ .../tests/initialize_input_checks/result.txt | 47 +++++++++++++++++++ .../tests/initialize_pda_checks/result.txt | 46 ++++++++++++++++++ examples/tree/interface/src/bindings.rs | 1 - examples/tree/src/lib.rs | 1 - 5 files changed, 139 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index b36b9ca3..2422ee23 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -4,6 +4,52 @@ | One account | 5 | 7 | +2 | +40.0% | | Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok +warning: unused import: `ptr::null` + --> tree/src/program.rs:3:5 + | +3 | ptr::null, + | ^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default +warning: unused import: `cpi` + --> tree/src/program.rs:5:17 + | +5 | use interface::{cpi, data, error_codes::error, input_buffer}; + | ^^^ +warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` + --> tree/src/program.rs:10:18 + | +10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +11 | error::ProgramError, + | ^^^^^^^^^^^^^^^^^^^ +12 | hint::{likely, unlikely}, +13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, + | ^^^^^^^^^^^ ^^^^^^^^^^^^^ +warning: unused variable: `bump` + --> tree/src/program.rs:129:9 + | +129 | let bump = bump.assume_init(); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:118:9 + | +118 | let mut pda = MaybeUninit::
::uninit(); + | ----^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:119:9 + | +119 | let mut bump = MaybeUninit::::uninit(); + | ----^^^^ + | | + | help: remove this `mut` +warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 1bcf1d9b..d4c09d18 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -7,6 +7,53 @@ | System program wrong data length | 15 | 17 | +2 | +13.3% | | Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok + Blocking waiting for file lock on build directory +warning: unused import: `ptr::null` + --> tree/src/program.rs:3:5 + | +3 | ptr::null, + | ^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default +warning: unused import: `cpi` + --> tree/src/program.rs:5:17 + | +5 | use interface::{cpi, data, error_codes::error, input_buffer}; + | ^^^ +warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` + --> tree/src/program.rs:10:18 + | +10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +11 | error::ProgramError, + | ^^^^^^^^^^^^^^^^^^^ +12 | hint::{likely, unlikely}, +13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, + | ^^^^^^^^^^^ ^^^^^^^^^^^^^ +warning: unused variable: `bump` + --> tree/src/program.rs:129:9 + | +129 | let bump = bump.assume_init(); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:118:9 + | +118 | let mut pda = MaybeUninit::
::uninit(); + | ----^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:119:9 + | +119 | let mut bump = MaybeUninit::::uninit(); + | ----^^^^ + | | + | help: remove this `mut` +warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 444c18e6..76a991d5 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -5,6 +5,52 @@ | PDA mismatch chunk 3 | 1536 | 1539 | +3 | +0.2% | | PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | test tests::test_initialize_pda_checks ... ok +warning: unused import: `ptr::null` + --> tree/src/program.rs:3:5 + | +3 | ptr::null, + | ^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default +warning: unused import: `cpi` + --> tree/src/program.rs:5:17 + | +5 | use interface::{cpi, data, error_codes::error, input_buffer}; + | ^^^ +warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` + --> tree/src/program.rs:10:18 + | +10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +11 | error::ProgramError, + | ^^^^^^^^^^^^^^^^^^^ +12 | hint::{likely, unlikely}, +13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, + | ^^^^^^^^^^^ ^^^^^^^^^^^^^ +warning: unused variable: `bump` + --> tree/src/program.rs:129:9 + | +129 | let bump = bump.assume_init(); + | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:118:9 + | +118 | let mut pda = MaybeUninit::
::uninit(); + | ----^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default +warning: variable does not need to be mutable + --> tree/src/program.rs:119:9 + | +119 | let mut bump = MaybeUninit::::uninit(); + | ----^^^^ + | | + | help: remove this `mut` +warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 diff --git a/examples/tree/interface/src/bindings.rs b/examples/tree/interface/src/bindings.rs index a4dfa338..68481dc4 100644 --- a/examples/tree/interface/src/bindings.rs +++ b/examples/tree/interface/src/bindings.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] /// Generated from Agave using bindgen. use pinocchio::Address; diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs index d17a169b..569ef2f5 100644 --- a/examples/tree/src/lib.rs +++ b/examples/tree/src/lib.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] #![cfg_attr(not(test), no_std)] mod program; From 01644c50613a73fe1919dcaa4f477808d8615ee6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:33:12 -0800 Subject: [PATCH 090/263] Clean up artifact generation --- .../tests/asm_expected_failures/result.txt | 18 ----- .../tests/asm_expected_failures/test.txt | 27 -------- .../tests/asm_pda_duplicate/result.txt | 15 ---- .../tests/asm_pda_duplicate/test.txt | 17 ----- .../asm_system_program_duplicate/result.txt | 15 ---- .../asm_system_program_duplicate/test.txt | 17 ----- .../tests/account_offsets/result.txt | 1 - .../artifacts/tests/account_offsets/test.txt | 68 ------------------- .../artifacts/tests/offsets/result.txt | 1 - .../transfer/artifacts/tests/offsets/test.txt | 68 ------------------- .../snippets/rs/initialize-pda-checks.txt | 2 +- .../tests/entrypoint_branching/result.txt | 40 +++-------- .../tests/initialize_input_checks/result.txt | 41 +++-------- .../tests/initialize_pda_checks/result.txt | 40 +++-------- examples/tree/macros/src/lib.rs | 7 +- examples/tree/src/program.rs | 14 ++-- examples/utils/build-examples/src/main.rs | 5 ++ 17 files changed, 42 insertions(+), 354 deletions(-) delete mode 100644 examples/counter/artifacts/tests/asm_expected_failures/result.txt delete mode 100644 examples/counter/artifacts/tests/asm_expected_failures/test.txt delete mode 100644 examples/counter/artifacts/tests/asm_pda_duplicate/result.txt delete mode 100644 examples/counter/artifacts/tests/asm_pda_duplicate/test.txt delete mode 100644 examples/counter/artifacts/tests/asm_system_program_duplicate/result.txt delete mode 100644 examples/counter/artifacts/tests/asm_system_program_duplicate/test.txt delete mode 100644 examples/transfer/artifacts/tests/account_offsets/result.txt delete mode 100644 examples/transfer/artifacts/tests/account_offsets/test.txt delete mode 100644 examples/transfer/artifacts/tests/offsets/result.txt delete mode 100644 examples/transfer/artifacts/tests/offsets/test.txt diff --git a/examples/counter/artifacts/tests/asm_expected_failures/result.txt b/examples/counter/artifacts/tests/asm_expected_failures/result.txt deleted file mode 100644 index f1bb1bc3..00000000 --- a/examples/counter/artifacts/tests/asm_expected_failures/result.txt +++ /dev/null @@ -1,18 +0,0 @@ -test tests::test_asm_expected_failures ... ok - Blocking waiting for file lock on package cache - Blocking waiting for file lock on package cache - Blocking waiting for file lock on package cache -warning: unused variable: `system_account` - --> counter/src/tests.rs:522:26 - | -522 | let (system_program, system_account) = program::keyed_account_for_system_program(); - | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_system_account` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: `counter` (lib test) generated 1 warning -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/counter/artifacts/tests/asm_expected_failures/test.txt b/examples/counter/artifacts/tests/asm_expected_failures/test.txt deleted file mode 100644 index 13fe1d58..00000000 --- a/examples/counter/artifacts/tests/asm_expected_failures/test.txt +++ /dev/null @@ -1,27 +0,0 @@ -#[test] -fn test_asm_expected_failures() { - let setup = setup_test(ProgramLanguage::Assembly); - let (system_program, system_account) = program::keyed_account_for_system_program(); - - // Check no accounts. - setup.mollusk.process_and_validate_instruction( - &Instruction::new_with_bytes(setup.program_id, &[], vec![]), - &[], - &[Check::err(ProgramError::Custom( - constants().get("E_N_ACCOUNTS") as u32, - ))], - ); - - // Check too many accounts. - let n_accounts: usize = 4; - let account_metas = vec![AccountMeta::new_readonly(Pubkey::new_unique(), false); n_accounts]; - let account_infos = - vec![(account_metas[0].pubkey, Account::new(0, 0, &system_program),); n_accounts]; - setup.mollusk.process_and_validate_instruction( - &Instruction::new_with_bytes(setup.program_id, &[], account_metas), - &account_infos, - &[Check::err(ProgramError::Custom( - constants().get("E_N_ACCOUNTS") as u32, - ))], - ); -} \ No newline at end of file diff --git a/examples/counter/artifacts/tests/asm_pda_duplicate/result.txt b/examples/counter/artifacts/tests/asm_pda_duplicate/result.txt deleted file mode 100644 index 0a15b250..00000000 --- a/examples/counter/artifacts/tests/asm_pda_duplicate/result.txt +++ /dev/null @@ -1,15 +0,0 @@ -test tests::test_asm_pda_duplicate ... ok -warning: variant `Increment` is never constructed - --> counter/src/tests.rs:39:5 - | -37 | enum Operation { - | --------- variant in this enum -38 | Initialize, -39 | Increment, - | ^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `counter` (lib test) generated 1 warning -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 \ No newline at end of file diff --git a/examples/counter/artifacts/tests/asm_pda_duplicate/test.txt b/examples/counter/artifacts/tests/asm_pda_duplicate/test.txt deleted file mode 100644 index a64d7a03..00000000 --- a/examples/counter/artifacts/tests/asm_pda_duplicate/test.txt +++ /dev/null @@ -1,17 +0,0 @@ -#[test] -fn test_asm_pda_duplicate() { - let (setup, mut instruction, mut accounts, _checks) = - happy_path_setup(ProgramLanguage::Assembly, Operation::Initialize); - - instruction.accounts[AccountIndex::Pda as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::Pda as usize] = accounts[AccountIndex::User as usize].clone(); - - setup.mollusk.process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - constants().get("E_PDA_DUPLICATE") as u32, - ))], - ); -} \ No newline at end of file diff --git a/examples/counter/artifacts/tests/asm_system_program_duplicate/result.txt b/examples/counter/artifacts/tests/asm_system_program_duplicate/result.txt deleted file mode 100644 index 1f9fa530..00000000 --- a/examples/counter/artifacts/tests/asm_system_program_duplicate/result.txt +++ /dev/null @@ -1,15 +0,0 @@ -test tests::test_asm_system_program_duplicate ... ok -warning: variant `Increment` is never constructed - --> counter/src/tests.rs:39:5 - | -37 | enum Operation { - | --------- variant in this enum -38 | Initialize, -39 | Increment, - | ^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `counter` (lib test) generated 1 warning -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 \ No newline at end of file diff --git a/examples/counter/artifacts/tests/asm_system_program_duplicate/test.txt b/examples/counter/artifacts/tests/asm_system_program_duplicate/test.txt deleted file mode 100644 index 4ef52f09..00000000 --- a/examples/counter/artifacts/tests/asm_system_program_duplicate/test.txt +++ /dev/null @@ -1,17 +0,0 @@ -#[test] -fn test_asm_system_program_duplicate() { - let (setup, mut instruction, mut accounts, _checks) = - happy_path_setup(ProgramLanguage::Assembly, Operation::Initialize); - - instruction.accounts[AccountIndex::SystemProgram as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::SystemProgram as usize] = accounts[AccountIndex::User as usize].clone(); - - setup.mollusk.process_and_validate_instruction( - &instruction, - &accounts, - &[Check::err(ProgramError::Custom( - constants().get("E_SYSTEM_PROGRAM_DUPLICATE") as u32, - ))], - ); -} \ No newline at end of file diff --git a/examples/transfer/artifacts/tests/account_offsets/result.txt b/examples/transfer/artifacts/tests/account_offsets/result.txt deleted file mode 100644 index fc6220f7..00000000 --- a/examples/transfer/artifacts/tests/account_offsets/result.txt +++ /dev/null @@ -1 +0,0 @@ -test tests::test_account_offsets ... ok \ No newline at end of file diff --git a/examples/transfer/artifacts/tests/account_offsets/test.txt b/examples/transfer/artifacts/tests/account_offsets/test.txt deleted file mode 100644 index d74d0d6a..00000000 --- a/examples/transfer/artifacts/tests/account_offsets/test.txt +++ /dev/null @@ -1,68 +0,0 @@ -#[test] -fn test_account_offsets() { - const MAX_PERMITTED_DATA_INCREASE: usize = 10240; - - #[allow(dead_code)] - #[repr(C)] - struct AccountLayout { - non_dup_marker: u8, - is_signer: u8, - is_writable: u8, - is_executable: u8, - padding: [u8; 4], - pubkey: [u8; 32], - owner: [u8; 32], - lamports: u64, - data_length: u64, - data_padded: [u8; PADDED_DATA_SIZE], - rent_epoch: u64, - } - - type StandardAccount = AccountLayout; - type SystemProgramAccount = AccountLayout<{ MAX_PERMITTED_DATA_INCREASE + 16 }>; - - // Sender. - const SENDER_OFFSET: usize = 8; - const SENDER_LAMPORTS_OFFSET: usize = 80; - const SENDER_DATA_LENGTH_OFFSET: usize = 88; - - // Recipient. - const RECIPIENT_OFFSET: usize = 10344; - const RECIPIENT_DATA_LENGTH_OFFSET: usize = 10424; - - // System program. - const SYSTEM_PROGRAM_OFFSET: usize = 20680; - - // Instruction data. - const INSTRUCTION_DATA_LENGTH_OFFSET: usize = 31032; - const INSTRUCTION_DATA_OFFSET: usize = 31040; - - assert_eq!( - SENDER_LAMPORTS_OFFSET, - SENDER_OFFSET + offset_of!(StandardAccount, lamports), - ); - assert_eq!( - SENDER_DATA_LENGTH_OFFSET, - SENDER_OFFSET + offset_of!(StandardAccount, data_length), - ); - assert_eq!( - RECIPIENT_OFFSET, - SENDER_OFFSET + size_of::() - ); - assert_eq!( - RECIPIENT_DATA_LENGTH_OFFSET, - RECIPIENT_OFFSET + offset_of!(StandardAccount, data_length), - ); - assert_eq!( - SYSTEM_PROGRAM_OFFSET, - RECIPIENT_OFFSET + size_of::() - ); - assert_eq!( - INSTRUCTION_DATA_LENGTH_OFFSET, - SYSTEM_PROGRAM_OFFSET + size_of::() - ); - assert_eq!( - INSTRUCTION_DATA_OFFSET, - INSTRUCTION_DATA_LENGTH_OFFSET + size_of::(), - ); -} \ No newline at end of file diff --git a/examples/transfer/artifacts/tests/offsets/result.txt b/examples/transfer/artifacts/tests/offsets/result.txt deleted file mode 100644 index 0b0bc214..00000000 --- a/examples/transfer/artifacts/tests/offsets/result.txt +++ /dev/null @@ -1 +0,0 @@ -test tests::test_offsets ... ok \ No newline at end of file diff --git a/examples/transfer/artifacts/tests/offsets/test.txt b/examples/transfer/artifacts/tests/offsets/test.txt deleted file mode 100644 index 44c137ba..00000000 --- a/examples/transfer/artifacts/tests/offsets/test.txt +++ /dev/null @@ -1,68 +0,0 @@ -#[test] -fn test_offsets() { - const MAX_PERMITTED_DATA_INCREASE: usize = 10240; - - #[allow(dead_code)] - #[repr(C)] - struct AccountLayout { - non_dup_marker: u8, - is_signer: u8, - is_writable: u8, - is_executable: u8, - padding: [u8; 4], - pubkey: [u8; 32], - owner: [u8; 32], - lamports: u64, - data_length: u64, - data_padded: [u8; PADDED_DATA_SIZE], - rent_epoch: u64, - } - - type StandardAccount = AccountLayout; - type SystemProgramAccount = AccountLayout<{ MAX_PERMITTED_DATA_INCREASE + 16 }>; - - // Sender. - const SENDER_OFFSET: usize = 8; - const SENDER_LAMPORTS_OFFSET: usize = 80; - const SENDER_DATA_LENGTH_OFFSET: usize = 88; - - // Recipient. - const RECIPIENT_OFFSET: usize = 10344; - const RECIPIENT_DATA_LENGTH_OFFSET: usize = 10424; - - // System program. - const SYSTEM_PROGRAM_OFFSET: usize = 20680; - - // Instruction data. - const INSTRUCTION_DATA_LENGTH_OFFSET: usize = 31032; - const INSTRUCTION_DATA_OFFSET: usize = 31040; - - assert_eq!( - SENDER_LAMPORTS_OFFSET, - SENDER_OFFSET + offset_of!(StandardAccount, lamports), - ); - assert_eq!( - SENDER_DATA_LENGTH_OFFSET, - SENDER_OFFSET + offset_of!(StandardAccount, data_length), - ); - assert_eq!( - RECIPIENT_OFFSET, - SENDER_OFFSET + size_of::() - ); - assert_eq!( - RECIPIENT_DATA_LENGTH_OFFSET, - RECIPIENT_OFFSET + offset_of!(StandardAccount, data_length), - ); - assert_eq!( - SYSTEM_PROGRAM_OFFSET, - RECIPIENT_OFFSET + size_of::() - ); - assert_eq!( - INSTRUCTION_DATA_LENGTH_OFFSET, - SYSTEM_PROGRAM_OFFSET + size_of::() - ); - assert_eq!( - INSTRUCTION_DATA_OFFSET, - INSTRUCTION_DATA_LENGTH_OFFSET + size_of::(), - ); -} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index a6afe48b..158f7523 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -10,7 +10,7 @@ bump.as_mut_ptr(), ); let pda = pda.assume_init(); - let bump = bump.assume_init(); + let _bump = bump.assume_init(); // Compare result with passed PDA. if !address_eq( diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 2422ee23..5146e255 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -4,52 +4,30 @@ | One account | 5 | 7 | +2 | +40.0% | | Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok -warning: unused import: `ptr::null` - --> tree/src/program.rs:3:5 - | -3 | ptr::null, - | ^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: unused import: `cpi` - --> tree/src/program.rs:5:17 + --> tree/src/program.rs:4:17 | -5 | use interface::{cpi, data, error_codes::error, input_buffer}; +4 | use interface::{cpi, data, error_codes::error, input_buffer}; | ^^^ -warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` - --> tree/src/program.rs:10:18 - | -10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, - | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ -11 | error::ProgramError, - | ^^^^^^^^^^^^^^^^^^^ -12 | hint::{likely, unlikely}, -13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, - | ^^^^^^^^^^^ ^^^^^^^^^^^^^ -warning: unused variable: `bump` - --> tree/src/program.rs:129:9 - | -129 | let bump = bump.assume_init(); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:118:9 + --> tree/src/program.rs:116:9 | -118 | let mut pda = MaybeUninit::
::uninit(); +116 | let mut pda = MaybeUninit::
::uninit(); | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:119:9 + --> tree/src/program.rs:117:9 | -119 | let mut bump = MaybeUninit::::uninit(); +117 | let mut bump = MaybeUninit::::uninit(); | ----^^^^ | | | help: remove this `mut` -warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) +warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index d4c09d18..deb87e38 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -7,53 +7,30 @@ | System program wrong data length | 15 | 17 | +2 | +13.3% | | Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok - Blocking waiting for file lock on build directory -warning: unused import: `ptr::null` - --> tree/src/program.rs:3:5 - | -3 | ptr::null, - | ^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: unused import: `cpi` - --> tree/src/program.rs:5:17 + --> tree/src/program.rs:4:17 | -5 | use interface::{cpi, data, error_codes::error, input_buffer}; +4 | use interface::{cpi, data, error_codes::error, input_buffer}; | ^^^ -warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` - --> tree/src/program.rs:10:18 - | -10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, - | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ -11 | error::ProgramError, - | ^^^^^^^^^^^^^^^^^^^ -12 | hint::{likely, unlikely}, -13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, - | ^^^^^^^^^^^ ^^^^^^^^^^^^^ -warning: unused variable: `bump` - --> tree/src/program.rs:129:9 - | -129 | let bump = bump.assume_init(); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:118:9 + --> tree/src/program.rs:116:9 | -118 | let mut pda = MaybeUninit::
::uninit(); +116 | let mut pda = MaybeUninit::
::uninit(); | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:119:9 + --> tree/src/program.rs:117:9 | -119 | let mut bump = MaybeUninit::::uninit(); +117 | let mut bump = MaybeUninit::::uninit(); | ----^^^^ | | | help: remove this `mut` -warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) +warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 76a991d5..03180a7d 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -5,52 +5,30 @@ | PDA mismatch chunk 3 | 1536 | 1539 | +3 | +0.2% | | PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | test tests::test_initialize_pda_checks ... ok -warning: unused import: `ptr::null` - --> tree/src/program.rs:3:5 - | -3 | ptr::null, - | ^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: unused import: `cpi` - --> tree/src/program.rs:5:17 + --> tree/src/program.rs:4:17 | -5 | use interface::{cpi, data, error_codes::error, input_buffer}; +4 | use interface::{cpi, data, error_codes::error, input_buffer}; | ^^^ -warning: unused imports: `AccountView`, `MaybeAccount`, `ProgramResult`, `error::ProgramError`, and `lazy::InstructionContext` - --> tree/src/program.rs:10:18 - | -10 | entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, - | ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ -11 | error::ProgramError, - | ^^^^^^^^^^^^^^^^^^^ -12 | hint::{likely, unlikely}, -13 | no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, - | ^^^^^^^^^^^ ^^^^^^^^^^^^^ -warning: unused variable: `bump` - --> tree/src/program.rs:129:9 - | -129 | let bump = bump.assume_init(); - | ^^^^ help: if this is intentional, prefix it with an underscore: `_bump` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:118:9 + --> tree/src/program.rs:116:9 | -118 | let mut pda = MaybeUninit::
::uninit(); +116 | let mut pda = MaybeUninit::
::uninit(); | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default warning: variable does not need to be mutable - --> tree/src/program.rs:119:9 + --> tree/src/program.rs:117:9 | -119 | let mut bump = MaybeUninit::::uninit(); +117 | let mut bump = MaybeUninit::::uninit(); | ----^^^^ | | | help: remove this `mut` -warning: `tree` (lib test) generated 6 warnings (run `cargo fix --lib -p tree --tests` to apply 5 suggestions) +warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 605bf2bc..6bb2133c 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -443,8 +443,7 @@ pub fn constant_group(input: TokenStream) -> TokenStream { value, literal_repr, } => { - let assert_name = - Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); const_value_strs.push(literal_repr.clone()); if literal_repr.is_some() { @@ -1423,8 +1422,8 @@ pub fn sizes(input: TokenStream) -> TokenStream { let mut const_doc_strs = Vec::new(); for ty in &input.types { - let type_name = extract_type_name(ty) - .unwrap_or_else(|| panic!("Expected a named type path in sizes!")); + let type_name = + extract_type_name(ty).unwrap_or_else(|| panic!("Expected a named type path in sizes!")); let screaming = type_name_to_upper_snake(&type_name); let name_str = format!("SIZE_OF_{}", screaming); let name = Ident::new(&name_str, proc_macro2::Span::call_site()); diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 88a9618d..da542646 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,16 +1,14 @@ -use core::{ - mem::{transmute, MaybeUninit}, - ptr::null, -}; +use core::mem::{transmute, MaybeUninit}; +#[cfg(target_os = "solana")] +use core::ptr::null; use interface::{cpi, data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] use pinocchio::syscalls::sol_try_find_program_address; use pinocchio::{ address::address_eq, - entrypoint::{lazy::InstructionContext, MaybeAccount, NON_DUP_MARKER}, - error::ProgramError, + entrypoint::NON_DUP_MARKER, hint::{likely, unlikely}, - no_allocator, nostd_panic_handler, AccountView, Address, ProgramResult, SUCCESS, + no_allocator, nostd_panic_handler, Address, SUCCESS, }; #[inline(always)] @@ -126,7 +124,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { bump.as_mut_ptr(), ); let pda = pda.assume_init(); - let bump = bump.assume_init(); + let _bump = bump.assume_init(); // Compare result with passed PDA. if !address_eq( diff --git a/examples/utils/build-examples/src/main.rs b/examples/utils/build-examples/src/main.rs index 41b5d9be..eed62c70 100644 --- a/examples/utils/build-examples/src/main.rs +++ b/examples/utils/build-examples/src/main.rs @@ -450,6 +450,11 @@ fn run_and_save_test_snippets(path: &Path, package_name: &str) { let tests = discover_tests(&tests_path); let tests_dir = path.join("artifacts/tests"); + // Clear existing test artifacts before regenerating. + if tests_dir.exists() { + fs::remove_dir_all(&tests_dir).expect("failed to clear test artifacts directory"); + } + for (test_name, test_code) in tests { // Verify test name starts with "test_". assert!( From fd7523e2ff147104a1818ae29eed11e09d2efb44 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:35:47 -0800 Subject: [PATCH 091/263] Remove stale file --- examples/tree/build-macros/src/lib.rs | 337 -------------------------- 1 file changed, 337 deletions(-) delete mode 100644 examples/tree/build-macros/src/lib.rs diff --git a/examples/tree/build-macros/src/lib.rs b/examples/tree/build-macros/src/lib.rs deleted file mode 100644 index 8f0fa0ee..00000000 --- a/examples/tree/build-macros/src/lib.rs +++ /dev/null @@ -1,337 +0,0 @@ -use convert_case::{Case, Casing}; -use proc_macro::TokenStream; -use quote::quote; -use syn::{ - braced, - parse::{Parse, ParseStream}, - parse_macro_input, Data, DeriveInput, Fields, Ident, Lit, LitInt, Meta, Token, -}; - -/// Attribute macro for defining error code enums shared between Rust and ASM. -/// -/// Automatically adds `#[repr(u64)]` to the enum. Each variant must have a doc -/// comment that will become the ASM comment. Variant names are converted from -/// PascalCase to SCREAMING_SNAKE_CASE and prefixed with `E_`. -/// -/// # Example -/// ```ignore -/// #[error_codes] -/// pub enum ErrorCodes { -/// /// An invalid number of accounts were passed. -/// NAccounts, -/// /// The user account has nonzero data length. -/// UserData, -/// } -/// ``` -/// -/// Generates ASM: -/// ```text -/// # Error codes. -/// # ------------ -/// .equ E_N_ACCOUNTS, 1 # An invalid number of accounts were passed. -/// .equ E_USER_DATA, 2 # The user account has nonzero data length. -/// ``` -#[proc_macro_attribute] -pub fn error_codes(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input = parse_macro_input!(item as DeriveInput); - let name = &input.ident; - let vis = &input.vis; - let attrs = &input.attrs; - - let variants = match &input.data { - Data::Enum(data) => &data.variants, - _ => { - return syn::Error::new_spanned(&input, "error_codes can only be applied to enums") - .to_compile_error() - .into(); - } - }; - - let mut error_entries = Vec::new(); - let mut variant_defs = Vec::new(); - - for (idx, variant) in variants.iter().enumerate() { - // Ensure no fields. - if !matches!(variant.fields, Fields::Unit) { - return syn::Error::new_spanned( - &variant.fields, - "error_codes variants must be unit variants (no fields)", - ) - .to_compile_error() - .into(); - } - - // Extract doc comment. - let doc_comment = extract_doc_comment(&variant.attrs); - let doc_comment = match doc_comment { - Some(doc) => doc, - None => { - return syn::Error::new_spanned( - &variant.ident, - format!("Variant `{}` must have a doc comment", variant.ident), - ) - .to_compile_error() - .into(); - } - }; - - // Validate doc comment ends with period. - if !doc_comment.ends_with('.') { - return syn::Error::new_spanned( - &variant.ident, - format!( - "Doc comment for `{}` must end with a period: {:?}", - variant.ident, doc_comment - ), - ) - .to_compile_error() - .into(); - } - - // Convert variant name to SCREAMING_SNAKE_CASE for ASM. - let asm_name = format!("E_{}", variant.ident.to_string().to_case(Case::UpperSnake)); - - // Error codes start at 1. - let value = idx + 1; - - error_entries.push((asm_name, value, doc_comment)); - - // Preserve variant with its attributes. - let variant_ident = &variant.ident; - let variant_attrs = &variant.attrs; - variant_defs.push(quote! { - #(#variant_attrs)* - #variant_ident - }); - } - - // Generate the to_asm() implementation. - let asm_lines: Vec = error_entries - .iter() - .map(|(name, value, comment)| format!(".equ {}, {} # {}", name, value, comment)) - .collect(); - - let header = "# Error codes.\n# ------------"; - let body = asm_lines.join("\n"); - - let expanded = quote! { - #(#attrs)* - #[repr(u64)] - #vis enum #name { - #(#variant_defs),* - } - - impl #name { - /// Generate ASM constants for this enum. - pub fn to_asm() -> alloc::string::String { - alloc::format!("{}\n{}\n", #header, #body) - } - } - }; - - TokenStream::from(expanded) -} - -/// Extract the doc comment from attributes. -fn extract_doc_comment(attrs: &[syn::Attribute]) -> Option { - let mut doc_parts = Vec::new(); - - for attr in attrs { - if attr.path().is_ident("doc") { - if let Meta::NameValue(meta) = &attr.meta { - if let syn::Expr::Lit(expr_lit) = &meta.value { - if let Lit::Str(lit_str) = &expr_lit.lit { - doc_parts.push(lit_str.value().trim().to_string()); - } - } - } - } - } - - if doc_parts.is_empty() { - None - } else { - Some(doc_parts.join(" ")) - } -} - -struct ConstantDef { - doc: String, - name: Ident, - ty: syn::Type, - value: LitInt, -} - -struct ConstantGroup { - doc: String, - name: Ident, - prefix: Option, - constants: Vec, -} - -struct AsmConstantsInput { - groups: Vec, -} - -impl Parse for AsmConstantsInput { - fn parse(input: ParseStream) -> syn::Result { - let mut groups = Vec::new(); - - while !input.is_empty() { - // Parse doc comments for the module. - let attrs = input.call(syn::Attribute::parse_outer)?; - let doc = extract_doc_comment(&attrs) - .ok_or_else(|| input.error("Module must have a doc comment"))?; - - // Parse group name (always pub). - let name: Ident = input.parse()?; - - // Parse module body. - let content; - braced!(content in input); - - // Check for optional prefix. - let prefix = if content.peek(Ident) { - let ident: Ident = content.parse()?; - if ident == "prefix" { - content.parse::()?; - let prefix_lit: syn::LitStr = content.parse()?; - content.parse::()?; - Some(prefix_lit.value()) - } else { - return Err(syn::Error::new( - ident.span(), - "Expected 'prefix' or constant", - )); - } - } else { - None - }; - - // Parse constants. - let mut constants = Vec::new(); - while !content.is_empty() { - let const_attrs = content.call(syn::Attribute::parse_outer)?; - let const_doc = extract_doc_comment(&const_attrs) - .ok_or_else(|| content.error("Constant must have a doc comment"))?; - - let const_name: Ident = content.parse()?; - content.parse::()?; - let const_ty: syn::Type = content.parse()?; - content.parse::()?; - let const_value: LitInt = content.parse()?; - - // Optional trailing comma. - let _ = content.parse::(); - - constants.push(ConstantDef { - doc: const_doc, - name: const_name, - ty: const_ty, - value: const_value, - }); - } - - groups.push(ConstantGroup { - doc, - name, - prefix, - constants, - }); - } - - Ok(AsmConstantsInput { groups }) - } -} - -/// Macro for defining groups of constants shared between Rust and ASM. -/// -/// Constants must specify their Rust type. Values are validated at compile time since they must -/// [fit in an `i32`][i32-imm], except for [`i64` immediates in `lddw`][lddw-bypass]. -/// -/// [i32-imm](https://github.com/anza-xya/sbpf/blob/v0.14.2/src/assembler.rs#L262-L264) -/// [lddw-bypass](https://github.com/alnoki/sbpf/blob/v0.14.2/src/assembler.rs#L484-L500) -/// -/// # Example -/// ```ignore -/// constant_group! { -/// /// Memory map. -/// memory_map { -/// /// Number of accounts expected. -/// N_ACCOUNTS: u64 = 2, -/// /// Offset to instruction data. -/// IX_DATA: usize = 8, -/// } -/// -/// /// Another group. -/// my_group { -/// prefix = "MY_PREFIX", -/// /// Foo constant. -/// FOO: u32 = 1, -/// } -/// } -/// ``` -#[proc_macro] -pub fn constant_group(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as AsmConstantsInput); - - let modules = input.groups.iter().map(|group| { - let mod_name = &group.name; - let prefix = group.prefix.as_deref().unwrap_or(""); - - // Generate Rust constants with i32 bounds checking for ASM compatibility. - let const_defs = group.constants.iter().map(|c| { - let name = &c.name; - let ty = &c.ty; - let value = &c.value; - let doc = &c.doc; - let assert_name = Ident::new(&format!("_ASSERT_{}_FITS_I32", name), name.span()); - quote! { - #[doc = #doc] - pub const #name: #ty = #value; - - const #assert_name: () = assert!( - (#value as i64) >= (i32::MIN as i64) && (#value as i64) <= (i32::MAX as i64), - "ASM immediate must fit in i32 range" - ); - } - }); - - // Generate ASM output. - let header_text = &group.doc; - let header_line = "-".repeat(header_text.len()); - let header = format!("# {}\n# {}", header_text, header_line); - - let asm_lines: Vec = group - .constants - .iter() - .map(|c| { - format!( - ".equ {}{}, {} # {}", - prefix, - c.name.to_string(), - c.value, - c.doc - ) - }) - .collect(); - let body = asm_lines.join("\n"); - - quote! { - pub mod #mod_name { - #(#const_defs)* - - /// Generate ASM constants for this module. - pub fn to_asm() -> alloc::string::String { - alloc::format!("{}\n{}\n", #header, #body) - } - } - } - }); - - let expanded = quote! { - #(#modules)* - }; - - TokenStream::from(expanded) -} From 92dcf88383ed56262208c66e612e8733da18977d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:39:57 -0800 Subject: [PATCH 092/263] Fix warnings --- .../tree/artifacts/snippets/rs/initialize-pda-checks.txt | 1 + examples/tree/macros/src/lib.rs | 6 +++--- examples/tree/src/program.rs | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 158f7523..0bb53dec 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -15,6 +15,7 @@ // Compare result with passed PDA. if !address_eq( &pda, + #[allow(clippy::transmute_ptr_to_ref)] transmute::<*const u8, &Address>( input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), ), diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 6bb2133c..7ceff4fa 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -89,7 +89,7 @@ pub fn error_codes(input: TokenStream) -> TokenStream { #variant_name = #value }); - asm_lines.push(asm_equ_line(&asm_name, &value, doc)); + asm_lines.push(asm_equ_line(&asm_name, value, doc)); } let header = asm_header("Error codes."); @@ -1522,11 +1522,11 @@ pub fn pubkey_chunk_group(_input: TokenStream) -> TokenStream { let mut const_name_strs = Vec::new(); let mut const_doc_strs = Vec::new(); - for i in 0..N_CHUNKS { + for (i, ordinal) in ORDINALS.iter().enumerate() { let offset = (i * CHUNK_SIZE) as i64; let name_str = format!("PUBKEY_CHUNK_OFF_{}", i); let name = Ident::new(&format!("OFF_{}", i), proc_macro2::Span::call_site()); - let doc = format!("Offset for the {} 8 bytes.", ORDINALS[i]); + let doc = format!("Offset for the {} 8 bytes.", ordinal); const_defs.push(quote! { #[doc = #doc] diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index da542646..a347380e 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,7 +1,7 @@ use core::mem::{transmute, MaybeUninit}; #[cfg(target_os = "solana")] use core::ptr::null; -use interface::{cpi, data, error_codes::error, input_buffer}; +use interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] use pinocchio::syscalls::sol_try_find_program_address; use pinocchio::{ @@ -129,6 +129,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Compare result with passed PDA. if !address_eq( &pda, + #[allow(clippy::transmute_ptr_to_ref)] transmute::<*const u8, &Address>( input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), ), From 813308704578526e5ec17caea485c47d50f8b40c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:41:25 -0800 Subject: [PATCH 093/263] Add cfg block --- examples/tree/src/program.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a347380e..426e108d 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,15 +1,13 @@ use core::mem::{transmute, MaybeUninit}; -#[cfg(target_os = "solana")] -use core::ptr::null; use interface::{data, error_codes::error, input_buffer}; -#[cfg(target_os = "solana")] -use pinocchio::syscalls::sol_try_find_program_address; use pinocchio::{ address::address_eq, entrypoint::NON_DUP_MARKER, hint::{likely, unlikely}, no_allocator, nostd_panic_handler, Address, SUCCESS, }; +#[cfg(target_os = "solana")] +use {core::ptr::null, interface::cpi, pinocchio::syscalls::sol_try_find_program_address}; #[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { From 6ce29acd17ca5b6118739a4139e5080328612e2c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:51:17 -0800 Subject: [PATCH 094/263] Build examples --- examples/tree/artifacts/dumps/rs.txt | 82 +++++++++---------- examples/tree/artifacts/rs-disassembly.s | 46 +++++------ .../snippets/rs/initialize-pda-checks.txt | 28 ++++--- .../tests/entrypoint_branching/result.txt | 24 ------ .../tests/initialize_input_checks/result.txt | 24 ------ .../tests/initialize_pda_checks/result.txt | 36 ++------ examples/tree/src/program.rs | 32 +++++--- 7 files changed, 102 insertions(+), 170 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index cd53f420..b90ed8ef 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3080 (bytes into file) + Start of section headers 3064 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xc08 +There are 8 section headers, starting at offset 0xbf8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0001f8 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000318 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000320 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000320 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000320 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000698 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006d6 000531 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0001e8 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000308 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000310 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000310 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000310 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000688 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006c6 000531 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001f8 0x0001f8 E 0x8 - LOAD 0x000318 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000320 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000320 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001e8 0x0001e8 E 0x8 + LOAD 0x000308 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000310 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000310 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 504 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 488 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 02 2a 00 03 00 00 00 jne r2, 0x3, +0x2a + 40 55 02 28 00 03 00 00 00 jne r2, 0x3, +0x28 48 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 50 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 + 50 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 60 55 02 28 00 ff 00 00 00 jne r2, 0xff, +0x28 + 60 55 02 26 00 ff 00 00 00 jne r2, 0xff, +0x26 68 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 70 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 + 70 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 78 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 80 55 02 28 00 ff 00 00 00 jne r2, 0xff, +0x28 + 80 55 02 26 00 ff 00 00 00 jne r2, 0xff, +0x26 88 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 90 55 02 28 00 0e 00 00 00 jne r2, 0xe, +0x28 + 90 55 02 26 00 0e 00 00 00 jne r2, 0xe, +0x26 98 9c 12 38 79 00 00 00 00 ldxdw r2, [r1 + 0x7938] - a0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 + a0 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 b0 07 03 00 00 40 79 00 00 add64 r3, 0x7940 b8 bf a4 00 00 00 00 00 00 mov64 r4, r10 @@ -136,34 +136,32 @@ Disassembly of section .text e8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 f0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 f8 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 100 9c 12 70 28 00 00 00 00 ldxdw r2, [r1 + 0x2870] - 108 9c a3 18 00 00 00 00 00 ldxdw r3, [r10 + 0x18] - 110 5d 23 0c 00 00 00 00 00 jne r3, r2, +0xc - 118 9c 12 78 28 00 00 00 00 ldxdw r2, [r1 + 0x2878] - 120 9c a3 20 00 00 00 00 00 ldxdw r3, [r10 + 0x20] - 128 5d 23 09 00 00 00 00 00 jne r3, r2, +0x9 - 130 9c a2 28 00 00 00 00 00 ldxdw r2, [r10 + 0x28] - 138 9c 13 80 28 00 00 00 00 ldxdw r3, [r1 + 0x2880] - 140 5d 32 06 00 00 00 00 00 jne r2, r3, +0x6 - 148 9c a2 30 00 00 00 00 00 ldxdw r2, [r10 + 0x30] - 150 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 100 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 108 9c a2 18 00 00 00 00 00 ldxdw r2, [r10 + 0x18] + 110 9c 13 70 28 00 00 00 00 ldxdw r3, [r1 + 0x2870] + 118 5d 32 e3 ff 00 00 00 00 jne r2, r3, -0x1d + 120 9c a2 20 00 00 00 00 00 ldxdw r2, [r10 + 0x20] + 128 9c 13 78 28 00 00 00 00 ldxdw r3, [r1 + 0x2878] + 130 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 + 138 9c a2 28 00 00 00 00 00 ldxdw r2, [r10 + 0x28] + 140 9c 13 80 28 00 00 00 00 ldxdw r3, [r1 + 0x2880] + 148 5d 32 dd ff 00 00 00 00 jne r2, r3, -0x23 + 150 9c a2 30 00 00 00 00 00 ldxdw r2, [r10 + 0x30] 158 9c 11 88 28 00 00 00 00 ldxdw r1, [r1 + 0x2888] 160 5d 12 da ff 00 00 00 00 jne r2, r1, -0x26 168 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 170 05 00 d8 ff 00 00 00 00 ja -0x28 - 178 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 178 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 180 05 00 d6 ff 00 00 00 00 ja -0x2a - 188 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 188 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 190 05 00 d4 ff 00 00 00 00 ja -0x2c - 198 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 198 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e - 1a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 1a8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 - 1b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1b8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 1c0 05 00 ce ff 00 00 00 00 ja -0x32 - 1c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1c8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 1d0 05 00 cc ff 00 00 00 00 ja -0x34 - 1d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1e0 05 00 ca ff 00 00 00 00 ja -0x36 - 1e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 \ No newline at end of file + 1d8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1e0 05 00 ca ff 00 00 00 00 ja -0x36 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 303dd100..36a0eaec 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r2, 3, jmp_0198 + jne r2, 3, jmp_0188 ldxdw r2, [r1+88] - jne r2, 0, jmp_0188 + jne r2, 0, jmp_0178 ldxb r2, [r1+10344] - jne r2, 255, jmp_01a8 + jne r2, 255, jmp_0198 ldxdw r2, [r1+10424] - jne r2, 0, jmp_01b8 + jne r2, 0, jmp_01a8 ldxb r2, [r1+20680] - jne r2, 255, jmp_01c8 + jne r2, 255, jmp_01b8 ldxdw r2, [r1+20760] - jne r2, 14, jmp_01d8 + jne r2, 14, jmp_01c8 ldxdw r2, [r1+31032] - jne r2, 0, jmp_01e8 + jne r2, 0, jmp_01d8 mov64 r3, r1 add64 r3, 31040 mov64 r4, r10 @@ -37,50 +37,46 @@ jmp_0040: mov64 r2, 0 call sol_try_find_program_address mov64 r1, r6 - ldxdw r2, [r1+10352] - ldxdw r3, [r10+24] - jne r3, r2, jmp_0178 - ldxdw r2, [r1+10360] - ldxdw r3, [r10+32] - jne r3, r2, jmp_0178 + mov64 r0, 8 + ldxdw r2, [r10+24] + ldxdw r3, [r1+10352] + jne r2, r3, jmp_0038 + ldxdw r2, [r10+32] + ldxdw r3, [r1+10360] + jne r2, r3, jmp_0038 ldxdw r2, [r10+40] ldxdw r3, [r1+10368] - jne r2, r3, jmp_0178 + jne r2, r3, jmp_0038 ldxdw r2, [r10+48] - mov64 r0, 8 ldxdw r1, [r1+10376] jne r2, r1, jmp_0038 mov64 r0, 0 ja jmp_0038 jmp_0178: - mov64 r0, 8 - ja jmp_0038 - -jmp_0188: mov64 r0, 2 ja jmp_0038 -jmp_0198: +jmp_0188: mov64 r0, 1 ja jmp_0038 -jmp_01a8: +jmp_0198: mov64 r0, 5 ja jmp_0038 -jmp_01b8: +jmp_01a8: mov64 r0, 3 ja jmp_0038 -jmp_01c8: +jmp_01b8: mov64 r0, 6 ja jmp_0038 -jmp_01d8: +jmp_01c8: mov64 r0, 4 ja jmp_0038 -jmp_01e8: +jmp_01d8: mov64 r0, 7 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 0bb53dec..06594509 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -1,16 +1,20 @@ - // Invoke syscall. - let mut pda = MaybeUninit::
::uninit(); - let mut bump = MaybeUninit::::uninit(); #[cfg(target_os = "solana")] - sol_try_find_program_address( - null(), - cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), - pda.as_mut_ptr().cast(), - bump.as_mut_ptr(), - ); - let pda = pda.assume_init(); - let _bump = bump.assume_init(); + // Invoke syscall. + let (pda, _bump) = { + let mut pda = MaybeUninit::
::uninit(); + let mut bump = MaybeUninit::::uninit(); + sol_try_find_program_address( + null(), + cpi::N_SEEDS_TRY_FIND_PDA, + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + pda.as_mut_ptr().cast(), + bump.as_mut_ptr(), + ); + (pda.assume_init(), bump.assume_init()) + }; + // Dummy block for non-Solana target, to satisfy clippy. + #[cfg(not(target_os = "solana"))] + let (pda, _bump) = (Address::default(), 0u8); // Compare result with passed PDA. if !address_eq( diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 5146e255..b36b9ca3 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -4,30 +4,6 @@ | One account | 5 | 7 | +2 | +40.0% | | Four accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok -warning: unused import: `cpi` - --> tree/src/program.rs:4:17 - | -4 | use interface::{cpi, data, error_codes::error, input_buffer}; - | ^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:116:9 - | -116 | let mut pda = MaybeUninit::
::uninit(); - | ----^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:117:9 - | -117 | let mut bump = MaybeUninit::::uninit(); - | ----^^^^ - | | - | help: remove this `mut` -warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index deb87e38..1bcf1d9b 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -7,30 +7,6 @@ | System program wrong data length | 15 | 17 | +2 | +13.3% | | Non-empty instruction data | 17 | 19 | +2 | +11.8% | test tests::test_initialize_input_checks ... ok -warning: unused import: `cpi` - --> tree/src/program.rs:4:17 - | -4 | use interface::{cpi, data, error_codes::error, input_buffer}; - | ^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:116:9 - | -116 | let mut pda = MaybeUninit::
::uninit(); - | ----^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:117:9 - | -117 | let mut bump = MaybeUninit::::uninit(); - | ----^^^^ - | | - | help: remove this `mut` -warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 03180a7d..3c9eedad 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,51 +1,27 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1530 | 1533 | +3 | +0.2% | -| PDA mismatch chunk 2 | 1533 | 1536 | +3 | +0.2% | -| PDA mismatch chunk 3 | 1536 | 1539 | +3 | +0.2% | +| PDA mismatch chunk 1 | 1530 | 1532 | +2 | +0.1% | +| PDA mismatch chunk 2 | 1533 | 1535 | +2 | +0.1% | +| PDA mismatch chunk 3 | 1536 | 1538 | +2 | +0.1% | | PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | test tests::test_initialize_pda_checks ... ok -warning: unused import: `cpi` - --> tree/src/program.rs:4:17 - | -4 | use interface::{cpi, data, error_codes::error, input_buffer}; - | ^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:116:9 - | -116 | let mut pda = MaybeUninit::
::uninit(); - | ----^^^ - | | - | help: remove this `mut` - | - = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default -warning: variable does not need to be mutable - --> tree/src/program.rs:117:9 - | -117 | let mut bump = MaybeUninit::::uninit(); - | ----^^^^ - | | - | help: remove this `mut` -warning: `tree` (lib test) generated 3 warnings (run `cargo fix --lib -p tree --tests` to apply 3 suggestions) [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 426e108d..2eae3e86 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,6 @@ -use core::mem::{transmute, MaybeUninit}; +use core::mem::transmute; +#[cfg(target_os = "solana")] +use core::mem::MaybeUninit; use interface::{data, error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, @@ -110,19 +112,23 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // ANCHOR_END: initialize-input-checks // ANCHOR: initialize-pda-checks - // Invoke syscall. - let mut pda = MaybeUninit::
::uninit(); - let mut bump = MaybeUninit::::uninit(); #[cfg(target_os = "solana")] - sol_try_find_program_address( - null(), - cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), - pda.as_mut_ptr().cast(), - bump.as_mut_ptr(), - ); - let pda = pda.assume_init(); - let _bump = bump.assume_init(); + // Invoke syscall. + let (pda, _bump) = { + let mut pda = MaybeUninit::
::uninit(); + let mut bump = MaybeUninit::::uninit(); + sol_try_find_program_address( + null(), + cpi::N_SEEDS_TRY_FIND_PDA, + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + pda.as_mut_ptr().cast(), + bump.as_mut_ptr(), + ); + (pda.assume_init(), bump.assume_init()) + }; + // Dummy block for non-Solana target, to satisfy clippy. + #[cfg(not(target_os = "solana"))] + let (pda, _bump) = (Address::default(), 0u8); // Compare result with passed PDA. if !address_eq( From 0f151cb5021778d9419601aa4af9f9bf4353ae08 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:55:01 -0800 Subject: [PATCH 095/263] Update deps --- examples/Cargo.lock | 20 +++++++++++--------- examples/Cargo.toml | 1 + examples/tree/Cargo.toml | 4 ++-- examples/tree/build.rs | 2 +- examples/tree/interface/Cargo.toml | 2 +- examples/tree/src/program.rs | 4 ++-- examples/tree/src/tests.rs | 2 +- examples/utils/deps/build/Cargo.toml | 1 + examples/utils/deps/program/Cargo.toml | 1 + 9 files changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 8e3a4048..ae7e8335 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -517,6 +517,7 @@ dependencies = [ "regex", "solana-rent", "solana-sdk", + "tree-interface", ] [[package]] @@ -1210,14 +1211,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "interface" -version = "0.1.0" -dependencies = [ - "macros", - "pinocchio", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1758,6 +1751,7 @@ version = "0.1.0" dependencies = [ "pinocchio", "pinocchio-system", + "tree-interface", ] [[package]] @@ -3597,11 +3591,19 @@ dependencies = [ name = "tree" version = "0.1.0" dependencies = [ - "interface", "mollusk-svm", "pinocchio", "solana-sdk", "test-utils", + "tree-interface", +] + +[[package]] +name = "tree-interface" +version = "0.1.0" +dependencies = [ + "macros", + "pinocchio", ] [[package]] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index bbe98c66..8fbfbcb5 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -18,6 +18,7 @@ resolver = "2" [workspace.dependencies] cargo-manifest = "0.19.1" +tree-interface = { path = "tree/interface" } convert_case = "0.11.0" fib-rs = "1.0.0" mollusk-svm = "0.10.1" diff --git a/examples/tree/Cargo.toml b/examples/tree/Cargo.toml index 40e66a0b..1a901cb8 100644 --- a/examples/tree/Cargo.toml +++ b/examples/tree/Cargo.toml @@ -1,9 +1,9 @@ [build-dependencies] -interface.path = "interface" +tree-interface.workspace = true [dependencies] pinocchio.workspace = true -interface.path = "interface" +tree-interface.workspace = true [dev-dependencies] mollusk-svm.workspace = true diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 59badf3a..48458925 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,4 +1,4 @@ -use interface::*; +use tree_interface::*; use std::{collections::HashSet, fs, path::Path}; const CONSTANTS_ANCHOR_START: &str = "# ANCHOR: constants"; diff --git a/examples/tree/interface/Cargo.toml b/examples/tree/interface/Cargo.toml index 69a9a945..cbb7337f 100644 --- a/examples/tree/interface/Cargo.toml +++ b/examples/tree/interface/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "interface" +name = "tree-interface" version = "0.1.0" edition = "2021" diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2eae3e86..7ad40d08 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,7 +1,7 @@ use core::mem::transmute; #[cfg(target_os = "solana")] use core::mem::MaybeUninit; -use interface::{data, error_codes::error, input_buffer}; +use tree_interface::{data, error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, entrypoint::NON_DUP_MARKER, @@ -9,7 +9,7 @@ use pinocchio::{ no_allocator, nostd_panic_handler, Address, SUCCESS, }; #[cfg(target_os = "solana")] -use {core::ptr::null, interface::cpi, pinocchio::syscalls::sol_try_find_program_address}; +use {core::ptr::null, tree_interface::cpi, pinocchio::syscalls::sol_try_find_program_address}; #[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 68589a65..989b7e24 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,7 +1,7 @@ mod entrypoint; mod init; -use interface::error_codes; +use tree_interface::error_codes; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_sdk::account::Account; use solana_sdk::instruction::Instruction; diff --git a/examples/utils/deps/build/Cargo.toml b/examples/utils/deps/build/Cargo.toml index 955ddf9a..f2cd1318 100644 --- a/examples/utils/deps/build/Cargo.toml +++ b/examples/utils/deps/build/Cargo.toml @@ -1,5 +1,6 @@ [dependencies] cargo-manifest.workspace = true +tree-interface.workspace = true pinocchio.workspace = true pinocchio-system.workspace = true regex.workspace = true diff --git a/examples/utils/deps/program/Cargo.toml b/examples/utils/deps/program/Cargo.toml index 4bda35bd..44e25533 100644 --- a/examples/utils/deps/program/Cargo.toml +++ b/examples/utils/deps/program/Cargo.toml @@ -1,4 +1,5 @@ [dependencies] +tree-interface.workspace = true pinocchio.workspace = true pinocchio-system.workspace = true From 9b6b602435803986a37b827fceb355901f7e5acb Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:56:42 -0800 Subject: [PATCH 096/263] fmt --- examples/tree/artifacts/dumps/rs.txt | 6 +++--- examples/tree/build.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index b90ed8ef..fa0692f9 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -30,7 +30,7 @@ Section Headers [ 4] .bss.heap NOBITS 0000000300000000 000310 001000 00 A 0 0 1 [ 5] .symtab SYMTAB 0000000000000000 000310 000378 18 7 36 8 [ 6] .shstrtab STRTAB 0000000000000000 000688 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006c6 000531 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006c6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -61,8 +61,8 @@ There are no relocations in this file. Symbol table '.symtab' contains 37 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND - 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.5ef7c9ba836945e-cgu.0 - 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 6xmo2o9jwpdggg5yf76ozzlzl + 1 0000000000000000 0 FILE LOCAL DEFAULT ABS tree.6625ec0a981394b8-cgu.0 + 2 0000000000000000 0 FILE LOCAL DEFAULT ABS 9xo1hdtfkmmy8s7c073n5kchv 3 0000000000000000 0 FILE LOCAL DEFAULT ABS alloc.63143c6bdd2830dc-cgu.0 4 0000000000000000 0 FILE LOCAL DEFAULT ABS core.e0b4368be1399d19-cgu.0 5 0000000000000000 0 FILE LOCAL DEFAULT ABS compiler_builtins.23e48371ed54d56c-cgu.078 diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 48458925..0cda671a 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -1,5 +1,5 @@ -use tree_interface::*; use std::{collections::HashSet, fs, path::Path}; +use tree_interface::*; const CONSTANTS_ANCHOR_START: &str = "# ANCHOR: constants"; const CONSTANTS_ANCHOR_END: &str = "# ANCHOR_END: constants"; From 6762ddf999092d09a97db1f1077071de14590465 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:57:32 -0800 Subject: [PATCH 097/263] fmt tests --- examples/tree/src/program.rs | 4 ++-- examples/tree/src/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 7ad40d08..a9691c02 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,15 +1,15 @@ use core::mem::transmute; #[cfg(target_os = "solana")] use core::mem::MaybeUninit; -use tree_interface::{data, error_codes::error, input_buffer}; use pinocchio::{ address::address_eq, entrypoint::NON_DUP_MARKER, hint::{likely, unlikely}, no_allocator, nostd_panic_handler, Address, SUCCESS, }; +use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] -use {core::ptr::null, tree_interface::cpi, pinocchio::syscalls::sol_try_find_program_address}; +use {core::ptr::null, pinocchio::syscalls::sol_try_find_program_address, tree_interface::cpi}; #[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 989b7e24..232cd669 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,13 +1,13 @@ mod entrypoint; mod init; -use tree_interface::error_codes; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_sdk::account::Account; use solana_sdk::instruction::Instruction; use solana_sdk::program_error::ProgramError; use solana_sdk::pubkey::Pubkey; use test_utils::{setup_test, ProgramLanguage, TestSetup}; +use tree_interface::error_codes; const USER_LAMPORTS: u64 = 1_000_000; From 412eef78470fa6ff19f1095994db029fd91286c6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:04:57 -0800 Subject: [PATCH 098/263] Use cast instead of transmute --- examples/tree/src/program.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a9691c02..2d938b09 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -26,7 +26,7 @@ macro_rules! ensure_ldxb { #[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { - *transmute::<*const u8, *const u64>(ptr.add(offset as usize)) + *ptr.add(offset as usize).cast() } macro_rules! ensure_ldxdw { From dd60a37baad88842f7a7657d8e19afbb6aa68cd0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:06:22 -0800 Subject: [PATCH 099/263] Consolidate imports --- examples/tree/src/program.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2d938b09..4b667cb7 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,6 +1,3 @@ -use core::mem::transmute; -#[cfg(target_os = "solana")] -use core::mem::MaybeUninit; use pinocchio::{ address::address_eq, entrypoint::NON_DUP_MARKER, @@ -9,7 +6,14 @@ use pinocchio::{ }; use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] -use {core::ptr::null, pinocchio::syscalls::sol_try_find_program_address, tree_interface::cpi}; +use { + core::{ + mem::{transmute, MaybeUninit}, + ptr::null, + }, + pinocchio::syscalls::sol_try_find_program_address, + tree_interface::cpi, +}; #[inline(always)] unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { From 8d3b0977dd61b8e6373db335ca085dea3901c3c8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:11:03 -0800 Subject: [PATCH 100/263] Fix ptr handling --- .../tests/entrypoint_branching/result.txt | 24 ---------- .../tests/initialize_input_checks/result.txt | 45 ------------------- .../tests/initialize_input_checks/test.txt | 4 -- .../tests/initialize_pda_checks/result.txt | 31 ------------- .../tests/initialize_pda_checks/test.txt | 4 -- examples/tree/src/program.rs | 8 ++-- 6 files changed, 3 insertions(+), 113 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index b36b9ca3..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,24 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Four accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 1bcf1d9b..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,45 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Non-empty instruction data | 17 | 19 | +2 | +11.8% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index d179220a..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 3c9eedad..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1530 | 1532 | +2 | +0.1% | -| PDA mismatch chunk 2 | 1533 | 1535 | +2 | +0.1% | -| PDA mismatch chunk 3 | 1536 | 1538 | +2 | +0.1% | -| PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 5bd90196..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES); -} \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 4b667cb7..84728a63 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,3 +1,4 @@ +use core::mem::transmute; use pinocchio::{ address::address_eq, entrypoint::NON_DUP_MARKER, @@ -7,10 +8,7 @@ use pinocchio::{ use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] use { - core::{ - mem::{transmute, MaybeUninit}, - ptr::null, - }, + core::{mem::MaybeUninit, ptr::null}, pinocchio::syscalls::sol_try_find_program_address, tree_interface::cpi, }; @@ -30,7 +28,7 @@ macro_rules! ensure_ldxb { #[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { - *ptr.add(offset as usize).cast() + *ptr.add(offset as usize).cast::() } macro_rules! ensure_ldxdw { From 08c9db974111edeb7fe0fd478009419653159572 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:11:50 -0800 Subject: [PATCH 101/263] Add tests --- .../tests/entrypoint_branching/result.txt | 24 ++++++++++ .../tests/initialize_input_checks/result.txt | 45 +++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 ++ .../tests/initialize_pda_checks/result.txt | 31 +++++++++++++ .../tests/initialize_pda_checks/test.txt | 4 ++ 5 files changed, 108 insertions(+) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..b36b9ca3 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,24 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Four accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..1bcf1d9b --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,45 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Non-empty instruction data | 17 | 19 | +2 | +11.8% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..d179220a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..3c9eedad --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1530 | 1532 | +2 | +0.1% | +| PDA mismatch chunk 2 | 1533 | 1535 | +2 | +0.1% | +| PDA mismatch chunk 3 | 1536 | 1538 | +2 | +0.1% | +| PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..5bd90196 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES); +} \ No newline at end of file From bbb81ed6e9b24b5cf558d990c2f60987be616b52 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:55:23 -0800 Subject: [PATCH 102/263] Clean up RS logic --- examples/tree/artifacts/dumps/rs.txt | 94 +++++++++---------- examples/tree/artifacts/rs-disassembly.s | 54 +++++------ .../tree/artifacts/snippets/asm/constants.txt | 4 + .../snippets/rs/initialize-input-checks.txt | 42 +++------ .../snippets/rs/initialize-pda-checks.txt | 3 +- .../tests/initialize_pda_checks/result.txt | 16 ++-- examples/tree/interface/src/common.rs | 6 ++ examples/tree/src/program.rs | 73 ++++++-------- examples/tree/src/tree/tree.s | 4 + 9 files changed, 139 insertions(+), 157 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index fa0692f9..b3c961e3 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3064 (bytes into file) + Start of section headers 3048 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xbf8 +There are 8 section headers, starting at offset 0xbe8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0001e8 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000308 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000310 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000310 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000310 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000688 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006c6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0001d8 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 0002f8 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000300 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000300 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000300 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000678 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006b6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001e8 0x0001e8 E 0x8 - LOAD 0x000308 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000310 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000310 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001d8 0x0001d8 E 0x8 + LOAD 0x0002f8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000300 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000300 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 488 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 472 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 02 28 00 03 00 00 00 jne r2, 0x3, +0x28 + 40 55 02 26 00 03 00 00 00 jne r2, 0x3, +0x26 48 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 50 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 + 50 55 02 22 00 00 00 00 00 jne r2, 0x0, +0x22 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 60 55 02 26 00 ff 00 00 00 jne r2, 0xff, +0x26 + 60 55 02 24 00 ff 00 00 00 jne r2, 0xff, +0x24 68 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 70 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 + 70 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 78 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 80 55 02 26 00 ff 00 00 00 jne r2, 0xff, +0x26 + 80 55 02 24 00 ff 00 00 00 jne r2, 0xff, +0x24 88 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 90 55 02 26 00 0e 00 00 00 jne r2, 0xe, +0x26 + 90 55 02 24 00 0e 00 00 00 jne r2, 0xe, +0x24 98 9c 12 38 79 00 00 00 00 ldxdw r2, [r1 + 0x7938] - a0 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 + a0 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 b0 07 03 00 00 40 79 00 00 add64 r3, 0x7940 b8 bf a4 00 00 00 00 00 00 mov64 r4, r10 @@ -132,36 +132,34 @@ Disassembly of section .text c8 bf a5 00 00 00 00 00 00 mov64 r5, r10 d0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f d8 bf 16 00 00 00 00 00 00 mov64 r6, r1 - e0 b7 01 00 00 00 00 00 00 mov64 r1, 0x0 - e8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - f0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - f8 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 100 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 108 9c a2 18 00 00 00 00 00 ldxdw r2, [r10 + 0x18] - 110 9c 13 70 28 00 00 00 00 ldxdw r3, [r1 + 0x2870] - 118 5d 32 e3 ff 00 00 00 00 jne r2, r3, -0x1d - 120 9c a2 20 00 00 00 00 00 ldxdw r2, [r10 + 0x20] - 128 9c 13 78 28 00 00 00 00 ldxdw r3, [r1 + 0x2878] - 130 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 - 138 9c a2 28 00 00 00 00 00 ldxdw r2, [r10 + 0x28] - 140 9c 13 80 28 00 00 00 00 ldxdw r3, [r1 + 0x2880] - 148 5d 32 dd ff 00 00 00 00 jne r2, r3, -0x23 - 150 9c a2 30 00 00 00 00 00 ldxdw r2, [r10 + 0x30] - 158 9c 11 88 28 00 00 00 00 ldxdw r1, [r1 + 0x2888] - 160 5d 12 da ff 00 00 00 00 jne r2, r1, -0x26 - 168 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + e0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + e8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + f8 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 100 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 108 5d 21 e5 ff 00 00 00 00 jne r1, r2, -0x1b + 110 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 118 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 120 5d 21 e2 ff 00 00 00 00 jne r1, r2, -0x1e + 128 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 130 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 138 5d 21 df ff 00 00 00 00 jne r1, r2, -0x21 + 140 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 148 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] + 150 5d 21 dc ff 00 00 00 00 jne r1, r2, -0x24 + 158 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 160 05 00 da ff 00 00 00 00 ja -0x26 + 168 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 170 05 00 d8 ff 00 00 00 00 ja -0x28 - 178 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 178 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 180 05 00 d6 ff 00 00 00 00 ja -0x2a - 188 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 188 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 190 05 00 d4 ff 00 00 00 00 ja -0x2c - 198 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 198 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e - 1a8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1a8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 - 1b8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1b8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 1c0 05 00 ce ff 00 00 00 00 ja -0x32 - 1c8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1d0 05 00 cc ff 00 00 00 00 ja -0x34 - 1d8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1e0 05 00 ca ff 00 00 00 00 ja -0x36 \ No newline at end of file + 1c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1d0 05 00 cc ff 00 00 00 00 ja -0x34 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 36a0eaec..dd282177 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r2, 3, jmp_0188 + jne r2, 3, jmp_0178 ldxdw r2, [r1+88] - jne r2, 0, jmp_0178 + jne r2, 0, jmp_0168 ldxb r2, [r1+10344] - jne r2, 255, jmp_0198 + jne r2, 255, jmp_0188 ldxdw r2, [r1+10424] - jne r2, 0, jmp_01a8 + jne r2, 0, jmp_0198 ldxb r2, [r1+20680] - jne r2, 255, jmp_01b8 + jne r2, 255, jmp_01a8 ldxdw r2, [r1+20760] - jne r2, 14, jmp_01c8 + jne r2, 14, jmp_01b8 ldxdw r2, [r1+31032] - jne r2, 0, jmp_01d8 + jne r2, 0, jmp_01c8 mov64 r3, r1 add64 r3, 31040 mov64 r4, r10 @@ -33,50 +33,48 @@ jmp_0040: mov64 r5, r10 add64 r5, 63 mov64 r6, r1 - mov64 r1, 0 mov64 r2, 0 call sol_try_find_program_address - mov64 r1, r6 mov64 r0, 8 - ldxdw r2, [r10+24] - ldxdw r3, [r1+10352] - jne r2, r3, jmp_0038 - ldxdw r2, [r10+32] - ldxdw r3, [r1+10360] - jne r2, r3, jmp_0038 - ldxdw r2, [r10+40] - ldxdw r3, [r1+10368] - jne r2, r3, jmp_0038 - ldxdw r2, [r10+48] - ldxdw r1, [r1+10376] - jne r2, r1, jmp_0038 + ldxdw r1, [r10+24] + ldxdw r2, [r6+10352] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+32] + ldxdw r2, [r6+10360] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+40] + ldxdw r2, [r6+10368] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+48] + ldxdw r2, [r6+10376] + jne r1, r2, jmp_0038 mov64 r0, 0 ja jmp_0038 -jmp_0178: +jmp_0168: mov64 r0, 2 ja jmp_0038 -jmp_0188: +jmp_0178: mov64 r0, 1 ja jmp_0038 -jmp_0198: +jmp_0188: mov64 r0, 5 ja jmp_0038 -jmp_01a8: +jmp_0198: mov64 r0, 3 ja jmp_0038 -jmp_01b8: +jmp_01a8: mov64 r0, 6 ja jmp_0038 -jmp_01c8: +jmp_01b8: mov64 r0, 4 ja jmp_0038 -jmp_01d8: +jmp_01c8: mov64 r0, 7 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index a2df7b3c..6ab001b0 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -35,6 +35,10 @@ # Input buffer layout. # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_ACCOUNT_OFF, 8 # User runtime account. +.equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. +# System Program runtime account header. +.equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 1f70c2a4..0399d126 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,45 +1,31 @@ #[inline(always)] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::USER_DATA_LEN_OFF, - data::DATA_LEN_ZERO, - error::USER_DATA_LEN - ); + let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate or has data. - ensure_ldxb!( - input_buffer_ptr, - input_buffer::TREE_NON_DUP_MARKER_OFF, - NON_DUP_MARKER, - error::TREE_DUPLICATE - ); - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::TREE_DATA_LEN_OFF, - data::DATA_LEN_ZERO, - error::TREE_DATA_LEN - ); + let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - ensure_ldxb!( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - NON_DUP_MARKER, + let system_program = account_at(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); + if_err!( + is_duplicate(&system_program), error::SYSTEM_PROGRAM_DUPLICATE ); - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF, - input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + if_err!( + system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if instruction data provided. - ensure_ldxdw!( + let instruction_data_len = ldxdw( input_buffer_ptr, input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - data::DATA_LEN_ZERO, + ); + if_err!( + instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA ); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 06594509..a23b3c8c 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -4,7 +4,8 @@ let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); sol_try_find_program_address( - null(), + // Pass a declared pointer instead of null to prevent unnecessary register assignment. + input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), pda.as_mut_ptr().cast(), diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 3c9eedad..bd526645 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,31 +1,31 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1530 | 1532 | +2 | +0.1% | -| PDA mismatch chunk 2 | 1533 | 1535 | +2 | +0.1% | -| PDA mismatch chunk 3 | 1536 | 1538 | +2 | +0.1% | -| PDA mismatch chunk 4 | 1539 | 1541 | +2 | +0.1% | +| PDA mismatch chunk 1 | 1530 | 1530 | +0 | +0.0% | +| PDA mismatch chunk 2 | 1533 | 1533 | +0 | +0.0% | +| PDA mismatch chunk 3 | 1536 | 1536 | +0 | +0.0% | +| PDA mismatch chunk 4 | 1539 | 1539 | +0 | +0.0% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index e1667c53..0f7f349f 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -28,6 +28,12 @@ constant_group! { input_buffer { /// Number of accounts field. offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), + /// User runtime account. + offset!(USER_ACCOUNT, InputBufferHeader.user), + /// Tree runtime account header. + offset!(TREE_ACCOUNT, InputBufferHeader.tree_header), + /// System Program runtime account header. + offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.system_program), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 84728a63..99d3d0ec 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,9 +1,8 @@ use core::mem::transmute; use pinocchio::{ address::address_eq, - entrypoint::NON_DUP_MARKER, hint::{likely, unlikely}, - no_allocator, nostd_panic_handler, Address, SUCCESS, + no_allocator, nostd_panic_handler, AccountView, Address, SUCCESS, }; use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] @@ -14,16 +13,8 @@ use { }; #[inline(always)] -unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { - *ptr.add(offset as usize) -} - -macro_rules! ensure_ldxb { - ($ptr:expr, $offset:expr, $expected:expr, $error:expr) => { - if unlikely(ldxb($ptr, $offset) != $expected) { - return $error.into(); - } - }; +unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { + AccountView::new_unchecked(input_buffer_ptr.add(offset as usize).cast()) } #[inline(always)] @@ -31,9 +22,16 @@ unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { *ptr.add(offset as usize).cast::() } -macro_rules! ensure_ldxdw { - ($ptr:expr, $offset:expr, $expected:expr, $error:expr) => { - if unlikely(ldxdw($ptr, $offset) != $expected) { +/// Checks if the account is a duplicate by checking if it's borrowed, since this is equivalent +/// via the underlying API due to the borrow state implementation. +#[inline(always)] +fn is_duplicate(account: &AccountView) -> bool { + account.is_borrowed() +} + +macro_rules! if_err { + ($condition:expr, $error:expr) => { + if unlikely($condition) { return $error.into(); } }; @@ -69,46 +67,32 @@ unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { #[inline(always)] unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { // Error if user has data. - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::USER_DATA_LEN_OFF, - data::DATA_LEN_ZERO, - error::USER_DATA_LEN - ); + let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate or has data. - ensure_ldxb!( - input_buffer_ptr, - input_buffer::TREE_NON_DUP_MARKER_OFF, - NON_DUP_MARKER, - error::TREE_DUPLICATE - ); - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::TREE_DATA_LEN_OFF, - data::DATA_LEN_ZERO, - error::TREE_DATA_LEN - ); + let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - ensure_ldxb!( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, - NON_DUP_MARKER, + let system_program = account_at(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); + if_err!( + is_duplicate(&system_program), error::SYSTEM_PROGRAM_DUPLICATE ); - ensure_ldxdw!( - input_buffer_ptr, - input_buffer::SYSTEM_PROGRAM_DATA_LEN_OFF, - input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + if_err!( + system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if instruction data provided. - ensure_ldxdw!( + let instruction_data_len = ldxdw( input_buffer_ptr, input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - data::DATA_LEN_ZERO, + ); + if_err!( + instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA ); // ANCHOR_END: initialize-input-checks @@ -120,7 +104,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); sol_try_find_program_address( - null(), + // Pass a declared pointer instead of null to prevent unnecessary register assignment. + input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), pda.as_mut_ptr().cast(), diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 1d46e927..135e7c4d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -36,6 +36,10 @@ # Input buffer layout. # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. +.equ IB_USER_ACCOUNT_OFF, 8 # User runtime account. +.equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. +# System Program runtime account header. +.equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. From 4261036c27471f7ed073aa9906d1bf3276e12151 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:57:11 -0800 Subject: [PATCH 103/263] Clean up ASM --- examples/tree/artifacts/dumps/asm.txt | 151 +++++++++--------- .../tree/artifacts/snippets/asm/constants.txt | 1 + .../snippets/asm/entrypoint-branching.txt | 6 +- .../snippets/asm/initialize-input-checks.txt | 30 ++-- .../snippets/asm/initialize-pda-checks.txt | 35 ++-- .../snippets/rs/entrypoint-branching.txt | 7 +- .../snippets/rs/initialize-input-checks.txt | 7 +- .../tests/initialize_pda_checks/result.txt | 31 ---- examples/tree/interface/src/asm.rs | 1 + examples/tree/src/program.rs | 18 +-- examples/tree/src/tree/tree.s | 85 +++++----- 11 files changed, 178 insertions(+), 194 deletions(-) delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index e9f6aed2..b177a146 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1080 (bytes into file) + Start of section headers 1056 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x438 +There are 7 section headers, starting at offset 0x420 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0001f8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000002e0 0002e0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000380 000380 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003c8 0003c8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000003f8 0003f8 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000408 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0001e0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000002c8 0002c8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000368 000368 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003b0 0003b0 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000003e0 0003e0 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0003f0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001f8 0x0001f8 R E 0x1000 - LOAD 0x000380 0x0000000000000380 0x0000000000000380 0x000088 0x000088 R 0x1000 - DYNAMIC 0x0002e0 0x00000000000002e0 0x00000000000002e0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001e0 0x0001e0 R E 0x1000 + LOAD 0x000368 0x0000000000000368 0x0000000000000368 0x000088 0x000088 R 0x1000 + DYNAMIC 0x0002c8 0x00000000000002c8 0x00000000000002c8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x2e0 contains 10 entries +Dynamic section at offset 0x2c8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x3f8 + 0x0000000000000011 (REL) 0x3e0 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x380 + 0x0000000000000006 (SYMTAB) 0x368 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3c8 + 0x0000000000000005 (STRTAB) 0x3b0 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x3f8 contains 1 entries +Relocation section '.rel.dyn' at offset 0x3e0 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -00000000000001d0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +00000000000001c8 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -81,66 +81,63 @@ tree.so file format elf64-bpf Disassembly of section .text 00000000000000e8 - 29 79 12 00 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x0) - 30 15 02 03 00 02 00 00 00 if r2 == 0x2 goto +0x3 - 31 15 02 07 00 03 00 00 00 if r2 == 0x3 goto +0x7 + 29 79 19 00 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x0) + 30 15 09 03 00 02 00 00 00 if r9 == 0x2 goto +0x3 + 31 15 09 07 00 03 00 00 00 if r9 == 0x3 goto +0x7 32 b7 00 00 00 01 00 00 00 r0 = 0x1 33 95 00 00 00 00 00 00 00 exit - 34 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 35 07 02 00 00 07 00 00 00 r2 += 0x7 - 36 57 02 00 00 f8 ff ff ff r2 &= -0x8 - 37 0f 12 00 00 00 00 00 00 r2 += r1 + 34 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 35 07 09 00 00 07 00 00 00 r9 += 0x7 + 36 57 09 00 00 f8 ff ff ff r9 &= -0x8 + 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit - 39 79 12 58 00 00 00 00 00 r2 = *(u64 *)(r1 + 0x58) - 40 55 02 31 00 00 00 00 00 if r2 != 0x0 goto +0x31 - 41 71 12 68 28 00 00 00 00 r2 = *(u8 *)(r1 + 0x2868) - 42 55 02 2d 00 ff 00 00 00 if r2 != 0xff goto +0x2d - 43 79 12 b8 28 00 00 00 00 r2 = *(u64 *)(r1 + 0x28b8) - 44 55 02 29 00 00 00 00 00 if r2 != 0x0 goto +0x29 - 45 71 12 c8 50 00 00 00 00 r2 = *(u8 *)(r1 + 0x50c8) - 46 55 02 25 00 ff 00 00 00 if r2 != 0xff goto +0x25 - 47 79 12 18 51 00 00 00 00 r2 = *(u64 *)(r1 + 0x5118) - 48 55 02 21 00 0e 00 00 00 if r2 != 0xe goto +0x21 - 49 79 12 38 79 00 00 00 00 r2 = *(u64 *)(r1 + 0x7938) - 50 55 02 1b 00 00 00 00 00 if r2 != 0x0 goto +0x1b - 51 b7 02 00 00 00 00 00 00 r2 = 0x0 - 52 bf 13 00 00 00 00 00 00 r3 = r1 - 53 07 03 00 00 40 79 00 00 r3 += 0x7940 - 54 bf a4 00 00 00 00 00 00 r4 = r10 - 55 07 04 00 00 98 ff ff ff r4 += -0x68 - 56 bf a5 00 00 00 00 00 00 r5 = r10 - 57 07 05 00 00 98 fe ff ff r5 += -0x168 - 58 85 10 00 00 ff ff ff ff call -0x1 - 59 bf 13 00 00 00 00 00 00 r3 = r1 - 60 07 03 00 00 70 28 00 00 r3 += 0x2870 - 61 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) - 62 79 46 00 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x0) - 63 5d 65 10 00 00 00 00 00 if r5 != r6 goto +0x10 - 64 79 35 08 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x8) - 65 79 46 08 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x8) - 66 5d 65 0d 00 00 00 00 00 if r5 != r6 goto +0xd - 67 79 35 10 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x10) - 68 79 46 10 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x10) - 69 5d 65 0a 00 00 00 00 00 if r5 != r6 goto +0xa - 70 79 35 18 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x18) - 71 79 46 18 00 00 00 00 00 r6 = *(u64 *)(r4 + 0x18) - 72 5d 65 07 00 00 00 00 00 if r5 != r6 goto +0x7 - 73 bf a2 00 00 00 00 00 00 r2 = r10 - 74 07 02 00 00 98 fe ff ff r2 += -0x168 - 75 7b 2a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r2 - 76 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 77 95 00 00 00 00 00 00 00 exit - 78 b7 00 00 00 07 00 00 00 r0 = 0x7 - 79 95 00 00 00 00 00 00 00 exit - 80 b7 00 00 00 08 00 00 00 r0 = 0x8 - 81 95 00 00 00 00 00 00 00 exit - 82 b7 00 00 00 04 00 00 00 r0 = 0x4 - 83 95 00 00 00 00 00 00 00 exit - 84 b7 00 00 00 06 00 00 00 r0 = 0x6 - 85 95 00 00 00 00 00 00 00 exit - 86 b7 00 00 00 03 00 00 00 r0 = 0x3 - 87 95 00 00 00 00 00 00 00 exit - 88 b7 00 00 00 05 00 00 00 r0 = 0x5 - 89 95 00 00 00 00 00 00 00 exit - 90 b7 00 00 00 02 00 00 00 r0 = 0x2 - 91 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 40 55 09 2e 00 00 00 00 00 if r9 != 0x0 goto +0x2e + 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 42 55 09 2a 00 ff 00 00 00 if r9 != 0xff goto +0x2a + 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 44 55 09 26 00 00 00 00 00 if r9 != 0x0 goto +0x26 + 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) + 46 55 09 22 00 ff 00 00 00 if r9 != 0xff goto +0x22 + 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) + 48 55 09 1e 00 0e 00 00 00 if r9 != 0xe goto +0x1e + 49 79 19 38 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7938) + 50 55 09 18 00 00 00 00 00 if r9 != 0x0 goto +0x18 + 51 bf 13 00 00 00 00 00 00 r3 = r1 + 52 07 03 00 00 40 79 00 00 r3 += 0x7940 + 53 bf a4 00 00 00 00 00 00 r4 = r10 + 54 07 04 00 00 98 ff ff ff r4 += -0x68 + 55 bf a5 00 00 00 00 00 00 r5 = r10 + 56 07 05 00 00 98 fe ff ff r5 += -0x168 + 57 85 10 00 00 ff ff ff ff call -0x1 + 58 bf 13 00 00 00 00 00 00 r3 = r1 + 59 07 03 00 00 70 28 00 00 r3 += 0x2870 + 60 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 61 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) + 62 5d 89 0e 00 00 00 00 00 if r9 != r8 goto +0xe + 63 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 64 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) + 65 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb + 66 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 67 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 68 5d 89 08 00 00 00 00 00 if r9 != r8 goto +0x8 + 69 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 70 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) + 71 5d 89 05 00 00 00 00 00 if r9 != r8 goto +0x5 + 72 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 73 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 74 95 00 00 00 00 00 00 00 exit + 75 b7 00 00 00 07 00 00 00 r0 = 0x7 + 76 95 00 00 00 00 00 00 00 exit + 77 b7 00 00 00 08 00 00 00 r0 = 0x8 + 78 95 00 00 00 00 00 00 00 exit + 79 b7 00 00 00 04 00 00 00 r0 = 0x4 + 80 95 00 00 00 00 00 00 00 exit + 81 b7 00 00 00 06 00 00 00 r0 = 0x6 + 82 95 00 00 00 00 00 00 00 exit + 83 b7 00 00 00 03 00 00 00 r0 = 0x3 + 84 95 00 00 00 00 00 00 00 exit + 85 b7 00 00 00 05 00 00 00 r0 = 0x5 + 86 95 00 00 00 00 00 00 00 exit + 87 b7 00 00 00 02 00 00 00 r0 = 0x2 + 88 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 6ab001b0..69c793cb 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -16,6 +16,7 @@ # Type sizes. # ----------- .equ SIZE_OF_U8, 1 # Size of u8. +.equ SIZE_OF_U64, 8 # Size of u64. # Data layout constants. # ---------------------- diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt index a48ee1cc..bdbd939a 100644 --- a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt @@ -3,8 +3,8 @@ entrypoint: # Check input buffer accounts. # ---------------------------- - ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r2, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. + jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index bfd6c8e6..138f09b1 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -2,24 +2,30 @@ initialize: # Error if user has data. # ----------------------- - ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_user_data_len + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len # Error if tree is duplicate or has data. # --------------------------------------- - ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_tree_data_len + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_tree_data_len # Error if System Program is duplicate or has invalid data length. # ---------------------------------------------------------------- - ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] - jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] - jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + ldxb r9, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if instruction data provided. # ----------------------------------- - ldxdw r2, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file + # Use the instruction data pointer in r2 from SIMD-0321, which is + # equivalent to the following static offset for static and verified + # account data lengths: + # ``` + # ldxdw r9, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] + # ``` + ldxdw r9, [r2 - SIZE_OF_U64] + jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index d85ec106..6061700a 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -1,6 +1,9 @@ # Compute PDA. - # ------------ - mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. + # --------------------------------------------------------------------- + # Skip assignment for r1, since no seeds need to be parsed and this + # argument is effectively ignored. + # --------------------------------------------------------------------- + mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. mov64 r3, r1 # Get input buffer pointer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. @@ -11,17 +14,17 @@ # Compare computed PDA against passed account. # -------------------------------------------- - mov64 r3, r1 # Get input buffer pointer. - add64 r3, IB_TREE_ADDRESS_OFF # Point at tree address. - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_0] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_0] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_1] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_1] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_2] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_2] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] - jne r5, r6, e_pda_mismatch \ No newline at end of file + mov64 r9, r1 # Get input buffer pointer. + add64 r9, IB_TREE_ADDRESS_OFF # Point at tree address. + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_0] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_1] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_2] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_3] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] + jne r8, r7, e_pda_mismatch \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 879dd8b5..1ad539ef 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -2,12 +2,15 @@ no_allocator!(); nostd_panic_handler!(); #[no_mangle] -pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { +pub unsafe extern "C" fn entrypoint( + input_buffer_ptr: *mut u8, + instruction_data_ptr: *mut u8, +) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { general(input_buffer_ptr) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr) + initialize(input_buffer_ptr, instruction_data_ptr) } else { error::N_ACCOUNTS.into() } diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 0399d126..aab1dfd2 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,5 +1,5 @@ #[inline(always)] -unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { +unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { // Error if user has data. let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); @@ -21,10 +21,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ); // Error if instruction data provided. - let instruction_data_len = ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ); + let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); if_err!( instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index bd526645..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1530 | 1530 | +0 | +0.0% | -| PDA mismatch chunk 2 | 1533 | 1533 | +0 | +0.0% | -| PDA mismatch chunk 3 | 1536 | 1536 | +0 | +0.0% | -| PDA mismatch chunk 4 | 1539 | 1539 | +0 | +0.0% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 735f563a..cea13f37 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -11,6 +11,7 @@ pubkey_chunk_group!(); sizes! { u8, + u64, } extend_constant_group!(data { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 99d3d0ec..ceb058e6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -7,9 +7,7 @@ use pinocchio::{ use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] use { - core::{mem::MaybeUninit, ptr::null}, - pinocchio::syscalls::sol_try_find_program_address, - tree_interface::cpi, + core::mem::MaybeUninit, pinocchio::syscalls::sol_try_find_program_address, tree_interface::cpi, }; #[inline(always)] @@ -42,12 +40,15 @@ no_allocator!(); nostd_panic_handler!(); #[no_mangle] -pub unsafe extern "C" fn entrypoint(input_buffer_ptr: *mut u8) -> u64 { +pub unsafe extern "C" fn entrypoint( + input_buffer_ptr: *mut u8, + instruction_data_ptr: *mut u8, +) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { general(input_buffer_ptr) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr) + initialize(input_buffer_ptr, instruction_data_ptr) } else { error::N_ACCOUNTS.into() } @@ -65,7 +66,7 @@ unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { // ANCHOR: initialize-input-checks #[inline(always)] -unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { +unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { // Error if user has data. let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); @@ -87,10 +88,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8) -> u64 { ); // Error if instruction data provided. - let instruction_data_len = ldxdw( - input_buffer_ptr, - input_buffer::INIT_INSTRUCTION_DATA_LEN_OFF, - ); + let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); if_err!( instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 135e7c4d..1c20b58c 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -17,6 +17,7 @@ # Type sizes. # ----------- .equ SIZE_OF_U8, 1 # Size of u8. +.equ SIZE_OF_U64, 8 # Size of u64. # Data layout constants. # ---------------------- @@ -82,18 +83,18 @@ entrypoint: # Check input buffer accounts. # ---------------------------- - ldxdw r2, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jeq r2, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r2, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. + ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. + jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. mov64 r0, E_N_ACCOUNTS # Else fail. exit # ANCHOR_END: entrypoint-branching general: - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. - add64 r2, MAX_DATA_PAD # Speculatively add max possible padding. - and64 r2, DATA_LEN_AND_MASK # Get data length plus required padding. - add64 r2, r1 # Get input buffer pointer shifted for tree data. + ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + add64 r9, MAX_DATA_PAD # Speculatively add max possible padding. + and64 r9, DATA_LEN_AND_MASK # Get data length plus required padding. + add64 r9, r1 # Get input buffer pointer shifted for tree data. exit # ANCHOR: initialize-input-checks @@ -101,33 +102,42 @@ initialize: # Error if user has data. # ----------------------- - ldxdw r2, [r1 + IB_USER_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_user_data_len + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len # Error if tree is duplicate or has data. # --------------------------------------- - ldxb r2, [r1 + IB_TREE_NON_DUP_MARKER_OFF] - jne r2, IB_NON_DUP_MARKER, e_tree_duplicate - ldxdw r2, [r1 + IB_TREE_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_tree_data_len + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_tree_data_len # Error if System Program is duplicate or has invalid data length. # ---------------------------------------------------------------- - ldxb r2, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] - jne r2, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r2, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] - jne r2, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + ldxb r9, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if instruction data provided. # ----------------------------------- - ldxdw r2, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] - jne r2, DATA_LEN_ZERO, e_instruction_data + # Use the instruction data pointer in r2 from SIMD-0321, which is + # equivalent to the following static offset for static and verified + # account data lengths: + # ``` + # ldxdw r9, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] + # ``` + ldxdw r9, [r2 - SIZE_OF_U64] + jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks # ANCHOR: initialize-pda-checks # Compute PDA. - # ------------ - mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Indicate no signer seeds. + # --------------------------------------------------------------------- + # Skip assignment for r1, since no seeds need to be parsed and this + # argument is effectively ignored. + # --------------------------------------------------------------------- + mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. mov64 r3, r1 # Get input buffer pointer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. @@ -138,27 +148,26 @@ initialize: # Compare computed PDA against passed account. # -------------------------------------------- - mov64 r3, r1 # Get input buffer pointer. - add64 r3, IB_TREE_ADDRESS_OFF # Point at tree address. - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_0] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_0] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_1] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_1] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_2] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_2] - jne r5, r6, e_pda_mismatch - ldxdw r5, [r3 + PUBKEY_CHUNK_OFF_3] - ldxdw r6, [r4 + PUBKEY_CHUNK_OFF_3] - jne r5, r6, e_pda_mismatch + mov64 r9, r1 # Get input buffer pointer. + add64 r9, IB_TREE_ADDRESS_OFF # Point at tree address. + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_0] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_1] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_2] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] + jne r8, r7, e_pda_mismatch + ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_3] + ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] + jne r8, r7, e_pda_mismatch # ANCHOR_END: initialize-pda-checks # Initialize signer seed for PDA bump key. # ---------------------------------------- - mov64 r2, r10 # Get stack frame pointer. - add64 r2, SF_INIT_BUMP_SEED_OFF # Point at bump seed on stack. - stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r2 # Store in signer seed. + # Store pointer to bump seed. + stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. exit From 6a1c2928ee7143b40d9594937a8445e8eb710679 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:11:14 -0800 Subject: [PATCH 104/263] Add ASM pubkey chunked offsets --- examples/tree/artifacts/dumps/asm.txt | 123 ++++++------ examples/tree/artifacts/dumps/rs.txt | 28 +-- examples/tree/artifacts/rs-disassembly.s | 28 +-- .../tree/artifacts/snippets/asm/constants.txt | 5 +- .../snippets/asm/initialize-pda-checks.txt | 10 +- .../snippets/rs/initialize-pda-checks.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 31 +++ examples/tree/interface/src/asm.rs | 6 +- examples/tree/macros/src/lib.rs | 177 +++++++++++++++++- examples/tree/src/program.rs | 2 +- examples/tree/src/tree/tree.s | 15 +- 11 files changed, 311 insertions(+), 116 deletions(-) create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index b177a146..bd4095a7 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1056 (bytes into file) + Start of section headers 1048 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x420 +There are 7 section headers, starting at offset 0x418 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0001e0 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000002c8 0002c8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000368 000368 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003b0 0003b0 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000003e0 0003e0 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0003f0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0001d8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000002c0 0002c0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000360 000360 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003a8 0003a8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000003d8 0003d8 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0003e8 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001e0 0x0001e0 R E 0x1000 - LOAD 0x000368 0x0000000000000368 0x0000000000000368 0x000088 0x000088 R 0x1000 - DYNAMIC 0x0002c8 0x00000000000002c8 0x00000000000002c8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001d8 0x0001d8 R E 0x1000 + LOAD 0x000360 0x0000000000000360 0x0000000000000360 0x000088 0x000088 R 0x1000 + DYNAMIC 0x0002c0 0x00000000000002c0 0x00000000000002c0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x2c8 contains 10 entries +Dynamic section at offset 0x2c0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x3e0 + 0x0000000000000011 (REL) 0x3d8 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x368 + 0x0000000000000006 (SYMTAB) 0x360 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3b0 + 0x0000000000000005 (STRTAB) 0x3a8 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x3e0 contains 1 entries +Relocation section '.rel.dyn' at offset 0x3d8 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -00000000000001c8 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +00000000000001d0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -92,52 +92,51 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 2e 00 00 00 00 00 if r9 != 0x0 goto +0x2e + 40 55 09 2d 00 00 00 00 00 if r9 != 0x0 goto +0x2d 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 2a 00 ff 00 00 00 if r9 != 0xff goto +0x2a + 42 55 09 29 00 ff 00 00 00 if r9 != 0xff goto +0x29 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 26 00 00 00 00 00 if r9 != 0x0 goto +0x26 + 44 55 09 25 00 00 00 00 00 if r9 != 0x0 goto +0x25 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 22 00 ff 00 00 00 if r9 != 0xff goto +0x22 + 46 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 1e 00 0e 00 00 00 if r9 != 0xe goto +0x1e - 49 79 19 38 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7938) - 50 55 09 18 00 00 00 00 00 if r9 != 0x0 goto +0x18 - 51 bf 13 00 00 00 00 00 00 r3 = r1 - 52 07 03 00 00 40 79 00 00 r3 += 0x7940 - 53 bf a4 00 00 00 00 00 00 r4 = r10 - 54 07 04 00 00 98 ff ff ff r4 += -0x68 - 55 bf a5 00 00 00 00 00 00 r5 = r10 - 56 07 05 00 00 98 fe ff ff r5 += -0x168 - 57 85 10 00 00 ff ff ff ff call -0x1 - 58 bf 13 00 00 00 00 00 00 r3 = r1 - 59 07 03 00 00 70 28 00 00 r3 += 0x2870 - 60 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 61 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 62 5d 89 0e 00 00 00 00 00 if r9 != r8 goto +0xe - 63 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) - 64 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 65 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb - 66 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) - 67 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 68 5d 89 08 00 00 00 00 00 if r9 != r8 goto +0x8 - 69 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) - 70 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 71 5d 89 05 00 00 00 00 00 if r9 != r8 goto +0x5 - 72 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 73 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 74 95 00 00 00 00 00 00 00 exit - 75 b7 00 00 00 07 00 00 00 r0 = 0x7 - 76 95 00 00 00 00 00 00 00 exit - 77 b7 00 00 00 08 00 00 00 r0 = 0x8 - 78 95 00 00 00 00 00 00 00 exit - 79 b7 00 00 00 04 00 00 00 r0 = 0x4 - 80 95 00 00 00 00 00 00 00 exit - 81 b7 00 00 00 06 00 00 00 r0 = 0x6 - 82 95 00 00 00 00 00 00 00 exit - 83 b7 00 00 00 03 00 00 00 r0 = 0x3 - 84 95 00 00 00 00 00 00 00 exit - 85 b7 00 00 00 05 00 00 00 r0 = 0x5 - 86 95 00 00 00 00 00 00 00 exit - 87 b7 00 00 00 02 00 00 00 r0 = 0x2 - 88 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 48 55 09 1d 00 0e 00 00 00 if r9 != 0xe goto +0x1d + 49 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 50 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 + 51 b7 02 00 00 00 00 00 00 r2 = 0x0 + 52 bf 13 00 00 00 00 00 00 r3 = r1 + 53 07 03 00 00 40 79 00 00 r3 += 0x7940 + 54 bf a4 00 00 00 00 00 00 r4 = r10 + 55 07 04 00 00 98 ff ff ff r4 += -0x68 + 56 bf a5 00 00 00 00 00 00 r5 = r10 + 57 07 05 00 00 98 fe ff ff r5 += -0x168 + 58 85 10 00 00 ff ff ff ff call -0x1 + 59 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) + 60 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) + 61 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe + 62 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) + 63 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) + 64 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb + 65 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) + 66 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) + 67 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 + 68 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) + 69 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) + 70 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 + 71 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 72 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 73 95 00 00 00 00 00 00 00 exit + 74 b7 00 00 00 07 00 00 00 r0 = 0x7 + 75 95 00 00 00 00 00 00 00 exit + 76 b7 00 00 00 08 00 00 00 r0 = 0x8 + 77 95 00 00 00 00 00 00 00 exit + 78 b7 00 00 00 04 00 00 00 r0 = 0x4 + 79 95 00 00 00 00 00 00 00 exit + 80 b7 00 00 00 06 00 00 00 r0 = 0x6 + 81 95 00 00 00 00 00 00 00 exit + 82 b7 00 00 00 03 00 00 00 r0 = 0x3 + 83 95 00 00 00 00 00 00 00 exit + 84 b7 00 00 00 05 00 00 00 r0 = 0x5 + 85 95 00 00 00 00 00 00 00 exit + 86 b7 00 00 00 02 00 00 00 r0 = 0x2 + 87 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index b3c961e3..57de8baf 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -105,25 +105,25 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 - 8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 10 55 02 05 00 02 00 00 00 jne r2, 0x2, +0x5 + 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] + 10 55 03 05 00 02 00 00 00 jne r3, 0x2, +0x5 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] 20 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 02 26 00 03 00 00 00 jne r2, 0x3, +0x26 - 48 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 50 55 02 22 00 00 00 00 00 jne r2, 0x0, +0x22 - 58 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 60 55 02 24 00 ff 00 00 00 jne r2, 0xff, +0x24 - 68 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 70 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 - 78 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 80 55 02 24 00 ff 00 00 00 jne r2, 0xff, +0x24 - 88 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 90 55 02 24 00 0e 00 00 00 jne r2, 0xe, +0x24 - 98 9c 12 38 79 00 00 00 00 ldxdw r2, [r1 + 0x7938] + 40 55 03 26 00 03 00 00 00 jne r3, 0x3, +0x26 + 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 50 55 03 22 00 00 00 00 00 jne r3, 0x0, +0x22 + 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 60 55 03 24 00 ff 00 00 00 jne r3, 0xff, +0x24 + 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 70 55 03 24 00 00 00 00 00 jne r3, 0x0, +0x24 + 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] + 80 55 03 24 00 ff 00 00 00 jne r3, 0xff, +0x24 + 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] + 90 55 03 24 00 0e 00 00 00 jne r3, 0xe, +0x24 + 98 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] a0 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 b0 07 03 00 00 40 79 00 00 add64 r3, 0x7940 diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index dd282177..08d96f35 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,8 +2,8 @@ entrypoint: add64 r10, -64 - ldxdw r2, [r1+0] - jne r2, 2, jmp_0040 + ldxdw r3, [r1+0] + jne r3, 2, jmp_0040 ldxdw r1, [r1+88] mov64 r0, 6677 jeq r1, 67, jmp_0038 @@ -13,18 +13,18 @@ jmp_0038: exit jmp_0040: - jne r2, 3, jmp_0178 - ldxdw r2, [r1+88] - jne r2, 0, jmp_0168 - ldxb r2, [r1+10344] - jne r2, 255, jmp_0188 - ldxdw r2, [r1+10424] - jne r2, 0, jmp_0198 - ldxb r2, [r1+20680] - jne r2, 255, jmp_01a8 - ldxdw r2, [r1+20760] - jne r2, 14, jmp_01b8 - ldxdw r2, [r1+31032] + jne r3, 3, jmp_0178 + ldxdw r3, [r1+88] + jne r3, 0, jmp_0168 + ldxb r3, [r1+10344] + jne r3, 255, jmp_0188 + ldxdw r3, [r1+10424] + jne r3, 0, jmp_0198 + ldxb r3, [r1+20680] + jne r3, 255, jmp_01a8 + ldxdw r3, [r1+20760] + jne r3, 14, jmp_01b8 + ldxdw r2, [r2-8] jne r2, 0, jmp_01c8 mov64 r3, r1 add64 r3, 31040 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 69c793cb..f4d8dc69 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -50,7 +50,10 @@ .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. -.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. +.equ IB_TREE_ADDRESS_OFF_0, 10352 # Tree address field (chunk index 0). +.equ IB_TREE_ADDRESS_OFF_1, 10360 # Tree address field (chunk index 1). +.equ IB_TREE_ADDRESS_OFF_2, 10368 # Tree address field (chunk index 2). +.equ IB_TREE_ADDRESS_OFF_3, 10376 # Tree address field (chunk index 3). .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 6061700a..6b8957ba 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -14,17 +14,15 @@ # Compare computed PDA against passed account. # -------------------------------------------- - mov64 r9, r1 # Get input buffer pointer. - add64 r9, IB_TREE_ADDRESS_OFF # Point at tree address. - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_0] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_0] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_1] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_1] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_2] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_2] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_3] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_3] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] jne r8, r7, e_pda_mismatch \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index a23b3c8c..654b807d 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -22,7 +22,7 @@ &pda, #[allow(clippy::transmute_ptr_to_ref)] transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), ), ) { return error::PDA_MISMATCH.into(); diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..2f3f25be --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1528 | 1530 | +2 | +0.1% | +| PDA mismatch chunk 2 | 1531 | 1533 | +2 | +0.1% | +| PDA mismatch chunk 3 | 1534 | 1536 | +2 | +0.1% | +| PDA mismatch chunk 4 | 1537 | 1539 | +2 | +0.1% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1528 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index cea13f37..2d4c961e 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,7 +4,9 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; +use macros::{ + asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame, +}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; pubkey_chunk_group!(); @@ -34,7 +36,7 @@ extend_constant_group!(input_buffer { /// Tree non-duplicate marker field. offset!(TREE_NON_DUP_MARKER, InputBufferHeader.tree_header.borrow_state), /// Tree address field. - offset!(TREE_ADDRESS, InputBufferHeader.tree_header.address), + pubkey_offset!(TREE_ADDRESS, InputBufferHeader.tree_header.address), /// Tree data length field. offset!(TREE_DATA_LEN, InputBufferHeader.tree_header.data_len), /// Instruction data length field for empty tree account. diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 7ceff4fa..460cf87a 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -206,6 +206,14 @@ enum ConstantKind { array_index: Option, aligned: bool, }, + /// Pubkey chunk offset (i16 validated). + /// Base offset + chunk_index * 8 for 8-byte register loads. + /// Name gets `_OFF_{chunk_index}` suffix appended. + PubkeyChunkOffset { + struct_name: Ident, + field_path: Vec, + chunk_index: usize, + }, } /// Array index info for stack frame offset computation. @@ -269,6 +277,45 @@ impl Parse for ConstantGroup { let ident: Ident = content.parse()?; + // pubkey_offset!(NAME, Struct.field) expands to 4 chunk constants. + if ident == "pubkey_offset" { + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let _ = content.parse::(); + + let base_doc = const_doc.trim_end_matches('.'); + for chunk in 0..4usize { + let chunk_name = + Ident::new(&format!("{}_OFF_{}", base_name, chunk), base_name.span()); + let chunk_doc = format!("{} (chunk index {}).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&chunk_doc) { + return Err(content.error(e)); + } + constants.push(ConstantDef { + doc: chunk_doc, + name: chunk_name, + kind: ConstantKind::PubkeyChunkOffset { + struct_name: struct_name.clone(), + field_path: field_path.clone(), + chunk_index: chunk, + }, + }); + } + continue; + } + // Support `offset!(NAME, Struct.field)`, `NAME: type = value`, // and `NAME = expr as Type` forms. let (const_name, kind) = if ident == "offset" { @@ -506,6 +553,20 @@ pub fn constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } + ConstantKind::PubkeyChunkOffset { + struct_name, + field_path, + chunk_index, + } => { + const_value_strs.push(None); + const_defs.push(gen_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path, + *chunk_index, + )); + } } } @@ -638,6 +699,14 @@ enum AsmConstantKind { array_index: Option, aligned: bool, }, + /// Pubkey chunk offset (i16 validated). + /// Base offset + chunk_index * 8 for 8-byte register loads. + /// Name gets `_OFF_{chunk_index}` suffix appended. + PubkeyChunkOffset { + struct_name: Ident, + field_path: Vec, + chunk_index: usize, + }, } /// Input for asm_constant_group! macro. @@ -803,11 +872,53 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> return Err(content.error(e)); } - // Check for offset!(NAME, Struct.field) syntax. + // Check for identifier. let lookahead = content.lookahead1(); - let (const_name, kind) = if lookahead.peek(Ident) { - let ident: Ident = content.parse()?; - if ident == "offset" { + if !lookahead.peek(Ident) { + return Err(lookahead.error()); + } + let ident: Ident = content.parse()?; + + // pubkey_offset!(NAME, Struct.field) expands to 4 chunk constants. + if ident == "pubkey_offset" { + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let _ = content.parse::(); + + let base_doc = const_doc.trim_end_matches('.'); + for chunk in 0..4usize { + let chunk_name = + Ident::new(&format!("{}_OFF_{}", base_name, chunk), base_name.span()); + let chunk_doc = format!("{} (chunk index {}).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&chunk_doc) { + return Err(content.error(e)); + } + constants.push(AsmConstantDef { + doc: chunk_doc, + name: chunk_name, + kind: AsmConstantKind::PubkeyChunkOffset { + struct_name: struct_name.clone(), + field_path: field_path.clone(), + chunk_index: chunk, + }, + }); + } + continue; + } + + let (const_name, kind) = if ident == "offset" { // Parse offset!(NAME, Struct.field.nested.path) content.parse::()?; let inner; @@ -866,10 +977,7 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> let expr: syn::Expr = content.parse()?; (ident, AsmConstantKind::Expr(expr)) } - } - } else { - return Err(lookahead.error()); - }; + }; // Optional trailing comma. let _ = content.parse::(); @@ -991,6 +1099,31 @@ fn gen_stack_frame_offset_code( (const_def, None) } +/// Generate code for a `pubkey_offset!` constant (single chunk). +/// +/// Computes `offset_of!(Struct, field) + chunk_index * 8` as an i16 constant. +fn gen_pubkey_chunk_offset_code( + name: &Ident, + doc: &str, + struct_name: &Ident, + field_path: &[Ident], + chunk_index: usize, +) -> proc_macro2::TokenStream { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + let chunk_byte_offset = (chunk_index * BPF_ALIGN as usize) as i64; + + quote! { + #[doc = #doc] + pub const #name: i16 = (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64 + #chunk_byte_offset) as i16; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64 + #chunk_byte_offset) >= (i16::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64 + #chunk_byte_offset) <= (i16::MAX as i64), + "Offset must fit in i16 range" + ); + } +} + /// Macro for defining ASM-only constant groups. /// /// Constants don't need types - values are `i64`, offsets are `i16`. @@ -1101,6 +1234,20 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } + AsmConstantKind::PubkeyChunkOffset { + struct_name, + field_path, + chunk_index, + } => { + const_value_strs.push(None); + const_defs.push(gen_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path, + *chunk_index, + )); + } } } @@ -1300,6 +1447,20 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } + AsmConstantKind::PubkeyChunkOffset { + struct_name, + field_path, + chunk_index, + } => { + const_value_strs.push(None); + const_defs.push(gen_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path, + *chunk_index, + )); + } } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index ceb058e6..1e1e77fc 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -120,7 +120,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - &pda, #[allow(clippy::transmute_ptr_to_ref)] transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize), + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), ), ) { return error::PDA_MISMATCH.into(); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 1c20b58c..5fb41ec8 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -51,7 +51,10 @@ .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. .equ IB_TREE_NON_DUP_MARKER_OFF, 10344 # Tree non-duplicate marker field. -.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. +.equ IB_TREE_ADDRESS_OFF_0, 10352 # Tree address field (chunk index 0). +.equ IB_TREE_ADDRESS_OFF_1, 10360 # Tree address field (chunk index 1). +.equ IB_TREE_ADDRESS_OFF_2, 10368 # Tree address field (chunk index 2). +.equ IB_TREE_ADDRESS_OFF_3, 10376 # Tree address field (chunk index 3). .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. # Instruction data length field for empty tree account. .equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 @@ -148,18 +151,16 @@ initialize: # Compare computed PDA against passed account. # -------------------------------------------- - mov64 r9, r1 # Get input buffer pointer. - add64 r9, IB_TREE_ADDRESS_OFF # Point at tree address. - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_0] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_0] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_1] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_1] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_2] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_2] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] jne r8, r7, e_pda_mismatch - ldxdw r8, [r9 + PUBKEY_CHUNK_OFF_3] + ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_3] ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] jne r8, r7, e_pda_mismatch # ANCHOR_END: initialize-pda-checks From 77edbf4eb04dbaa94b78e4dbc199101cfe6dd7a7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:23:10 -0800 Subject: [PATCH 105/263] Cold-path PDA mismatch --- examples/tree/artifacts/dumps/rs.txt | 26 +++++------ examples/tree/artifacts/rs-disassembly.s | 14 +++--- .../snippets/rs/initialize-pda-checks.txt | 17 +++---- .../tests/entrypoint_branching/result.txt | 24 ---------- .../tests/initialize_input_checks/result.txt | 45 ------------------- .../tests/initialize_input_checks/test.txt | 4 -- .../tests/initialize_pda_checks/result.txt | 31 ------------- .../tests/initialize_pda_checks/test.txt | 4 -- examples/tree/src/program.rs | 17 +++---- 9 files changed, 39 insertions(+), 143 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 57de8baf..82d3f455 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -134,20 +134,20 @@ Disassembly of section .text d8 bf 16 00 00 00 00 00 00 mov64 r6, r1 e0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 e8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - f8 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 100 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 108 5d 21 e5 ff 00 00 00 00 jne r1, r2, -0x1b - 110 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 118 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 120 5d 21 e2 ff 00 00 00 00 jne r1, r2, -0x1e - 128 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 130 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 138 5d 21 df ff 00 00 00 00 jne r1, r2, -0x21 - 140 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + f0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + f8 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 100 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa + 108 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 110 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 118 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 + 120 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 128 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 130 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 + 138 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 140 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 148 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 150 5d 21 dc ff 00 00 00 00 jne r1, r2, -0x24 - 158 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 150 1d 21 dc ff 00 00 00 00 jeq r1, r2, -0x24 + 158 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 160 05 00 da ff 00 00 00 00 ja -0x26 168 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 170 05 00 d8 ff 00 00 00 00 ja -0x28 diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 08d96f35..7afafb97 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -35,20 +35,22 @@ jmp_0040: mov64 r6, r1 mov64 r2, 0 call sol_try_find_program_address - mov64 r0, 8 ldxdw r1, [r10+24] ldxdw r2, [r6+10352] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0158 ldxdw r1, [r10+32] ldxdw r2, [r6+10360] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0158 ldxdw r1, [r10+40] ldxdw r2, [r6+10368] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0158 ldxdw r1, [r10+48] - ldxdw r2, [r6+10376] - jne r1, r2, jmp_0038 mov64 r0, 0 + ldxdw r2, [r6+10376] + jeq r1, r2, jmp_0038 + +jmp_0158: + mov64 r0, 8 ja jmp_0038 jmp_0168: diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 654b807d..0deb076d 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -18,12 +18,13 @@ let (pda, _bump) = (Address::default(), 0u8); // Compare result with passed PDA. - if !address_eq( - &pda, - #[allow(clippy::transmute_ptr_to_ref)] - transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), + if_err!( + !address_eq( + &pda, + #[allow(clippy::transmute_ptr_to_ref)] + transmute::<*const u8, &Address>( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), + ), ), - ) { - return error::PDA_MISMATCH.into(); - } \ No newline at end of file + error::PDA_MISMATCH + ); \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index b36b9ca3..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,24 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Four accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 1bcf1d9b..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,45 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Non-empty instruction data | 17 | 19 | +2 | +11.8% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index d179220a..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 2f3f25be..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1528 | 1530 | +2 | +0.1% | -| PDA mismatch chunk 2 | 1531 | 1533 | +2 | +0.1% | -| PDA mismatch chunk 3 | 1534 | 1536 | +2 | +0.1% | -| PDA mismatch chunk 4 | 1537 | 1539 | +2 | +0.1% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1528 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1530 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1533 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1536 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1539 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 5bd90196..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES); -} \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1e1e77fc..ffdf7d3f 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -116,15 +116,16 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let (pda, _bump) = (Address::default(), 0u8); // Compare result with passed PDA. - if !address_eq( - &pda, - #[allow(clippy::transmute_ptr_to_ref)] - transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), + if_err!( + !address_eq( + &pda, + #[allow(clippy::transmute_ptr_to_ref)] + transmute::<*const u8, &Address>( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), + ), ), - ) { - return error::PDA_MISMATCH.into(); - } + error::PDA_MISMATCH + ); // ANCHOR_END: initialize-pda-checks SUCCESS From 0569a7fc9cfef1f8e16c15a792da9483f5383b7d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:23:27 -0800 Subject: [PATCH 106/263] Check in tests --- .../tests/entrypoint_branching/result.txt | 24 ++++++++++ .../tests/initialize_input_checks/result.txt | 45 +++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 ++ .../tests/initialize_pda_checks/result.txt | 31 +++++++++++++ .../tests/initialize_pda_checks/test.txt | 4 ++ 5 files changed, 108 insertions(+) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..b36b9ca3 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,24 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Four accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..1bcf1d9b --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,45 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Non-empty instruction data | 17 | 19 | +2 | +11.8% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..d179220a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..df2416b4 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1528 | 1531 | +3 | +0.2% | +| PDA mismatch chunk 2 | 1531 | 1534 | +3 | +0.2% | +| PDA mismatch chunk 3 | 1534 | 1537 | +3 | +0.2% | +| PDA mismatch chunk 4 | 1537 | 1541 | +4 | +0.3% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1528 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..5bd90196 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES); +} \ No newline at end of file From d95c33cafe3b48b81311f6805ce04222d45ad36d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:17:08 -0800 Subject: [PATCH 107/263] Begin refactors for 4 accounts --- examples/tree/artifacts/dumps/asm.txt | 4 +- examples/tree/artifacts/dumps/rs.txt | 109 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 51 ++++---- .../tree/artifacts/snippets/asm/constants.txt | 11 +- .../artifacts/snippets/rs/initialize-rent.txt | 0 .../tests/entrypoint_branching/result.txt | 24 ---- .../tests/initialize_input_checks/result.txt | 45 -------- .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 31 ----- .../tests/initialize_pda_checks/test.txt | 4 - examples/tree/interface/src/asm.rs | 20 ++-- examples/tree/interface/src/common.rs | 26 ++++- examples/tree/src/program.rs | 4 + examples/tree/src/tree/tree.s | 11 +- 14 files changed, 130 insertions(+), 214 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/initialize-rent.txt delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index bd4095a7..e2294062 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -83,7 +83,7 @@ Disassembly of section .text 00000000000000e8 29 79 19 00 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x0) 30 15 09 03 00 02 00 00 00 if r9 == 0x2 goto +0x3 - 31 15 09 07 00 03 00 00 00 if r9 == 0x3 goto +0x7 + 31 15 09 07 00 04 00 00 00 if r9 == 0x4 goto +0x7 32 b7 00 00 00 01 00 00 00 r0 = 0x1 33 95 00 00 00 00 00 00 00 exit 34 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) @@ -105,7 +105,7 @@ Disassembly of section .text 50 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 51 b7 02 00 00 00 00 00 00 r2 = 0x0 52 bf 13 00 00 00 00 00 00 r3 = r1 - 53 07 03 00 00 40 79 00 00 r3 += 0x7940 + 53 07 03 00 00 78 28 00 00 r3 += 0x2878 54 bf a4 00 00 00 00 00 00 r4 = r10 55 07 04 00 00 98 ff ff ff r4 += -0x68 56 bf a5 00 00 00 00 00 00 r5 = r10 diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 82d3f455..98188189 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3048 (bytes into file) + Start of section headers 3056 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xbe8 +There are 8 section headers, starting at offset 0xbf0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0001d8 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 0002f8 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000300 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000300 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000300 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000678 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006b6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0001e0 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000300 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000308 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000308 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000308 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000680 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006be 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001d8 0x0001d8 E 0x8 - LOAD 0x0002f8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000300 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000300 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001e0 0x0001e0 E 0x8 + LOAD 0x000300 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000308 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000308 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 472 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 480 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,54 +112,55 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 26 00 03 00 00 00 jne r3, 0x3, +0x26 + 40 55 03 27 00 04 00 00 00 jne r3, 0x4, +0x27 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 22 00 00 00 00 00 jne r3, 0x0, +0x22 + 50 55 03 23 00 00 00 00 00 jne r3, 0x0, +0x23 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 24 00 ff 00 00 00 jne r3, 0xff, +0x24 + 60 55 03 25 00 ff 00 00 00 jne r3, 0xff, +0x25 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 24 00 00 00 00 00 jne r3, 0x0, +0x24 + 70 55 03 25 00 00 00 00 00 jne r3, 0x0, +0x25 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 24 00 ff 00 00 00 jne r3, 0xff, +0x24 + 80 55 03 25 00 ff 00 00 00 jne r3, 0xff, +0x25 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 24 00 0e 00 00 00 jne r3, 0xe, +0x24 + 90 55 03 25 00 0e 00 00 00 jne r3, 0xe, +0x25 98 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - a0 55 02 24 00 00 00 00 00 jne r2, 0x0, +0x24 - a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - b0 07 03 00 00 40 79 00 00 add64 r3, 0x7940 + a0 55 02 25 00 00 00 00 00 jne r2, 0x0, +0x25 + a8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + b0 07 06 00 00 78 28 00 00 add64 r6, 0x2878 b8 bf a4 00 00 00 00 00 00 mov64 r4, r10 c0 07 04 00 00 18 00 00 00 add64 r4, 0x18 c8 bf a5 00 00 00 00 00 00 mov64 r5, r10 d0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f - d8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + d8 bf 17 00 00 00 00 00 00 mov64 r7, r1 e0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - e8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - f0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - f8 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 100 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa - 108 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 110 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 118 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 - 120 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 128 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 130 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 - 138 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] - 140 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 148 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 150 1d 21 dc ff 00 00 00 00 jeq r1, r2, -0x24 - 158 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 160 05 00 da ff 00 00 00 00 ja -0x26 - 168 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 170 05 00 d8 ff 00 00 00 00 ja -0x28 - 178 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 180 05 00 d6 ff 00 00 00 00 ja -0x2a - 188 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 190 05 00 d4 ff 00 00 00 00 ja -0x2c - 198 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e - 1a8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 - 1b8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1c0 05 00 ce ff 00 00 00 00 ja -0x32 - 1c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1d0 05 00 cc ff 00 00 00 00 ja -0x34 \ No newline at end of file + e8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + f0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + f8 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 100 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 108 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa + 110 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 118 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] + 120 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 + 128 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 130 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 138 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 + 140 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 148 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 150 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 158 1d 21 db ff 00 00 00 00 jeq r1, r2, -0x25 + 160 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 168 05 00 d9 ff 00 00 00 00 ja -0x27 + 170 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 178 05 00 d7 ff 00 00 00 00 ja -0x29 + 180 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 188 05 00 d5 ff 00 00 00 00 ja -0x2b + 190 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 198 05 00 d3 ff 00 00 00 00 ja -0x2d + 1a0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1a8 05 00 d1 ff 00 00 00 00 ja -0x2f + 1b0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1b8 05 00 cf ff 00 00 00 00 ja -0x31 + 1c0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 1c8 05 00 cd ff 00 00 00 00 ja -0x33 + 1d0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1d8 05 00 cb ff 00 00 00 00 ja -0x35 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 7afafb97..30027ef3 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,70 +13,71 @@ jmp_0038: exit jmp_0040: - jne r3, 3, jmp_0178 + jne r3, 4, jmp_0180 ldxdw r3, [r1+88] - jne r3, 0, jmp_0168 + jne r3, 0, jmp_0170 ldxb r3, [r1+10344] - jne r3, 255, jmp_0188 + jne r3, 255, jmp_0190 ldxdw r3, [r1+10424] - jne r3, 0, jmp_0198 + jne r3, 0, jmp_01a0 ldxb r3, [r1+20680] - jne r3, 255, jmp_01a8 + jne r3, 255, jmp_01b0 ldxdw r3, [r1+20760] - jne r3, 14, jmp_01b8 + jne r3, 14, jmp_01c0 ldxdw r2, [r2-8] - jne r2, 0, jmp_01c8 - mov64 r3, r1 - add64 r3, 31040 + jne r2, 0, jmp_01d0 + mov64 r6, r1 + add64 r6, 10360 mov64 r4, r10 add64 r4, 24 mov64 r5, r10 add64 r5, 63 - mov64 r6, r1 + mov64 r7, r1 mov64 r2, 0 + mov64 r3, r6 call sol_try_find_program_address ldxdw r1, [r10+24] - ldxdw r2, [r6+10352] - jne r1, r2, jmp_0158 + ldxdw r2, [r7+10352] + jne r1, r2, jmp_0160 ldxdw r1, [r10+32] - ldxdw r2, [r6+10360] - jne r1, r2, jmp_0158 + ldxdw r2, [r6+0] + jne r1, r2, jmp_0160 ldxdw r1, [r10+40] - ldxdw r2, [r6+10368] - jne r1, r2, jmp_0158 + ldxdw r2, [r7+10368] + jne r1, r2, jmp_0160 ldxdw r1, [r10+48] mov64 r0, 0 - ldxdw r2, [r6+10376] + ldxdw r2, [r7+10376] jeq r1, r2, jmp_0038 -jmp_0158: +jmp_0160: mov64 r0, 8 ja jmp_0038 -jmp_0168: +jmp_0170: mov64 r0, 2 ja jmp_0038 -jmp_0178: +jmp_0180: mov64 r0, 1 ja jmp_0038 -jmp_0188: +jmp_0190: mov64 r0, 5 ja jmp_0038 -jmp_0198: +jmp_01a0: mov64 r0, 3 ja jmp_0038 -jmp_01a8: +jmp_01b0: mov64 r0, 6 ja jmp_0038 -jmp_01b8: +jmp_01c0: mov64 r0, 4 ja jmp_0038 -jmp_01c8: +jmp_01d0: mov64 r0, 7 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index f4d8dc69..db1c1bd5 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -43,7 +43,7 @@ # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. -.equ IB_N_ACCOUNTS_INIT, 3 +.equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_USER_ADDRESS_OFF, 16 # User address field. @@ -55,14 +55,15 @@ .equ IB_TREE_ADDRESS_OFF_2, 10368 # Tree address field (chunk index 2). .equ IB_TREE_ADDRESS_OFF_3, 10376 # Tree address field (chunk index 3). .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. -# Instruction data length field for empty tree account. -.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 -# Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF, 31040 # System Program non-duplicate marker field. .equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 +.equ IB_FOOTER_OFF, 31032 # Footer. +# Instruction data length field for empty tree account, inside footer. +.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 10352 +# Program ID field for initialize instruction, inside footer. +.equ IB_INIT_PROGRAM_ID_OFF, 10360 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/rs/initialize-rent.txt b/examples/tree/artifacts/snippets/rs/initialize-rent.txt new file mode 100644 index 00000000..e69de29b diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index b36b9ca3..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,24 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Four accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 1bcf1d9b..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,45 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Non-empty instruction data | 17 | 19 | +2 | +11.8% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index d179220a..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index df2416b4..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1528 | 1531 | +3 | +0.2% | -| PDA mismatch chunk 2 | 1531 | 1534 | +3 | +0.2% | -| PDA mismatch chunk 3 | 1534 | 1537 | +3 | +0.2% | -| PDA mismatch chunk 4 | 1537 | 1541 | +4 | +0.3% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1528 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1531 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1534 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1537 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 5bd90196..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES); -} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 2d4c961e..1841c453 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,10 +3,10 @@ extern crate alloc; use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; -use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; -use macros::{ - asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame, +use crate::common::{ + cpi, CreateAccountInstructionData, InitInputBuffer, InitInputBufferFooter, InputBufferHeader, }; +use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; pubkey_chunk_group!(); @@ -39,14 +39,16 @@ extend_constant_group!(input_buffer { pubkey_offset!(TREE_ADDRESS, InputBufferHeader.tree_header.address), /// Tree data length field. offset!(TREE_DATA_LEN, InputBufferHeader.tree_header.data_len), - /// Instruction data length field for empty tree account. - offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBuffer.instruction_data_len), - /// Program ID field for initialize instruction. - offset!(INIT_PROGRAM_ID, InitInputBuffer.program_id), /// System Program non-duplicate marker field. - offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.system_program.header.borrow_state), + offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.header.system_program.header.borrow_state), /// System Program data length field. - offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.system_program.header.data_len), + offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.header.system_program.header.data_len), + /// Footer. + offset!(FOOTER, InitInputBuffer.footer), + /// Instruction data length field for empty tree account, inside footer. + offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBufferFooter.instruction_data_len), + /// Program ID field for initialize instruction, inside footer. + offset!(INIT_PROGRAM_ID, InitInputBufferFooter.program_id), }); #[stack_frame] diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0f7f349f..8dd54f07 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,6 +1,8 @@ +use core::mem::size_of; use macros::{constant_group, error_codes}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, + sysvars::rent::Rent, Address, }; @@ -33,11 +35,11 @@ constant_group! { /// Tree runtime account header. offset!(TREE_ACCOUNT, InputBufferHeader.tree_header), /// System Program runtime account header. - offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.system_program), + offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.header.system_program), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. - N_ACCOUNTS_INIT: u64 = 3, + N_ACCOUNTS_INIT: u64 = 4, /// Expected data length of system program account. SYSTEM_PROGRAM_DATA_LEN: usize = b"system_program".len(), } @@ -86,12 +88,23 @@ pub struct InputBufferHeader { } #[repr(C, packed)] -/// Input buffer for tree initialization instruction. +/// Input buffer for tree initialization instruction. Broken up to fit relative offsets in i16. pub struct InitInputBuffer { - pub n_accounts: u64, - pub user: EmptyRuntimeAccount, - pub tree: EmptyRuntimeAccount, + pub header: InitInputBufferHeader, + pub footer: InitInputBufferFooter, +} + +#[repr(C, packed)] +pub struct InitInputBufferHeader { + pub _n_accounts: u64, + pub _user: EmptyRuntimeAccount, + pub _tree: EmptyRuntimeAccount, pub system_program: SystemProgramRuntimeAccount, +} + +#[repr(C, packed)] +pub struct InitInputBufferFooter { + pub _rent: RentRuntimeAccount, /// No actual instruction data follows. pub instruction_data_len: u64, pub program_id: Address, @@ -107,6 +120,7 @@ pub struct RuntimeAccount { type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(data::DATA_LEN_ZERO as usize) }>; type SystemProgramRuntimeAccount = RuntimeAccount<{ runtime_data_size(input_buffer::SYSTEM_PROGRAM_DATA_LEN) }>; +type RentRuntimeAccount = RuntimeAccount<{ runtime_data_size(size_of::()) }>; /// Compute the data buffer size for a runtime account with the given data length. const fn runtime_data_size(data_len: usize) -> usize { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index ffdf7d3f..e8594b69 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -128,5 +128,9 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // ANCHOR_END: initialize-pda-checks + // ANCHOR: initialize-rent + + // ANCHOR_END: initialize-rent + SUCCESS } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 5fb41ec8..02ed0d7f 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -44,7 +44,7 @@ # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. -.equ IB_N_ACCOUNTS_INIT, 3 +.equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_USER_ADDRESS_OFF, 16 # User address field. @@ -56,14 +56,15 @@ .equ IB_TREE_ADDRESS_OFF_2, 10368 # Tree address field (chunk index 2). .equ IB_TREE_ADDRESS_OFF_3, 10376 # Tree address field (chunk index 3). .equ IB_TREE_DATA_LEN_OFF, 10424 # Tree data length field. -# Instruction data length field for empty tree account. -.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 31032 -# Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF, 31040 # System Program non-duplicate marker field. .equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 +.equ IB_FOOTER_OFF, 31032 # Footer. +# Instruction data length field for empty tree account, inside footer. +.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 10352 +# Program ID field for initialize instruction, inside footer. +.equ IB_INIT_PROGRAM_ID_OFF, 10360 # Init stack frame layout. # ------------------------ From 4e25e3b83a1054853e2942366ca875af712a6f17 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:46:27 -0800 Subject: [PATCH 108/263] Begin passing rent sysvar --- examples/tree/artifacts/dumps/asm.txt | 124 +++++++++-------- examples/tree/artifacts/dumps/rs.txt | 129 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 65 +++++---- .../tree/artifacts/snippets/asm/constants.txt | 14 +- .../snippets/asm/initialize-input-checks.txt | 18 ++- .../snippets/asm/initialize-pda-checks.txt | 2 +- .../snippets/rs/initialize-input-checks.txt | 11 ++ .../snippets/rs/initialize-pda-checks.txt | 2 +- examples/tree/interface/src/asm.rs | 6 +- examples/tree/interface/src/common.rs | 10 +- examples/tree/src/program.rs | 13 +- examples/tree/src/tests.rs | 1 + examples/tree/src/tests/entrypoint.rs | 17 ++- examples/tree/src/tests/init.rs | 8 ++ examples/tree/src/tree/tree.s | 42 ++++-- 15 files changed, 285 insertions(+), 177 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index e2294062..c87b4dda 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1048 (bytes into file) + Start of section headers 1128 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x418 +There are 7 section headers, starting at offset 0x468 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0001d8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000002c0 0002c0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000360 000360 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003a8 0003a8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000003d8 0003d8 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0003e8 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000228 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000310 000310 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000003b0 0003b0 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003f8 0003f8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000428 000428 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000438 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0001d8 0x0001d8 R E 0x1000 - LOAD 0x000360 0x0000000000000360 0x0000000000000360 0x000088 0x000088 R 0x1000 - DYNAMIC 0x0002c0 0x00000000000002c0 0x00000000000002c0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000228 0x000228 R E 0x1000 + LOAD 0x0003b0 0x00000000000003b0 0x00000000000003b0 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000310 0x0000000000000310 0x0000000000000310 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x2c0 contains 10 entries +Dynamic section at offset 0x310 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x3d8 + 0x0000000000000011 (REL) 0x428 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x360 + 0x0000000000000006 (SYMTAB) 0x3b0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3a8 + 0x0000000000000005 (STRTAB) 0x3f8 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x3d8 contains 1 entries +Relocation section '.rel.dyn' at offset 0x428 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -00000000000001d0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000200 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -92,51 +92,61 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 2d 00 00 00 00 00 if r9 != 0x0 goto +0x2d + 40 55 09 37 00 00 00 00 00 if r9 != 0x0 goto +0x37 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 29 00 ff 00 00 00 if r9 != 0xff goto +0x29 + 42 55 09 33 00 ff 00 00 00 if r9 != 0xff goto +0x33 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 25 00 00 00 00 00 if r9 != 0x0 goto +0x25 + 44 55 09 2f 00 00 00 00 00 if r9 != 0x0 goto +0x2f 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 + 46 55 09 2b 00 ff 00 00 00 if r9 != 0xff goto +0x2b 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 1d 00 0e 00 00 00 if r9 != 0xe goto +0x1d - 49 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 50 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 - 51 b7 02 00 00 00 00 00 00 r2 = 0x0 - 52 bf 13 00 00 00 00 00 00 r3 = r1 - 53 07 03 00 00 78 28 00 00 r3 += 0x2878 - 54 bf a4 00 00 00 00 00 00 r4 = r10 - 55 07 04 00 00 98 ff ff ff r4 += -0x68 - 56 bf a5 00 00 00 00 00 00 r5 = r10 - 57 07 05 00 00 98 fe ff ff r5 += -0x168 - 58 85 10 00 00 ff ff ff ff call -0x1 - 59 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) - 60 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) - 61 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe - 62 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) - 63 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) - 64 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb - 65 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) - 66 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) - 67 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 - 68 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) - 69 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) - 70 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 - 71 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 72 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 73 95 00 00 00 00 00 00 00 exit - 74 b7 00 00 00 07 00 00 00 r0 = 0x7 - 75 95 00 00 00 00 00 00 00 exit - 76 b7 00 00 00 08 00 00 00 r0 = 0x8 - 77 95 00 00 00 00 00 00 00 exit - 78 b7 00 00 00 04 00 00 00 r0 = 0x4 + 48 55 09 27 00 0e 00 00 00 if r9 != 0xe goto +0x27 + 49 bf 16 00 00 00 00 00 00 r6 = r1 + 50 07 06 00 00 38 79 00 00 r6 += 0x7938 + 51 71 69 00 00 00 00 00 00 r9 = *(u8 *)(r6 + 0x0) + 52 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 + 53 79 69 50 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x50) + 54 55 09 1d 00 10 00 00 00 if r9 != 0x10 goto +0x1d + 55 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 56 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 + 57 b7 02 00 00 00 00 00 00 r2 = 0x0 + 58 bf 63 00 00 00 00 00 00 r3 = r6 + 59 07 03 00 00 78 28 00 00 r3 += 0x2878 + 60 bf a4 00 00 00 00 00 00 r4 = r10 + 61 07 04 00 00 98 ff ff ff r4 += -0x68 + 62 bf a5 00 00 00 00 00 00 r5 = r10 + 63 07 05 00 00 98 fe ff ff r5 += -0x168 + 64 85 10 00 00 ff ff ff ff call -0x1 + 65 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) + 66 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) + 67 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe + 68 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) + 69 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) + 70 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb + 71 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) + 72 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) + 73 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 + 74 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) + 75 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) + 76 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 + 77 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 78 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 79 95 00 00 00 00 00 00 00 exit - 80 b7 00 00 00 06 00 00 00 r0 = 0x6 + 80 b7 00 00 00 09 00 00 00 r0 = 0x9 81 95 00 00 00 00 00 00 00 exit - 82 b7 00 00 00 03 00 00 00 r0 = 0x3 + 82 b7 00 00 00 0a 00 00 00 r0 = 0xa 83 95 00 00 00 00 00 00 00 exit - 84 b7 00 00 00 05 00 00 00 r0 = 0x5 + 84 b7 00 00 00 08 00 00 00 r0 = 0x8 85 95 00 00 00 00 00 00 00 exit - 86 b7 00 00 00 02 00 00 00 r0 = 0x2 - 87 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 86 b7 00 00 00 07 00 00 00 r0 = 0x7 + 87 95 00 00 00 00 00 00 00 exit + 88 b7 00 00 00 04 00 00 00 r0 = 0x4 + 89 95 00 00 00 00 00 00 00 exit + 90 b7 00 00 00 06 00 00 00 r0 = 0x6 + 91 95 00 00 00 00 00 00 00 exit + 92 b7 00 00 00 03 00 00 00 r0 = 0x3 + 93 95 00 00 00 00 00 00 00 exit + 94 b7 00 00 00 05 00 00 00 r0 = 0x5 + 95 95 00 00 00 00 00 00 00 exit + 96 b7 00 00 00 02 00 00 00 r0 = 0x2 + 97 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 98188189..4d113e42 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3056 (bytes into file) + Start of section headers 3112 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xbf0 +There are 8 section headers, starting at offset 0xc28 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 0001e0 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000300 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000308 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000308 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000308 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000680 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006be 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000218 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000338 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000340 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000340 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000340 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0006b8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0006f6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0001e0 0x0001e0 E 0x8 - LOAD 0x000300 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000308 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000308 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000218 0x000218 E 0x8 + LOAD 0x000338 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000340 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000340 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 480 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 536 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,55 +112,62 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 27 00 04 00 00 00 jne r3, 0x4, +0x27 + 40 55 03 2a 00 04 00 00 00 jne r3, 0x4, +0x2a 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 23 00 00 00 00 00 jne r3, 0x0, +0x23 + 50 55 03 26 00 00 00 00 00 jne r3, 0x0, +0x26 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 25 00 ff 00 00 00 jne r3, 0xff, +0x25 + 60 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 25 00 00 00 00 00 jne r3, 0x0, +0x25 + 70 55 03 28 00 00 00 00 00 jne r3, 0x0, +0x28 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 25 00 ff 00 00 00 jne r3, 0xff, +0x25 + 80 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 25 00 0e 00 00 00 jne r3, 0xe, +0x25 - 98 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - a0 55 02 25 00 00 00 00 00 jne r2, 0x0, +0x25 - a8 bf 16 00 00 00 00 00 00 mov64 r6, r1 - b0 07 06 00 00 78 28 00 00 add64 r6, 0x2878 - b8 bf a4 00 00 00 00 00 00 mov64 r4, r10 - c0 07 04 00 00 18 00 00 00 add64 r4, 0x18 - c8 bf a5 00 00 00 00 00 00 mov64 r5, r10 - d0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f - d8 bf 17 00 00 00 00 00 00 mov64 r7, r1 - e0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - e8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - f0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - f8 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 100 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 108 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa - 110 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 118 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] - 120 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 - 128 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 130 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 138 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 - 140 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] - 148 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 150 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 158 1d 21 db ff 00 00 00 00 jeq r1, r2, -0x25 - 160 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 168 05 00 d9 ff 00 00 00 00 ja -0x27 - 170 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 178 05 00 d7 ff 00 00 00 00 ja -0x29 - 180 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 188 05 00 d5 ff 00 00 00 00 ja -0x2b - 190 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 198 05 00 d3 ff 00 00 00 00 ja -0x2d - 1a0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 1a8 05 00 d1 ff 00 00 00 00 ja -0x2f - 1b0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 1b8 05 00 cf ff 00 00 00 00 ja -0x31 - 1c0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1c8 05 00 cd ff 00 00 00 00 ja -0x33 - 1d0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 1d8 05 00 cb ff 00 00 00 00 ja -0x35 \ No newline at end of file + 90 55 03 28 00 0e 00 00 00 jne r3, 0xe, +0x28 + 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] + a0 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 + a8 9c 13 88 79 00 00 00 00 ldxdw r3, [r1 + 0x7988] + b0 55 03 28 00 10 00 00 00 jne r3, 0x10, +0x28 + b8 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] + c0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 + c8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + d0 07 03 00 00 b0 a1 00 00 add64 r3, 0xa1b0 + d8 bf a4 00 00 00 00 00 00 mov64 r4, r10 + e0 07 04 00 00 18 00 00 00 add64 r4, 0x18 + e8 bf a5 00 00 00 00 00 00 mov64 r5, r10 + f0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f + f8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 100 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 108 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 110 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 118 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 120 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa + 128 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 130 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 138 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 + 140 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 148 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 150 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 + 158 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 160 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 168 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] + 170 1d 21 d8 ff 00 00 00 00 jeq r1, r2, -0x28 + 178 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 180 05 00 d6 ff 00 00 00 00 ja -0x2a + 188 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 190 05 00 d4 ff 00 00 00 00 ja -0x2c + 198 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e + 1a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 + 1b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1c0 05 00 ce ff 00 00 00 00 ja -0x32 + 1c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1d0 05 00 cc ff 00 00 00 00 ja -0x34 + 1d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 1e0 05 00 ca ff 00 00 00 00 ja -0x36 + 1e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 + 1f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 200 05 00 c6 ff 00 00 00 00 ja -0x3a + 208 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 210 05 00 c4 ff 00 00 00 00 ja -0x3c \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 30027ef3..c84068dd 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,71 +13,82 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0180 + jne r3, 4, jmp_0198 ldxdw r3, [r1+88] - jne r3, 0, jmp_0170 + jne r3, 0, jmp_0188 ldxb r3, [r1+10344] - jne r3, 255, jmp_0190 + jne r3, 255, jmp_01a8 ldxdw r3, [r1+10424] - jne r3, 0, jmp_01a0 + jne r3, 0, jmp_01b8 ldxb r3, [r1+20680] - jne r3, 255, jmp_01b0 + jne r3, 255, jmp_01c8 ldxdw r3, [r1+20760] - jne r3, 14, jmp_01c0 + jne r3, 14, jmp_01d8 + ldxb r3, [r1+31032] + jne r3, 255, jmp_01e8 + ldxdw r3, [r1+31112] + jne r3, 16, jmp_01f8 ldxdw r2, [r2-8] - jne r2, 0, jmp_01d0 - mov64 r6, r1 - add64 r6, 10360 + jne r2, 0, jmp_0208 + mov64 r3, r1 + add64 r3, 41392 mov64 r4, r10 add64 r4, 24 mov64 r5, r10 add64 r5, 63 - mov64 r7, r1 + mov64 r6, r1 mov64 r2, 0 - mov64 r3, r6 call sol_try_find_program_address ldxdw r1, [r10+24] - ldxdw r2, [r7+10352] - jne r1, r2, jmp_0160 + ldxdw r2, [r6+10352] + jne r1, r2, jmp_0178 ldxdw r1, [r10+32] - ldxdw r2, [r6+0] - jne r1, r2, jmp_0160 + ldxdw r2, [r6+10360] + jne r1, r2, jmp_0178 ldxdw r1, [r10+40] - ldxdw r2, [r7+10368] - jne r1, r2, jmp_0160 + ldxdw r2, [r6+10368] + jne r1, r2, jmp_0178 ldxdw r1, [r10+48] mov64 r0, 0 - ldxdw r2, [r7+10376] + ldxdw r2, [r6+10376] jeq r1, r2, jmp_0038 -jmp_0160: - mov64 r0, 8 +jmp_0178: + mov64 r0, 10 ja jmp_0038 -jmp_0170: +jmp_0188: mov64 r0, 2 ja jmp_0038 -jmp_0180: +jmp_0198: mov64 r0, 1 ja jmp_0038 -jmp_0190: +jmp_01a8: mov64 r0, 5 ja jmp_0038 -jmp_01a0: +jmp_01b8: mov64 r0, 3 ja jmp_0038 -jmp_01b0: +jmp_01c8: mov64 r0, 6 ja jmp_0038 -jmp_01c0: +jmp_01d8: mov64 r0, 4 ja jmp_0038 -jmp_01d0: +jmp_01e8: mov64 r0, 7 ja jmp_0038 + +jmp_01f8: + mov64 r0, 8 + ja jmp_0038 + +jmp_0208: + mov64 r0, 9 + ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index db1c1bd5..6fcf3f7f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -8,10 +8,12 @@ .equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 +.equ E_RENT_DUPLICATE, 7 # The rent sysvar account is a duplicate. +.equ E_RENT_DATA_LEN, 8 # The rent sysvar account has invalid data length. # Instruction data provided during initialization instruction. -.equ E_INSTRUCTION_DATA, 7 +.equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 8 +.equ E_PDA_MISMATCH, 10 # Type sizes. # ----------- @@ -40,12 +42,14 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 +.equ IB_RENT_ACCOUNT_OFF, 0 # Rent sysvar account header, in footer. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 +.equ IB_RENT_DATA_LEN, 16 # Expected data length of rent sysvar account. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -60,8 +64,10 @@ # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 .equ IB_FOOTER_OFF, 31032 # Footer. -# Instruction data length field for empty tree account, inside footer. -.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 10352 +# Rent account non-duplicate marker field, inside footer. +.equ IB_RENT_NON_DUP_MARKER_OFF, 0 +# Rent account data length field, inside footer. +.equ IB_RENT_DATA_LEN_OFF, 80 # Program ID field for initialize instruction, inside footer. .equ IB_INIT_PROGRAM_ID_OFF, 10360 diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 138f09b1..5d77f060 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -19,13 +19,19 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + # Get input buffer footer pointer. + # -------------------------------- + mov64 r6, r1 + add64 r6, IB_FOOTER_OFF + + # Error if Rent account is duplicate or has invalid length. + # --------------------------------------------------------- + ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r9, [r6 + IB_RENT_DATA_LEN_OFF] + jne r9, IB_RENT_DATA_LEN, e_rent_data_len + # Error if instruction data provided. # ----------------------------------- - # Use the instruction data pointer in r2 from SIMD-0321, which is - # equivalent to the following static offset for static and verified - # account data lengths: - # ``` - # ldxdw r9, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] - # ``` ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 6b8957ba..0138d8d4 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -4,7 +4,7 @@ # argument is effectively ignored. # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. - mov64 r3, r1 # Get input buffer pointer. + mov64 r3, r6 # Get input buffer footer pointer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index aab1dfd2..a1e9df3b 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -20,6 +20,17 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); + // Get input buffer footer pointer. + let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); + + // Error if Rent account is duplicate or has invalid data length. + let rent_sysvar = account_at(input_buffer_footer_ptr, input_buffer::RENT_ACCOUNT_OFF); + if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); + if_err!( + rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, + error::RENT_DATA_LEN + ); + // Error if instruction data provided. let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); if_err!( diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 0deb076d..1fac19a8 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -7,7 +7,7 @@ // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + input_buffer_footer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 1841c453..5f2512a6 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -45,8 +45,10 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.header.system_program.header.data_len), /// Footer. offset!(FOOTER, InitInputBuffer.footer), - /// Instruction data length field for empty tree account, inside footer. - offset!(INIT_INSTRUCTION_DATA_LEN, InitInputBufferFooter.instruction_data_len), + /// Rent account non-duplicate marker field, inside footer. + offset!(RENT_NON_DUP_MARKER, InitInputBufferFooter.rent.header.borrow_state), + /// Rent account data length field, inside footer. + offset!(RENT_DATA_LEN, InitInputBufferFooter.rent.header.data_len), /// Program ID field for initialize instruction, inside footer. offset!(INIT_PROGRAM_ID, InitInputBufferFooter.program_id), }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 8dd54f07..ad0f10b2 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -19,6 +19,10 @@ error_codes! { TREE_DUPLICATE, /// The System Program account is a duplicate. SYSTEM_PROGRAM_DUPLICATE, + /// The rent sysvar account is a duplicate. + RENT_DUPLICATE, + /// The rent sysvar account has invalid data length. + RENT_DATA_LEN, /// Instruction data provided during initialization instruction. INSTRUCTION_DATA, /// The passed PDA does not match the expected address. @@ -36,12 +40,16 @@ constant_group! { offset!(TREE_ACCOUNT, InputBufferHeader.tree_header), /// System Program runtime account header. offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.header.system_program), + /// Rent sysvar account header, in footer. + offset!(RENT_ACCOUNT, InitInputBufferFooter.rent), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. N_ACCOUNTS_INIT: u64 = 4, /// Expected data length of system program account. SYSTEM_PROGRAM_DATA_LEN: usize = b"system_program".len(), + /// Expected data length of rent sysvar account. + RENT_DATA_LEN: usize = size_of::(), } } @@ -104,7 +112,7 @@ pub struct InitInputBufferHeader { #[repr(C, packed)] pub struct InitInputBufferFooter { - pub _rent: RentRuntimeAccount, + pub rent: RentRuntimeAccount, /// No actual instruction data follows. pub instruction_data_len: u64, pub program_id: Address, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index e8594b69..9bab5ffa 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -87,6 +87,17 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); + // Get input buffer footer pointer. + let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); + + // Error if Rent account is duplicate or has invalid data length. + let rent_sysvar = account_at(input_buffer_footer_ptr, input_buffer::RENT_ACCOUNT_OFF); + if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); + if_err!( + rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, + error::RENT_DATA_LEN + ); + // Error if instruction data provided. let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); if_err!( @@ -105,7 +116,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + input_buffer_footer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 232cd669..e00cef74 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -15,6 +15,7 @@ enum AccountIndex { User = 0, Tree = 1, SystemProgram = 2, + RentSysvar = 3, } struct CaseResult { diff --git a/examples/tree/src/tests/entrypoint.rs b/examples/tree/src/tests/entrypoint.rs index b2f5425f..7219d20d 100644 --- a/examples/tree/src/tests/entrypoint.rs +++ b/examples/tree/src/tests/entrypoint.rs @@ -5,18 +5,24 @@ use solana_sdk::instruction::AccountMeta; pub(super) enum EntrypointCase { NoAccounts, OneAccount, - FourAccounts, + ThreeAccounts, + FiveAccounts, } impl EntrypointCase { - pub(super) const CASES: &'static [Self] = - &[Self::NoAccounts, Self::OneAccount, Self::FourAccounts]; + pub(super) const CASES: &'static [Self] = &[ + Self::NoAccounts, + Self::OneAccount, + Self::ThreeAccounts, + Self::FiveAccounts, + ]; const fn n_accounts(&self) -> usize { match self { Self::NoAccounts => 0, Self::OneAccount => 1, - Self::FourAccounts => 4, + Self::ThreeAccounts => 3, + Self::FiveAccounts => 5, } } } @@ -26,7 +32,8 @@ impl TestCase for EntrypointCase { match self { Self::NoAccounts => "No accounts", Self::OneAccount => "One account", - Self::FourAccounts => "Four accounts", + Self::ThreeAccounts => "Three accounts", + Self::FiveAccounts => "Five accounts", } } diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 6d512ee6..a9299f05 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -8,6 +8,8 @@ fn init_setup( let setup = setup_test(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); + let (rent_sysvar_pubkey, rent_sysvar_account) = + setup.mollusk.sysvars.keyed_account_for_rent_sysvar(); let user_pubkey = Pubkey::new_unique(); let tree_pubkey = Pubkey::new_unique(); @@ -19,6 +21,7 @@ fn init_setup( AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), AccountMeta::new_readonly(system_program_pubkey, false), + AccountMeta::new_readonly(rent_sysvar_pubkey, false), ], ); @@ -29,6 +32,7 @@ fn init_setup( ), (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), (system_program_pubkey, system_program_account), + (rent_sysvar_pubkey, rent_sysvar_account), ]; (setup, instruction, accounts) @@ -40,6 +44,8 @@ fn pda_init_setup( let setup = setup_test(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); + let (rent_sysvar_pubkey, rent_sysvar_account) = + setup.mollusk.sysvars.keyed_account_for_rent_sysvar(); let user_pubkey = Pubkey::new_unique(); let (tree_pubkey, _bump) = Pubkey::find_program_address(&[], &setup.program_id); @@ -51,6 +57,7 @@ fn pda_init_setup( AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), AccountMeta::new_readonly(system_program_pubkey, false), + AccountMeta::new_readonly(rent_sysvar_pubkey, false), ], ); @@ -61,6 +68,7 @@ fn pda_init_setup( ), (tree_pubkey, Account::new(0, 0, &system_program_pubkey)), (system_program_pubkey, system_program_account), + (rent_sysvar_pubkey, rent_sysvar_account), ]; (setup, instruction, accounts) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 02ed0d7f..55d4591d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -9,10 +9,12 @@ .equ E_TREE_DUPLICATE, 5 # The tree account is a duplicate. # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 +.equ E_RENT_DUPLICATE, 7 # The rent sysvar account is a duplicate. +.equ E_RENT_DATA_LEN, 8 # The rent sysvar account has invalid data length. # Instruction data provided during initialization instruction. -.equ E_INSTRUCTION_DATA, 7 +.equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. -.equ E_PDA_MISMATCH, 8 +.equ E_PDA_MISMATCH, 10 # Type sizes. # ----------- @@ -41,12 +43,14 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 +.equ IB_RENT_ACCOUNT_OFF, 0 # Rent sysvar account header, in footer. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 +.equ IB_RENT_DATA_LEN, 16 # Expected data length of rent sysvar account. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -61,8 +65,10 @@ # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 .equ IB_FOOTER_OFF, 31032 # Footer. -# Instruction data length field for empty tree account, inside footer. -.equ IB_INIT_INSTRUCTION_DATA_LEN_OFF, 10352 +# Rent account non-duplicate marker field, inside footer. +.equ IB_RENT_NON_DUP_MARKER_OFF, 0 +# Rent account data length field, inside footer. +.equ IB_RENT_DATA_LEN_OFF, 80 # Program ID field for initialize instruction, inside footer. .equ IB_INIT_PROGRAM_ID_OFF, 10360 @@ -123,14 +129,20 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + # Get input buffer footer pointer. + # -------------------------------- + mov64 r6, r1 + add64 r6, IB_FOOTER_OFF + + # Error if Rent account is duplicate or has invalid length. + # --------------------------------------------------------- + ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r9, [r6 + IB_RENT_DATA_LEN_OFF] + jne r9, IB_RENT_DATA_LEN, e_rent_data_len + # Error if instruction data provided. # ----------------------------------- - # Use the instruction data pointer in r2 from SIMD-0321, which is - # equivalent to the following static offset for static and verified - # account data lengths: - # ``` - # ldxdw r9, [r1 + IB_INIT_INSTRUCTION_DATA_LEN_OFF] - # ``` ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks @@ -142,7 +154,7 @@ initialize: # argument is effectively ignored. # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. - mov64 r3, r1 # Get input buffer pointer. + mov64 r3, r6 # Get input buffer footer pointer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. @@ -182,6 +194,14 @@ e_pda_mismatch: mov64 r0, E_PDA_MISMATCH exit +e_rent_data_len: + mov64 r0, E_RENT_DATA_LEN + exit + +e_rent_duplicate: + mov64 r0, E_RENT_DUPLICATE + exit + e_system_program_data_len: mov64 r0, E_SYSTEM_PROGRAM_DATA_LEN exit From 75ded32511e9bc8f51190936fc6dc1715c7ec8b7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:10:10 -0800 Subject: [PATCH 109/263] Add rent/header/footer layout --- docs/src/examples/tree.md | 2 +- examples/tree/artifacts/dumps/asm.txt | 141 +++++++++--------- examples/tree/artifacts/dumps/rs.txt | 2 +- examples/tree/artifacts/rs-disassembly.s | 2 +- .../tree/artifacts/snippets/asm/constants.txt | 15 +- .../snippets/asm/initialize-input-checks.txt | 5 - .../snippets/asm/initialize-pda-checks.txt | 3 +- .../snippets/rs/initialize-input-checks.txt | 5 +- .../snippets/rs/initialize-pda-checks.txt | 2 + .../tests/entrypoint_branching/result.txt | 31 ++++ .../tests/initialize_input_checks/test.txt | 4 + examples/tree/interface/src/asm.rs | 15 +- examples/tree/interface/src/common.rs | 8 +- examples/tree/src/program.rs | 7 +- examples/tree/src/tests/init.rs | 29 ++++ examples/tree/src/tree/tree.s | 23 ++- 16 files changed, 174 insertions(+), 120 deletions(-) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index bb2e8d79..75dda7d5 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -21,7 +21,7 @@ performance. ::: - + ## Initialize input checks diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index c87b4dda..0ee5afed 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1128 (bytes into file) + Start of section headers 1120 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x468 +There are 7 section headers, starting at offset 0x460 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000228 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000310 000310 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000003b0 0003b0 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003f8 0003f8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000428 000428 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000438 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000220 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000308 000308 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000003a8 0003a8 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003f0 0003f0 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000420 000420 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000430 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000228 0x000228 R E 0x1000 - LOAD 0x0003b0 0x00000000000003b0 0x00000000000003b0 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000310 0x0000000000000310 0x0000000000000310 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000220 0x000220 R E 0x1000 + LOAD 0x0003a8 0x00000000000003a8 0x00000000000003a8 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000308 0x0000000000000308 0x0000000000000308 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x310 contains 10 entries +Dynamic section at offset 0x308 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x428 + 0x0000000000000011 (REL) 0x420 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x3b0 + 0x0000000000000006 (SYMTAB) 0x3a8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3f8 + 0x0000000000000005 (STRTAB) 0x3f0 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x428 contains 1 entries +Relocation section '.rel.dyn' at offset 0x420 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -0000000000000200 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +00000000000001f8 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -92,61 +92,60 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 37 00 00 00 00 00 if r9 != 0x0 goto +0x37 + 40 55 09 36 00 00 00 00 00 if r9 != 0x0 goto +0x36 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 33 00 ff 00 00 00 if r9 != 0xff goto +0x33 + 42 55 09 32 00 ff 00 00 00 if r9 != 0xff goto +0x32 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 2f 00 00 00 00 00 if r9 != 0x0 goto +0x2f + 44 55 09 2e 00 00 00 00 00 if r9 != 0x0 goto +0x2e 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 2b 00 ff 00 00 00 if r9 != 0xff goto +0x2b + 46 55 09 2a 00 ff 00 00 00 if r9 != 0xff goto +0x2a 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 27 00 0e 00 00 00 if r9 != 0xe goto +0x27 - 49 bf 16 00 00 00 00 00 00 r6 = r1 - 50 07 06 00 00 38 79 00 00 r6 += 0x7938 - 51 71 69 00 00 00 00 00 00 r9 = *(u8 *)(r6 + 0x0) - 52 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 - 53 79 69 50 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x50) - 54 55 09 1d 00 10 00 00 00 if r9 != 0x10 goto +0x1d - 55 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 56 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 - 57 b7 02 00 00 00 00 00 00 r2 = 0x0 - 58 bf 63 00 00 00 00 00 00 r3 = r6 - 59 07 03 00 00 78 28 00 00 r3 += 0x2878 - 60 bf a4 00 00 00 00 00 00 r4 = r10 - 61 07 04 00 00 98 ff ff ff r4 += -0x68 - 62 bf a5 00 00 00 00 00 00 r5 = r10 - 63 07 05 00 00 98 fe ff ff r5 += -0x168 - 64 85 10 00 00 ff ff ff ff call -0x1 - 65 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) - 66 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) - 67 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe - 68 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) - 69 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) - 70 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb - 71 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) - 72 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) - 73 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 - 74 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) - 75 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) - 76 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 - 77 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 78 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 79 95 00 00 00 00 00 00 00 exit - 80 b7 00 00 00 09 00 00 00 r0 = 0x9 - 81 95 00 00 00 00 00 00 00 exit - 82 b7 00 00 00 0a 00 00 00 r0 = 0xa - 83 95 00 00 00 00 00 00 00 exit - 84 b7 00 00 00 08 00 00 00 r0 = 0x8 - 85 95 00 00 00 00 00 00 00 exit - 86 b7 00 00 00 07 00 00 00 r0 = 0x7 - 87 95 00 00 00 00 00 00 00 exit - 88 b7 00 00 00 04 00 00 00 r0 = 0x4 - 89 95 00 00 00 00 00 00 00 exit - 90 b7 00 00 00 06 00 00 00 r0 = 0x6 - 91 95 00 00 00 00 00 00 00 exit - 92 b7 00 00 00 03 00 00 00 r0 = 0x3 - 93 95 00 00 00 00 00 00 00 exit - 94 b7 00 00 00 05 00 00 00 r0 = 0x5 - 95 95 00 00 00 00 00 00 00 exit - 96 b7 00 00 00 02 00 00 00 r0 = 0x2 - 97 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 48 55 09 26 00 0e 00 00 00 if r9 != 0xe goto +0x26 + 49 71 69 38 79 00 00 00 00 r9 = *(u8 *)(r6 + 0x7938) + 50 55 09 22 00 ff 00 00 00 if r9 != 0xff goto +0x22 + 51 79 69 88 79 00 00 00 00 r9 = *(u64 *)(r6 + 0x7988) + 52 55 09 1e 00 11 00 00 00 if r9 != 0x11 goto +0x1e + 53 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 54 55 09 18 00 00 00 00 00 if r9 != 0x0 goto +0x18 + 55 b7 02 00 00 00 00 00 00 r2 = 0x0 + 56 bf 13 00 00 00 00 00 00 r3 = r1 + 57 07 03 00 00 a8 a1 00 00 r3 += 0xa1a8 + 58 07 03 00 00 08 00 00 00 r3 += 0x8 + 59 bf a4 00 00 00 00 00 00 r4 = r10 + 60 07 04 00 00 98 ff ff ff r4 += -0x68 + 61 bf a5 00 00 00 00 00 00 r5 = r10 + 62 07 05 00 00 98 fe ff ff r5 += -0x168 + 63 85 10 00 00 ff ff ff ff call -0x1 + 64 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) + 65 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) + 66 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe + 67 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) + 68 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) + 69 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb + 70 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) + 71 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) + 72 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 + 73 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) + 74 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) + 75 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 + 76 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 77 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 78 95 00 00 00 00 00 00 00 exit + 79 b7 00 00 00 09 00 00 00 r0 = 0x9 + 80 95 00 00 00 00 00 00 00 exit + 81 b7 00 00 00 0a 00 00 00 r0 = 0xa + 82 95 00 00 00 00 00 00 00 exit + 83 b7 00 00 00 08 00 00 00 r0 = 0x8 + 84 95 00 00 00 00 00 00 00 exit + 85 b7 00 00 00 07 00 00 00 r0 = 0x7 + 86 95 00 00 00 00 00 00 00 exit + 87 b7 00 00 00 04 00 00 00 r0 = 0x4 + 88 95 00 00 00 00 00 00 00 exit + 89 b7 00 00 00 06 00 00 00 r0 = 0x6 + 90 95 00 00 00 00 00 00 00 exit + 91 b7 00 00 00 03 00 00 00 r0 = 0x3 + 92 95 00 00 00 00 00 00 00 exit + 93 b7 00 00 00 05 00 00 00 r0 = 0x5 + 94 95 00 00 00 00 00 00 00 exit + 95 b7 00 00 00 02 00 00 00 r0 = 0x2 + 96 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 4d113e42..91699bdb 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -126,7 +126,7 @@ Disassembly of section .text 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] a0 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 a8 9c 13 88 79 00 00 00 00 ldxdw r3, [r1 + 0x7988] - b0 55 03 28 00 10 00 00 00 jne r3, 0x10, +0x28 + b0 55 03 28 00 11 00 00 00 jne r3, 0x11, +0x28 b8 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] c0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 c8 bf 13 00 00 00 00 00 00 mov64 r3, r1 diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index c84068dd..dc354aa0 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -27,7 +27,7 @@ jmp_0040: ldxb r3, [r1+31032] jne r3, 255, jmp_01e8 ldxdw r3, [r1+31112] - jne r3, 16, jmp_01f8 + jne r3, 17, jmp_01f8 ldxdw r2, [r2-8] jne r2, 0, jmp_0208 mov64 r3, r1 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 6fcf3f7f..75a4ea90 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -42,14 +42,14 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 -.equ IB_RENT_ACCOUNT_OFF, 0 # Rent sysvar account header, in footer. +.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header, in footer. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 -.equ IB_RENT_DATA_LEN, 16 # Expected data length of rent sysvar account. +.equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -63,13 +63,12 @@ .equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 -.equ IB_FOOTER_OFF, 31032 # Footer. -# Rent account non-duplicate marker field, inside footer. -.equ IB_RENT_NON_DUP_MARKER_OFF, 0 -# Rent account data length field, inside footer. -.equ IB_RENT_DATA_LEN_OFF, 80 +# Rent account non-duplicate marker field. +.equ IB_RENT_NON_DUP_MARKER_OFF, 31032 +.equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. # Program ID field for initialize instruction, inside footer. -.equ IB_INIT_PROGRAM_ID_OFF, 10360 +.equ IB_INIT_PROGRAM_ID_OFF, 8 +.equ IB_FOOTER_OFF, 41384 # Input buffer footer offset. # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 5d77f060..c6416e25 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -19,11 +19,6 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len - # Get input buffer footer pointer. - # -------------------------------- - mov64 r6, r1 - add64 r6, IB_FOOTER_OFF - # Error if Rent account is duplicate or has invalid length. # --------------------------------------------------------- ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 0138d8d4..87a2b7dd 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -4,7 +4,8 @@ # argument is effectively ignored. # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. - mov64 r3, r6 # Get input buffer footer pointer. + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_FOOTER_OFF # Advance to footer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index a1e9df3b..64b8ed52 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -20,11 +20,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); - // Get input buffer footer pointer. - let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); - // Error if Rent account is duplicate or has invalid data length. - let rent_sysvar = account_at(input_buffer_footer_ptr, input_buffer::RENT_ACCOUNT_OFF); + let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 1fac19a8..d4b4fcbf 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -3,6 +3,8 @@ let (pda, _bump) = { let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); + // Get input buffer footer pointer. + let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..a4015b68 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Three accounts | 5 | 7 | +2 | +40.0% | +| Five accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..d179220a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES); +} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 5f2512a6..b591f283 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,7 +4,8 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, CreateAccountInstructionData, InitInputBuffer, InitInputBufferFooter, InputBufferHeader, + cpi, CreateAccountInstructionData, InitInputBuffer, InitInputBufferFooter, + InitInputBufferHeader, InputBufferHeader, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; @@ -43,14 +44,14 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.header.system_program.header.borrow_state), /// System Program data length field. offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.header.system_program.header.data_len), - /// Footer. - offset!(FOOTER, InitInputBuffer.footer), - /// Rent account non-duplicate marker field, inside footer. - offset!(RENT_NON_DUP_MARKER, InitInputBufferFooter.rent.header.borrow_state), - /// Rent account data length field, inside footer. - offset!(RENT_DATA_LEN, InitInputBufferFooter.rent.header.data_len), + /// Rent account non-duplicate marker field. + offset!(RENT_NON_DUP_MARKER, InitInputBuffer.header.rent.header.borrow_state), + /// Rent account data length field. + offset!(RENT_DATA_LEN, InitInputBuffer.header.rent.header.data_len), /// Program ID field for initialize instruction, inside footer. offset!(INIT_PROGRAM_ID, InitInputBufferFooter.program_id), + /// Input buffer footer offset. + FOOTER_OFF = size_of::(), }); #[stack_frame] diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index ad0f10b2..6e1b6bc4 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -41,7 +41,7 @@ constant_group! { /// System Program runtime account header. offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.header.system_program), /// Rent sysvar account header, in footer. - offset!(RENT_ACCOUNT, InitInputBufferFooter.rent), + offset!(RENT_ACCOUNT, InitInputBuffer.header.rent), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. @@ -49,7 +49,9 @@ constant_group! { /// Expected data length of system program account. SYSTEM_PROGRAM_DATA_LEN: usize = b"system_program".len(), /// Expected data length of rent sysvar account. - RENT_DATA_LEN: usize = size_of::(), + // Includes extra byte for deprecated burn_percent field that is still present in test + // framework. + RENT_DATA_LEN: usize = size_of::() + size_of::(), } } @@ -108,11 +110,11 @@ pub struct InitInputBufferHeader { pub _user: EmptyRuntimeAccount, pub _tree: EmptyRuntimeAccount, pub system_program: SystemProgramRuntimeAccount, + pub rent: RentRuntimeAccount, } #[repr(C, packed)] pub struct InitInputBufferFooter { - pub rent: RentRuntimeAccount, /// No actual instruction data follows. pub instruction_data_len: u64, pub program_id: Address, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 9bab5ffa..db9dc242 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -87,11 +87,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); - // Get input buffer footer pointer. - let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); - // Error if Rent account is duplicate or has invalid data length. - let rent_sysvar = account_at(input_buffer_footer_ptr, input_buffer::RENT_ACCOUNT_OFF); + let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, @@ -112,6 +109,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let (pda, _bump) = { let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); + // Get input buffer footer pointer. + let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index a9299f05..32f12623 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -99,6 +99,8 @@ pub(super) enum InitCase { TreeDataLen, SystemProgramDuplicate, SystemProgramDataLen, + RentDuplicate, + RentDataLen, InstructionData, PdaMismatchChunk0, PdaMismatchChunk1, @@ -113,6 +115,8 @@ impl InitCase { Self::TreeDataLen, Self::SystemProgramDuplicate, Self::SystemProgramDataLen, + Self::RentDuplicate, + Self::RentDataLen, Self::InstructionData, ]; @@ -132,6 +136,8 @@ impl TestCase for InitCase { Self::TreeDataLen => "Tree has nonzero data length", Self::SystemProgramDuplicate => "System program is duplicate", Self::SystemProgramDataLen => "System program wrong data length", + Self::RentDuplicate => "Rent sysvar is duplicate", + Self::RentDataLen => "Rent sysvar wrong data length", Self::InstructionData => "Non-empty instruction data", Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", @@ -198,6 +204,29 @@ impl TestCase for InitCase { error_codes::error::SYSTEM_PROGRAM_DATA_LEN, ) } + Self::RentDuplicate => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + instruction.accounts[AccountIndex::RentSysvar as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::RentSysvar as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::RENT_DUPLICATE, + ) + } + Self::RentDataLen => { + let (setup, instruction, mut accounts) = init_setup(lang); + accounts[AccountIndex::RentSysvar as usize].1.data = vec![]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::RENT_DATA_LEN, + ) + } Self::InstructionData => { let (setup, mut instruction, accounts) = init_setup(lang); instruction.data = vec![1u8; 1]; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 55d4591d..d01bd6bb 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -43,14 +43,14 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 -.equ IB_RENT_ACCOUNT_OFF, 0 # Rent sysvar account header, in footer. +.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header, in footer. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. .equ IB_N_ACCOUNTS_INIT, 4 # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 -.equ IB_RENT_DATA_LEN, 16 # Expected data length of rent sysvar account. +.equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -64,13 +64,12 @@ .equ IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF, 20680 # System Program data length field. .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 -.equ IB_FOOTER_OFF, 31032 # Footer. -# Rent account non-duplicate marker field, inside footer. -.equ IB_RENT_NON_DUP_MARKER_OFF, 0 -# Rent account data length field, inside footer. -.equ IB_RENT_DATA_LEN_OFF, 80 +# Rent account non-duplicate marker field. +.equ IB_RENT_NON_DUP_MARKER_OFF, 31032 +.equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. # Program ID field for initialize instruction, inside footer. -.equ IB_INIT_PROGRAM_ID_OFF, 10360 +.equ IB_INIT_PROGRAM_ID_OFF, 8 +.equ IB_FOOTER_OFF, 41384 # Input buffer footer offset. # Init stack frame layout. # ------------------------ @@ -129,11 +128,6 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len - # Get input buffer footer pointer. - # -------------------------------- - mov64 r6, r1 - add64 r6, IB_FOOTER_OFF - # Error if Rent account is duplicate or has invalid length. # --------------------------------------------------------- ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] @@ -154,7 +148,8 @@ initialize: # argument is effectively ignored. # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. - mov64 r3, r6 # Get input buffer footer pointer. + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_FOOTER_OFF # Advance to footer. add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. From ef9a24ad49cdcb5b9c0cb43bffce2f38b89bcaea Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:37:14 -0800 Subject: [PATCH 110/263] Update offset arithmetic --- examples/tree/artifacts/dumps/asm.txt | 133 +++++++++--------- .../tree/artifacts/snippets/asm/constants.txt | 5 +- .../snippets/asm/initialize-input-checks.txt | 4 +- .../snippets/asm/initialize-pda-checks.txt | 3 +- .../snippets/rs/initialize-pda-checks.txt | 3 +- .../tests/initialize_input_checks/result.txt | 59 ++++++++ .../tests/initialize_pda_checks/result.txt | 31 ++++ .../tests/initialize_pda_checks/test.txt | 4 + examples/tree/interface/src/asm.rs | 11 +- examples/tree/macros/src/lib.rs | 115 ++++++++++++++- examples/tree/src/program.rs | 3 +- examples/tree/src/tree/tree.s | 12 +- 12 files changed, 288 insertions(+), 95 deletions(-) create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 0ee5afed..0504a9f2 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1120 (bytes into file) + Start of section headers 1112 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x460 +There are 7 section headers, starting at offset 0x458 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000220 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000308 000308 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000003a8 0003a8 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003f0 0003f0 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000420 000420 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000430 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000218 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000300 000300 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000003a0 0003a0 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003e8 0003e8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000418 000418 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000428 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000220 0x000220 R E 0x1000 - LOAD 0x0003a8 0x00000000000003a8 0x00000000000003a8 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000308 0x0000000000000308 0x0000000000000308 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000218 0x000218 R E 0x1000 + LOAD 0x0003a0 0x00000000000003a0 0x00000000000003a0 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000300 0x0000000000000300 0x0000000000000300 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x308 contains 10 entries +Dynamic section at offset 0x300 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x420 + 0x0000000000000011 (REL) 0x418 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x3a8 + 0x0000000000000006 (SYMTAB) 0x3a0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3f0 + 0x0000000000000005 (STRTAB) 0x3e8 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x420 contains 1 entries +Relocation section '.rel.dyn' at offset 0x418 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -00000000000001f8 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +00000000000001f0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -92,60 +92,59 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 36 00 00 00 00 00 if r9 != 0x0 goto +0x36 + 40 55 09 35 00 00 00 00 00 if r9 != 0x0 goto +0x35 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 32 00 ff 00 00 00 if r9 != 0xff goto +0x32 + 42 55 09 31 00 ff 00 00 00 if r9 != 0xff goto +0x31 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 2e 00 00 00 00 00 if r9 != 0x0 goto +0x2e + 44 55 09 2d 00 00 00 00 00 if r9 != 0x0 goto +0x2d 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 2a 00 ff 00 00 00 if r9 != 0xff goto +0x2a + 46 55 09 29 00 ff 00 00 00 if r9 != 0xff goto +0x29 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 26 00 0e 00 00 00 if r9 != 0xe goto +0x26 - 49 71 69 38 79 00 00 00 00 r9 = *(u8 *)(r6 + 0x7938) - 50 55 09 22 00 ff 00 00 00 if r9 != 0xff goto +0x22 - 51 79 69 88 79 00 00 00 00 r9 = *(u64 *)(r6 + 0x7988) - 52 55 09 1e 00 11 00 00 00 if r9 != 0x11 goto +0x1e + 48 55 09 25 00 0e 00 00 00 if r9 != 0xe goto +0x25 + 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) + 50 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 + 51 79 19 88 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7988) + 52 55 09 1d 00 11 00 00 00 if r9 != 0x11 goto +0x1d 53 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 54 55 09 18 00 00 00 00 00 if r9 != 0x0 goto +0x18 + 54 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 55 b7 02 00 00 00 00 00 00 r2 = 0x0 56 bf 13 00 00 00 00 00 00 r3 = r1 - 57 07 03 00 00 a8 a1 00 00 r3 += 0xa1a8 - 58 07 03 00 00 08 00 00 00 r3 += 0x8 - 59 bf a4 00 00 00 00 00 00 r4 = r10 - 60 07 04 00 00 98 ff ff ff r4 += -0x68 - 61 bf a5 00 00 00 00 00 00 r5 = r10 - 62 07 05 00 00 98 fe ff ff r5 += -0x168 - 63 85 10 00 00 ff ff ff ff call -0x1 - 64 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) - 65 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) - 66 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe - 67 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) - 68 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) - 69 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb - 70 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) - 71 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) - 72 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 - 73 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) - 74 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) - 75 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 - 76 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 77 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 78 95 00 00 00 00 00 00 00 exit - 79 b7 00 00 00 09 00 00 00 r0 = 0x9 - 80 95 00 00 00 00 00 00 00 exit - 81 b7 00 00 00 0a 00 00 00 r0 = 0xa - 82 95 00 00 00 00 00 00 00 exit - 83 b7 00 00 00 08 00 00 00 r0 = 0x8 - 84 95 00 00 00 00 00 00 00 exit - 85 b7 00 00 00 07 00 00 00 r0 = 0x7 - 86 95 00 00 00 00 00 00 00 exit - 87 b7 00 00 00 04 00 00 00 r0 = 0x4 - 88 95 00 00 00 00 00 00 00 exit - 89 b7 00 00 00 06 00 00 00 r0 = 0x6 - 90 95 00 00 00 00 00 00 00 exit - 91 b7 00 00 00 03 00 00 00 r0 = 0x3 - 92 95 00 00 00 00 00 00 00 exit - 93 b7 00 00 00 05 00 00 00 r0 = 0x5 - 94 95 00 00 00 00 00 00 00 exit - 95 b7 00 00 00 02 00 00 00 r0 = 0x2 - 96 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 57 07 03 00 00 b0 a1 00 00 r3 += 0xa1b0 + 58 bf a4 00 00 00 00 00 00 r4 = r10 + 59 07 04 00 00 98 ff ff ff r4 += -0x68 + 60 bf a5 00 00 00 00 00 00 r5 = r10 + 61 07 05 00 00 98 fe ff ff r5 += -0x168 + 62 85 10 00 00 ff ff ff ff call -0x1 + 63 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) + 64 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) + 65 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe + 66 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) + 67 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) + 68 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb + 69 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) + 70 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) + 71 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 + 72 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) + 73 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) + 74 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 + 75 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 76 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 77 95 00 00 00 00 00 00 00 exit + 78 b7 00 00 00 09 00 00 00 r0 = 0x9 + 79 95 00 00 00 00 00 00 00 exit + 80 b7 00 00 00 0a 00 00 00 r0 = 0xa + 81 95 00 00 00 00 00 00 00 exit + 82 b7 00 00 00 08 00 00 00 r0 = 0x8 + 83 95 00 00 00 00 00 00 00 exit + 84 b7 00 00 00 07 00 00 00 r0 = 0x7 + 85 95 00 00 00 00 00 00 00 exit + 86 b7 00 00 00 04 00 00 00 r0 = 0x4 + 87 95 00 00 00 00 00 00 00 exit + 88 b7 00 00 00 06 00 00 00 r0 = 0x6 + 89 95 00 00 00 00 00 00 00 exit + 90 b7 00 00 00 03 00 00 00 r0 = 0x3 + 91 95 00 00 00 00 00 00 00 exit + 92 b7 00 00 00 05 00 00 00 r0 = 0x5 + 93 95 00 00 00 00 00 00 00 exit + 94 b7 00 00 00 02 00 00 00 r0 = 0x2 + 95 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 75a4ea90..f8aeda0f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -66,9 +66,8 @@ # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. -# Program ID field for initialize instruction, inside footer. -.equ IB_INIT_PROGRAM_ID_OFF, 8 -.equ IB_FOOTER_OFF, 41384 # Input buffer footer offset. +# Program ID field for initialize instruction. +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41392 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index c6416e25..656308a0 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -21,9 +21,9 @@ initialize: # Error if Rent account is duplicate or has invalid length. # --------------------------------------------------------- - ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] + ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r6 + IB_RENT_DATA_LEN_OFF] + ldxdw r9, [r1 + IB_RENT_DATA_LEN_OFF] jne r9, IB_RENT_DATA_LEN, e_rent_data_len # Error if instruction data provided. diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 87a2b7dd..5ee2ca79 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -5,8 +5,7 @@ # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. mov64 r3, r1 # Get input buffer pointer. - add64 r3, IB_FOOTER_OFF # Advance to footer. - add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. + add64 r3, IB_INIT_PROGRAM_ID_OFF_IMM # Point at program ID. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. mov64 r5, r10 # Get stack frame pointer. diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index d4b4fcbf..3061d6cb 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -4,12 +4,11 @@ let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); // Get input buffer footer pointer. - let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_footer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..febf6701 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,59 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | +| Rent sysvar wrong data length | 19 | 21 | +2 | +10.5% | +| Non-empty instruction data | 21 | 23 | +2 | +9.5% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..73a27968 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 3032 | 3035 | +3 | +0.1% | +| PDA mismatch chunk 2 | 3032 | 3035 | +3 | +0.1% | +| PDA mismatch chunk 3 | 3032 | 3035 | +3 | +0.1% | +| PDA mismatch chunk 4 | 3032 | 3035 | +3 | +0.1% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..5bd90196 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES); +} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index b591f283..a923e326 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,10 +3,7 @@ extern crate alloc; use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; -use crate::common::{ - cpi, CreateAccountInstructionData, InitInputBuffer, InitInputBufferFooter, - InitInputBufferHeader, InputBufferHeader, -}; +use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; @@ -48,10 +45,8 @@ extend_constant_group!(input_buffer { offset!(RENT_NON_DUP_MARKER, InitInputBuffer.header.rent.header.borrow_state), /// Rent account data length field. offset!(RENT_DATA_LEN, InitInputBuffer.header.rent.header.data_len), - /// Program ID field for initialize instruction, inside footer. - offset!(INIT_PROGRAM_ID, InitInputBufferFooter.program_id), - /// Input buffer footer offset. - FOOTER_OFF = size_of::(), + /// Program ID field for initialize instruction. + offset_immediate!(INIT_PROGRAM_ID, InitInputBuffer.footer.program_id), }); #[stack_frame] diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 460cf87a..7905f441 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -195,6 +195,12 @@ enum ConstantKind { struct_name: Ident, field_path: Vec, }, + /// Offset derived from struct field path (i32 validated). + /// Name gets `_OFF_IMM` suffix appended. For use as BPF immediate operand. + OffsetImmediate { + struct_name: Ident, + field_path: Vec, + }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. /// Name gets `_OFF` suffix (aligned) or `_UOFF` suffix (unaligned). @@ -316,8 +322,8 @@ impl Parse for ConstantGroup { continue; } - // Support `offset!(NAME, Struct.field)`, `NAME: type = value`, - // and `NAME = expr as Type` forms. + // Support `offset!(NAME, Struct.field)`, `offset_immediate!(NAME, Struct.field)`, + // `NAME: type = value`, and `NAME = expr as Type` forms. let (const_name, kind) = if ident == "offset" { // offset!(NAME, Struct.field.nested.path) content.parse::()?; @@ -342,6 +348,30 @@ impl Parse for ConstantGroup { field_path, }, ) + } else if ident == "offset_immediate" { + // offset_immediate!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); + ( + full_name, + ConstantKind::OffsetImmediate { + struct_name, + field_path, + }, + ) } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { let aligned = ident == "stack_frame_offset"; let suffix = if aligned { "_OFF" } else { "_UOFF" }; @@ -536,6 +566,24 @@ pub fn constant_group(input: TokenStream) -> TokenStream { ); }); } + ConstantKind::OffsetImmediate { + struct_name, + field_path, + } => { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + const_value_strs.push(None); + + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + "Offset immediate must fit in i32 range" + ); + }); + } ConstantKind::StackFrameOffset { struct_name, field_path_tokens, @@ -688,6 +736,12 @@ enum AsmConstantKind { struct_name: Ident, field_path: Vec, }, + /// Offset derived from struct field path (i32 validated). + /// Name gets `_OFF_IMM` suffix appended. For use as BPF immediate operand. + OffsetImmediate { + struct_name: Ident, + field_path: Vec, + }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. /// Name gets `_OFF` suffix (aligned) or `_UOFF` suffix (unaligned). @@ -944,6 +998,31 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> field_path, }, ) + } else if ident == "offset_immediate" { + // Parse offset_immediate!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + // Append _OFF_IMM suffix to the name. + let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); + ( + full_name, + AsmConstantKind::OffsetImmediate { + struct_name, + field_path, + }, + ) } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { let aligned = ident == "stack_frame_offset"; let suffix = if aligned { "_OFF" } else { "_UOFF" }; @@ -1217,6 +1296,22 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { ); }); } + AsmConstantKind::OffsetImmediate { + struct_name, + field_path, + } => { + const_value_strs.push(None); + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + "Offset immediate must fit in i32 range" + ); + }); + } AsmConstantKind::StackFrameOffset { struct_name, field_path_tokens, @@ -1430,6 +1525,22 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { ); }); } + AsmConstantKind::OffsetImmediate { + struct_name, + field_path, + } => { + const_value_strs.push(None); + const_defs.push(quote! { + #[doc = #doc] + pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) + && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + "Offset immediate must fit in i32 range" + ); + }); + } AsmConstantKind::StackFrameOffset { struct_name, field_path_tokens, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index db9dc242..b61065eb 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -110,12 +110,11 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); // Get input buffer footer pointer. - let input_buffer_footer_ptr = input_buffer_ptr.add(input_buffer::FOOTER_OFF as usize); sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. input_buffer_ptr, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_footer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF as usize), + input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d01bd6bb..c338d4a5 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -67,9 +67,8 @@ # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. -# Program ID field for initialize instruction, inside footer. -.equ IB_INIT_PROGRAM_ID_OFF, 8 -.equ IB_FOOTER_OFF, 41384 # Input buffer footer offset. +# Program ID field for initialize instruction. +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41392 # Init stack frame layout. # ------------------------ @@ -130,9 +129,9 @@ initialize: # Error if Rent account is duplicate or has invalid length. # --------------------------------------------------------- - ldxb r9, [r6 + IB_RENT_NON_DUP_MARKER_OFF] + ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r6 + IB_RENT_DATA_LEN_OFF] + ldxdw r9, [r1 + IB_RENT_DATA_LEN_OFF] jne r9, IB_RENT_DATA_LEN, e_rent_data_len # Error if instruction data provided. @@ -149,8 +148,7 @@ initialize: # --------------------------------------------------------------------- mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. mov64 r3, r1 # Get input buffer pointer. - add64 r3, IB_FOOTER_OFF # Advance to footer. - add64 r3, IB_INIT_PROGRAM_ID_OFF # Point at program ID in input buffer. + add64 r3, IB_INIT_PROGRAM_ID_OFF_IMM # Point at program ID. mov64 r4, r10 # Get stack frame pointer. add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. mov64 r5, r10 # Get stack frame pointer. From 312cd5fc9ce3dbeb8e129f9dedf3932135c2ff42 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:55:46 -0800 Subject: [PATCH 111/263] Add happy path PDA test --- docs/src/examples/tree.md | 4 ++-- examples/tree/src/tests.rs | 18 ++++++++++++++++++ examples/tree/src/tests/init.rs | 7 +++++++ examples/tree/src/tree/tree.s | 4 ++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 75dda7d5..cb8bdc76 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -35,7 +35,7 @@ performance. ::: - + @@ -51,7 +51,7 @@ performance. ::: - + diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index e00cef74..f80c9d1a 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -23,6 +23,24 @@ struct CaseResult { error: Option, } +fn check_success( + setup: &TestSetup, + instruction: &Instruction, + accounts: &[(Pubkey, Account)], +) -> CaseResult { + let result = setup.mollusk.process_instruction(instruction, accounts); + match &result.program_result { + MolluskResult::Success => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } +} + fn check_error( setup: &TestSetup, instruction: &Instruction, diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 32f12623..8a8a7fc1 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -106,6 +106,7 @@ pub(super) enum InitCase { PdaMismatchChunk1, PdaMismatchChunk2, PdaMismatchChunk3, + PdaMatch, } impl InitCase { @@ -125,6 +126,7 @@ impl InitCase { Self::PdaMismatchChunk1, Self::PdaMismatchChunk2, Self::PdaMismatchChunk3, + Self::PdaMatch, ]; } @@ -143,6 +145,7 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", + Self::PdaMatch => "PDA match (happy path)", } } @@ -241,6 +244,10 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => run_pda_mismatch_chunk(lang, 1), Self::PdaMismatchChunk2 => run_pda_mismatch_chunk(lang, 2), Self::PdaMismatchChunk3 => run_pda_mismatch_chunk(lang, 3), + Self::PdaMatch => { + let (setup, instruction, accounts) = pda_init_setup(lang); + check_success(&setup, &instruction, &accounts) + } } } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index c338d4a5..f0275191 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -174,8 +174,8 @@ initialize: # Initialize signer seed for PDA bump key. # ---------------------------------------- # Store pointer to bump seed. - stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 - stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. + # stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 + # stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. exit From 66fff6d5b8e753ee869a4f006a24c3b26f6b1627 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:02:43 -0800 Subject: [PATCH 112/263] Fix rent size offset issue --- examples/tree/artifacts/dumps/asm.txt | 82 +++++++++---------- examples/tree/artifacts/dumps/rs.txt | 2 +- examples/tree/artifacts/rs-disassembly.s | 2 +- .../tree/artifacts/snippets/asm/constants.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 33 +++++--- examples/tree/interface/src/common.rs | 2 +- examples/tree/src/tree/tree.s | 2 +- 7 files changed, 65 insertions(+), 60 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 0504a9f2..32fee4f8 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1112 (bytes into file) + Start of section headers 1096 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x458 +There are 7 section headers, starting at offset 0x448 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000218 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000300 000300 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000003a0 0003a0 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003e8 0003e8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000418 000418 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000428 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000208 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000002f0 0002f0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000390 000390 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000003d8 0003d8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000408 000408 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000418 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000218 0x000218 R E 0x1000 - LOAD 0x0003a0 0x00000000000003a0 0x00000000000003a0 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000300 0x0000000000000300 0x0000000000000300 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000208 0x000208 R E 0x1000 + LOAD 0x000390 0x0000000000000390 0x0000000000000390 0x000088 0x000088 R 0x1000 + DYNAMIC 0x0002f0 0x00000000000002f0 0x00000000000002f0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x300 contains 10 entries +Dynamic section at offset 0x2f0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x418 + 0x0000000000000011 (REL) 0x408 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x3a0 + 0x0000000000000006 (SYMTAB) 0x390 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3e8 + 0x0000000000000005 (STRTAB) 0x3d8 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x418 contains 1 entries +Relocation section '.rel.dyn' at offset 0x408 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 00000000000001f0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,24 +92,24 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 35 00 00 00 00 00 if r9 != 0x0 goto +0x35 + 40 55 09 33 00 00 00 00 00 if r9 != 0x0 goto +0x33 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 31 00 ff 00 00 00 if r9 != 0xff goto +0x31 + 42 55 09 2f 00 ff 00 00 00 if r9 != 0xff goto +0x2f 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 2d 00 00 00 00 00 if r9 != 0x0 goto +0x2d + 44 55 09 2b 00 00 00 00 00 if r9 != 0x0 goto +0x2b 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 29 00 ff 00 00 00 if r9 != 0xff goto +0x29 + 46 55 09 27 00 ff 00 00 00 if r9 != 0xff goto +0x27 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 25 00 0e 00 00 00 if r9 != 0xe goto +0x25 + 48 55 09 23 00 0e 00 00 00 if r9 != 0xe goto +0x23 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 21 00 ff 00 00 00 if r9 != 0xff goto +0x21 + 50 55 09 1f 00 ff 00 00 00 if r9 != 0xff goto +0x1f 51 79 19 88 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7988) - 52 55 09 1d 00 11 00 00 00 if r9 != 0x11 goto +0x1d + 52 55 09 1b 00 11 00 00 00 if r9 != 0x11 goto +0x1b 53 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 54 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 + 54 55 09 15 00 00 00 00 00 if r9 != 0x0 goto +0x15 55 b7 02 00 00 00 00 00 00 r2 = 0x0 56 bf 13 00 00 00 00 00 00 r3 = r1 - 57 07 03 00 00 b0 a1 00 00 r3 += 0xa1b0 + 57 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 58 bf a4 00 00 00 00 00 00 r4 = r10 59 07 04 00 00 98 ff ff ff r4 += -0x68 60 bf a5 00 00 00 00 00 00 r5 = r10 @@ -117,34 +117,32 @@ Disassembly of section .text 62 85 10 00 00 ff ff ff ff call -0x1 63 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) 64 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) - 65 5d 78 0e 00 00 00 00 00 if r8 != r7 goto +0xe + 65 5d 78 0c 00 00 00 00 00 if r8 != r7 goto +0xc 66 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) 67 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) - 68 5d 78 0b 00 00 00 00 00 if r8 != r7 goto +0xb + 68 5d 78 09 00 00 00 00 00 if r8 != r7 goto +0x9 69 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) 70 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) - 71 5d 78 08 00 00 00 00 00 if r8 != r7 goto +0x8 + 71 5d 78 06 00 00 00 00 00 if r8 != r7 goto +0x6 72 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) 73 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) - 74 5d 78 05 00 00 00 00 00 if r8 != r7 goto +0x5 - 75 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 76 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 74 5d 78 03 00 00 00 00 00 if r8 != r7 goto +0x3 + 75 95 00 00 00 00 00 00 00 exit + 76 b7 00 00 00 09 00 00 00 r0 = 0x9 77 95 00 00 00 00 00 00 00 exit - 78 b7 00 00 00 09 00 00 00 r0 = 0x9 + 78 b7 00 00 00 0a 00 00 00 r0 = 0xa 79 95 00 00 00 00 00 00 00 exit - 80 b7 00 00 00 0a 00 00 00 r0 = 0xa + 80 b7 00 00 00 08 00 00 00 r0 = 0x8 81 95 00 00 00 00 00 00 00 exit - 82 b7 00 00 00 08 00 00 00 r0 = 0x8 + 82 b7 00 00 00 07 00 00 00 r0 = 0x7 83 95 00 00 00 00 00 00 00 exit - 84 b7 00 00 00 07 00 00 00 r0 = 0x7 + 84 b7 00 00 00 04 00 00 00 r0 = 0x4 85 95 00 00 00 00 00 00 00 exit - 86 b7 00 00 00 04 00 00 00 r0 = 0x4 + 86 b7 00 00 00 06 00 00 00 r0 = 0x6 87 95 00 00 00 00 00 00 00 exit - 88 b7 00 00 00 06 00 00 00 r0 = 0x6 + 88 b7 00 00 00 03 00 00 00 r0 = 0x3 89 95 00 00 00 00 00 00 00 exit - 90 b7 00 00 00 03 00 00 00 r0 = 0x3 + 90 b7 00 00 00 05 00 00 00 r0 = 0x5 91 95 00 00 00 00 00 00 00 exit - 92 b7 00 00 00 05 00 00 00 r0 = 0x5 - 93 95 00 00 00 00 00 00 00 exit - 94 b7 00 00 00 02 00 00 00 r0 = 0x2 - 95 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 92 b7 00 00 00 02 00 00 00 r0 = 0x2 + 93 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 91699bdb..e817baed 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -130,7 +130,7 @@ Disassembly of section .text b8 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] c0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 c8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - d0 07 03 00 00 b0 a1 00 00 add64 r3, 0xa1b0 + d0 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 d8 bf a4 00 00 00 00 00 00 mov64 r4, r10 e0 07 04 00 00 18 00 00 00 add64 r4, 0x18 e8 bf a5 00 00 00 00 00 00 mov64 r5, r10 diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index dc354aa0..7d73d8f6 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -31,7 +31,7 @@ jmp_0040: ldxdw r2, [r2-8] jne r2, 0, jmp_0208 mov64 r3, r1 - add64 r3, 41392 + add64 r3, 41400 mov64 r4, r10 add64 r4, 24 mov64 r5, r10 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index f8aeda0f..b2381e62 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -67,7 +67,7 @@ .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. # Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41392 +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 73a27968..79eceebf 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,31 +1,38 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 3032 | 3035 | +3 | +0.1% | -| PDA mismatch chunk 2 | 3032 | 3035 | +3 | +0.1% | -| PDA mismatch chunk 3 | 3032 | 3035 | +3 | +0.1% | -| PDA mismatch chunk 4 | 3032 | 3035 | +3 | +0.1% | +| PDA mismatch chunk 1 | 1532 | 1535 | +3 | +0.2% | +| PDA mismatch chunk 2 | 1535 | 1538 | +3 | +0.2% | +| PDA mismatch chunk 3 | 1538 | 1541 | +3 | +0.2% | +| PDA mismatch chunk 4 | 1541 | 1545 | +4 | +0.3% | +| PDA match (happy path) | 1540 | 1543 | +3 | +0.2% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3032 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 3035 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1540 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1543 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 6e1b6bc4..7cd372b9 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -130,7 +130,7 @@ pub struct RuntimeAccount { type EmptyRuntimeAccount = RuntimeAccount<{ runtime_data_size(data::DATA_LEN_ZERO as usize) }>; type SystemProgramRuntimeAccount = RuntimeAccount<{ runtime_data_size(input_buffer::SYSTEM_PROGRAM_DATA_LEN) }>; -type RentRuntimeAccount = RuntimeAccount<{ runtime_data_size(size_of::()) }>; +type RentRuntimeAccount = RuntimeAccount<{ runtime_data_size(input_buffer::RENT_DATA_LEN) }>; /// Compute the data buffer size for a runtime account with the given data length. const fn runtime_data_size(data_len: usize) -> usize { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index f0275191..1cb95974 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -68,7 +68,7 @@ .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. # Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41392 +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 # Init stack frame layout. # ------------------------ From b6091698defc90a95f0d026ae85ff026eb5e89cb Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:04:55 -0800 Subject: [PATCH 113/263] Take out tempo happy path test --- examples/tree/src/tests/init.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 8a8a7fc1..32f12623 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -106,7 +106,6 @@ pub(super) enum InitCase { PdaMismatchChunk1, PdaMismatchChunk2, PdaMismatchChunk3, - PdaMatch, } impl InitCase { @@ -126,7 +125,6 @@ impl InitCase { Self::PdaMismatchChunk1, Self::PdaMismatchChunk2, Self::PdaMismatchChunk3, - Self::PdaMatch, ]; } @@ -145,7 +143,6 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", - Self::PdaMatch => "PDA match (happy path)", } } @@ -244,10 +241,6 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => run_pda_mismatch_chunk(lang, 1), Self::PdaMismatchChunk2 => run_pda_mismatch_chunk(lang, 2), Self::PdaMismatchChunk3 => run_pda_mismatch_chunk(lang, 3), - Self::PdaMatch => { - let (setup, instruction, accounts) = pda_init_setup(lang); - check_success(&setup, &instruction, &accounts) - } } } } From 28e87242deaf1626689cf5f608609673e4accbd8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:49:56 -0800 Subject: [PATCH 114/263] Optimize rent sysvar pubkey compare --- docs/src/examples/tree.md | 6 +- examples/tree/artifacts/dumps/asm.txt | 142 +++++++++-------- examples/tree/artifacts/dumps/rs.txt | 142 +++++++++-------- examples/tree/artifacts/rs-disassembly.s | 62 ++++---- .../tree/artifacts/snippets/asm/constants.txt | 18 ++- .../snippets/asm/initialize-input-checks.txt | 25 ++- .../snippets/asm/initialize-pda-checks.txt | 24 +-- .../snippets/rs/initialize-input-checks.txt | 6 +- .../tests/entrypoint_branching/result.txt | 8 + .../tests/entrypoint_branching/test.txt | 2 +- .../tests/initialize_input_checks/result.txt | 41 ++++- .../tests/initialize_input_checks/test.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 41 ++--- .../tests/initialize_pda_checks/test.txt | 2 +- examples/tree/interface/src/asm.rs | 10 +- examples/tree/interface/src/common.rs | 2 +- examples/tree/macros/src/lib.rs | 144 ++++++++++++++++++ examples/tree/src/program.rs | 10 +- examples/tree/src/tests.rs | 14 +- examples/tree/src/tests/init.rs | 58 +++---- examples/tree/src/tree/tree.s | 71 ++++++--- 21 files changed, 564 insertions(+), 266 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index cb8bdc76..63af5e26 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -35,7 +35,7 @@ performance. ::: - + @@ -51,10 +51,12 @@ performance. ::: - + + + ## :white_check_mark: All tests ::: details `tests.rs` diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 32fee4f8..b1d6e6f9 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1096 (bytes into file) + Start of section headers 1200 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x448 +There are 7 section headers, starting at offset 0x4b0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000208 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000002f0 0002f0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000390 000390 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000003d8 0003d8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000408 000408 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000418 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000270 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000358 000358 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000003f8 0003f8 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000440 000440 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000470 000470 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000480 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000208 0x000208 R E 0x1000 - LOAD 0x000390 0x0000000000000390 0x0000000000000390 0x000088 0x000088 R 0x1000 - DYNAMIC 0x0002f0 0x00000000000002f0 0x00000000000002f0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000270 0x000270 R E 0x1000 + LOAD 0x0003f8 0x00000000000003f8 0x00000000000003f8 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000358 0x0000000000000358 0x0000000000000358 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,22 +52,22 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x2f0 contains 10 entries +Dynamic section at offset 0x358 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x408 + 0x0000000000000011 (REL) 0x470 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x390 + 0x0000000000000006 (SYMTAB) 0x3f8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x3d8 + 0x0000000000000005 (STRTAB) 0x440 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x408 contains 1 entries +Relocation section '.rel.dyn' at offset 0x470 contains 1 entries Offset Info Type Symbol's Value Symbol's Name -00000000000001f0 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address Symbol table '.dynsym' contains 3 entries Num Value Size Type Bind Vis Ndx Name @@ -92,57 +92,67 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 33 00 00 00 00 00 if r9 != 0x0 goto +0x33 + 40 55 09 40 00 00 00 00 00 if r9 != 0x0 goto +0x40 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 2f 00 ff 00 00 00 if r9 != 0xff goto +0x2f + 42 55 09 3c 00 ff 00 00 00 if r9 != 0xff goto +0x3c 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 2b 00 00 00 00 00 if r9 != 0x0 goto +0x2b + 44 55 09 38 00 00 00 00 00 if r9 != 0x0 goto +0x38 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 27 00 ff 00 00 00 if r9 != 0xff goto +0x27 + 46 55 09 34 00 ff 00 00 00 if r9 != 0xff goto +0x34 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 23 00 0e 00 00 00 if r9 != 0xe goto +0x23 + 48 55 09 30 00 0e 00 00 00 if r9 != 0xe goto +0x30 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 1f 00 ff 00 00 00 if r9 != 0xff goto +0x1f - 51 79 19 88 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7988) - 52 55 09 1b 00 11 00 00 00 if r9 != 0x11 goto +0x1b - 53 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 54 55 09 15 00 00 00 00 00 if r9 != 0x0 goto +0x15 - 55 b7 02 00 00 00 00 00 00 r2 = 0x0 - 56 bf 13 00 00 00 00 00 00 r3 = r1 - 57 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 - 58 bf a4 00 00 00 00 00 00 r4 = r10 - 59 07 04 00 00 98 ff ff ff r4 += -0x68 - 60 bf a5 00 00 00 00 00 00 r5 = r10 - 61 07 05 00 00 98 fe ff ff r5 += -0x168 - 62 85 10 00 00 ff ff ff ff call -0x1 - 63 79 18 70 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2870) - 64 79 47 00 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x0) - 65 5d 78 0c 00 00 00 00 00 if r8 != r7 goto +0xc - 66 79 18 78 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2878) - 67 79 47 08 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x8) - 68 5d 78 09 00 00 00 00 00 if r8 != r7 goto +0x9 - 69 79 18 80 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2880) - 70 79 47 10 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x10) - 71 5d 78 06 00 00 00 00 00 if r8 != r7 goto +0x6 - 72 79 18 88 28 00 00 00 00 r8 = *(u64 *)(r1 + 0x2888) - 73 79 47 18 00 00 00 00 00 r7 = *(u64 *)(r4 + 0x18) - 74 5d 78 03 00 00 00 00 00 if r8 != r7 goto +0x3 - 75 95 00 00 00 00 00 00 00 exit - 76 b7 00 00 00 09 00 00 00 r0 = 0x9 - 77 95 00 00 00 00 00 00 00 exit - 78 b7 00 00 00 0a 00 00 00 r0 = 0xa - 79 95 00 00 00 00 00 00 00 exit - 80 b7 00 00 00 08 00 00 00 r0 = 0x8 - 81 95 00 00 00 00 00 00 00 exit - 82 b7 00 00 00 07 00 00 00 r0 = 0x7 - 83 95 00 00 00 00 00 00 00 exit - 84 b7 00 00 00 04 00 00 00 r0 = 0x4 - 85 95 00 00 00 00 00 00 00 exit - 86 b7 00 00 00 06 00 00 00 r0 = 0x6 - 87 95 00 00 00 00 00 00 00 exit - 88 b7 00 00 00 03 00 00 00 r0 = 0x3 - 89 95 00 00 00 00 00 00 00 exit - 90 b7 00 00 00 05 00 00 00 r0 = 0x5 - 91 95 00 00 00 00 00 00 00 exit - 92 b7 00 00 00 02 00 00 00 r0 = 0x2 - 93 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 50 55 09 2c 00 ff 00 00 00 if r9 != 0xff goto +0x2c + 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) + 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll + 54 5d 89 26 00 00 00 00 00 if r9 != r8 goto +0x26 + 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) + 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll + 58 5d 89 22 00 00 00 00 00 if r9 != r8 goto +0x22 + 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) + 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll + 62 5d 89 1e 00 00 00 00 00 if r9 != r8 goto +0x1e + 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) + 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d + 65 5d 89 1b 00 00 00 00 00 if r9 != r8 goto +0x1b + 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 67 55 09 15 00 00 00 00 00 if r9 != 0x0 goto +0x15 + 68 b7 02 00 00 00 00 00 00 r2 = 0x0 + 69 bf 13 00 00 00 00 00 00 r3 = r1 + 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 + 71 bf a4 00 00 00 00 00 00 r4 = r10 + 72 07 04 00 00 98 ff ff ff r4 += -0x68 + 73 bf a5 00 00 00 00 00 00 r5 = r10 + 74 07 05 00 00 98 fe ff ff r5 += -0x168 + 75 85 10 00 00 ff ff ff ff call -0x1 + 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) + 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) + 78 5d 89 0c 00 00 00 00 00 if r9 != r8 goto +0xc + 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) + 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) + 81 5d 89 09 00 00 00 00 00 if r9 != r8 goto +0x9 + 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) + 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 84 5d 89 06 00 00 00 00 00 if r9 != r8 goto +0x6 + 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) + 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) + 87 5d 89 03 00 00 00 00 00 if r9 != r8 goto +0x3 + 88 95 00 00 00 00 00 00 00 exit + 89 b7 00 00 00 09 00 00 00 r0 = 0x9 + 90 95 00 00 00 00 00 00 00 exit + 91 b7 00 00 00 0a 00 00 00 r0 = 0xa + 92 95 00 00 00 00 00 00 00 exit + 93 b7 00 00 00 08 00 00 00 r0 = 0x8 + 94 95 00 00 00 00 00 00 00 exit + 95 b7 00 00 00 07 00 00 00 r0 = 0x7 + 96 95 00 00 00 00 00 00 00 exit + 97 b7 00 00 00 04 00 00 00 r0 = 0x4 + 98 95 00 00 00 00 00 00 00 exit + 99 b7 00 00 00 06 00 00 00 r0 = 0x6 + 100 95 00 00 00 00 00 00 00 exit + 101 b7 00 00 00 03 00 00 00 r0 = 0x3 + 102 95 00 00 00 00 00 00 00 exit + 103 b7 00 00 00 05 00 00 00 r0 = 0x5 + 104 95 00 00 00 00 00 00 00 exit + 105 b7 00 00 00 02 00 00 00 r0 = 0x2 + 106 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index e817baed..85b8db44 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3112 (bytes into file) + Start of section headers 3208 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xc28 +There are 8 section headers, starting at offset 0xc88 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000218 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000338 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000340 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000340 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000340 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0006b8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0006f6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000278 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000398 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 0003a0 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 0003a0 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 0003a0 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000718 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000756 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000218 0x000218 E 0x8 - LOAD 0x000338 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000340 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000340 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000278 0x000278 E 0x8 + LOAD 0x000398 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x0003a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x0003a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 536 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 632 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,62 +112,74 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 2a 00 04 00 00 00 jne r3, 0x4, +0x2a + 40 55 03 38 00 04 00 00 00 jne r3, 0x4, +0x38 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 26 00 00 00 00 00 jne r3, 0x0, +0x26 + 50 55 03 34 00 00 00 00 00 jne r3, 0x0, +0x34 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 + 60 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 28 00 00 00 00 00 jne r3, 0x0, +0x28 + 70 55 03 36 00 00 00 00 00 jne r3, 0x0, +0x36 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 + 80 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 28 00 0e 00 00 00 jne r3, 0xe, +0x28 + 90 55 03 36 00 0e 00 00 00 jne r3, 0xe, +0x36 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 28 00 ff 00 00 00 jne r3, 0xff, +0x28 - a8 9c 13 88 79 00 00 00 00 ldxdw r3, [r1 + 0x7988] - b0 55 03 28 00 11 00 00 00 jne r3, 0x11, +0x28 - b8 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - c0 55 02 28 00 00 00 00 00 jne r2, 0x0, +0x28 - c8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - d0 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 - d8 bf a4 00 00 00 00 00 00 mov64 r4, r10 - e0 07 04 00 00 18 00 00 00 add64 r4, 0x18 - e8 bf a5 00 00 00 00 00 00 mov64 r5, r10 - f0 07 05 00 00 3f 00 00 00 add64 r5, 0x3f - f8 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 100 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 108 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 110 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 118 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 120 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa - 128 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 130 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 138 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 - 140 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 148 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 150 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 - 158 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] - 160 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 168 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 170 1d 21 d8 ff 00 00 00 00 jeq r1, r2, -0x28 - 178 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 180 05 00 d6 ff 00 00 00 00 ja -0x2a - 188 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 190 05 00 d4 ff 00 00 00 00 ja -0x2c - 198 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 1a0 05 00 d2 ff 00 00 00 00 ja -0x2e - 1a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 1b0 05 00 d0 ff 00 00 00 00 ja -0x30 - 1b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 1c0 05 00 ce ff 00 00 00 00 ja -0x32 - 1c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 1d0 05 00 cc ff 00 00 00 00 ja -0x34 - 1d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 1e0 05 00 ca ff 00 00 00 00 ja -0x36 - 1e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + a0 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 + b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 + c0 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] + c8 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 + d0 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 + d8 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d + e0 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] + e8 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 + f0 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 + f8 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b + 100 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] + 108 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b + 110 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] + 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d + 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e + 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] + 130 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 + 138 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 140 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 + 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 150 07 04 00 00 18 00 00 00 add64 r4, 0x18 + 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 160 07 05 00 00 3f 00 00 00 add64 r5, 0x3f + 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 180 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 190 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa + 198 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 1a8 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 + 1b0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 1c0 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 + 1c8 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1d8 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] + 1e0 1d 21 ca ff 00 00 00 00 jeq r1, r2, -0x36 + 1e8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 - 1f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 1f8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 200 05 00 c6 ff 00 00 00 00 ja -0x3a - 208 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 210 05 00 c4 ff 00 00 00 00 ja -0x3c \ No newline at end of file + 208 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 210 05 00 c4 ff 00 00 00 00 ja -0x3c + 218 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 220 05 00 c2 ff 00 00 00 00 ja -0x3e + 228 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 230 05 00 c0 ff 00 00 00 00 ja -0x40 + 238 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 240 05 00 be ff 00 00 00 00 ja -0x42 + 248 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 250 05 00 bc ff 00 00 00 00 ja -0x44 + 258 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 260 05 00 ba ff 00 00 00 00 ja -0x46 + 268 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 270 05 00 b8 ff 00 00 00 00 ja -0x48 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 7d73d8f6..25b7b247 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,23 +13,37 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0198 + jne r3, 4, jmp_0208 ldxdw r3, [r1+88] - jne r3, 0, jmp_0188 + jne r3, 0, jmp_01f8 ldxb r3, [r1+10344] - jne r3, 255, jmp_01a8 + jne r3, 255, jmp_0218 ldxdw r3, [r1+10424] - jne r3, 0, jmp_01b8 + jne r3, 0, jmp_0228 ldxb r3, [r1+20680] - jne r3, 255, jmp_01c8 + jne r3, 255, jmp_0238 ldxdw r3, [r1+20760] - jne r3, 14, jmp_01d8 + jne r3, 14, jmp_0248 ldxb r3, [r1+31032] - jne r3, 255, jmp_01e8 - ldxdw r3, [r1+31112] - jne r3, 17, jmp_01f8 + jne r3, 255, jmp_0258 + mov64 r0, 8 + mov32 r3, 399877894 + hor64 r3, 1364995097 + ldxdw r4, [r1+31040] + jne r4, r3, jmp_0038 + mov32 r3, 1288277025 + hor64 r3, 2146519613 + ldxdw r4, [r1+31048] + jne r4, r3, jmp_0038 + mov32 r3, 149871192 + hor64 r3, 1157472667 + ldxdw r4, [r1+31056] + jne r4, r3, jmp_0038 + ldxdw r3, [r1+31064] + mov32 r4, -1965433885 + jne r3, r4, jmp_0038 ldxdw r2, [r2-8] - jne r2, 0, jmp_0208 + jne r2, 0, jmp_0268 mov64 r3, r1 add64 r3, 41400 mov64 r4, r10 @@ -41,54 +55,50 @@ jmp_0040: call sol_try_find_program_address ldxdw r1, [r10+24] ldxdw r2, [r6+10352] - jne r1, r2, jmp_0178 + jne r1, r2, jmp_01e8 ldxdw r1, [r10+32] ldxdw r2, [r6+10360] - jne r1, r2, jmp_0178 + jne r1, r2, jmp_01e8 ldxdw r1, [r10+40] ldxdw r2, [r6+10368] - jne r1, r2, jmp_0178 + jne r1, r2, jmp_01e8 ldxdw r1, [r10+48] mov64 r0, 0 ldxdw r2, [r6+10376] jeq r1, r2, jmp_0038 -jmp_0178: +jmp_01e8: mov64 r0, 10 ja jmp_0038 -jmp_0188: +jmp_01f8: mov64 r0, 2 ja jmp_0038 -jmp_0198: +jmp_0208: mov64 r0, 1 ja jmp_0038 -jmp_01a8: +jmp_0218: mov64 r0, 5 ja jmp_0038 -jmp_01b8: +jmp_0228: mov64 r0, 3 ja jmp_0038 -jmp_01c8: +jmp_0238: mov64 r0, 6 ja jmp_0038 -jmp_01d8: +jmp_0248: mov64 r0, 4 ja jmp_0038 -jmp_01e8: +jmp_0258: mov64 r0, 7 ja jmp_0038 -jmp_01f8: - mov64 r0, 8 - ja jmp_0038 - -jmp_0208: +jmp_0268: mov64 r0, 9 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index b2381e62..53f48746 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -9,7 +9,7 @@ # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 .equ E_RENT_DUPLICATE, 7 # The rent sysvar account is a duplicate. -.equ E_RENT_DATA_LEN, 8 # The rent sysvar account has invalid data length. +.equ E_RENT_ADDRESS, 8 # The rent sysvar account has invalid data length. # Instruction data provided during initialization instruction. .equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. @@ -66,6 +66,22 @@ # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. +.equ IB_RENT_ADDRESS_OFF_0, 31040 # Rent address field (chunk index 0). +.equ IB_RENT_ADDRESS_OFF_1, 31048 # Rent address field (chunk index 1). +.equ IB_RENT_ADDRESS_OFF_2, 31056 # Rent address field (chunk index 2). +.equ IB_RENT_ADDRESS_OFF_3, 31064 # Rent address field (chunk index 3). +.equ IB_RENT_ID_CHUNK_0, 5862609301215225606 # Rent sysvar ID (chunk 0). +.equ IB_RENT_ID_CHUNK_0_LO, 399877894 # Rent sysvar ID (chunk 0 lo). +.equ IB_RENT_ID_CHUNK_0_HI, 1364995097 # Rent sysvar ID (chunk 0 hi). +.equ IB_RENT_ID_CHUNK_1, 9219231539345853473 # Rent sysvar ID (chunk 1). +.equ IB_RENT_ID_CHUNK_1_LO, 1288277025 # Rent sysvar ID (chunk 1 lo). +.equ IB_RENT_ID_CHUNK_1_HI, 2146519613 # Rent sysvar ID (chunk 1 hi). +.equ IB_RENT_ID_CHUNK_2, 4971307250928769624 # Rent sysvar ID (chunk 2). +.equ IB_RENT_ID_CHUNK_2_LO, 149871192 # Rent sysvar ID (chunk 2 lo). +.equ IB_RENT_ID_CHUNK_2_HI, 1157472667 # Rent sysvar ID (chunk 2 hi). +.equ IB_RENT_ID_CHUNK_3, 2329533411 # Rent sysvar ID (chunk 3). +.equ IB_RENT_ID_CHUNK_3_LO, -1965433885 # Rent sysvar ID (chunk 3 lo). +.equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 656308a0..5e2961ae 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -19,12 +19,29 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len - # Error if Rent account is duplicate or has invalid length. - # --------------------------------------------------------- + # Error if Rent account is duplicate or has incorrect address. + # ------------------------------------------------------------ ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r1 + IB_RENT_DATA_LEN_OFF] - jne r9, IB_RENT_DATA_LEN, e_rent_data_len + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_0] + lddw r8, IB_RENT_ID_CHUNK_0 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_1] + lddw r8, IB_RENT_ID_CHUNK_1 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_2] + lddw r8, IB_RENT_ID_CHUNK_2 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_3] + # Optimize out the following line, which costs two CUs due to two + # 32-bit immediate loads across two opcodes: + # ``` + # lddw r8, IB_RENT_ID_CHUNK_3 + # ``` + # Instead, replace with mov32, which only loads one 32-bit immediate, + # since the rent sysvar address has all chunk 3 hit bits unset. + mov32 r8, IB_RENT_ID_CHUNK_3_LO + jne r9, r8, e_rent_address # Error if instruction data provided. # ----------------------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 5ee2ca79..3b277f7a 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -14,15 +14,15 @@ # Compare computed PDA against passed account. # -------------------------------------------- - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_0] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_1] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_2] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_3] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] - jne r8, r7, e_pda_mismatch \ No newline at end of file + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_1] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_1] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_2] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_2] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_3] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_3] + jne r9, r8, e_pda_mismatch \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 64b8ed52..1648b4e7 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -20,12 +20,12 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); - // Error if Rent account is duplicate or has invalid data length. + // Error if Rent account is duplicate or has incorrect address. let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( - rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, - error::RENT_DATA_LEN + !address_eq(rent_sysvar.address(), &RENT_ID,), + error::RENT_ADDRESS ); // Error if instruction data provided. diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index a4015b68..34848438 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -5,6 +5,14 @@ | Three accounts | 5 | 7 | +2 | +40.0% | | Five accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok +warning: function `check_success` is never used + --> tree/src/tests.rs:26:4 + | +26 | fn check_success( + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/entrypoint_branching/test.txt b/examples/tree/artifacts/tests/entrypoint_branching/test.txt index 6c056146..6cbbe3ae 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/test.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/test.txt @@ -1,4 +1,4 @@ #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES); + print_comparison_table(entrypoint::EntrypointCase::CASES, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index febf6701..e9de1b09 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -6,9 +6,20 @@ | System program is duplicate | 13 | 15 | +2 | +15.4% | | System program wrong data length | 15 | 17 | +2 | +13.3% | | Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent sysvar wrong data length | 19 | 21 | +2 | +10.5% | -| Non-empty instruction data | 21 | 23 | +2 | +9.5% | +| Rent address mismatch chunk 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch chunk 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch chunk 3 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch chunk 4 | 29 | 33 | +4 | +13.8% | +| Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok +warning: function `check_success` is never used + --> tree/src/tests.rs:26:4 + | +26 | fn check_success( + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 @@ -46,14 +57,32 @@ test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt index d179220a..bc91bf0a 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES); + print_comparison_table(init::InitCase::CASES, true); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 79eceebf..f6f1d48c 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,38 +1,39 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1532 | 1535 | +3 | +0.2% | -| PDA mismatch chunk 2 | 1535 | 1538 | +3 | +0.2% | -| PDA mismatch chunk 3 | 1538 | 1541 | +3 | +0.2% | -| PDA mismatch chunk 4 | 1541 | 1545 | +4 | +0.3% | -| PDA match (happy path) | 1540 | 1543 | +3 | +0.2% | +| PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | +| PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | +| PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | +| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | test tests::test_initialize_pda_checks ... ok +warning: function `check_success` is never used + --> tree/src/tests.rs:26:4 + | +26 | fn check_success( + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default +warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1532 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1549 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1535 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1538 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1541 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1540 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1543 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt index 5bd90196..785e888f 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES); + print_comparison_table(init::InitCase::PDA_CASES, false); } \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index a923e326..6703edd6 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -5,7 +5,11 @@ use crate::bindings::{ }; use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; -use pinocchio::{entrypoint::NON_DUP_MARKER, sysvars::rent::Rent, Address}; +use pinocchio::{ + entrypoint::NON_DUP_MARKER, + sysvars::rent::{Rent, RENT_ID}, + Address, +}; pubkey_chunk_group!(); @@ -45,6 +49,10 @@ extend_constant_group!(input_buffer { offset!(RENT_NON_DUP_MARKER, InitInputBuffer.header.rent.header.borrow_state), /// Rent account data length field. offset!(RENT_DATA_LEN, InitInputBuffer.header.rent.header.data_len), + /// Rent address field. + pubkey_offset!(RENT_ADDRESS, InitInputBuffer.header.rent.header.address), + /// Rent sysvar ID. + pubkey_value!(RENT_ID, RENT_ID), /// Program ID field for initialize instruction. offset_immediate!(INIT_PROGRAM_ID, InitInputBuffer.footer.program_id), }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 7cd372b9..847dd6b8 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -22,7 +22,7 @@ error_codes! { /// The rent sysvar account is a duplicate. RENT_DUPLICATE, /// The rent sysvar account has invalid data length. - RENT_DATA_LEN, + RENT_ADDRESS, /// Instruction data provided during initialization instruction. INSTRUCTION_DATA, /// The passed PDA does not match the expected address. diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 7905f441..53146465 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -761,6 +761,14 @@ enum AsmConstantKind { field_path: Vec, chunk_index: usize, }, + /// Chunk of a known pubkey/address constant. + /// Extracts `width` bytes at `byte_offset` from the 32-byte address. + /// Width 4 produces i32 (for LO/HI halves), width 8 produces i64 (for lddw). + PubkeyValueChunk { + expr: syn::Expr, + byte_offset: usize, + width: usize, + }, } /// Input for asm_constant_group! macro. @@ -972,6 +980,80 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> continue; } + // pubkey_value!(NAME, expr) expands to 8 chunk constants (4 LO/HI pairs). + if ident == "pubkey_value" { + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let expr: syn::Expr = inner.parse()?; + let _ = content.parse::(); + + let base_doc = const_doc.trim_end_matches('.'); + for chunk in 0..4usize { + let byte_base = chunk * 8; + + // Full i64 chunk (for lddw). + let full_name = Ident::new( + &format!("{}_CHUNK_{}", base_name, chunk), + base_name.span(), + ); + let full_doc = format!("{} (chunk {}).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&full_doc) { + return Err(content.error(e)); + } + constants.push(AsmConstantDef { + doc: full_doc, + name: full_name, + kind: AsmConstantKind::PubkeyValueChunk { + expr: expr.clone(), + byte_offset: byte_base, + width: 8, + }, + }); + + // Low i32 half (for jne reg, imm32 when sign-extension is safe). + let lo_name = Ident::new( + &format!("{}_CHUNK_{}_LO", base_name, chunk), + base_name.span(), + ); + let lo_doc = format!("{} (chunk {} lo).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&lo_doc) { + return Err(content.error(e)); + } + constants.push(AsmConstantDef { + doc: lo_doc, + name: lo_name, + kind: AsmConstantKind::PubkeyValueChunk { + expr: expr.clone(), + byte_offset: byte_base, + width: 4, + }, + }); + + // High i32 half (to check if lddw can be avoided). + let hi_name = Ident::new( + &format!("{}_CHUNK_{}_HI", base_name, chunk), + base_name.span(), + ); + let hi_doc = format!("{} (chunk {} hi).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&hi_doc) { + return Err(content.error(e)); + } + constants.push(AsmConstantDef { + doc: hi_doc, + name: hi_name, + kind: AsmConstantKind::PubkeyValueChunk { + expr: expr.clone(), + byte_offset: byte_base + 4, + width: 4, + }, + }); + } + continue; + } + let (const_name, kind) = if ident == "offset" { // Parse offset!(NAME, Struct.field.nested.path) content.parse::()?; @@ -1203,6 +1285,52 @@ fn gen_pubkey_chunk_offset_code( } } +/// Generate code for a `pubkey_value!` constant (single chunk). +/// +/// Extracts `width` bytes at `byte_offset` from a 32-byte address constant. +/// Width 4 produces i32, width 8 produces i64. +fn gen_pubkey_value_chunk_code( + name: &Ident, + doc: &str, + expr: &syn::Expr, + byte_offset: usize, + width: usize, +) -> proc_macro2::TokenStream { + if width == 8 { + let b0 = byte_offset; + let b1 = byte_offset + 1; + let b2 = byte_offset + 2; + let b3 = byte_offset + 3; + let b4 = byte_offset + 4; + let b5 = byte_offset + 5; + let b6 = byte_offset + 6; + let b7 = byte_offset + 7; + + quote! { + #[doc = #doc] + pub const #name: i64 = { + use super::*; + let bytes: [u8; 32] = unsafe { core::mem::transmute(#expr) }; + i64::from_le_bytes([bytes[#b0], bytes[#b1], bytes[#b2], bytes[#b3], bytes[#b4], bytes[#b5], bytes[#b6], bytes[#b7]]) + }; + } + } else { + let b0 = byte_offset; + let b1 = byte_offset + 1; + let b2 = byte_offset + 2; + let b3 = byte_offset + 3; + + quote! { + #[doc = #doc] + pub const #name: i32 = { + use super::*; + let bytes: [u8; 32] = unsafe { core::mem::transmute(#expr) }; + i32::from_le_bytes([bytes[#b0], bytes[#b1], bytes[#b2], bytes[#b3]]) + }; + } + } +} + /// Macro for defining ASM-only constant groups. /// /// Constants don't need types - values are `i64`, offsets are `i16`. @@ -1343,6 +1471,14 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { *chunk_index, )); } + AsmConstantKind::PubkeyValueChunk { + expr, + byte_offset, + width, + } => { + const_value_strs.push(None); + const_defs.push(gen_pubkey_value_chunk_code(name, doc, expr, *byte_offset, *width)); + } } } @@ -1572,6 +1708,14 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { *chunk_index, )); } + AsmConstantKind::PubkeyValueChunk { + expr, + byte_offset, + width, + } => { + const_value_strs.push(None); + const_defs.push(gen_pubkey_value_chunk_code(name, doc, expr, *byte_offset, *width)); + } } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index b61065eb..b89e43ec 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -2,7 +2,9 @@ use core::mem::transmute; use pinocchio::{ address::address_eq, hint::{likely, unlikely}, - no_allocator, nostd_panic_handler, AccountView, Address, SUCCESS, + no_allocator, nostd_panic_handler, + sysvars::rent::RENT_ID, + AccountView, Address, SUCCESS, }; use tree_interface::{data, error_codes::error, input_buffer}; #[cfg(target_os = "solana")] @@ -87,12 +89,12 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - error::SYSTEM_PROGRAM_DATA_LEN ); - // Error if Rent account is duplicate or has invalid data length. + // Error if Rent account is duplicate or has incorrect address. let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( - rent_sysvar.data_len() != input_buffer::RENT_DATA_LEN, - error::RENT_DATA_LEN + !address_eq(rent_sysvar.address(), &RENT_ID,), + error::RENT_ADDRESS ); // Error if instruction data provided. diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index f80c9d1a..075b1d18 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -66,7 +66,7 @@ trait TestCase: Copy { fn run(&self, lang: ProgramLanguage) -> CaseResult; } -fn print_comparison_table(cases: &[T]) { +fn print_comparison_table(cases: &[T], allow_asm_failures: bool) { let mut failures = Vec::new(); println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); @@ -91,7 +91,11 @@ fn print_comparison_table(cases: &[T]) { ); if let Some(err) = &asm.error { - failures.push(format!(" ASM {}: {}", case.name(), err)); + if allow_asm_failures { + println!(" (ASM) {}: {}", case.name(), err); + } else { + failures.push(format!(" ASM {}: {}", case.name(), err)); + } } if let Some(err) = &rs.error { failures.push(format!(" Rust {}: {}", case.name(), err)); @@ -107,15 +111,15 @@ fn print_comparison_table(cases: &[T]) { #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES); + print_comparison_table(entrypoint::EntrypointCase::CASES, false); } #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES); + print_comparison_table(init::InitCase::CASES, true); } #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES); + print_comparison_table(init::InitCase::PDA_CASES, false); } diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 32f12623..ea24e39e 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -74,22 +74,21 @@ fn pda_init_setup( (setup, instruction, accounts) } -fn run_pda_mismatch_chunk(lang: ProgramLanguage, chunk: usize) -> CaseResult { +fn run_address_mismatch_chunk( + lang: ProgramLanguage, + account_index: usize, + chunk: usize, + expected_error: error_codes::error, +) -> CaseResult { const FINAL_BIT: usize = size_of::() - 1; let (setup, mut instruction, mut accounts) = pda_init_setup(lang); let flip_index = (chunk * size_of::()) + FINAL_BIT; - accounts[AccountIndex::Tree as usize].0.as_mut()[flip_index] ^= 1; - instruction.accounts[AccountIndex::Tree as usize].pubkey = - accounts[AccountIndex::Tree as usize].0; - - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::PDA_MISMATCH, - ) + accounts[account_index].0.as_mut()[flip_index] ^= 1; + instruction.accounts[account_index].pubkey = accounts[account_index].0; + + check_error(&setup, &instruction, &accounts, expected_error) } #[derive(Clone, Copy)] @@ -100,7 +99,10 @@ pub(super) enum InitCase { SystemProgramDuplicate, SystemProgramDataLen, RentDuplicate, - RentDataLen, + RentAddressChunk0, + RentAddressChunk1, + RentAddressChunk2, + RentAddressChunk3, InstructionData, PdaMismatchChunk0, PdaMismatchChunk1, @@ -116,7 +118,10 @@ impl InitCase { Self::SystemProgramDuplicate, Self::SystemProgramDataLen, Self::RentDuplicate, - Self::RentDataLen, + Self::RentAddressChunk0, + Self::RentAddressChunk1, + Self::RentAddressChunk2, + Self::RentAddressChunk3, Self::InstructionData, ]; @@ -137,7 +142,10 @@ impl TestCase for InitCase { Self::SystemProgramDuplicate => "System program is duplicate", Self::SystemProgramDataLen => "System program wrong data length", Self::RentDuplicate => "Rent sysvar is duplicate", - Self::RentDataLen => "Rent sysvar wrong data length", + Self::RentAddressChunk0 => "Rent address mismatch chunk 1", + Self::RentAddressChunk1 => "Rent address mismatch chunk 2", + Self::RentAddressChunk2 => "Rent address mismatch chunk 3", + Self::RentAddressChunk3 => "Rent address mismatch chunk 4", Self::InstructionData => "Non-empty instruction data", Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", @@ -217,16 +225,10 @@ impl TestCase for InitCase { error_codes::error::RENT_DUPLICATE, ) } - Self::RentDataLen => { - let (setup, instruction, mut accounts) = init_setup(lang); - accounts[AccountIndex::RentSysvar as usize].1.data = vec![]; - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::RENT_DATA_LEN, - ) - } + Self::RentAddressChunk0 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 0, error_codes::error::RENT_ADDRESS), + Self::RentAddressChunk1 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 1, error_codes::error::RENT_ADDRESS), + Self::RentAddressChunk2 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 2, error_codes::error::RENT_ADDRESS), + Self::RentAddressChunk3 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 3, error_codes::error::RENT_ADDRESS), Self::InstructionData => { let (setup, mut instruction, accounts) = init_setup(lang); instruction.data = vec![1u8; 1]; @@ -237,10 +239,10 @@ impl TestCase for InitCase { error_codes::error::INSTRUCTION_DATA, ) } - Self::PdaMismatchChunk0 => run_pda_mismatch_chunk(lang, 0), - Self::PdaMismatchChunk1 => run_pda_mismatch_chunk(lang, 1), - Self::PdaMismatchChunk2 => run_pda_mismatch_chunk(lang, 2), - Self::PdaMismatchChunk3 => run_pda_mismatch_chunk(lang, 3), + Self::PdaMismatchChunk0 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 0, error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk1 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 1, error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk2 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 2, error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk3 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 3, error_codes::error::PDA_MISMATCH), } } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 1cb95974..b530a033 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -10,7 +10,7 @@ # The System Program account is a duplicate. .equ E_SYSTEM_PROGRAM_DUPLICATE, 6 .equ E_RENT_DUPLICATE, 7 # The rent sysvar account is a duplicate. -.equ E_RENT_DATA_LEN, 8 # The rent sysvar account has invalid data length. +.equ E_RENT_ADDRESS, 8 # The rent sysvar account has invalid data length. # Instruction data provided during initialization instruction. .equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. @@ -67,6 +67,22 @@ # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 .equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. +.equ IB_RENT_ADDRESS_OFF_0, 31040 # Rent address field (chunk index 0). +.equ IB_RENT_ADDRESS_OFF_1, 31048 # Rent address field (chunk index 1). +.equ IB_RENT_ADDRESS_OFF_2, 31056 # Rent address field (chunk index 2). +.equ IB_RENT_ADDRESS_OFF_3, 31064 # Rent address field (chunk index 3). +.equ IB_RENT_ID_CHUNK_0, 5862609301215225606 # Rent sysvar ID (chunk 0). +.equ IB_RENT_ID_CHUNK_0_LO, 399877894 # Rent sysvar ID (chunk 0 lo). +.equ IB_RENT_ID_CHUNK_0_HI, 1364995097 # Rent sysvar ID (chunk 0 hi). +.equ IB_RENT_ID_CHUNK_1, 9219231539345853473 # Rent sysvar ID (chunk 1). +.equ IB_RENT_ID_CHUNK_1_LO, 1288277025 # Rent sysvar ID (chunk 1 lo). +.equ IB_RENT_ID_CHUNK_1_HI, 2146519613 # Rent sysvar ID (chunk 1 hi). +.equ IB_RENT_ID_CHUNK_2, 4971307250928769624 # Rent sysvar ID (chunk 2). +.equ IB_RENT_ID_CHUNK_2_LO, 149871192 # Rent sysvar ID (chunk 2 lo). +.equ IB_RENT_ID_CHUNK_2_HI, 1157472667 # Rent sysvar ID (chunk 2 hi). +.equ IB_RENT_ID_CHUNK_3, 2329533411 # Rent sysvar ID (chunk 3). +.equ IB_RENT_ID_CHUNK_3_LO, -1965433885 # Rent sysvar ID (chunk 3 lo). +.equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 @@ -127,12 +143,29 @@ initialize: ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len - # Error if Rent account is duplicate or has invalid length. - # --------------------------------------------------------- + # Error if Rent account is duplicate or has incorrect address. + # ------------------------------------------------------------ ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r1 + IB_RENT_DATA_LEN_OFF] - jne r9, IB_RENT_DATA_LEN, e_rent_data_len + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_0] + lddw r8, IB_RENT_ID_CHUNK_0 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_1] + lddw r8, IB_RENT_ID_CHUNK_1 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_2] + lddw r8, IB_RENT_ID_CHUNK_2 + jne r9, r8, e_rent_address + ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_3] + # Optimize out the following line, which costs two CUs due to two + # 32-bit immediate loads across two opcodes: + # ``` + # lddw r8, IB_RENT_ID_CHUNK_3 + # ``` + # Instead, replace with mov32, which only loads one 32-bit immediate, + # since the rent sysvar address has all chunk 3 hit bits unset. + mov32 r8, IB_RENT_ID_CHUNK_3_LO + jne r9, r8, e_rent_address # Error if instruction data provided. # ----------------------------------- @@ -157,18 +190,18 @@ initialize: # Compare computed PDA against passed account. # -------------------------------------------- - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_0] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_0] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_1] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_1] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_2] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_2] - jne r8, r7, e_pda_mismatch - ldxdw r8, [r1 + IB_TREE_ADDRESS_OFF_3] - ldxdw r7, [r4 + PUBKEY_CHUNK_OFF_3] - jne r8, r7, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_1] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_1] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_2] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_2] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_3] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_3] + jne r9, r8, e_pda_mismatch # ANCHOR_END: initialize-pda-checks # Initialize signer seed for PDA bump key. @@ -187,8 +220,8 @@ e_pda_mismatch: mov64 r0, E_PDA_MISMATCH exit -e_rent_data_len: - mov64 r0, E_RENT_DATA_LEN +e_rent_address: + mov64 r0, E_RENT_ADDRESS exit e_rent_duplicate: From 5b3e8ad17c3cb7df23ff380b5efe0bf0723f35f5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:01:48 -0800 Subject: [PATCH 115/263] Correct comment --- .../tree/artifacts/snippets/asm/initialize-input-checks.txt | 2 +- examples/tree/src/tree/tree.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 5e2961ae..2e5f7204 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -39,7 +39,7 @@ initialize: # lddw r8, IB_RENT_ID_CHUNK_3 # ``` # Instead, replace with mov32, which only loads one 32-bit immediate, - # since the rent sysvar address has all chunk 3 hit bits unset. + # since the rent sysvar address has all chunk 3 hi bits unset. mov32 r8, IB_RENT_ID_CHUNK_3_LO jne r9, r8, e_rent_address diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b530a033..24593600 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -163,7 +163,7 @@ initialize: # lddw r8, IB_RENT_ID_CHUNK_3 # ``` # Instead, replace with mov32, which only loads one 32-bit immediate, - # since the rent sysvar address has all chunk 3 hit bits unset. + # since the rent sysvar address has all chunk 3 hi bits unset. mov32 r8, IB_RENT_ID_CHUNK_3_LO jne r9, r8, e_rent_address From 44da0c5c168d1098e759f9e93329b954538bf0f7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:21:31 -0800 Subject: [PATCH 116/263] Test chunks --- docs/src/examples/tree.md | 2 +- .../tests/initialize_input_checks/result.txt | 36 ++++++++-- examples/tree/src/tests/init.rs | 65 ++++++++++++------- 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 63af5e26..1f624a88 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -35,7 +35,7 @@ performance. ::: - + diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index e9de1b09..09a88631 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -6,10 +6,14 @@ | System program is duplicate | 13 | 15 | +2 | +15.4% | | System program wrong data length | 15 | 17 | +2 | +13.3% | | Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch chunk 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch chunk 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch chunk 3 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch chunk 4 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | | Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok warning: function `check_success` is never used @@ -63,6 +67,18 @@ warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] @@ -75,6 +91,18 @@ warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index ea24e39e..38cff7eb 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -74,17 +74,16 @@ fn pda_init_setup( (setup, instruction, accounts) } -fn run_address_mismatch_chunk( +fn run_address_mismatch( lang: ProgramLanguage, account_index: usize, - chunk: usize, + word_index: usize, + word_size: usize, expected_error: error_codes::error, ) -> CaseResult { - const FINAL_BIT: usize = size_of::() - 1; - let (setup, mut instruction, mut accounts) = pda_init_setup(lang); - let flip_index = (chunk * size_of::()) + FINAL_BIT; + let flip_index = (word_index * word_size) + (word_size - 1); accounts[account_index].0.as_mut()[flip_index] ^= 1; instruction.accounts[account_index].pubkey = accounts[account_index].0; @@ -99,10 +98,14 @@ pub(super) enum InitCase { SystemProgramDuplicate, SystemProgramDataLen, RentDuplicate, - RentAddressChunk0, - RentAddressChunk1, - RentAddressChunk2, - RentAddressChunk3, + RentAddressWord0, + RentAddressWord1, + RentAddressWord2, + RentAddressWord3, + RentAddressWord4, + RentAddressWord5, + RentAddressWord6, + RentAddressWord7, InstructionData, PdaMismatchChunk0, PdaMismatchChunk1, @@ -118,10 +121,14 @@ impl InitCase { Self::SystemProgramDuplicate, Self::SystemProgramDataLen, Self::RentDuplicate, - Self::RentAddressChunk0, - Self::RentAddressChunk1, - Self::RentAddressChunk2, - Self::RentAddressChunk3, + Self::RentAddressWord0, + Self::RentAddressWord1, + Self::RentAddressWord2, + Self::RentAddressWord3, + Self::RentAddressWord4, + Self::RentAddressWord5, + Self::RentAddressWord6, + Self::RentAddressWord7, Self::InstructionData, ]; @@ -142,10 +149,14 @@ impl TestCase for InitCase { Self::SystemProgramDuplicate => "System program is duplicate", Self::SystemProgramDataLen => "System program wrong data length", Self::RentDuplicate => "Rent sysvar is duplicate", - Self::RentAddressChunk0 => "Rent address mismatch chunk 1", - Self::RentAddressChunk1 => "Rent address mismatch chunk 2", - Self::RentAddressChunk2 => "Rent address mismatch chunk 3", - Self::RentAddressChunk3 => "Rent address mismatch chunk 4", + Self::RentAddressWord0 => "Rent address mismatch word 0", + Self::RentAddressWord1 => "Rent address mismatch word 1", + Self::RentAddressWord2 => "Rent address mismatch word 2", + Self::RentAddressWord3 => "Rent address mismatch word 3", + Self::RentAddressWord4 => "Rent address mismatch word 4", + Self::RentAddressWord5 => "Rent address mismatch word 5", + Self::RentAddressWord6 => "Rent address mismatch word 6", + Self::RentAddressWord7 => "Rent address mismatch word 7", Self::InstructionData => "Non-empty instruction data", Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", @@ -225,10 +236,14 @@ impl TestCase for InitCase { error_codes::error::RENT_DUPLICATE, ) } - Self::RentAddressChunk0 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 0, error_codes::error::RENT_ADDRESS), - Self::RentAddressChunk1 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 1, error_codes::error::RENT_ADDRESS), - Self::RentAddressChunk2 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 2, error_codes::error::RENT_ADDRESS), - Self::RentAddressChunk3 => run_address_mismatch_chunk(lang, AccountIndex::RentSysvar as usize, 3, error_codes::error::RENT_ADDRESS), + Self::RentAddressWord0 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 0, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord1 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 1, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord2 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 2, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord3 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 3, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord4 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 4, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord5 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 5, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord6 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 6, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord7 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 7, size_of::(), error_codes::error::RENT_ADDRESS), Self::InstructionData => { let (setup, mut instruction, accounts) = init_setup(lang); instruction.data = vec![1u8; 1]; @@ -239,10 +254,10 @@ impl TestCase for InitCase { error_codes::error::INSTRUCTION_DATA, ) } - Self::PdaMismatchChunk0 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 0, error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk1 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 1, error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk2 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 2, error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk3 => run_address_mismatch_chunk(lang, AccountIndex::Tree as usize, 3, error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk0 => run_address_mismatch(lang, AccountIndex::Tree as usize, 0, size_of::(), error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk1 => run_address_mismatch(lang, AccountIndex::Tree as usize, 1, size_of::(), error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk2 => run_address_mismatch(lang, AccountIndex::Tree as usize, 2, size_of::(), error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk3 => run_address_mismatch(lang, AccountIndex::Tree as usize, 3, size_of::(), error_codes::error::PDA_MISMATCH), } } } From e48c7541401336fb5481d843f637bda58e086a00 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:39:24 -0800 Subject: [PATCH 117/263] Clean up ptr syntax --- .../artifacts/snippets/rs/initialize-input-checks.txt | 2 +- .../artifacts/snippets/rs/initialize-pda-checks.txt | 6 ++---- .../artifacts/tests/initialize_input_checks/test.txt | 2 +- .../artifacts/tests/initialize_pda_checks/result.txt | 1 + examples/tree/src/program.rs | 11 +++++------ examples/tree/src/tests.rs | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 1648b4e7..4912538c 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -24,7 +24,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( - !address_eq(rent_sysvar.address(), &RENT_ID,), + !address_eq(rent_sysvar.address(), &RENT_ID), error::RENT_ADDRESS ); diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 3061d6cb..61701537 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -22,10 +22,8 @@ if_err!( !address_eq( &pda, - #[allow(clippy::transmute_ptr_to_ref)] - transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), - ), + #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] + transmute(input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) ), error::PDA_MISMATCH ); \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt index bc91bf0a..986f546b 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, true); + print_comparison_table(init::InitCase::CASES, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index f6f1d48c..f086a8f7 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -5,6 +5,7 @@ | PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | | PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | test tests::test_initialize_pda_checks ... ok + Blocking waiting for file lock on build directory warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index b89e43ec..1ea61589 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,5 @@ use core::mem::transmute; +use core::ptr::read_unaligned; use pinocchio::{ address::address_eq, hint::{likely, unlikely}, @@ -19,7 +20,7 @@ unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { #[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { - *ptr.add(offset as usize).cast::() + read_unaligned(ptr.add(offset as usize).cast()) } /// Checks if the account is a duplicate by checking if it's borrowed, since this is equivalent @@ -93,7 +94,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( - !address_eq(rent_sysvar.address(), &RENT_ID,), + !address_eq(rent_sysvar.address(), &RENT_ID), error::RENT_ADDRESS ); @@ -130,10 +131,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - if_err!( !address_eq( &pda, - #[allow(clippy::transmute_ptr_to_ref)] - transmute::<*const u8, &Address>( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize), - ), + #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] + transmute(input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) ), error::PDA_MISMATCH ); diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 075b1d18..73862604 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -116,7 +116,7 @@ fn test_entrypoint_branching() { #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, true); + print_comparison_table(init::InitCase::CASES, false); } #[test] From 55af72b5ae22e8cd5dbc448212cf318e4041ccb6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:25:10 -0800 Subject: [PATCH 118/263] Begin CreateAccount construction --- examples/tree/artifacts/dumps/asm.txt | 86 +++++------ examples/tree/artifacts/dumps/rs.txt | 136 ++++++++++-------- examples/tree/artifacts/rs-disassembly.s | 84 ++++++----- .../tree/artifacts/snippets/asm/constants.txt | 11 +- .../snippets/rs/initialize-create-account.txt | 18 +++ .../artifacts/snippets/rs/initialize-rent.txt | 0 .../tests/initialize_pda_checks/result.txt | 5 +- examples/tree/interface/src/asm.rs | 2 - examples/tree/interface/src/common.rs | 28 +++- examples/tree/interface/src/lib.rs | 1 + examples/tree/src/program.rs | 28 +++- examples/tree/src/tree/tree.s | 17 ++- 12 files changed, 257 insertions(+), 159 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/initialize-create-account.txt delete mode 100644 examples/tree/artifacts/snippets/rs/initialize-rent.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index b1d6e6f9..1ce8128c 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1200 (bytes into file) + Start of section headers 1216 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x4b0 +There are 7 section headers, starting at offset 0x4c0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000270 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000358 000358 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000003f8 0003f8 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000440 000440 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000470 000470 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000480 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000280 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000368 000368 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000408 000408 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000450 000450 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000480 000480 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000490 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000270 0x000270 R E 0x1000 - LOAD 0x0003f8 0x00000000000003f8 0x00000000000003f8 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000358 0x0000000000000358 0x0000000000000358 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000280 0x000280 R E 0x1000 + LOAD 0x000408 0x0000000000000408 0x0000000000000408 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000368 0x0000000000000368 0x0000000000000368 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x358 contains 10 entries +Dynamic section at offset 0x368 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x470 + 0x0000000000000011 (REL) 0x480 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x3f8 + 0x0000000000000006 (SYMTAB) 0x408 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x440 + 0x0000000000000005 (STRTAB) 0x450 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x470 contains 1 entries +Relocation section '.rel.dyn' at offset 0x480 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,31 +92,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 40 00 00 00 00 00 if r9 != 0x0 goto +0x40 + 40 55 09 42 00 00 00 00 00 if r9 != 0x0 goto +0x42 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 3c 00 ff 00 00 00 if r9 != 0xff goto +0x3c + 42 55 09 3e 00 ff 00 00 00 if r9 != 0xff goto +0x3e 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 38 00 00 00 00 00 if r9 != 0x0 goto +0x38 + 44 55 09 3a 00 00 00 00 00 if r9 != 0x0 goto +0x3a 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 34 00 ff 00 00 00 if r9 != 0xff goto +0x34 + 46 55 09 36 00 ff 00 00 00 if r9 != 0xff goto +0x36 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 30 00 0e 00 00 00 if r9 != 0xe goto +0x30 + 48 55 09 32 00 0e 00 00 00 if r9 != 0xe goto +0x32 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 2c 00 ff 00 00 00 if r9 != 0xff goto +0x2c + 50 55 09 2e 00 ff 00 00 00 if r9 != 0xff goto +0x2e 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 26 00 00 00 00 00 if r9 != r8 goto +0x26 + 54 5d 89 28 00 00 00 00 00 if r9 != r8 goto +0x28 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 22 00 00 00 00 00 if r9 != r8 goto +0x22 + 58 5d 89 24 00 00 00 00 00 if r9 != r8 goto +0x24 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 1e 00 00 00 00 00 if r9 != r8 goto +0x1e + 62 5d 89 20 00 00 00 00 00 if r9 != r8 goto +0x20 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 1b 00 00 00 00 00 if r9 != r8 goto +0x1b + 65 5d 89 1d 00 00 00 00 00 if r9 != r8 goto +0x1d 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 15 00 00 00 00 00 if r9 != 0x0 goto +0x15 + 67 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,32 +127,34 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 0c 00 00 00 00 00 if r9 != r8 goto +0xc + 78 5d 89 0e 00 00 00 00 00 if r9 != r8 goto +0xe 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 09 00 00 00 00 00 if r9 != r8 goto +0x9 + 81 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 06 00 00 00 00 00 if r9 != r8 goto +0x6 + 84 5d 89 08 00 00 00 00 00 if r9 != r8 goto +0x8 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 03 00 00 00 00 00 if r9 != r8 goto +0x3 - 88 95 00 00 00 00 00 00 00 exit - 89 b7 00 00 00 09 00 00 00 r0 = 0x9 + 87 5d 89 05 00 00 00 00 00 if r9 != r8 goto +0x5 + 88 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 89 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 90 95 00 00 00 00 00 00 00 exit - 91 b7 00 00 00 0a 00 00 00 r0 = 0xa + 91 b7 00 00 00 09 00 00 00 r0 = 0x9 92 95 00 00 00 00 00 00 00 exit - 93 b7 00 00 00 08 00 00 00 r0 = 0x8 + 93 b7 00 00 00 0a 00 00 00 r0 = 0xa 94 95 00 00 00 00 00 00 00 exit - 95 b7 00 00 00 07 00 00 00 r0 = 0x7 + 95 b7 00 00 00 08 00 00 00 r0 = 0x8 96 95 00 00 00 00 00 00 00 exit - 97 b7 00 00 00 04 00 00 00 r0 = 0x4 + 97 b7 00 00 00 07 00 00 00 r0 = 0x7 98 95 00 00 00 00 00 00 00 exit - 99 b7 00 00 00 06 00 00 00 r0 = 0x6 + 99 b7 00 00 00 04 00 00 00 r0 = 0x4 100 95 00 00 00 00 00 00 00 exit - 101 b7 00 00 00 03 00 00 00 r0 = 0x3 + 101 b7 00 00 00 06 00 00 00 r0 = 0x6 102 95 00 00 00 00 00 00 00 exit - 103 b7 00 00 00 05 00 00 00 r0 = 0x5 + 103 b7 00 00 00 03 00 00 00 r0 = 0x3 104 95 00 00 00 00 00 00 00 exit - 105 b7 00 00 00 02 00 00 00 r0 = 0x2 - 106 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 105 b7 00 00 00 05 00 00 00 r0 = 0x5 + 106 95 00 00 00 00 00 00 00 exit + 107 b7 00 00 00 02 00 00 00 r0 = 0x2 + 108 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 85b8db44..87990e08 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3208 (bytes into file) + Start of section headers 3352 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xc88 +There are 8 section headers, starting at offset 0xd18 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000278 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000398 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 0003a0 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 0003a0 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 0003a0 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000718 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000756 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000308 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000428 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000430 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000430 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000430 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0007a8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0007e6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000278 0x000278 E 0x8 - LOAD 0x000398 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x0003a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x0003a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000308 0x000308 E 0x8 + LOAD 0x000428 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000430 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000430 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 632 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 776 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 38 00 04 00 00 00 jne r3, 0x4, +0x38 + 40 55 03 4a 00 04 00 00 00 jne r3, 0x4, +0x4a 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 34 00 00 00 00 00 jne r3, 0x0, +0x34 + 50 55 03 46 00 00 00 00 00 jne r3, 0x0, +0x46 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + 60 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 36 00 00 00 00 00 jne r3, 0x0, +0x36 + 70 55 03 48 00 00 00 00 00 jne r3, 0x0, +0x48 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + 80 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 36 00 0e 00 00 00 jne r3, 0xe, +0x36 + 90 55 03 48 00 0e 00 00 00 jne r3, 0xe, +0x48 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + a0 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 @@ -142,44 +142,62 @@ Disassembly of section .text 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 130 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 - 138 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 140 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 + 130 55 02 38 00 00 00 00 00 jne r2, 0x0, +0x38 + 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 140 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 18 00 00 00 add64 r4, 0x18 + 150 07 04 00 00 08 00 00 00 add64 r4, 0x8 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 3f 00 00 00 add64 r5, 0x3f - 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 160 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 180 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 190 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa - 198 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 1a8 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 - 1b0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 1c0 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 - 1c8 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] - 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1d8 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 1e0 1d 21 ca ff 00 00 00 00 jeq r1, r2, -0x36 - 1e8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 - 1f8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 200 05 00 c6 ff 00 00 00 00 ja -0x3a - 208 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 210 05 00 c4 ff 00 00 00 00 ja -0x3c - 218 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 220 05 00 c2 ff 00 00 00 00 ja -0x3e - 228 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 230 05 00 c0 ff 00 00 00 00 ja -0x40 - 238 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 240 05 00 be ff 00 00 00 00 ja -0x42 - 248 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 250 05 00 bc ff 00 00 00 00 ja -0x44 - 258 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 260 05 00 ba ff 00 00 00 00 ja -0x46 - 268 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 270 05 00 b8 ff 00 00 00 00 ja -0x48 \ No newline at end of file + 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 188 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 190 9c a1 08 00 00 00 00 00 ldxdw r1, [r10 + 0x8] + 198 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 1a0 5d 21 d2 ff 00 00 00 00 jne r1, r2, -0x2e + 1a8 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] + 1b0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1b8 5d 21 cf ff 00 00 00 00 jne r1, r2, -0x31 + 1c0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 1c8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1d0 5d 21 cc ff 00 00 00 00 jne r1, r2, -0x34 + 1d8 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 1e0 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 1e8 5d 21 c9 ff 00 00 00 00 jne r1, r2, -0x37 + 1f0 9c 71 90 79 00 00 00 00 ldxdw r1, [r7 + 0x7990] + 1f8 9c 62 18 00 00 00 00 00 ldxdw r2, [r6 + 0x18] + 200 9f 2a 34 00 00 00 00 00 stxdw [r10 + 0x34], r2 + 208 9c 62 10 00 00 00 00 00 ldxdw r2, [r6 + 0x10] + 210 9f 2a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r2 + 218 9c 62 08 00 00 00 00 00 ldxdw r2, [r6 + 0x8] + 220 9f 2a 24 00 00 00 00 00 stxdw [r10 + 0x24], r2 + 228 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] + 230 9f 2a 1c 00 00 00 00 00 stxdw [r10 + 0x1c], r2 + 238 96 01 00 00 90 00 00 00 lmul64 r1, 0x90 + 240 9f 1a 0c 00 00 00 00 00 stxdw [r10 + 0xc], r1 + 248 97 0a 14 00 10 00 00 00 stdw [r10 + 0x14], 0x10 + 250 87 0a 08 00 00 00 00 00 stw [r10 + 0x8], 0x0 + 258 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 260 07 01 00 00 08 00 00 00 add64 r1, 0x8 + 268 b7 02 00 00 34 00 00 00 mov64 r2, 0x34 + 270 95 00 00 00 eb d3 26 a2 syscall -0x5dd92c15 + 278 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 280 05 00 b6 ff 00 00 00 00 ja -0x4a + 288 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 290 05 00 b4 ff 00 00 00 00 ja -0x4c + 298 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 2a0 05 00 b2 ff 00 00 00 00 ja -0x4e + 2a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 2b0 05 00 b0 ff 00 00 00 00 ja -0x50 + 2b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 2c0 05 00 ae ff 00 00 00 00 ja -0x52 + 2c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 2d0 05 00 ac ff 00 00 00 00 ja -0x54 + 2d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 2e0 05 00 aa ff 00 00 00 00 ja -0x56 + 2e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 2f0 05 00 a8 ff 00 00 00 00 ja -0x58 + 2f8 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 300 05 00 a6 ff 00 00 00 00 ja -0x5a \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 25b7b247..dee5080d 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0208 + jne r3, 4, jmp_0298 ldxdw r3, [r1+88] - jne r3, 0, jmp_01f8 + jne r3, 0, jmp_0288 ldxb r3, [r1+10344] - jne r3, 255, jmp_0218 + jne r3, 255, jmp_02a8 ldxdw r3, [r1+10424] - jne r3, 0, jmp_0228 + jne r3, 0, jmp_02b8 ldxb r3, [r1+20680] - jne r3, 255, jmp_0238 + jne r3, 255, jmp_02c8 ldxdw r3, [r1+20760] - jne r3, 14, jmp_0248 + jne r3, 14, jmp_02d8 ldxb r3, [r1+31032] - jne r3, 255, jmp_0258 + jne r3, 255, jmp_02e8 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 @@ -43,62 +43,78 @@ jmp_0040: mov32 r4, -1965433885 jne r3, r4, jmp_0038 ldxdw r2, [r2-8] - jne r2, 0, jmp_0268 - mov64 r3, r1 - add64 r3, 41400 + jne r2, 0, jmp_02f8 + mov64 r6, r1 + add64 r6, 41400 mov64 r4, r10 - add64 r4, 24 + add64 r4, 8 mov64 r5, r10 - add64 r5, 63 - mov64 r6, r1 + add64 r5, 7 + mov64 r7, r1 mov64 r2, 0 + mov64 r3, r6 call sol_try_find_program_address + mov64 r0, 10 + ldxdw r1, [r10+8] + ldxdw r2, [r7+10352] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+16] + ldxdw r2, [r7+10360] + jne r1, r2, jmp_0038 ldxdw r1, [r10+24] - ldxdw r2, [r6+10352] - jne r1, r2, jmp_01e8 + ldxdw r2, [r7+10368] + jne r1, r2, jmp_0038 ldxdw r1, [r10+32] - ldxdw r2, [r6+10360] - jne r1, r2, jmp_01e8 - ldxdw r1, [r10+40] - ldxdw r2, [r6+10368] - jne r1, r2, jmp_01e8 - ldxdw r1, [r10+48] + ldxdw r2, [r7+10376] + jne r1, r2, jmp_0038 + ldxdw r1, [r7+31120] + ldxdw r2, [r6+24] + stxdw [r10+52], r2 + ldxdw r2, [r6+16] + stxdw [r10+44], r2 + ldxdw r2, [r6+8] + stxdw [r10+36], r2 + ldxdw r2, [r6+0] + stxdw [r10+28], r2 + lmul64 r1, 144 + stxdw [r10+12], r1 + stdw [r10+20], 16 + stw [r10+8], 0 + mov64 r1, r10 + add64 r1, 8 + mov64 r2, 52 + call sol_set_return_data mov64 r0, 0 - ldxdw r2, [r6+10376] - jeq r1, r2, jmp_0038 - -jmp_01e8: - mov64 r0, 10 ja jmp_0038 -jmp_01f8: +jmp_0288: mov64 r0, 2 ja jmp_0038 -jmp_0208: +jmp_0298: mov64 r0, 1 ja jmp_0038 -jmp_0218: +jmp_02a8: mov64 r0, 5 ja jmp_0038 -jmp_0228: +jmp_02b8: mov64 r0, 3 ja jmp_0038 -jmp_0238: +jmp_02c8: mov64 r0, 6 ja jmp_0038 -jmp_0248: +jmp_02d8: mov64 r0, 4 ja jmp_0038 -jmp_0258: +jmp_02e8: mov64 r0, 7 ja jmp_0038 -jmp_0268: +jmp_02f8: mov64 r0, 9 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 53f48746..f0a74483 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -42,7 +42,8 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 -.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header, in footer. +.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header. +.equ IB_RENT_DATA_OFF, 31120 # Rent sysvar account data. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. @@ -65,7 +66,6 @@ .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 -.equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. .equ IB_RENT_ADDRESS_OFF_0, 31040 # Rent address field (chunk index 0). .equ IB_RENT_ADDRESS_OFF_1, 31048 # Rent address field (chunk index 1). .equ IB_RENT_ADDRESS_OFF_2, 31056 # Rent address field (chunk index 2). @@ -97,4 +97,9 @@ .equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign CPI. .equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. .equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. -.equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. \ No newline at end of file +.equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. +.equ CPI_TREE_DATA_LEN, 16 # Tree account data length. +# Account data scalar for base rent calculation. +.equ CPI_ACCOUNT_DATA_SCALAR, 144 +# CreateAccount discriminator for CPI. +.equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt new file mode 100644 index 00000000..f2eea815 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -0,0 +1,18 @@ + let instruction_data = CreateAccountInstructionData { + discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) + * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + space: cpi::TREE_DATA_LEN as u64, + owner: read_unaligned( + input_buffer_ptr + .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) + .cast(), + ), + }; + #[cfg(target_os = "solana")] + sol_set_return_data( + transmute(&instruction_data), + size_of::() as u64, + ); + #[cfg(not(target_os = "solana"))] + let _foo = instruction_data; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-rent.txt b/examples/tree/artifacts/snippets/rs/initialize-rent.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index f086a8f7..2ea396c6 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -3,9 +3,8 @@ | PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | | PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | | PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | -| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | +| PDA mismatch chunk 4 | 1551 | 1558 | +7 | +0.5% | test tests::test_initialize_pda_checks ... ok - Blocking waiting for file lock on build directory warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | @@ -36,5 +35,5 @@ warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 6703edd6..f9fcb63e 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -47,8 +47,6 @@ extend_constant_group!(input_buffer { offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.header.system_program.header.data_len), /// Rent account non-duplicate marker field. offset!(RENT_NON_DUP_MARKER, InitInputBuffer.header.rent.header.borrow_state), - /// Rent account data length field. - offset!(RENT_DATA_LEN, InitInputBuffer.header.rent.header.data_len), /// Rent address field. pubkey_offset!(RENT_ADDRESS, InitInputBuffer.header.rent.header.address), /// Rent sysvar ID. diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 847dd6b8..38b08071 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -2,7 +2,7 @@ use core::mem::size_of; use macros::{constant_group, error_codes}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, - sysvars::rent::Rent, + sysvars::rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, Address, }; @@ -40,8 +40,10 @@ constant_group! { offset!(TREE_ACCOUNT, InputBufferHeader.tree_header), /// System Program runtime account header. offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.header.system_program), - /// Rent sysvar account header, in footer. + /// Rent sysvar account header. offset!(RENT_ACCOUNT, InitInputBuffer.header.rent), + /// Rent sysvar account data. + offset!(RENT_DATA, InitInputBuffer.header.rent.data), /// Expected number of accounts for general instructions. N_ACCOUNTS_GENERAL: u64 = 2, /// Expected number of accounts for tree initialization. @@ -67,16 +69,22 @@ constant_group! { N_SEEDS: usize = 1, /// Number of seeds for PDA generation. N_SEEDS_TRY_FIND_PDA: u64 = 0, + /// Tree account data length. + TREE_DATA_LEN: usize = size_of::(), + /// Account data scalar for base rent calculation. + ACCOUNT_DATA_SCALAR: usize = (ACCOUNT_STORAGE_OVERHEAD as usize) + TREE_DATA_LEN, + /// CreateAccount discriminator for CPI. + CREATE_ACCOUNT_DISCRIMINATOR: u32 = 0, } } #[repr(C, packed)] /// For CPI to create tree account. pub struct CreateAccountInstructionData { - instruction_tag: u32, - lamports: u64, - space: u64, - owner: Address, + pub discriminator: u32, + pub lamports: u64, + pub space: u64, + pub owner: Address, } constant_group! { @@ -113,6 +121,14 @@ pub struct InitInputBufferHeader { pub rent: RentRuntimeAccount, } +#[repr(C, packed)] +struct TreeDataHeader { + /// Pointer to tree root. + root: u64, + /// Pointer to stack top. + top: u64, +} + #[repr(C, packed)] pub struct InitInputBufferFooter { /// No actual instruction data follows. diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 5bda0316..50d0c9ee 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -9,3 +9,4 @@ mod common; pub use asm::*; pub use common::cpi; pub use common::error_codes; +pub use common::CreateAccountInstructionData; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1ea61589..ee08d903 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -7,10 +7,11 @@ use pinocchio::{ sysvars::rent::RENT_ID, AccountView, Address, SUCCESS, }; -use tree_interface::{data, error_codes::error, input_buffer}; +use tree_interface::{cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData}; #[cfg(target_os = "solana")] use { - core::mem::MaybeUninit, pinocchio::syscalls::sol_try_find_program_address, tree_interface::cpi, + core::mem::MaybeUninit, + pinocchio::syscalls::{sol_set_return_data, sol_try_find_program_address}, }; #[inline(always)] @@ -138,9 +139,26 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // ANCHOR_END: initialize-pda-checks - // ANCHOR: initialize-rent - - // ANCHOR_END: initialize-rent + // ANCHOR: initialize-create-account + let instruction_data = CreateAccountInstructionData { + discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) + * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + space: cpi::TREE_DATA_LEN as u64, + owner: read_unaligned( + input_buffer_ptr + .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) + .cast(), + ), + }; + #[cfg(target_os = "solana")] + sol_set_return_data( + transmute(&instruction_data), + size_of::() as u64, + ); + #[cfg(not(target_os = "solana"))] + let _foo = instruction_data; + // ANCHOR_END: initialize-create-account SUCCESS } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 24593600..4be565b9 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -43,7 +43,8 @@ .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 -.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header, in footer. +.equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header. +.equ IB_RENT_DATA_OFF, 31120 # Rent sysvar account data. # Expected number of accounts for general instructions. .equ IB_N_ACCOUNTS_GENERAL, 2 # Expected number of accounts for tree initialization. @@ -66,7 +67,6 @@ .equ IB_SYSTEM_PROGRAM_DATA_LEN_OFF, 20760 # Rent account non-duplicate marker field. .equ IB_RENT_NON_DUP_MARKER_OFF, 31032 -.equ IB_RENT_DATA_LEN_OFF, 31112 # Rent account data length field. .equ IB_RENT_ADDRESS_OFF_0, 31040 # Rent address field (chunk index 0). .equ IB_RENT_ADDRESS_OFF_1, 31048 # Rent address field (chunk index 1). .equ IB_RENT_ADDRESS_OFF_2, 31056 # Rent address field (chunk index 2). @@ -99,6 +99,11 @@ .equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. .equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. +.equ CPI_TREE_DATA_LEN, 16 # Tree account data length. +# Account data scalar for base rent calculation. +.equ CPI_ACCOUNT_DATA_SCALAR, 144 +# CreateAccount discriminator for CPI. +.equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -205,10 +210,12 @@ initialize: # ANCHOR_END: initialize-pda-checks # Initialize signer seed for PDA bump key. - # ---------------------------------------- + # --------------------------------------------------------------------- + # Relies on r5 from PDA derivation syscall. + # --------------------------------------------------------------------- # Store pointer to bump seed. - # stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 - # stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. + stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 + stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. exit From 22606293827449b77bdc541827ea68624af2cbe5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:42:18 -0800 Subject: [PATCH 119/263] Begin packing create account insn --- examples/tree/artifacts/dumps/asm.txt | 109 +++++++++--------- .../tree/artifacts/snippets/asm/constants.txt | 4 + .../asm/initialize-create-account.txt | 21 ++++ examples/tree/interface/src/asm.rs | 4 + examples/tree/interface/src/common.rs | 2 +- examples/tree/src/tree/tree.s | 24 +++- 6 files changed, 110 insertions(+), 54 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/initialize-create-account.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 1ce8128c..3a0c3101 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1216 (bytes into file) + Start of section headers 1256 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x4c0 +There are 7 section headers, starting at offset 0x4e8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000280 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000368 000368 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000408 000408 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000450 000450 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000480 000480 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000490 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0002a8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000390 000390 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000430 000430 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000478 000478 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000004a8 0004a8 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0004b8 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000280 0x000280 R E 0x1000 - LOAD 0x000408 0x0000000000000408 0x0000000000000408 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000368 0x0000000000000368 0x0000000000000368 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0002a8 0x0002a8 R E 0x1000 + LOAD 0x000430 0x0000000000000430 0x0000000000000430 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000390 0x0000000000000390 0x0000000000000390 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x368 contains 10 entries +Dynamic section at offset 0x390 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x480 + 0x0000000000000011 (REL) 0x4a8 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x408 + 0x0000000000000006 (SYMTAB) 0x430 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x450 + 0x0000000000000005 (STRTAB) 0x478 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x480 contains 1 entries +Relocation section '.rel.dyn' at offset 0x4a8 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,31 +92,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 42 00 00 00 00 00 if r9 != 0x0 goto +0x42 + 40 55 09 47 00 00 00 00 00 if r9 != 0x0 goto +0x47 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 3e 00 ff 00 00 00 if r9 != 0xff goto +0x3e + 42 55 09 43 00 ff 00 00 00 if r9 != 0xff goto +0x43 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 3a 00 00 00 00 00 if r9 != 0x0 goto +0x3a + 44 55 09 3f 00 00 00 00 00 if r9 != 0x0 goto +0x3f 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 36 00 ff 00 00 00 if r9 != 0xff goto +0x36 + 46 55 09 3b 00 ff 00 00 00 if r9 != 0xff goto +0x3b 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 32 00 0e 00 00 00 if r9 != 0xe goto +0x32 + 48 55 09 37 00 0e 00 00 00 if r9 != 0xe goto +0x37 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 2e 00 ff 00 00 00 if r9 != 0xff goto +0x2e + 50 55 09 33 00 ff 00 00 00 if r9 != 0xff goto +0x33 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 28 00 00 00 00 00 if r9 != r8 goto +0x28 + 54 5d 89 2d 00 00 00 00 00 if r9 != r8 goto +0x2d 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 24 00 00 00 00 00 if r9 != r8 goto +0x24 + 58 5d 89 29 00 00 00 00 00 if r9 != r8 goto +0x29 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 20 00 00 00 00 00 if r9 != r8 goto +0x20 + 62 5d 89 25 00 00 00 00 00 if r9 != r8 goto +0x25 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 1d 00 00 00 00 00 if r9 != r8 goto +0x1d + 65 5d 89 22 00 00 00 00 00 if r9 != r8 goto +0x22 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 17 00 00 00 00 00 if r9 != 0x0 goto +0x17 + 67 55 09 1c 00 00 00 00 00 if r9 != 0x0 goto +0x1c 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,34 +127,39 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 0e 00 00 00 00 00 if r9 != r8 goto +0xe + 78 5d 89 13 00 00 00 00 00 if r9 != r8 goto +0x13 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb + 81 5d 89 10 00 00 00 00 00 if r9 != r8 goto +0x10 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 08 00 00 00 00 00 if r9 != r8 goto +0x8 + 84 5d 89 0d 00 00 00 00 00 if r9 != r8 goto +0xd 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 05 00 00 00 00 00 if r9 != r8 goto +0x5 - 88 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 89 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 90 95 00 00 00 00 00 00 00 exit - 91 b7 00 00 00 09 00 00 00 r0 = 0x9 - 92 95 00 00 00 00 00 00 00 exit - 93 b7 00 00 00 0a 00 00 00 r0 = 0xa - 94 95 00 00 00 00 00 00 00 exit - 95 b7 00 00 00 08 00 00 00 r0 = 0x8 - 96 95 00 00 00 00 00 00 00 exit - 97 b7 00 00 00 07 00 00 00 r0 = 0x7 - 98 95 00 00 00 00 00 00 00 exit - 99 b7 00 00 00 04 00 00 00 r0 = 0x4 - 100 95 00 00 00 00 00 00 00 exit - 101 b7 00 00 00 06 00 00 00 r0 = 0x6 - 102 95 00 00 00 00 00 00 00 exit - 103 b7 00 00 00 03 00 00 00 r0 = 0x3 - 104 95 00 00 00 00 00 00 00 exit - 105 b7 00 00 00 05 00 00 00 r0 = 0x5 - 106 95 00 00 00 00 00 00 00 exit - 107 b7 00 00 00 02 00 00 00 r0 = 0x2 - 108 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 87 5d 89 0a 00 00 00 00 00 if r9 != r8 goto +0xa + 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) + 89 27 09 00 00 90 00 00 00 r9 *= 0x90 + 90 7b 9a cc ff 00 00 00 00 *(u64 *)(r10 - 0x34) = r9 + 91 7a 0a d4 ff 10 00 00 00 *(u64 *)(r10 - 0x2c) = 0x10 + 92 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 93 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 94 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 95 95 00 00 00 00 00 00 00 exit + 96 b7 00 00 00 09 00 00 00 r0 = 0x9 + 97 95 00 00 00 00 00 00 00 exit + 98 b7 00 00 00 0a 00 00 00 r0 = 0xa + 99 95 00 00 00 00 00 00 00 exit + 100 b7 00 00 00 08 00 00 00 r0 = 0x8 + 101 95 00 00 00 00 00 00 00 exit + 102 b7 00 00 00 07 00 00 00 r0 = 0x7 + 103 95 00 00 00 00 00 00 00 exit + 104 b7 00 00 00 04 00 00 00 r0 = 0x4 + 105 95 00 00 00 00 00 00 00 exit + 106 b7 00 00 00 06 00 00 00 r0 = 0x6 + 107 95 00 00 00 00 00 00 00 exit + 108 b7 00 00 00 03 00 00 00 r0 = 0x3 + 109 95 00 00 00 00 00 00 00 exit + 110 b7 00 00 00 05 00 00 00 r0 = 0x5 + 111 95 00 00 00 00 00 00 00 exit + 112 b7 00 00 00 02 00 00 00 r0 = 0x2 + 113 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index f0a74483..f269df71 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -91,6 +91,10 @@ .equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. .equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. .equ SF_INIT_PDA_OFF, -104 # PDA address field. +# Lamports field in CreateAccount instruction data. +.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 +# Space address field in CreateAccount instruction data. +.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 # CPI-specific constants. # ----------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt new file mode 100644 index 00000000..4e37e31a --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -0,0 +1,21 @@ + # Pack CreateAccount instruction data. + # --------------------------------------------------------------------- + # - Discriminator is already set to 0 since stack is zero initialized. + # - Reuses r3 from PDA syscall. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_RENT_DATA_OFF] # Load lamports per byte + mul64 r9, CPI_ACCOUNT_DATA_SCALAR # Multiply to get rent-exempt cost. + # Store in instruction data. + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + # Store new account data length. + stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN + # Copy in program ID to instruction data. + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] + + # Initialize signer seed for PDA bump key. + # --------------------------------------------------------------------- + # Reuses r5 from PDA derivation syscall. + # --------------------------------------------------------------------- + # Store pointer to bump seed. + stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 + stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index f9fcb63e..c458ffe4 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -82,5 +82,9 @@ asm_constant_group! { stack_frame_offset!(SIGNER_SEED_LEN, InitStackFrame.signer_seeds[0].len), /// PDA address field. stack_frame_offset!(PDA, InitStackFrame.pda), + /// Lamports field in CreateAccount instruction data. + stack_frame_offset_unaligned!(CREATE_ACCOUNT_LAMPORTS, InitStackFrame.instruction_data.lamports), + /// Space address field in CreateAccount instruction data. + stack_frame_offset_unaligned!(CREATE_ACCOUNT_SPACE, InitStackFrame.instruction_data.space), } } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 38b08071..792a6378 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -32,7 +32,7 @@ error_codes! { constant_group! { /// Input buffer layout. input_buffer { - /// Number of accounts field. + /// Number of accounts field. offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User runtime account. offset!(USER_ACCOUNT, InputBufferHeader.user), diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 4be565b9..39f29682 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -92,6 +92,10 @@ .equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. .equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. .equ SF_INIT_PDA_OFF, -104 # PDA address field. +# Lamports field in CreateAccount instruction data. +.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 +# Space address field in CreateAccount instruction data. +.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 # CPI-specific constants. # ----------------------- @@ -209,14 +213,32 @@ initialize: jne r9, r8, e_pda_mismatch # ANCHOR_END: initialize-pda-checks + // ANCHOR: initialize-create-account + # Pack CreateAccount instruction data. + # --------------------------------------------------------------------- + # - Discriminator is already set to 0 since stack is zero initialized. + # - Reuses r3 from PDA syscall. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_RENT_DATA_OFF] # Load lamports per byte + mul64 r9, CPI_ACCOUNT_DATA_SCALAR # Multiply to get rent-exempt cost. + # Store in instruction data. + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + # Store new account data length. + stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN + # Copy in program ID to instruction data. + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] + # Initialize signer seed for PDA bump key. # --------------------------------------------------------------------- - # Relies on r5 from PDA derivation syscall. + # Reuses r5 from PDA derivation syscall. # --------------------------------------------------------------------- # Store pointer to bump seed. stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. + // ANCHOR_END: initialize-create-account + + exit e_instruction_data: From 3dc3ca519f159d11511714a7ee808c685463f019 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:58:44 -0800 Subject: [PATCH 120/263] Pack insn data --- examples/tree/artifacts/dumps/asm.txt | 111 +++++----- examples/tree/artifacts/dumps/rs.txt | 136 ++++++------ examples/tree/artifacts/rs-disassembly.s | 84 +++----- .../tree/artifacts/snippets/asm/constants.txt | 8 + .../asm/initialize-create-account.txt | 7 + .../snippets/rs/initialize-create-account.txt | 10 +- .../snippets/rs/initialize-pda-checks.txt | 3 +- .../tests/initialize_pda_checks/result.txt | 7 +- examples/tree/interface/src/asm.rs | 15 +- examples/tree/macros/src/lib.rs | 200 ++++++++++++++++++ examples/tree/src/program.rs | 19 +- examples/tree/src/tree/tree.s | 15 ++ 12 files changed, 410 insertions(+), 205 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 3a0c3101..0436d8e5 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1256 (bytes into file) + Start of section headers 1312 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x4e8 +There are 7 section headers, starting at offset 0x520 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0002a8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000390 000390 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000430 000430 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000478 000478 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000004a8 0004a8 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0004b8 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0002e0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000003c8 0003c8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000468 000468 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000004b0 0004b0 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000004e0 0004e0 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0004f0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0002a8 0x0002a8 R E 0x1000 - LOAD 0x000430 0x0000000000000430 0x0000000000000430 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000390 0x0000000000000390 0x0000000000000390 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0002e0 0x0002e0 R E 0x1000 + LOAD 0x000468 0x0000000000000468 0x0000000000000468 0x000088 0x000088 R 0x1000 + DYNAMIC 0x0003c8 0x00000000000003c8 0x00000000000003c8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x390 contains 10 entries +Dynamic section at offset 0x3c8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x4a8 + 0x0000000000000011 (REL) 0x4e0 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x430 + 0x0000000000000006 (SYMTAB) 0x468 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x478 + 0x0000000000000005 (STRTAB) 0x4b0 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x4a8 contains 1 entries +Relocation section '.rel.dyn' at offset 0x4e0 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,31 +92,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 47 00 00 00 00 00 if r9 != 0x0 goto +0x47 + 40 55 09 4e 00 00 00 00 00 if r9 != 0x0 goto +0x4e 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 43 00 ff 00 00 00 if r9 != 0xff goto +0x43 + 42 55 09 4a 00 ff 00 00 00 if r9 != 0xff goto +0x4a 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 3f 00 00 00 00 00 if r9 != 0x0 goto +0x3f + 44 55 09 46 00 00 00 00 00 if r9 != 0x0 goto +0x46 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 3b 00 ff 00 00 00 if r9 != 0xff goto +0x3b + 46 55 09 42 00 ff 00 00 00 if r9 != 0xff goto +0x42 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 37 00 0e 00 00 00 if r9 != 0xe goto +0x37 + 48 55 09 3e 00 0e 00 00 00 if r9 != 0xe goto +0x3e 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 33 00 ff 00 00 00 if r9 != 0xff goto +0x33 + 50 55 09 3a 00 ff 00 00 00 if r9 != 0xff goto +0x3a 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 2d 00 00 00 00 00 if r9 != r8 goto +0x2d + 54 5d 89 34 00 00 00 00 00 if r9 != r8 goto +0x34 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 29 00 00 00 00 00 if r9 != r8 goto +0x29 + 58 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 25 00 00 00 00 00 if r9 != r8 goto +0x25 + 62 5d 89 2c 00 00 00 00 00 if r9 != r8 goto +0x2c 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 22 00 00 00 00 00 if r9 != r8 goto +0x22 + 65 5d 89 29 00 00 00 00 00 if r9 != r8 goto +0x29 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 1c 00 00 00 00 00 if r9 != 0x0 goto +0x1c + 67 55 09 23 00 00 00 00 00 if r9 != 0x0 goto +0x23 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,39 +127,46 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 13 00 00 00 00 00 if r9 != r8 goto +0x13 + 78 5d 89 1a 00 00 00 00 00 if r9 != r8 goto +0x1a 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 10 00 00 00 00 00 if r9 != r8 goto +0x10 + 81 5d 89 17 00 00 00 00 00 if r9 != r8 goto +0x17 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 0d 00 00 00 00 00 if r9 != r8 goto +0xd + 84 5d 89 14 00 00 00 00 00 if r9 != r8 goto +0x14 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 0a 00 00 00 00 00 if r9 != r8 goto +0xa + 87 5d 89 11 00 00 00 00 00 if r9 != r8 goto +0x11 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) 89 27 09 00 00 90 00 00 00 r9 *= 0x90 90 7b 9a cc ff 00 00 00 00 *(u64 *)(r10 - 0x34) = r9 91 7a 0a d4 ff 10 00 00 00 *(u64 *)(r10 - 0x2c) = 0x10 92 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 93 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 94 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 95 95 00 00 00 00 00 00 00 exit - 96 b7 00 00 00 09 00 00 00 r0 = 0x9 - 97 95 00 00 00 00 00 00 00 exit - 98 b7 00 00 00 0a 00 00 00 r0 = 0xa - 99 95 00 00 00 00 00 00 00 exit - 100 b7 00 00 00 08 00 00 00 r0 = 0x8 - 101 95 00 00 00 00 00 00 00 exit - 102 b7 00 00 00 07 00 00 00 r0 = 0x7 - 103 95 00 00 00 00 00 00 00 exit - 104 b7 00 00 00 04 00 00 00 r0 = 0x4 - 105 95 00 00 00 00 00 00 00 exit - 106 b7 00 00 00 06 00 00 00 r0 = 0x6 - 107 95 00 00 00 00 00 00 00 exit - 108 b7 00 00 00 03 00 00 00 r0 = 0x3 - 109 95 00 00 00 00 00 00 00 exit - 110 b7 00 00 00 05 00 00 00 r0 = 0x5 - 111 95 00 00 00 00 00 00 00 exit - 112 b7 00 00 00 02 00 00 00 r0 = 0x2 - 113 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 93 7b 9a dc ff 00 00 00 00 *(u64 *)(r10 - 0x24) = r9 + 94 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 95 7b 9a e4 ff 00 00 00 00 *(u64 *)(r10 - 0x1c) = r9 + 96 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 97 7b 9a ec ff 00 00 00 00 *(u64 *)(r10 - 0x14) = r9 + 98 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 99 7b 9a f4 ff 00 00 00 00 *(u64 *)(r10 - 0xc) = r9 + 100 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 + 101 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 + 102 95 00 00 00 00 00 00 00 exit + 103 b7 00 00 00 09 00 00 00 r0 = 0x9 + 104 95 00 00 00 00 00 00 00 exit + 105 b7 00 00 00 0a 00 00 00 r0 = 0xa + 106 95 00 00 00 00 00 00 00 exit + 107 b7 00 00 00 08 00 00 00 r0 = 0x8 + 108 95 00 00 00 00 00 00 00 exit + 109 b7 00 00 00 07 00 00 00 r0 = 0x7 + 110 95 00 00 00 00 00 00 00 exit + 111 b7 00 00 00 04 00 00 00 r0 = 0x4 + 112 95 00 00 00 00 00 00 00 exit + 113 b7 00 00 00 06 00 00 00 r0 = 0x6 + 114 95 00 00 00 00 00 00 00 exit + 115 b7 00 00 00 03 00 00 00 r0 = 0x3 + 116 95 00 00 00 00 00 00 00 exit + 117 b7 00 00 00 05 00 00 00 r0 = 0x5 + 118 95 00 00 00 00 00 00 00 exit + 119 b7 00 00 00 02 00 00 00 r0 = 0x2 + 120 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 87990e08..85b8db44 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3352 (bytes into file) + Start of section headers 3208 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xd18 +There are 8 section headers, starting at offset 0xc88 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000308 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000428 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000430 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000430 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000430 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0007a8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0007e6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000278 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000398 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 0003a0 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 0003a0 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 0003a0 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000718 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000756 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000308 0x000308 E 0x8 - LOAD 0x000428 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000430 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000430 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000278 0x000278 E 0x8 + LOAD 0x000398 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x0003a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x0003a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 776 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 632 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 4a 00 04 00 00 00 jne r3, 0x4, +0x4a + 40 55 03 38 00 04 00 00 00 jne r3, 0x4, +0x38 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 46 00 00 00 00 00 jne r3, 0x0, +0x46 + 50 55 03 34 00 00 00 00 00 jne r3, 0x0, +0x34 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 + 60 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 48 00 00 00 00 00 jne r3, 0x0, +0x48 + 70 55 03 36 00 00 00 00 00 jne r3, 0x0, +0x36 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 + 80 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 48 00 0e 00 00 00 jne r3, 0xe, +0x48 + 90 55 03 36 00 0e 00 00 00 jne r3, 0xe, +0x36 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 48 00 ff 00 00 00 jne r3, 0xff, +0x48 + a0 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 @@ -142,62 +142,44 @@ Disassembly of section .text 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 130 55 02 38 00 00 00 00 00 jne r2, 0x0, +0x38 - 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 140 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 + 130 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 + 138 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 140 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 08 00 00 00 add64 r4, 0x8 + 150 07 04 00 00 18 00 00 00 add64 r4, 0x18 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 160 07 05 00 00 3f 00 00 00 add64 r5, 0x3f + 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 188 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 190 9c a1 08 00 00 00 00 00 ldxdw r1, [r10 + 0x8] - 198 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 1a0 5d 21 d2 ff 00 00 00 00 jne r1, r2, -0x2e - 1a8 9c a1 10 00 00 00 00 00 ldxdw r1, [r10 + 0x10] - 1b0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1b8 5d 21 cf ff 00 00 00 00 jne r1, r2, -0x31 - 1c0 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 1c8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1d0 5d 21 cc ff 00 00 00 00 jne r1, r2, -0x34 - 1d8 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 1e0 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 1e8 5d 21 c9 ff 00 00 00 00 jne r1, r2, -0x37 - 1f0 9c 71 90 79 00 00 00 00 ldxdw r1, [r7 + 0x7990] - 1f8 9c 62 18 00 00 00 00 00 ldxdw r2, [r6 + 0x18] - 200 9f 2a 34 00 00 00 00 00 stxdw [r10 + 0x34], r2 - 208 9c 62 10 00 00 00 00 00 ldxdw r2, [r6 + 0x10] - 210 9f 2a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r2 - 218 9c 62 08 00 00 00 00 00 ldxdw r2, [r6 + 0x8] - 220 9f 2a 24 00 00 00 00 00 stxdw [r10 + 0x24], r2 - 228 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] - 230 9f 2a 1c 00 00 00 00 00 stxdw [r10 + 0x1c], r2 - 238 96 01 00 00 90 00 00 00 lmul64 r1, 0x90 - 240 9f 1a 0c 00 00 00 00 00 stxdw [r10 + 0xc], r1 - 248 97 0a 14 00 10 00 00 00 stdw [r10 + 0x14], 0x10 - 250 87 0a 08 00 00 00 00 00 stw [r10 + 0x8], 0x0 - 258 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 260 07 01 00 00 08 00 00 00 add64 r1, 0x8 - 268 b7 02 00 00 34 00 00 00 mov64 r2, 0x34 - 270 95 00 00 00 eb d3 26 a2 syscall -0x5dd92c15 - 278 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 280 05 00 b6 ff 00 00 00 00 ja -0x4a - 288 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 290 05 00 b4 ff 00 00 00 00 ja -0x4c - 298 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 2a0 05 00 b2 ff 00 00 00 00 ja -0x4e - 2a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 2b0 05 00 b0 ff 00 00 00 00 ja -0x50 - 2b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 2c0 05 00 ae ff 00 00 00 00 ja -0x52 - 2c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 2d0 05 00 ac ff 00 00 00 00 ja -0x54 - 2d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 2e0 05 00 aa ff 00 00 00 00 ja -0x56 - 2e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 2f0 05 00 a8 ff 00 00 00 00 ja -0x58 - 2f8 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 300 05 00 a6 ff 00 00 00 00 ja -0x5a \ No newline at end of file + 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 180 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] + 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 190 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa + 198 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] + 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 1a8 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 + 1b0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] + 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 1c0 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 + 1c8 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1d8 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] + 1e0 1d 21 ca ff 00 00 00 00 jeq r1, r2, -0x36 + 1e8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 + 1f8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 200 05 00 c6 ff 00 00 00 00 ja -0x3a + 208 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 210 05 00 c4 ff 00 00 00 00 ja -0x3c + 218 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 220 05 00 c2 ff 00 00 00 00 ja -0x3e + 228 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 230 05 00 c0 ff 00 00 00 00 ja -0x40 + 238 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 240 05 00 be ff 00 00 00 00 ja -0x42 + 248 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 250 05 00 bc ff 00 00 00 00 ja -0x44 + 258 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 260 05 00 ba ff 00 00 00 00 ja -0x46 + 268 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 270 05 00 b8 ff 00 00 00 00 ja -0x48 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index dee5080d..25b7b247 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0298 + jne r3, 4, jmp_0208 ldxdw r3, [r1+88] - jne r3, 0, jmp_0288 + jne r3, 0, jmp_01f8 ldxb r3, [r1+10344] - jne r3, 255, jmp_02a8 + jne r3, 255, jmp_0218 ldxdw r3, [r1+10424] - jne r3, 0, jmp_02b8 + jne r3, 0, jmp_0228 ldxb r3, [r1+20680] - jne r3, 255, jmp_02c8 + jne r3, 255, jmp_0238 ldxdw r3, [r1+20760] - jne r3, 14, jmp_02d8 + jne r3, 14, jmp_0248 ldxb r3, [r1+31032] - jne r3, 255, jmp_02e8 + jne r3, 255, jmp_0258 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 @@ -43,78 +43,62 @@ jmp_0040: mov32 r4, -1965433885 jne r3, r4, jmp_0038 ldxdw r2, [r2-8] - jne r2, 0, jmp_02f8 - mov64 r6, r1 - add64 r6, 41400 + jne r2, 0, jmp_0268 + mov64 r3, r1 + add64 r3, 41400 mov64 r4, r10 - add64 r4, 8 + add64 r4, 24 mov64 r5, r10 - add64 r5, 7 - mov64 r7, r1 + add64 r5, 63 + mov64 r6, r1 mov64 r2, 0 - mov64 r3, r6 call sol_try_find_program_address - mov64 r0, 10 - ldxdw r1, [r10+8] - ldxdw r2, [r7+10352] - jne r1, r2, jmp_0038 - ldxdw r1, [r10+16] - ldxdw r2, [r7+10360] - jne r1, r2, jmp_0038 ldxdw r1, [r10+24] - ldxdw r2, [r7+10368] - jne r1, r2, jmp_0038 + ldxdw r2, [r6+10352] + jne r1, r2, jmp_01e8 ldxdw r1, [r10+32] - ldxdw r2, [r7+10376] - jne r1, r2, jmp_0038 - ldxdw r1, [r7+31120] - ldxdw r2, [r6+24] - stxdw [r10+52], r2 - ldxdw r2, [r6+16] - stxdw [r10+44], r2 - ldxdw r2, [r6+8] - stxdw [r10+36], r2 - ldxdw r2, [r6+0] - stxdw [r10+28], r2 - lmul64 r1, 144 - stxdw [r10+12], r1 - stdw [r10+20], 16 - stw [r10+8], 0 - mov64 r1, r10 - add64 r1, 8 - mov64 r2, 52 - call sol_set_return_data + ldxdw r2, [r6+10360] + jne r1, r2, jmp_01e8 + ldxdw r1, [r10+40] + ldxdw r2, [r6+10368] + jne r1, r2, jmp_01e8 + ldxdw r1, [r10+48] mov64 r0, 0 + ldxdw r2, [r6+10376] + jeq r1, r2, jmp_0038 + +jmp_01e8: + mov64 r0, 10 ja jmp_0038 -jmp_0288: +jmp_01f8: mov64 r0, 2 ja jmp_0038 -jmp_0298: +jmp_0208: mov64 r0, 1 ja jmp_0038 -jmp_02a8: +jmp_0218: mov64 r0, 5 ja jmp_0038 -jmp_02b8: +jmp_0228: mov64 r0, 3 ja jmp_0038 -jmp_02c8: +jmp_0238: mov64 r0, 6 ja jmp_0038 -jmp_02d8: +jmp_0248: mov64 r0, 4 ja jmp_0038 -jmp_02e8: +jmp_0258: mov64 r0, 7 ja jmp_0038 -jmp_02f8: +jmp_0268: mov64 r0, 9 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index f269df71..79c626a1 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -95,6 +95,14 @@ .equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 # Space address field in CreateAccount instruction data. .equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 +# Owner field in CreateAccount instruction data (chunk index 0). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -36 +# Owner field in CreateAccount instruction data (chunk index 1). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -28 +# Owner field in CreateAccount instruction data (chunk index 2). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -20 +# Owner field in CreateAccount instruction data (chunk index 3). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -12 # CPI-specific constants. # ----------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 4e37e31a..86164bbf 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -11,6 +11,13 @@ stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN # Copy in program ID to instruction data. ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_1] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_2] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 # Initialize signer seed for PDA bump key. # --------------------------------------------------------------------- diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index f2eea815..96606101 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,4 +1,5 @@ - let instruction_data = CreateAccountInstructionData { + // Pack CreateAccount instruction data. + let _instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), @@ -9,10 +10,5 @@ .cast(), ), }; - #[cfg(target_os = "solana")] - sol_set_return_data( - transmute(&instruction_data), - size_of::() as u64, - ); #[cfg(not(target_os = "solana"))] - let _foo = instruction_data; \ No newline at end of file + let _ = _instruction_data; // Silence clippy. diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 61701537..2f5fa7c8 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -14,9 +14,8 @@ ); (pda.assume_init(), bump.assume_init()) }; - // Dummy block for non-Solana target, to satisfy clippy. #[cfg(not(target_os = "solana"))] - let (pda, _bump) = (Address::default(), 0u8); + let (pda, _bump) = (Address::default(), 0); // Silence clippy. // Compare result with passed PDA. if_err!( diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 2ea396c6..25a5e4d6 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -3,8 +3,11 @@ | PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | | PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | | PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | -| PDA mismatch chunk 4 | 1551 | 1558 | +7 | +0.5% | +| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | test tests::test_initialize_pda_checks ... ok + Blocking waiting for file lock on package cache + Blocking waiting for file lock on package cache + Blocking waiting for file lock on package cache warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | @@ -35,5 +38,5 @@ warning: `tree` (lib test) generated 1 warning [ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index c458ffe4..c0acb6d0 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -42,7 +42,10 @@ extend_constant_group!(input_buffer { /// Tree data length field. offset!(TREE_DATA_LEN, InputBufferHeader.tree_header.data_len), /// System Program non-duplicate marker field. - offset!(SYSTEM_PROGRAM_NON_DUP_MARKER, InitInputBuffer.header.system_program.header.borrow_state), + offset!( + SYSTEM_PROGRAM_NON_DUP_MARKER, + InitInputBuffer.header.system_program.header.borrow_state + ), /// System Program data length field. offset!(SYSTEM_PROGRAM_DATA_LEN, InitInputBuffer.header.system_program.header.data_len), /// Rent account non-duplicate marker field. @@ -83,8 +86,16 @@ asm_constant_group! { /// PDA address field. stack_frame_offset!(PDA, InitStackFrame.pda), /// Lamports field in CreateAccount instruction data. - stack_frame_offset_unaligned!(CREATE_ACCOUNT_LAMPORTS, InitStackFrame.instruction_data.lamports), + stack_frame_offset_unaligned!( + CREATE_ACCOUNT_LAMPORTS, + InitStackFrame.instruction_data.lamports + ), /// Space address field in CreateAccount instruction data. stack_frame_offset_unaligned!(CREATE_ACCOUNT_SPACE, InitStackFrame.instruction_data.space), + /// Owner field in CreateAccount instruction data. + stack_frame_pubkey_offset_unaligned!( + CREATE_ACCOUNT_OWNER, + InitStackFrame.instruction_data.owner + ), } } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 53146465..8aa2af4f 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -220,6 +220,15 @@ enum ConstantKind { field_path: Vec, chunk_index: usize, }, + /// Negative stack frame offset for pubkey chunks (i16 validated). + /// Computed as `offset_of!(Struct, field) + chunk_index * 8 - size_of::()`. + /// Always unaligned. Name gets `_UOFF_{chunk_index}` suffix appended. + StackFramePubkeyChunkOffset { + struct_name: Ident, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, + chunk_index: usize, + }, } /// Array index info for stack frame offset computation. @@ -322,6 +331,43 @@ impl Parse for ConstantGroup { continue; } + // stack_frame_pubkey_offset_unaligned!(NAME, Struct.field) expands to 4 chunk constants. + if ident == "stack_frame_pubkey_offset_unaligned" { + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let parsed = parse_stack_frame_field_path(&inner)?; + let _ = content.parse::(); + + let base_doc = const_doc.trim_end_matches('.'); + for chunk in 0..4usize { + let chunk_name = + Ident::new(&format!("{}_UOFF_{}", base_name, chunk), base_name.span()); + let chunk_doc = format!("{} (chunk index {}).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&chunk_doc) { + return Err(content.error(e)); + } + constants.push(ConstantDef { + doc: chunk_doc, + name: chunk_name, + kind: ConstantKind::StackFramePubkeyChunkOffset { + struct_name: struct_name.clone(), + field_path_tokens: parsed.field_path_tokens.clone(), + array_index: parsed.array_index.as_ref().map(|a| ArrayIndexInfo { + array_field_name: a.array_field_name.clone(), + index_expr: a.index_expr.clone(), + inner_field_path: a.inner_field_path.clone(), + }), + chunk_index: chunk, + }, + }); + } + continue; + } + // Support `offset!(NAME, Struct.field)`, `offset_immediate!(NAME, Struct.field)`, // `NAME: type = value`, and `NAME = expr as Type` forms. let (const_name, kind) = if ident == "offset" { @@ -615,6 +661,23 @@ pub fn constant_group(input: TokenStream) -> TokenStream { *chunk_index, )); } + ConstantKind::StackFramePubkeyChunkOffset { + struct_name, + field_path_tokens, + array_index, + chunk_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + *chunk_index, + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } } } @@ -761,6 +824,15 @@ enum AsmConstantKind { field_path: Vec, chunk_index: usize, }, + /// Negative stack frame offset for pubkey chunks (i16 validated). + /// Computed as `offset_of!(Struct, field) + chunk_index * 8 - size_of::()`. + /// Always unaligned. Name gets `_UOFF_{chunk_index}` suffix appended. + StackFramePubkeyChunkOffset { + struct_name: Ident, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, + chunk_index: usize, + }, /// Chunk of a known pubkey/address constant. /// Extracts `width` bytes at `byte_offset` from the 32-byte address. /// Width 4 produces i32 (for LO/HI halves), width 8 produces i64 (for lddw). @@ -980,6 +1052,43 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> continue; } + // stack_frame_pubkey_offset_unaligned!(NAME, Struct.field) expands to 4 chunk constants. + if ident == "stack_frame_pubkey_offset_unaligned" { + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let parsed = parse_stack_frame_field_path(&inner)?; + let _ = content.parse::(); + + let base_doc = const_doc.trim_end_matches('.'); + for chunk in 0..4usize { + let chunk_name = + Ident::new(&format!("{}_UOFF_{}", base_name, chunk), base_name.span()); + let chunk_doc = format!("{} (chunk index {}).", base_doc, chunk); + if let Err(e) = validate_doc_comment(&chunk_doc) { + return Err(content.error(e)); + } + constants.push(AsmConstantDef { + doc: chunk_doc, + name: chunk_name, + kind: AsmConstantKind::StackFramePubkeyChunkOffset { + struct_name: struct_name.clone(), + field_path_tokens: parsed.field_path_tokens.clone(), + array_index: parsed.array_index.as_ref().map(|a| ArrayIndexInfo { + array_field_name: a.array_field_name.clone(), + index_expr: a.index_expr.clone(), + inner_field_path: a.inner_field_path.clone(), + }), + chunk_index: chunk, + }, + }); + } + continue; + } + // pubkey_value!(NAME, expr) expands to 8 chunk constants (4 LO/HI pairs). if ident == "pubkey_value" { content.parse::()?; @@ -1260,6 +1369,63 @@ fn gen_stack_frame_offset_code( (const_def, None) } +/// Generate code for a `stack_frame_pubkey_offset_unaligned!` constant (single chunk). +/// +/// Computes `offset_of!(Struct, field) + chunk_index * 8 - size_of::()` as an i16 constant. +fn gen_stack_frame_pubkey_chunk_offset_code( + name: &Ident, + doc: &str, + struct_name: &Ident, + field_path_tokens: &proc_macro2::TokenStream, + array_index: &Option, + chunk_index: usize, +) -> (proc_macro2::TokenStream, Option) { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); + let chunk_byte_offset = (chunk_index * BPF_ALIGN as usize) as i64; + + let offset_expr = match array_index { + Some(info) => { + let array_field_name = &info.array_field_name; + let index_expr = &info.index_expr; + let inner_offset = match &info.inner_field_path { + Some(path) => quote! { + + core::mem::offset_of!(#fields_mod::#array_field_name, #path) as i64 + }, + None => quote! {}, + }; + quote! { + core::mem::offset_of!(#struct_name, #field_path_tokens) as i64 + + (#index_expr) as i64 * core::mem::size_of::<#fields_mod::#array_field_name>() as i64 + #inner_offset + } + } + None => quote! { + core::mem::offset_of!(#struct_name, #field_path_tokens) as i64 + }, + }; + + let const_def = quote! { + #[doc = #doc] + pub const #name: i16 = { + use super::*; + (#offset_expr + #chunk_byte_offset - core::mem::size_of::<#struct_name>() as i64) as i16 + }; + + const #assert_name: () = { + use super::*; + let result = #offset_expr + #chunk_byte_offset - core::mem::size_of::<#struct_name>() as i64; + assert!( + result >= (i16::MIN as i64) && result <= (i16::MAX as i64), + "Stack frame offset must fit in i16" + ); + assert!(result < 0, "Stack frame offset must be negative"); + }; + }; + + (const_def, None) +} + /// Generate code for a `pubkey_offset!` constant (single chunk). /// /// Computes `offset_of!(Struct, field) + chunk_index * 8` as an i16 constant. @@ -1471,6 +1637,23 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { *chunk_index, )); } + AsmConstantKind::StackFramePubkeyChunkOffset { + struct_name, + field_path_tokens, + array_index, + chunk_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + *chunk_index, + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } AsmConstantKind::PubkeyValueChunk { expr, byte_offset, @@ -1708,6 +1891,23 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { *chunk_index, )); } + AsmConstantKind::StackFramePubkeyChunkOffset { + struct_name, + field_path_tokens, + array_index, + chunk_index, + } => { + let (const_def, literal_repr) = gen_stack_frame_pubkey_chunk_offset_code( + name, + doc, + struct_name, + field_path_tokens, + array_index, + *chunk_index, + ); + const_value_strs.push(literal_repr); + const_defs.push(const_def); + } AsmConstantKind::PubkeyValueChunk { expr, byte_offset, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index ee08d903..685a7f93 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,10 +9,7 @@ use pinocchio::{ }; use tree_interface::{cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData}; #[cfg(target_os = "solana")] -use { - core::mem::MaybeUninit, - pinocchio::syscalls::{sol_set_return_data, sol_try_find_program_address}, -}; +use {core::mem::MaybeUninit, pinocchio::syscalls::sol_try_find_program_address}; #[inline(always)] unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { @@ -124,9 +121,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); (pda.assume_init(), bump.assume_init()) }; - // Dummy block for non-Solana target, to satisfy clippy. #[cfg(not(target_os = "solana"))] - let (pda, _bump) = (Address::default(), 0u8); + let (pda, _bump) = (Address::default(), 0); // Silence clippy. // Compare result with passed PDA. if_err!( @@ -140,7 +136,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR_END: initialize-pda-checks // ANCHOR: initialize-create-account - let instruction_data = CreateAccountInstructionData { + // Pack CreateAccount instruction data. + let _instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), @@ -151,13 +148,9 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - .cast(), ), }; - #[cfg(target_os = "solana")] - sol_set_return_data( - transmute(&instruction_data), - size_of::() as u64, - ); #[cfg(not(target_os = "solana"))] - let _foo = instruction_data; + let _ = _instruction_data; // Silence clippy. + // ANCHOR_END: initialize-create-account SUCCESS diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 39f29682..040ab517 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -96,6 +96,14 @@ .equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 # Space address field in CreateAccount instruction data. .equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 +# Owner field in CreateAccount instruction data (chunk index 0). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -36 +# Owner field in CreateAccount instruction data (chunk index 1). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -28 +# Owner field in CreateAccount instruction data (chunk index 2). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -20 +# Owner field in CreateAccount instruction data (chunk index 3). +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -12 # CPI-specific constants. # ----------------------- @@ -227,6 +235,13 @@ initialize: stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN # Copy in program ID to instruction data. ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_1] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_2] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 # Initialize signer seed for PDA bump key. # --------------------------------------------------------------------- From d950ca01853e8ab8531a0386ffb02d94e34f1d39 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:04:05 -0800 Subject: [PATCH 121/263] Prepare bulk pointer ops --- examples/tree/artifacts/dumps/asm.txt | 139 +++++++++--------- .../tree/artifacts/snippets/asm/constants.txt | 39 +++-- .../snippets/asm/entrypoint-branching.txt | 2 +- .../asm/initialize-create-account.txt | 60 +++++++- .../snippets/asm/initialize-input-checks.txt | 10 +- .../snippets/asm/initialize-pda-checks.txt | 2 +- .../snippets/rs/initialize-create-account.txt | 14 ++ .../snippets/rs/initialize-pda-checks.txt | 4 +- .../tests/entrypoint_branching/result.txt | 9 +- .../tests/initialize_input_checks/result.txt | 9 +- .../tests/initialize_pda_checks/result.txt | 12 +- examples/tree/interface/src/asm.rs | 36 ++++- examples/tree/interface/src/common.rs | 8 + examples/tree/interface/src/lib.rs | 5 +- examples/tree/src/program.rs | 23 ++- examples/tree/src/tree/tree.s | 112 +++++++++++--- 16 files changed, 363 insertions(+), 121 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 0436d8e5..ea0a40cf 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1312 (bytes into file) + Start of section headers 1368 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x520 +There are 7 section headers, starting at offset 0x558 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0002e0 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000003c8 0003c8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000468 000468 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000004b0 0004b0 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000004e0 0004e0 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0004f0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000318 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000400 000400 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000004a0 0004a0 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000004e8 0004e8 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000518 000518 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000528 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0002e0 0x0002e0 R E 0x1000 - LOAD 0x000468 0x0000000000000468 0x0000000000000468 0x000088 0x000088 R 0x1000 - DYNAMIC 0x0003c8 0x00000000000003c8 0x00000000000003c8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000318 0x000318 R E 0x1000 + LOAD 0x0004a0 0x00000000000004a0 0x00000000000004a0 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000400 0x0000000000000400 0x0000000000000400 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x3c8 contains 10 entries +Dynamic section at offset 0x400 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x4e0 + 0x0000000000000011 (REL) 0x518 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x468 + 0x0000000000000006 (SYMTAB) 0x4a0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x4b0 + 0x0000000000000005 (STRTAB) 0x4e8 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x4e0 contains 1 entries +Relocation section '.rel.dyn' at offset 0x518 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,81 +92,88 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 4e 00 00 00 00 00 if r9 != 0x0 goto +0x4e + 40 55 09 55 00 00 00 00 00 if r9 != 0x0 goto +0x55 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 4a 00 ff 00 00 00 if r9 != 0xff goto +0x4a + 42 55 09 51 00 ff 00 00 00 if r9 != 0xff goto +0x51 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 46 00 00 00 00 00 if r9 != 0x0 goto +0x46 + 44 55 09 4d 00 00 00 00 00 if r9 != 0x0 goto +0x4d 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 42 00 ff 00 00 00 if r9 != 0xff goto +0x42 + 46 55 09 49 00 ff 00 00 00 if r9 != 0xff goto +0x49 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 3e 00 0e 00 00 00 if r9 != 0xe goto +0x3e + 48 55 09 45 00 0e 00 00 00 if r9 != 0xe goto +0x45 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 3a 00 ff 00 00 00 if r9 != 0xff goto +0x3a + 50 55 09 41 00 ff 00 00 00 if r9 != 0xff goto +0x41 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 34 00 00 00 00 00 if r9 != r8 goto +0x34 + 54 5d 89 3b 00 00 00 00 00 if r9 != r8 goto +0x3b 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 + 58 5d 89 37 00 00 00 00 00 if r9 != r8 goto +0x37 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 2c 00 00 00 00 00 if r9 != r8 goto +0x2c + 62 5d 89 33 00 00 00 00 00 if r9 != r8 goto +0x33 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 29 00 00 00 00 00 if r9 != r8 goto +0x29 + 65 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 23 00 00 00 00 00 if r9 != 0x0 goto +0x23 + 67 55 09 2a 00 00 00 00 00 if r9 != 0x0 goto +0x2a 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 71 bf a4 00 00 00 00 00 00 r4 = r10 - 72 07 04 00 00 98 ff ff ff r4 += -0x68 + 72 07 04 00 00 b0 ff ff ff r4 += -0x50 73 bf a5 00 00 00 00 00 00 r5 = r10 - 74 07 05 00 00 98 fe ff ff r5 += -0x168 + 74 07 05 00 00 a0 fe ff ff r5 += -0x160 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 1a 00 00 00 00 00 if r9 != r8 goto +0x1a + 78 5d 89 21 00 00 00 00 00 if r9 != r8 goto +0x21 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 17 00 00 00 00 00 if r9 != r8 goto +0x17 + 81 5d 89 1e 00 00 00 00 00 if r9 != r8 goto +0x1e 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 14 00 00 00 00 00 if r9 != r8 goto +0x14 + 84 5d 89 1b 00 00 00 00 00 if r9 != r8 goto +0x1b 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 11 00 00 00 00 00 if r9 != r8 goto +0x11 - 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) - 89 27 09 00 00 90 00 00 00 r9 *= 0x90 - 90 7b 9a cc ff 00 00 00 00 *(u64 *)(r10 - 0x34) = r9 - 91 7a 0a d4 ff 10 00 00 00 *(u64 *)(r10 - 0x2c) = 0x10 - 92 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 93 7b 9a dc ff 00 00 00 00 *(u64 *)(r10 - 0x24) = r9 - 94 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) - 95 7b 9a e4 ff 00 00 00 00 *(u64 *)(r10 - 0x1c) = r9 - 96 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) - 97 7b 9a ec ff 00 00 00 00 *(u64 *)(r10 - 0x14) = r9 - 98 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) - 99 7b 9a f4 ff 00 00 00 00 *(u64 *)(r10 - 0xc) = r9 - 100 7b 5a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r5 - 101 7a 0a 90 ff 01 00 00 00 *(u64 *)(r10 - 0x70) = 0x1 - 102 95 00 00 00 00 00 00 00 exit - 103 b7 00 00 00 09 00 00 00 r0 = 0x9 - 104 95 00 00 00 00 00 00 00 exit - 105 b7 00 00 00 0a 00 00 00 r0 = 0xa - 106 95 00 00 00 00 00 00 00 exit - 107 b7 00 00 00 08 00 00 00 r0 = 0x8 - 108 95 00 00 00 00 00 00 00 exit - 109 b7 00 00 00 07 00 00 00 r0 = 0x7 - 110 95 00 00 00 00 00 00 00 exit - 111 b7 00 00 00 04 00 00 00 r0 = 0x4 - 112 95 00 00 00 00 00 00 00 exit - 113 b7 00 00 00 06 00 00 00 r0 = 0x6 - 114 95 00 00 00 00 00 00 00 exit - 115 b7 00 00 00 03 00 00 00 r0 = 0x3 - 116 95 00 00 00 00 00 00 00 exit - 117 b7 00 00 00 05 00 00 00 r0 = 0x5 - 118 95 00 00 00 00 00 00 00 exit - 119 b7 00 00 00 02 00 00 00 r0 = 0x2 - 120 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 87 5d 89 18 00 00 00 00 00 if r9 != r8 goto +0x18 + 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 + 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) + 91 27 09 00 00 90 00 00 00 r9 *= 0x90 + 92 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 + 93 7a 0a ad fe 10 00 00 00 *(u64 *)(r10 - 0x153) = 0x10 + 94 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 95 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 + 96 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 97 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 + 98 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 99 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 + 100 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 101 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 + 102 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 103 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 + 104 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 105 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 + 106 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 + 107 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 + 108 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 + 109 95 00 00 00 00 00 00 00 exit + 110 b7 00 00 00 09 00 00 00 r0 = 0x9 + 111 95 00 00 00 00 00 00 00 exit + 112 b7 00 00 00 0a 00 00 00 r0 = 0xa + 113 95 00 00 00 00 00 00 00 exit + 114 b7 00 00 00 08 00 00 00 r0 = 0x8 + 115 95 00 00 00 00 00 00 00 exit + 116 b7 00 00 00 07 00 00 00 r0 = 0x7 + 117 95 00 00 00 00 00 00 00 exit + 118 b7 00 00 00 04 00 00 00 r0 = 0x4 + 119 95 00 00 00 00 00 00 00 exit + 120 b7 00 00 00 06 00 00 00 r0 = 0x6 + 121 95 00 00 00 00 00 00 00 exit + 122 b7 00 00 00 03 00 00 00 r0 = 0x3 + 123 95 00 00 00 00 00 00 00 exit + 124 b7 00 00 00 05 00 00 00 r0 = 0x5 + 125 95 00 00 00 00 00 00 00 exit + 126 b7 00 00 00 02 00 00 00 r0 = 0x2 + 127 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 79c626a1..0d5567c5 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -87,22 +87,35 @@ # Init stack frame layout. # ------------------------ -.equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. -.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. -.equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. -.equ SF_INIT_PDA_OFF, -104 # PDA address field. +.equ SF_INIT_BUMP_SEED_OFF, -352 # Bump seed. +.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -96 # Bump signer seed address field. +.equ SF_INIT_SIGNER_SEED_LEN_OFF, -88 # Bump signer seed length field. +.equ SF_INIT_PDA_OFF, -80 # PDA address field. # Lamports field in CreateAccount instruction data. -.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 +.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -347 # Space address field in CreateAccount instruction data. -.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 +.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -339 # Owner field in CreateAccount instruction data (chunk index 0). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -36 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -331 # Owner field in CreateAccount instruction data (chunk index 1). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -28 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -323 # Owner field in CreateAccount instruction data (chunk index 2). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -20 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -315 # Owner field in CreateAccount instruction data (chunk index 3). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -12 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -307 +.equ SF_INIT_SIGNERS_SEEDS_ADDR_OFF, -112 # Signers seeds address field. +.equ SF_INIT_SIGNERS_SEEDS_LEN_OFF, -104 # Signers seeds length field. +.equ SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF, -32 # System Program address. +.equ SF_INIT_INSN_ACCOUNT_LEN_OFF, -280 # SolInstruction account_len field. +.equ SF_INIT_INSN_DATA_LEN_OFF, -264 # SolInstruction data_len field. +# SolAccountMeta is_writable field for user account. +.equ SF_INIT_USER_META_IS_WRITABLE_OFF, -248 +# SolAccountMeta is_writable field for tree account. +.equ SF_INIT_TREE_META_IS_WRITABLE_OFF, -232 +# SolAccountInfo is_signer field for user account. +.equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 +# SolAccountInfo is_signer field for tree account. +.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 # CPI-specific constants. # ----------------------- @@ -114,4 +127,8 @@ # Account data scalar for base rent calculation. .equ CPI_ACCOUNT_DATA_SCALAR, 144 # CreateAccount discriminator for CPI. -.equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 \ No newline at end of file +.equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 +.equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. +.equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. +.equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. +.equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt index bdbd939a..c1c13eff 100644 --- a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt @@ -2,7 +2,7 @@ entrypoint: # Check input buffer accounts. - # ---------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 86164bbf..10ca4cdf 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -1,3 +1,13 @@ + # Pack SolInstruction. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] Program ID pointer. + # - [ ] Account metas pointer. + # - [ ] Instruction data pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN + # Pack CreateAccount instruction data. # --------------------------------------------------------------------- # - Discriminator is already set to 0 since stack is zero initialized. @@ -19,10 +29,58 @@ ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 - # Initialize signer seed for PDA bump key. + # Pack SolAccountMeta for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] User pubkey pointer. + # - [ ] Tree pubkey pointer. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + + # Pack SolAccountInfo for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] User pubkey pointer. + # - [ ] Tree pubkey pointer. + # - [ ] User lamports pointer. + # - [ ] Tree lamports pointer. + # - [ ] User data pointer. + # - [ ] Tree data pointer. + # - [ ] User owner pointer. + # - [ ] Tree owner pointer. + # Skipped due to zero-initialized stack memory: + # - User data length (already checked as zero). + # - Tree data length (already checked as zero). + # - User rent epoch. + # - Tree rent epoch. + # - User executable. + # - Tree executable. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + + # Initialize signer seed for PDA bump seed. # --------------------------------------------------------------------- # Reuses r5 from PDA derivation syscall. # --------------------------------------------------------------------- # Store pointer to bump seed. stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. + + # Initialize signers seeds for PDA. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] Signer seed pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS + + # Bulk load pointers. + # --------------------------------------------------------------------- + # Finish with: + # r1 = pointer to instruction. + # r2 = pointer to account infos. + # r3 = number of account infos. + # r4 = pointer to signer's seeds. + # r5 = number of signers. + diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 2e5f7204..071f20ee 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -1,26 +1,26 @@ initialize: # Error if user has data. - # ----------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] jne r9, DATA_LEN_ZERO, e_user_data_len # Error if tree is duplicate or has data. - # --------------------------------------- + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_tree_duplicate ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] jne r9, DATA_LEN_ZERO, e_tree_data_len # Error if System Program is duplicate or has invalid data length. - # ---------------------------------------------------------------- + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if Rent account is duplicate or has incorrect address. - # ------------------------------------------------------------ + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_0] @@ -44,6 +44,6 @@ initialize: jne r9, r8, e_rent_address # Error if instruction data provided. - # ----------------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt index 3b277f7a..e7617371 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -13,7 +13,7 @@ call sol_try_find_program_address # Find PDA. # Compare computed PDA against passed account. - # -------------------------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] jne r9, r8, e_pda_mismatch diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 96606101..8bb0dca5 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -12,3 +12,17 @@ }; #[cfg(not(target_os = "solana"))] let _ = _instruction_data; // Silence clippy. + + // Initialize signer seed for PDA bump. + let bump_seed = SolSignerSeed { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] + addr: transmute(&bump), + len: size_of::() as u64, + }; + + // Initialize signer seeds for PDA. + let signers_seeds = SolSignerSeeds { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] + addr: transmute(&bump_seed), + len: cpi::N_SEEDS as u64, + }; diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 2f5fa7c8..7808d48f 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -1,6 +1,6 @@ #[cfg(target_os = "solana")] // Invoke syscall. - let (pda, _bump) = { + let (pda, bump) = { let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); // Get input buffer footer pointer. @@ -15,7 +15,7 @@ (pda.assume_init(), bump.assume_init()) }; #[cfg(not(target_os = "solana"))] - let (pda, _bump) = (Address::default(), 0); // Silence clippy. + let (pda, bump) = (Address::default(), 0); // Compare result with passed PDA. if_err!( diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 34848438..f7752b8f 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -5,6 +5,13 @@ | Three accounts | 5 | 7 | +2 | +40.0% | | Five accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok +warning: unused variable: `signers_seeds` + --> tree/src/program.rs:165:9 + | +165 | let signers_seeds = SolSignerSeeds { + | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | @@ -12,7 +19,7 @@ warning: function `check_success` is never used | ^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 1 warning +warning: `tree` (lib test) generated 2 warnings [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 09a88631..90945de3 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -16,6 +16,13 @@ | Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | | Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok +warning: unused variable: `signers_seeds` + --> tree/src/program.rs:165:9 + | +165 | let signers_seeds = SolSignerSeeds { + | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | @@ -23,7 +30,7 @@ warning: function `check_success` is never used | ^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 1 warning +warning: `tree` (lib test) generated 2 warnings [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 25a5e4d6..0b7ae552 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -5,9 +5,13 @@ | PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | | PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | test tests::test_initialize_pda_checks ... ok - Blocking waiting for file lock on package cache - Blocking waiting for file lock on package cache - Blocking waiting for file lock on package cache +warning: unused variable: `signers_seeds` + --> tree/src/program.rs:165:9 + | +165 | let signers_seeds = SolSignerSeeds { + | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default warning: function `check_success` is never used --> tree/src/tests.rs:26:4 | @@ -15,7 +19,7 @@ warning: function `check_success` is never used | ^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 1 warning +warning: `tree` (lib test) generated 2 warnings [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index c0acb6d0..1a962194 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -61,8 +61,7 @@ extend_constant_group!(input_buffer { #[stack_frame] struct InitStackFrame { bump_seed: u8, - /// Zero-initialized on stack. - system_program_address: Address, + instruction_data: CreateAccountInstructionData, instruction: SolInstruction, account_metas: [SolAccountMeta; cpi::N_ACCOUNTS], account_infos: [SolAccountInfo; cpi::N_ACCOUNTS], @@ -70,7 +69,8 @@ struct InitStackFrame { signer_seeds: [SolSignerSeed; cpi::N_SEEDS], pda: Address, rent: Rent, - instruction_data: CreateAccountInstructionData, + /// Zero-initialized on stack. + system_program_address: Address, } asm_constant_group! { @@ -97,5 +97,35 @@ asm_constant_group! { CREATE_ACCOUNT_OWNER, InitStackFrame.instruction_data.owner ), + /// Signers seeds address field. + stack_frame_offset!(SIGNERS_SEEDS_ADDR, InitStackFrame.signers_seeds), + /// Signers seeds length field. + stack_frame_offset!(SIGNERS_SEEDS_LEN, InitStackFrame.signers_seeds[0].len), + /// System Program address. + stack_frame_offset!(SYSTEM_PROGRAM_ADDRESS, InitStackFrame.system_program_address), + /// SolInstruction account_len field. + stack_frame_offset!(INSN_ACCOUNT_LEN, InitStackFrame.instruction.account_len), + /// SolInstruction data_len field. + stack_frame_offset!(INSN_DATA_LEN, InitStackFrame.instruction.data_len), + /// SolAccountMeta is_writable field for user account. + stack_frame_offset!( + USER_META_IS_WRITABLE, + InitStackFrame.account_metas[cpi::USER_ACCOUNT_INDEX].is_writable + ), + /// SolAccountMeta is_writable field for tree account. + stack_frame_offset!( + TREE_META_IS_WRITABLE, + InitStackFrame.account_metas[cpi::TREE_ACCOUNT_INDEX].is_writable + ), + /// SolAccountInfo is_signer field for user account. + stack_frame_offset!( + USER_INFO_IS_SIGNER, + InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].is_signer + ), + /// SolAccountInfo is_signer field for tree account. + stack_frame_offset!( + TREE_INFO_IS_SIGNER, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_signer + ), } } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 792a6378..cd66ae6a 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -75,6 +75,14 @@ constant_group! { ACCOUNT_DATA_SCALAR: usize = (ACCOUNT_STORAGE_OVERHEAD as usize) + TREE_DATA_LEN, /// CreateAccount discriminator for CPI. CREATE_ACCOUNT_DISCRIMINATOR: u32 = 0, + /// Length of CreateAccount instruction data. + INSN_DATA_LEN: usize = size_of::(), + /// Mask for writable signer. + WRITABLE_SIGNER: u64 = 0x0101, + /// Account index for user account in CPI. + USER_ACCOUNT_INDEX: usize = 0, + /// Account index for tree account in CPI. + TREE_ACCOUNT_INDEX: usize = 1, } } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 50d0c9ee..4df0db6f 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -7,6 +7,5 @@ mod bindings; mod common; pub use asm::*; -pub use common::cpi; -pub use common::error_codes; -pub use common::CreateAccountInstructionData; +pub use bindings::{SolSignerSeed, SolSignerSeeds}; +pub use common::{cpi, error_codes, CreateAccountInstructionData}; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 685a7f93..9eb9d644 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -7,7 +7,10 @@ use pinocchio::{ sysvars::rent::RENT_ID, AccountView, Address, SUCCESS, }; -use tree_interface::{cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData}; +use tree_interface::{ + cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData, SolSignerSeed, + SolSignerSeeds, +}; #[cfg(target_os = "solana")] use {core::mem::MaybeUninit, pinocchio::syscalls::sol_try_find_program_address}; @@ -107,7 +110,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR: initialize-pda-checks #[cfg(target_os = "solana")] // Invoke syscall. - let (pda, _bump) = { + let (pda, bump) = { let mut pda = MaybeUninit::
::uninit(); let mut bump = MaybeUninit::::uninit(); // Get input buffer footer pointer. @@ -122,7 +125,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - (pda.assume_init(), bump.assume_init()) }; #[cfg(not(target_os = "solana"))] - let (pda, _bump) = (Address::default(), 0); // Silence clippy. + let (pda, bump) = (Address::default(), 0); // Compare result with passed PDA. if_err!( @@ -151,6 +154,20 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - #[cfg(not(target_os = "solana"))] let _ = _instruction_data; // Silence clippy. + // Initialize signer seed for PDA bump. + let bump_seed = SolSignerSeed { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] + addr: transmute(&bump), + len: size_of::() as u64, + }; + + // Initialize signer seeds for PDA. + let signers_seeds = SolSignerSeeds { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] + addr: transmute(&bump_seed), + len: cpi::N_SEEDS as u64, + }; + // ANCHOR_END: initialize-create-account SUCCESS diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 040ab517..8b0b0c6b 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -88,22 +88,35 @@ # Init stack frame layout. # ------------------------ -.equ SF_INIT_BUMP_SEED_OFF, -360 # Bump seed. -.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -120 # Bump signer seed address field. -.equ SF_INIT_SIGNER_SEED_LEN_OFF, -112 # Bump signer seed length field. -.equ SF_INIT_PDA_OFF, -104 # PDA address field. +.equ SF_INIT_BUMP_SEED_OFF, -352 # Bump seed. +.equ SF_INIT_SIGNER_SEED_ADDR_OFF, -96 # Bump signer seed address field. +.equ SF_INIT_SIGNER_SEED_LEN_OFF, -88 # Bump signer seed length field. +.equ SF_INIT_PDA_OFF, -80 # PDA address field. # Lamports field in CreateAccount instruction data. -.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -52 +.equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -347 # Space address field in CreateAccount instruction data. -.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -44 +.equ SF_INIT_CREATE_ACCOUNT_SPACE_UOFF, -339 # Owner field in CreateAccount instruction data (chunk index 0). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -36 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0, -331 # Owner field in CreateAccount instruction data (chunk index 1). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -28 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1, -323 # Owner field in CreateAccount instruction data (chunk index 2). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -20 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2, -315 # Owner field in CreateAccount instruction data (chunk index 3). -.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -12 +.equ SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3, -307 +.equ SF_INIT_SIGNERS_SEEDS_ADDR_OFF, -112 # Signers seeds address field. +.equ SF_INIT_SIGNERS_SEEDS_LEN_OFF, -104 # Signers seeds length field. +.equ SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF, -32 # System Program address. +.equ SF_INIT_INSN_ACCOUNT_LEN_OFF, -280 # SolInstruction account_len field. +.equ SF_INIT_INSN_DATA_LEN_OFF, -264 # SolInstruction data_len field. +# SolAccountMeta is_writable field for user account. +.equ SF_INIT_USER_META_IS_WRITABLE_OFF, -248 +# SolAccountMeta is_writable field for tree account. +.equ SF_INIT_TREE_META_IS_WRITABLE_OFF, -232 +# SolAccountInfo is_signer field for user account. +.equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 +# SolAccountInfo is_signer field for tree account. +.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 # CPI-specific constants. # ----------------------- @@ -116,6 +129,10 @@ .equ CPI_ACCOUNT_DATA_SCALAR, 144 # CreateAccount discriminator for CPI. .equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 +.equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. +.equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. +.equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. +.equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -123,7 +140,7 @@ entrypoint: # Check input buffer accounts. - # ---------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. @@ -142,26 +159,26 @@ general: initialize: # Error if user has data. - # ----------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] jne r9, DATA_LEN_ZERO, e_user_data_len # Error if tree is duplicate or has data. - # --------------------------------------- + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_tree_duplicate ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] jne r9, DATA_LEN_ZERO, e_tree_data_len # Error if System Program is duplicate or has invalid data length. - # ---------------------------------------------------------------- + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate ldxdw r9, [r1 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Error if Rent account is duplicate or has incorrect address. - # ------------------------------------------------------------ + # --------------------------------------------------------------------- ldxb r9, [r1 + IB_RENT_NON_DUP_MARKER_OFF] jne r9, IB_NON_DUP_MARKER, e_rent_duplicate ldxdw r9, [r1 + IB_RENT_ADDRESS_OFF_0] @@ -185,7 +202,7 @@ initialize: jne r9, r8, e_rent_address # Error if instruction data provided. - # ----------------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks @@ -206,7 +223,7 @@ initialize: call sol_try_find_program_address # Find PDA. # Compare computed PDA against passed account. - # -------------------------------------------- + # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] jne r9, r8, e_pda_mismatch @@ -222,6 +239,16 @@ initialize: # ANCHOR_END: initialize-pda-checks // ANCHOR: initialize-create-account + # Pack SolInstruction. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] Program ID pointer. + # - [ ] Account metas pointer. + # - [ ] Instruction data pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN + # Pack CreateAccount instruction data. # --------------------------------------------------------------------- # - Discriminator is already set to 0 since stack is zero initialized. @@ -243,7 +270,38 @@ initialize: ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 - # Initialize signer seed for PDA bump key. + # Pack SolAccountMeta for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] User pubkey pointer. + # - [ ] Tree pubkey pointer. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + + # Pack SolAccountInfo for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] User pubkey pointer. + # - [ ] Tree pubkey pointer. + # - [ ] User lamports pointer. + # - [ ] Tree lamports pointer. + # - [ ] User data pointer. + # - [ ] Tree data pointer. + # - [ ] User owner pointer. + # - [ ] Tree owner pointer. + # Skipped due to zero-initialized stack memory: + # - User data length (already checked as zero). + # - Tree data length (already checked as zero). + # - User rent epoch. + # - Tree rent epoch. + # - User executable. + # - Tree executable. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + + # Initialize signer seed for PDA bump seed. # --------------------------------------------------------------------- # Reuses r5 from PDA derivation syscall. # --------------------------------------------------------------------- @@ -251,9 +309,25 @@ initialize: stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. - // ANCHOR_END: initialize-create-account + # Initialize signers seeds for PDA. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [ ] Signer seed pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS + + # Bulk load pointers. + # --------------------------------------------------------------------- + # Finish with: + # r1 = pointer to instruction. + # r2 = pointer to account infos. + # r3 = number of account infos. + # r4 = pointer to signer's seeds. + # r5 = number of signers. + // ANCHOR_END: initialize-create-account + exit e_instruction_data: From 3035bb2579d8f332c43ab8d8a21883c48ddcca32 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:19:57 -0800 Subject: [PATCH 122/263] Begin bulk pointer operations --- examples/tree/artifacts/dumps/asm.txt | 109 ++++++++++-------- .../tree/artifacts/snippets/asm/constants.txt | 12 ++ .../asm/initialize-create-account.txt | 34 ++++-- examples/tree/interface/src/asm.rs | 27 +++++ examples/tree/src/tree/tree.s | 46 ++++++-- 5 files changed, 154 insertions(+), 74 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index ea0a40cf..b0bf82f0 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1368 (bytes into file) + Start of section headers 1440 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x558 +There are 7 section headers, starting at offset 0x5a0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000318 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000400 000400 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000004a0 0004a0 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000004e8 0004e8 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000518 000518 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000528 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000360 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000448 000448 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000004e8 0004e8 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000530 000530 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000560 000560 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000570 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000318 0x000318 R E 0x1000 - LOAD 0x0004a0 0x00000000000004a0 0x00000000000004a0 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000400 0x0000000000000400 0x0000000000000400 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000360 0x000360 R E 0x1000 + LOAD 0x0004e8 0x00000000000004e8 0x00000000000004e8 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000448 0x0000000000000448 0x0000000000000448 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x400 contains 10 entries +Dynamic section at offset 0x448 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x518 + 0x0000000000000011 (REL) 0x560 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x4a0 + 0x0000000000000006 (SYMTAB) 0x4e8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x4e8 + 0x0000000000000005 (STRTAB) 0x530 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x518 contains 1 entries +Relocation section '.rel.dyn' at offset 0x560 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,31 +92,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 55 00 00 00 00 00 if r9 != 0x0 goto +0x55 + 40 55 09 5e 00 00 00 00 00 if r9 != 0x0 goto +0x5e 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 51 00 ff 00 00 00 if r9 != 0xff goto +0x51 + 42 55 09 5a 00 ff 00 00 00 if r9 != 0xff goto +0x5a 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 4d 00 00 00 00 00 if r9 != 0x0 goto +0x4d + 44 55 09 56 00 00 00 00 00 if r9 != 0x0 goto +0x56 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 49 00 ff 00 00 00 if r9 != 0xff goto +0x49 + 46 55 09 52 00 ff 00 00 00 if r9 != 0xff goto +0x52 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 45 00 0e 00 00 00 if r9 != 0xe goto +0x45 + 48 55 09 4e 00 0e 00 00 00 if r9 != 0xe goto +0x4e 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 41 00 ff 00 00 00 if r9 != 0xff goto +0x41 + 50 55 09 4a 00 ff 00 00 00 if r9 != 0xff goto +0x4a 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 3b 00 00 00 00 00 if r9 != r8 goto +0x3b + 54 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 37 00 00 00 00 00 if r9 != r8 goto +0x37 + 58 5d 89 40 00 00 00 00 00 if r9 != r8 goto +0x40 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 33 00 00 00 00 00 if r9 != r8 goto +0x33 + 62 5d 89 3c 00 00 00 00 00 if r9 != r8 goto +0x3c 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 + 65 5d 89 39 00 00 00 00 00 if r9 != r8 goto +0x39 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 2a 00 00 00 00 00 if r9 != 0x0 goto +0x2a + 67 55 09 33 00 00 00 00 00 if r9 != 0x0 goto +0x33 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,16 +127,16 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 21 00 00 00 00 00 if r9 != r8 goto +0x21 + 78 5d 89 2a 00 00 00 00 00 if r9 != r8 goto +0x2a 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 1e 00 00 00 00 00 if r9 != r8 goto +0x1e + 81 5d 89 27 00 00 00 00 00 if r9 != r8 goto +0x27 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 1b 00 00 00 00 00 if r9 != r8 goto +0x1b + 84 5d 89 24 00 00 00 00 00 if r9 != r8 goto +0x24 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 18 00 00 00 00 00 if r9 != r8 goto +0x18 + 87 5d 89 21 00 00 00 00 00 if r9 != r8 goto +0x21 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -158,22 +158,31 @@ Disassembly of section .text 106 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 107 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 108 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 - 109 95 00 00 00 00 00 00 00 exit - 110 b7 00 00 00 09 00 00 00 r0 = 0x9 - 111 95 00 00 00 00 00 00 00 exit - 112 b7 00 00 00 0a 00 00 00 r0 = 0xa - 113 95 00 00 00 00 00 00 00 exit - 114 b7 00 00 00 08 00 00 00 r0 = 0x8 - 115 95 00 00 00 00 00 00 00 exit - 116 b7 00 00 00 07 00 00 00 r0 = 0x7 - 117 95 00 00 00 00 00 00 00 exit - 118 b7 00 00 00 04 00 00 00 r0 = 0x4 - 119 95 00 00 00 00 00 00 00 exit - 120 b7 00 00 00 06 00 00 00 r0 = 0x6 - 121 95 00 00 00 00 00 00 00 exit - 122 b7 00 00 00 03 00 00 00 r0 = 0x3 - 123 95 00 00 00 00 00 00 00 exit - 124 b7 00 00 00 05 00 00 00 r0 = 0x5 - 125 95 00 00 00 00 00 00 00 exit - 126 b7 00 00 00 02 00 00 00 r0 = 0x2 - 127 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 109 07 01 00 00 10 00 00 00 r1 += 0x10 + 110 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 111 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 112 07 01 00 00 20 00 00 00 r1 += 0x20 + 113 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 114 07 01 00 00 20 00 00 00 r1 += 0x20 + 115 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 116 07 01 00 00 10 00 00 00 r1 += 0x10 + 117 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 118 95 00 00 00 00 00 00 00 exit + 119 b7 00 00 00 09 00 00 00 r0 = 0x9 + 120 95 00 00 00 00 00 00 00 exit + 121 b7 00 00 00 0a 00 00 00 r0 = 0xa + 122 95 00 00 00 00 00 00 00 exit + 123 b7 00 00 00 08 00 00 00 r0 = 0x8 + 124 95 00 00 00 00 00 00 00 exit + 125 b7 00 00 00 07 00 00 00 r0 = 0x7 + 126 95 00 00 00 00 00 00 00 exit + 127 b7 00 00 00 04 00 00 00 r0 = 0x4 + 128 95 00 00 00 00 00 00 00 exit + 129 b7 00 00 00 06 00 00 00 r0 = 0x6 + 130 95 00 00 00 00 00 00 00 exit + 131 b7 00 00 00 03 00 00 00 r0 = 0x3 + 132 95 00 00 00 00 00 00 00 exit + 133 b7 00 00 00 05 00 00 00 r0 = 0x5 + 134 95 00 00 00 00 00 00 00 exit + 135 b7 00 00 00 02 00 00 00 r0 = 0x2 + 136 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 0d5567c5..eb9540ae 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -19,6 +19,8 @@ # ----------- .equ SIZE_OF_U8, 1 # Size of u8. .equ SIZE_OF_U64, 8 # Size of u64. +.equ SIZE_OF_ADDRESS, 32 # Size of Address. +.equ SIZE_OF_U128, 16 # Size of u128. # Data layout constants. # ---------------------- @@ -116,6 +118,16 @@ .equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 # SolAccountInfo is_signer field for tree account. .equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountMeta pubkey field for user account. +.equ SF_INIT_USER_META_PUBKEY_OFF, -256 +# SolAccountInfo pubkey field for user account. +.equ SF_INIT_USER_INFO_PUBKEY_OFF, -224 +# SolAccountInfo owner field for user account. +.equ SF_INIT_USER_INFO_OWNER_OFF, -192 +# SolAccountInfo lamports field for user account. +.equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 +# SollAccountInfo data_len field for user account. +.equ SF_INIT_USER_INFO_DATA_OFF, -200 # CPI-specific constants. # ----------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 10ca4cdf..5a6615c2 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -1,7 +1,7 @@ # Pack SolInstruction. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] Program ID pointer. + # - [ ] System Program ID pointer. # - [ ] Account metas pointer. # - [ ] Instruction data pointer. # --------------------------------------------------------------------- @@ -32,7 +32,7 @@ # Pack SolAccountMeta for user and tree. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] User pubkey pointer. + # - [x] User pubkey pointer. # - [ ] Tree pubkey pointer. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER @@ -41,13 +41,13 @@ # Pack SolAccountInfo for user and tree. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] User pubkey pointer. + # - [x] User pubkey pointer. # - [ ] Tree pubkey pointer. - # - [ ] User lamports pointer. + # - [x] User lamports pointer. # - [ ] Tree lamports pointer. - # - [ ] User data pointer. + # - [x] User data pointer. # - [ ] Tree data pointer. - # - [ ] User owner pointer. + # - [x] User owner pointer. # - [ ] Tree owner pointer. # Skipped due to zero-initialized stack memory: # - User data length (already checked as zero). @@ -75,12 +75,22 @@ # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk load pointers. + # Bulk assign/load pointers. # --------------------------------------------------------------------- # Finish with: - # r1 = pointer to instruction. - # r2 = pointer to account infos. - # r3 = number of account infos. - # r4 = pointer to signer's seeds. - # r5 = number of signers. + # - [ ] r1 = pointer to instruction. + # - [ ] r2 = pointer to account infos. + # - [ ] r3 = number of account infos. + # - [ ] r4 = pointer to signer's seeds. + # - [ ] r5 = number of signers. + # --------------------------------------------------------------------- + add64 r1, IB_USER_ADDRESS_OFF # Point to user address. + stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user owner. + stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. + stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to user data. + stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 1a962194..92b249b8 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -16,6 +16,8 @@ pubkey_chunk_group!(); sizes! { u8, u64, + Address, + u128, } extend_constant_group!(data { @@ -127,5 +129,30 @@ asm_constant_group! { TREE_INFO_IS_SIGNER, InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_signer ), + /// SolAccountMeta pubkey field for user account. + stack_frame_offset!( + USER_META_PUBKEY, + InitStackFrame.account_metas[cpi::USER_ACCOUNT_INDEX].pubkey + ), + /// SolAccountInfo pubkey field for user account. + stack_frame_offset!( + USER_INFO_PUBKEY, + InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].key + ), + /// SolAccountInfo owner field for user account. + stack_frame_offset!( + USER_INFO_OWNER, + InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].owner + ), + /// SolAccountInfo lamports field for user account. + stack_frame_offset!( + USER_INFO_LAMPORTS, + InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].lamports + ), + /// SollAccountInfo data_len field for user account. + stack_frame_offset!( + USER_INFO_DATA, + InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].data + ), } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 8b0b0c6b..bb44b723 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -20,6 +20,8 @@ # ----------- .equ SIZE_OF_U8, 1 # Size of u8. .equ SIZE_OF_U64, 8 # Size of u64. +.equ SIZE_OF_ADDRESS, 32 # Size of Address. +.equ SIZE_OF_U128, 16 # Size of u128. # Data layout constants. # ---------------------- @@ -117,6 +119,16 @@ .equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 # SolAccountInfo is_signer field for tree account. .equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountMeta pubkey field for user account. +.equ SF_INIT_USER_META_PUBKEY_OFF, -256 +# SolAccountInfo pubkey field for user account. +.equ SF_INIT_USER_INFO_PUBKEY_OFF, -224 +# SolAccountInfo owner field for user account. +.equ SF_INIT_USER_INFO_OWNER_OFF, -192 +# SolAccountInfo lamports field for user account. +.equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 +# SollAccountInfo data_len field for user account. +.equ SF_INIT_USER_INFO_DATA_OFF, -200 # CPI-specific constants. # ----------------------- @@ -242,7 +254,7 @@ initialize: # Pack SolInstruction. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] Program ID pointer. + # - [ ] System Program ID pointer. # - [ ] Account metas pointer. # - [ ] Instruction data pointer. # --------------------------------------------------------------------- @@ -273,7 +285,7 @@ initialize: # Pack SolAccountMeta for user and tree. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] User pubkey pointer. + # - [x] User pubkey pointer. # - [ ] Tree pubkey pointer. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER @@ -282,13 +294,13 @@ initialize: # Pack SolAccountInfo for user and tree. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] User pubkey pointer. + # - [x] User pubkey pointer. # - [ ] Tree pubkey pointer. - # - [ ] User lamports pointer. + # - [x] User lamports pointer. # - [ ] Tree lamports pointer. - # - [ ] User data pointer. + # - [x] User data pointer. # - [ ] Tree data pointer. - # - [ ] User owner pointer. + # - [x] User owner pointer. # - [ ] Tree owner pointer. # Skipped due to zero-initialized stack memory: # - User data length (already checked as zero). @@ -316,14 +328,24 @@ initialize: # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk load pointers. + # Bulk assign/load pointers. # --------------------------------------------------------------------- # Finish with: - # r1 = pointer to instruction. - # r2 = pointer to account infos. - # r3 = number of account infos. - # r4 = pointer to signer's seeds. - # r5 = number of signers. + # - [ ] r1 = pointer to instruction. + # - [ ] r2 = pointer to account infos. + # - [ ] r3 = number of account infos. + # - [ ] r4 = pointer to signer's seeds. + # - [ ] r5 = number of signers. + # --------------------------------------------------------------------- + add64 r1, IB_USER_ADDRESS_OFF # Point to user address. + stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user owner. + stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. + stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to user data. + stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. // ANCHOR_END: initialize-create-account From bc57144cc5cd2ddb727b1a90f5fe3bfd52742713 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:33:43 -0800 Subject: [PATCH 123/263] Pack meta/infos --- examples/tree/artifacts/dumps/asm.txt | 109 ++--- .../tree/artifacts/snippets/asm/constants.txt | 18 +- .../asm/initialize-create-account.txt | 22 +- examples/tree/interface/src/asm.rs | 44 ++- examples/tree/macros/src/lib.rs | 371 +++++++++++++----- examples/tree/src/tree/tree.s | 40 +- 6 files changed, 439 insertions(+), 165 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index b0bf82f0..abf701d7 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1440 (bytes into file) + Start of section headers 1512 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x5a0 +There are 7 section headers, starting at offset 0x5e8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000360 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000448 000448 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000004e8 0004e8 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000530 000530 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000560 000560 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000570 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0003a8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000490 000490 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000530 000530 000048 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000578 000578 000030 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000005a8 0005a8 000010 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0005b8 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000360 0x000360 R E 0x1000 - LOAD 0x0004e8 0x00000000000004e8 0x00000000000004e8 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000448 0x0000000000000448 0x0000000000000448 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0003a8 0x0003a8 R E 0x1000 + LOAD 0x000530 0x0000000000000530 0x0000000000000530 0x000088 0x000088 R 0x1000 + DYNAMIC 0x000490 0x0000000000000490 0x0000000000000490 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x448 contains 10 entries +Dynamic section at offset 0x490 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x560 + 0x0000000000000011 (REL) 0x5a8 0x0000000000000012 (RELSZ) 16 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x4e8 + 0x0000000000000006 (SYMTAB) 0x530 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x530 + 0x0000000000000005 (STRTAB) 0x578 0x000000000000000a (STRSZ) 48 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x560 contains 1 entries +Relocation section '.rel.dyn' at offset 0x5a8 contains 1 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address @@ -92,31 +92,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 5e 00 00 00 00 00 if r9 != 0x0 goto +0x5e + 40 55 09 67 00 00 00 00 00 if r9 != 0x0 goto +0x67 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 5a 00 ff 00 00 00 if r9 != 0xff goto +0x5a + 42 55 09 63 00 ff 00 00 00 if r9 != 0xff goto +0x63 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 56 00 00 00 00 00 if r9 != 0x0 goto +0x56 + 44 55 09 5f 00 00 00 00 00 if r9 != 0x0 goto +0x5f 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 52 00 ff 00 00 00 if r9 != 0xff goto +0x52 + 46 55 09 5b 00 ff 00 00 00 if r9 != 0xff goto +0x5b 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 4e 00 0e 00 00 00 if r9 != 0xe goto +0x4e + 48 55 09 57 00 0e 00 00 00 if r9 != 0xe goto +0x57 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 4a 00 ff 00 00 00 if r9 != 0xff goto +0x4a + 50 55 09 53 00 ff 00 00 00 if r9 != 0xff goto +0x53 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 + 54 5d 89 4d 00 00 00 00 00 if r9 != r8 goto +0x4d 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 40 00 00 00 00 00 if r9 != r8 goto +0x40 + 58 5d 89 49 00 00 00 00 00 if r9 != r8 goto +0x49 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 3c 00 00 00 00 00 if r9 != r8 goto +0x3c + 62 5d 89 45 00 00 00 00 00 if r9 != r8 goto +0x45 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 39 00 00 00 00 00 if r9 != r8 goto +0x39 + 65 5d 89 42 00 00 00 00 00 if r9 != r8 goto +0x42 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 33 00 00 00 00 00 if r9 != 0x0 goto +0x33 + 67 55 09 3c 00 00 00 00 00 if r9 != 0x0 goto +0x3c 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,16 +127,16 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 2a 00 00 00 00 00 if r9 != r8 goto +0x2a + 78 5d 89 33 00 00 00 00 00 if r9 != r8 goto +0x33 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 27 00 00 00 00 00 if r9 != r8 goto +0x27 + 81 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 24 00 00 00 00 00 if r9 != r8 goto +0x24 + 84 5d 89 2d 00 00 00 00 00 if r9 != r8 goto +0x2d 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 21 00 00 00 00 00 if r9 != r8 goto +0x21 + 87 5d 89 2a 00 00 00 00 00 if r9 != r8 goto +0x2a 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -167,22 +167,31 @@ Disassembly of section .text 115 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 116 07 01 00 00 10 00 00 00 r1 += 0x10 117 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 118 95 00 00 00 00 00 00 00 exit - 119 b7 00 00 00 09 00 00 00 r0 = 0x9 - 120 95 00 00 00 00 00 00 00 exit - 121 b7 00 00 00 0a 00 00 00 r0 = 0xa - 122 95 00 00 00 00 00 00 00 exit - 123 b7 00 00 00 08 00 00 00 r0 = 0x8 - 124 95 00 00 00 00 00 00 00 exit - 125 b7 00 00 00 07 00 00 00 r0 = 0x7 - 126 95 00 00 00 00 00 00 00 exit - 127 b7 00 00 00 04 00 00 00 r0 = 0x4 - 128 95 00 00 00 00 00 00 00 exit - 129 b7 00 00 00 06 00 00 00 r0 = 0x6 - 130 95 00 00 00 00 00 00 00 exit - 131 b7 00 00 00 03 00 00 00 r0 = 0x3 - 132 95 00 00 00 00 00 00 00 exit - 133 b7 00 00 00 05 00 00 00 r0 = 0x5 - 134 95 00 00 00 00 00 00 00 exit - 135 b7 00 00 00 02 00 00 00 r0 = 0x2 - 136 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 118 07 01 00 00 10 28 00 00 r1 += 0x2810 + 119 7a 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = 0x0 + 120 7a 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = 0x0 + 121 07 01 00 00 20 00 00 00 r1 += 0x20 + 122 7a 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = 0x0 + 123 07 01 00 00 20 00 00 00 r1 += 0x20 + 124 7a 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = 0x0 + 125 07 01 00 00 10 00 00 00 r1 += 0x10 + 126 7a 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = 0x0 + 127 95 00 00 00 00 00 00 00 exit + 128 b7 00 00 00 09 00 00 00 r0 = 0x9 + 129 95 00 00 00 00 00 00 00 exit + 130 b7 00 00 00 0a 00 00 00 r0 = 0xa + 131 95 00 00 00 00 00 00 00 exit + 132 b7 00 00 00 08 00 00 00 r0 = 0x8 + 133 95 00 00 00 00 00 00 00 exit + 134 b7 00 00 00 07 00 00 00 r0 = 0x7 + 135 95 00 00 00 00 00 00 00 exit + 136 b7 00 00 00 04 00 00 00 r0 = 0x4 + 137 95 00 00 00 00 00 00 00 exit + 138 b7 00 00 00 06 00 00 00 r0 = 0x6 + 139 95 00 00 00 00 00 00 00 exit + 140 b7 00 00 00 03 00 00 00 r0 = 0x3 + 141 95 00 00 00 00 00 00 00 exit + 142 b7 00 00 00 05 00 00 00 r0 = 0x5 + 143 95 00 00 00 00 00 00 00 exit + 144 b7 00 00 00 02 00 00 00 r0 = 0x2 + 145 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index eb9540ae..5c598bdf 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -86,6 +86,8 @@ .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 +# Relative offset from user data field to tree pubkey field. +.equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 # Init stack frame layout. # ------------------------ @@ -116,8 +118,6 @@ .equ SF_INIT_TREE_META_IS_WRITABLE_OFF, -232 # SolAccountInfo is_signer field for user account. .equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 -# SolAccountInfo is_signer field for tree account. -.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 # SolAccountMeta pubkey field for user account. .equ SF_INIT_USER_META_PUBKEY_OFF, -256 # SolAccountInfo pubkey field for user account. @@ -126,8 +126,20 @@ .equ SF_INIT_USER_INFO_OWNER_OFF, -192 # SolAccountInfo lamports field for user account. .equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 -# SollAccountInfo data_len field for user account. +# SolAccountInfo data_len field for user account. .equ SF_INIT_USER_INFO_DATA_OFF, -200 +# SolAccountInfo is_signer field for tree account. +.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountMeta pubkey field for tree account. +.equ SF_INIT_TREE_META_PUBKEY_OFF, -240 +# SolAccountInfo pubkey field for tree account. +.equ SF_INIT_TREE_INFO_PUBKEY_OFF, -168 +# SolAccountInfo owner field for tree account. +.equ SF_INIT_TREE_INFO_OWNER_OFF, -136 +# SolAccountInfo lamports field for tree account. +.equ SF_INIT_TREE_INFO_LAMPORTS_OFF, -160 +# SolAccountInfo data_len field for tree account. +.equ SF_INIT_TREE_INFO_DATA_OFF, -144 # CPI-specific constants. # ----------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 5a6615c2..10616a2e 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -33,7 +33,7 @@ # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: # - [x] User pubkey pointer. - # - [ ] Tree pubkey pointer. + # - [x] Tree pubkey pointer. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER @@ -42,13 +42,13 @@ # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: # - [x] User pubkey pointer. - # - [ ] Tree pubkey pointer. + # - [x] Tree pubkey pointer. # - [x] User lamports pointer. - # - [ ] Tree lamports pointer. + # - [x] Tree lamports pointer. # - [x] User data pointer. - # - [ ] Tree data pointer. + # - [x] Tree data pointer. # - [x] User owner pointer. - # - [ ] Tree owner pointer. + # - [x] Tree owner pointer. # Skipped due to zero-initialized stack memory: # - User data length (already checked as zero). # - Tree data length (already checked as zero). @@ -84,7 +84,7 @@ # - [ ] r4 = pointer to signer's seeds. # - [ ] r5 = number of signers. # --------------------------------------------------------------------- - add64 r1, IB_USER_ADDRESS_OFF # Point to user address. + add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to user owner. @@ -93,4 +93,14 @@ stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to user data. stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. + # Advance to tree address field. + add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM + stdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. + stdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. + stdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to tree data. + stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 92b249b8..829772dc 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -58,6 +58,13 @@ extend_constant_group!(input_buffer { pubkey_value!(RENT_ID, RENT_ID), /// Program ID field for initialize instruction. offset_immediate!(INIT_PROGRAM_ID, InitInputBuffer.footer.program_id), + /// Relative offset from user data field to tree pubkey field. + relative_offset_immediate!( + USER_DATA, + TREE_ADDRESS, + InputBufferHeader.user.data, + InputBufferHeader.tree_header.address + ), }); #[stack_frame] @@ -124,11 +131,6 @@ asm_constant_group! { USER_INFO_IS_SIGNER, InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].is_signer ), - /// SolAccountInfo is_signer field for tree account. - stack_frame_offset!( - TREE_INFO_IS_SIGNER, - InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_signer - ), /// SolAccountMeta pubkey field for user account. stack_frame_offset!( USER_META_PUBKEY, @@ -149,10 +151,40 @@ asm_constant_group! { USER_INFO_LAMPORTS, InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].lamports ), - /// SollAccountInfo data_len field for user account. + /// SolAccountInfo data_len field for user account. stack_frame_offset!( USER_INFO_DATA, InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].data ), + /// SolAccountInfo is_signer field for tree account. + stack_frame_offset!( + TREE_INFO_IS_SIGNER, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_signer + ), + /// SolAccountMeta pubkey field for tree account. + stack_frame_offset!( + TREE_META_PUBKEY, + InitStackFrame.account_metas[cpi::TREE_ACCOUNT_INDEX].pubkey + ), + /// SolAccountInfo pubkey field for tree account. + stack_frame_offset!( + TREE_INFO_PUBKEY, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].key + ), + /// SolAccountInfo owner field for tree account. + stack_frame_offset!( + TREE_INFO_OWNER, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].owner + ), + /// SolAccountInfo lamports field for tree account. + stack_frame_offset!( + TREE_INFO_LAMPORTS, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].lamports + ), + /// SolAccountInfo data_len field for tree account. + stack_frame_offset!( + TREE_INFO_DATA, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].data + ), } } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 8aa2af4f..ae3d1664 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -229,6 +229,15 @@ enum ConstantKind { array_index: Option, chunk_index: usize, }, + /// Relative offset between two fields (i32 validated). + /// Computed as `offset_of!(Struct, to_field) - offset_of!(Struct, from_field)`. + /// Name is `{FROM}_TO_{TO}_REL_OFF_IMM`. + RelativeOffsetImmediate { + from_struct_name: Ident, + from_field_path: Vec, + to_struct_name: Ident, + to_field_path: Vec, + }, } /// Array index info for stack frame offset computation. @@ -369,8 +378,50 @@ impl Parse for ConstantGroup { } // Support `offset!(NAME, Struct.field)`, `offset_immediate!(NAME, Struct.field)`, + // `relative_offset_immediate!(FROM, TO, Struct.from, Struct.to)`, // `NAME: type = value`, and `NAME = expr as Type` forms. - let (const_name, kind) = if ident == "offset" { + let (const_name, kind) = if ident == "relative_offset_immediate" { + // relative_offset_immediate!(FROM_NAME, TO_NAME, Struct.from.path, Struct.to.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let from_name: Ident = inner.parse()?; + inner.parse::()?; + let to_name: Ident = inner.parse()?; + inner.parse::()?; + let from_struct_name: Ident = inner.parse()?; + let mut from_field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + from_field_path.push(inner.parse::()?); + } + if from_field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + inner.parse::()?; + let to_struct_name: Ident = inner.parse()?; + let mut to_field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + to_field_path.push(inner.parse::()?); + } + if to_field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let full_name = Ident::new( + &format!("{}_TO_{}_REL_OFF_IMM", from_name, to_name), + from_name.span(), + ); + ( + full_name, + ConstantKind::RelativeOffsetImmediate { + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + }, + ) + } else if ident == "offset" { // offset!(NAME, Struct.field.nested.path) content.parse::()?; let inner; @@ -678,6 +729,22 @@ pub fn constant_group(input: TokenStream) -> TokenStream { const_value_strs.push(literal_repr); const_defs.push(const_def); } + ConstantKind::RelativeOffsetImmediate { + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + } => { + const_value_strs.push(None); + const_defs.push(gen_relative_offset_immediate_code( + name, + doc, + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + )); + } } } @@ -841,6 +908,15 @@ enum AsmConstantKind { byte_offset: usize, width: usize, }, + /// Relative offset between two fields (i32 validated). + /// Computed as `offset_of!(Struct, to_field) - offset_of!(Struct, from_field)`. + /// Name is `{FROM}_TO_{TO}_REL_OFF_IMM`. + RelativeOffsetImmediate { + from_struct_name: Ident, + from_field_path: Vec, + to_struct_name: Ident, + to_field_path: Vec, + }, } /// Input for asm_constant_group! macro. @@ -1104,10 +1180,8 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> let byte_base = chunk * 8; // Full i64 chunk (for lddw). - let full_name = Ident::new( - &format!("{}_CHUNK_{}", base_name, chunk), - base_name.span(), - ); + let full_name = + Ident::new(&format!("{}_CHUNK_{}", base_name, chunk), base_name.span()); let full_doc = format!("{} (chunk {}).", base_doc, chunk); if let Err(e) = validate_doc_comment(&full_doc) { return Err(content.error(e)); @@ -1163,91 +1237,132 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> continue; } - let (const_name, kind) = if ident == "offset" { - // Parse offset!(NAME, Struct.field.nested.path) - content.parse::()?; - let inner; - syn::parenthesized!(inner in content); - let base_name: Ident = inner.parse()?; - inner.parse::()?; - let struct_name: Ident = inner.parse()?; - // Parse field path (one or more fields separated by dots). - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } - // Append _OFF suffix to the name. - let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); - ( - full_name, - AsmConstantKind::Offset { - struct_name, - field_path, - }, - ) - } else if ident == "offset_immediate" { - // Parse offset_immediate!(NAME, Struct.field.nested.path) - content.parse::()?; - let inner; - syn::parenthesized!(inner in content); - let base_name: Ident = inner.parse()?; - inner.parse::()?; - let struct_name: Ident = inner.parse()?; - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } - // Append _OFF_IMM suffix to the name. - let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); - ( - full_name, - AsmConstantKind::OffsetImmediate { - struct_name, - field_path, - }, - ) - } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { - let aligned = ident == "stack_frame_offset"; - let suffix = if aligned { "_OFF" } else { "_UOFF" }; - content.parse::()?; - let inner; - syn::parenthesized!(inner in content); - let base_name: Ident = inner.parse()?; - inner.parse::()?; - let struct_name: Ident = inner.parse()?; - let parsed = parse_stack_frame_field_path(&inner)?; - let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); - ( - full_name, - AsmConstantKind::StackFrameOffset { - struct_name, - field_path_tokens: parsed.field_path_tokens, - array_index: parsed.array_index, - aligned, - }, - ) + let (const_name, kind) = if ident == "relative_offset_immediate" { + // relative_offset_immediate!(FROM_NAME, TO_NAME, Struct.from.path, Struct.to.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let from_name: Ident = inner.parse()?; + inner.parse::()?; + let to_name: Ident = inner.parse()?; + inner.parse::()?; + let from_struct_name: Ident = inner.parse()?; + let mut from_field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + from_field_path.push(inner.parse::()?); + } + if from_field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + inner.parse::()?; + let to_struct_name: Ident = inner.parse()?; + let mut to_field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + to_field_path.push(inner.parse::()?); + } + if to_field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + let full_name = Ident::new( + &format!("{}_TO_{}_REL_OFF_IMM", from_name, to_name), + from_name.span(), + ); + ( + full_name, + AsmConstantKind::RelativeOffsetImmediate { + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + }, + ) + } else if ident == "offset" { + // Parse offset!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + // Parse field path (one or more fields separated by dots). + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + // Append _OFF suffix to the name. + let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); + ( + full_name, + AsmConstantKind::Offset { + struct_name, + field_path, + }, + ) + } else if ident == "offset_immediate" { + // Parse offset_immediate!(NAME, Struct.field.nested.path) + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let mut field_path = Vec::new(); + while inner.peek(Token![.]) { + inner.parse::()?; + field_path.push(inner.parse::()?); + } + if field_path.is_empty() { + return Err(inner.error("Expected at least one field after struct name")); + } + // Append _OFF_IMM suffix to the name. + let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); + ( + full_name, + AsmConstantKind::OffsetImmediate { + struct_name, + field_path, + }, + ) + } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { + let aligned = ident == "stack_frame_offset"; + let suffix = if aligned { "_OFF" } else { "_UOFF" }; + content.parse::()?; + let inner; + syn::parenthesized!(inner in content); + let base_name: Ident = inner.parse()?; + inner.parse::()?; + let struct_name: Ident = inner.parse()?; + let parsed = parse_stack_frame_field_path(&inner)?; + let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); + ( + full_name, + AsmConstantKind::StackFrameOffset { + struct_name, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, + aligned, + }, + ) + } else { + // Regular NAME = value syntax. + content.parse::()?; + // Try to parse as literal first (to preserve hex/binary representation), + // otherwise parse as expression (for constants like NON_DUP_MARKER). + let fork = content.fork(); + if let Ok(lit) = fork.parse::() { + content.advance_to(&fork); + (ident, AsmConstantKind::Literal(lit)) } else { - // Regular NAME = value syntax. - content.parse::()?; - // Try to parse as literal first (to preserve hex/binary representation), - // otherwise parse as expression (for constants like NON_DUP_MARKER). - let fork = content.fork(); - if let Ok(lit) = fork.parse::() { - content.advance_to(&fork); - (ident, AsmConstantKind::Literal(lit)) - } else { - let expr: syn::Expr = content.parse()?; - (ident, AsmConstantKind::Expr(expr)) - } - }; + let expr: syn::Expr = content.parse()?; + (ident, AsmConstantKind::Expr(expr)) + } + }; // Optional trailing comma. let _ = content.parse::(); @@ -1451,6 +1566,36 @@ fn gen_pubkey_chunk_offset_code( } } +/// Generate code for a `relative_offset_immediate!` constant. +/// +/// Computes `offset_of!(Struct, to_field) - offset_of!(Struct, from_field)` as an i32 constant. +fn gen_relative_offset_immediate_code( + name: &Ident, + doc: &str, + from_struct_name: &Ident, + from_field_path: &[Ident], + to_struct_name: &Ident, + to_field_path: &[Ident], +) -> proc_macro2::TokenStream { + let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); + + quote! { + #[doc = #doc] + pub const #name: i32 = ( + core::mem::offset_of!(super::#to_struct_name, #(#to_field_path).*) as i64 + - core::mem::offset_of!(super::#from_struct_name, #(#from_field_path).*) as i64 + ) as i32; + + const #assert_name: () = assert!( + (core::mem::offset_of!(super::#to_struct_name, #(#to_field_path).*) as i64 + - core::mem::offset_of!(super::#from_struct_name, #(#from_field_path).*) as i64) >= (i32::MIN as i64) + && (core::mem::offset_of!(super::#to_struct_name, #(#to_field_path).*) as i64 + - core::mem::offset_of!(super::#from_struct_name, #(#from_field_path).*) as i64) <= (i32::MAX as i64), + "Relative offset immediate must fit in i32 range" + ); + } +} + /// Generate code for a `pubkey_value!` constant (single chunk). /// /// Extracts `width` bytes at `byte_offset` from a 32-byte address constant. @@ -1660,7 +1805,29 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { width, } => { const_value_strs.push(None); - const_defs.push(gen_pubkey_value_chunk_code(name, doc, expr, *byte_offset, *width)); + const_defs.push(gen_pubkey_value_chunk_code( + name, + doc, + expr, + *byte_offset, + *width, + )); + } + AsmConstantKind::RelativeOffsetImmediate { + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + } => { + const_value_strs.push(None); + const_defs.push(gen_relative_offset_immediate_code( + name, + doc, + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + )); } } } @@ -1914,7 +2081,29 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { width, } => { const_value_strs.push(None); - const_defs.push(gen_pubkey_value_chunk_code(name, doc, expr, *byte_offset, *width)); + const_defs.push(gen_pubkey_value_chunk_code( + name, + doc, + expr, + *byte_offset, + *width, + )); + } + AsmConstantKind::RelativeOffsetImmediate { + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + } => { + const_value_strs.push(None); + const_defs.push(gen_relative_offset_immediate_code( + name, + doc, + from_struct_name, + from_field_path, + to_struct_name, + to_field_path, + )); } } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index bb44b723..fc392a62 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -87,6 +87,8 @@ .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 +# Relative offset from user data field to tree pubkey field. +.equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 # Init stack frame layout. # ------------------------ @@ -117,8 +119,6 @@ .equ SF_INIT_TREE_META_IS_WRITABLE_OFF, -232 # SolAccountInfo is_signer field for user account. .equ SF_INIT_USER_INFO_IS_SIGNER_OFF, -176 -# SolAccountInfo is_signer field for tree account. -.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 # SolAccountMeta pubkey field for user account. .equ SF_INIT_USER_META_PUBKEY_OFF, -256 # SolAccountInfo pubkey field for user account. @@ -127,8 +127,20 @@ .equ SF_INIT_USER_INFO_OWNER_OFF, -192 # SolAccountInfo lamports field for user account. .equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 -# SollAccountInfo data_len field for user account. +# SolAccountInfo data_len field for user account. .equ SF_INIT_USER_INFO_DATA_OFF, -200 +# SolAccountInfo is_signer field for tree account. +.equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountMeta pubkey field for tree account. +.equ SF_INIT_TREE_META_PUBKEY_OFF, -240 +# SolAccountInfo pubkey field for tree account. +.equ SF_INIT_TREE_INFO_PUBKEY_OFF, -168 +# SolAccountInfo owner field for tree account. +.equ SF_INIT_TREE_INFO_OWNER_OFF, -136 +# SolAccountInfo lamports field for tree account. +.equ SF_INIT_TREE_INFO_LAMPORTS_OFF, -160 +# SolAccountInfo data_len field for tree account. +.equ SF_INIT_TREE_INFO_DATA_OFF, -144 # CPI-specific constants. # ----------------------- @@ -286,7 +298,7 @@ initialize: # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: # - [x] User pubkey pointer. - # - [ ] Tree pubkey pointer. + # - [x] Tree pubkey pointer. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER @@ -295,13 +307,13 @@ initialize: # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: # - [x] User pubkey pointer. - # - [ ] Tree pubkey pointer. + # - [x] Tree pubkey pointer. # - [x] User lamports pointer. - # - [ ] Tree lamports pointer. + # - [x] Tree lamports pointer. # - [x] User data pointer. - # - [ ] Tree data pointer. + # - [x] Tree data pointer. # - [x] User owner pointer. - # - [ ] Tree owner pointer. + # - [x] Tree owner pointer. # Skipped due to zero-initialized stack memory: # - User data length (already checked as zero). # - Tree data length (already checked as zero). @@ -337,7 +349,7 @@ initialize: # - [ ] r4 = pointer to signer's seeds. # - [ ] r5 = number of signers. # --------------------------------------------------------------------- - add64 r1, IB_USER_ADDRESS_OFF # Point to user address. + add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to user owner. @@ -346,6 +358,16 @@ initialize: stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to user data. stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. + # Advance to tree address field. + add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM + stdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. + stdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. + stdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to tree data. + stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. // ANCHOR_END: initialize-create-account From 2cb0e180d48fd018050e892ded16627898b72494 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:02:53 -0800 Subject: [PATCH 124/263] Finalize CPI draft impl --- examples/tree/artifacts/dumps/asm.txt | 126 ++++++++++-------- .../tree/artifacts/snippets/asm/constants.txt | 14 ++ .../asm/initialize-create-account.txt | 53 ++++++-- .../tests/entrypoint_branching/result.txt | 46 ------- .../tests/initialize_input_checks/result.txt | 123 ----------------- .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 46 ------- .../tests/initialize_pda_checks/test.txt | 4 - examples/tree/interface/src/asm.rs | 43 ++++++ examples/tree/src/tree/tree.s | 67 ++++++++-- 10 files changed, 229 insertions(+), 297 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index abf701d7..ac9b0a85 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1512 (bytes into file) + Start of section headers 1704 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x5e8 +There are 7 section headers, starting at offset 0x6a8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0003a8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000490 000490 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000530 000530 000048 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000578 000578 000030 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000005a8 0005a8 000010 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0005b8 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000428 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000510 000510 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000005b0 0005b0 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000610 000610 000048 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000658 000658 000020 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000678 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0003a8 0x0003a8 R E 0x1000 - LOAD 0x000530 0x0000000000000530 0x0000000000000530 0x000088 0x000088 R 0x1000 - DYNAMIC 0x000490 0x0000000000000490 0x0000000000000490 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000428 0x000428 R E 0x1000 + LOAD 0x0005b0 0x00000000000005b0 0x00000000000005b0 0x0000c8 0x0000c8 R 0x1000 + DYNAMIC 0x000510 0x0000000000000510 0x0000000000000510 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,28 +52,30 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x490 contains 10 entries +Dynamic section at offset 0x510 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x5a8 - 0x0000000000000012 (RELSZ) 16 (bytes) + 0x0000000000000011 (REL) 0x658 + 0x0000000000000012 (RELSZ) 32 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x530 + 0x0000000000000006 (SYMTAB) 0x5b0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x578 - 0x000000000000000a (STRSZ) 48 (bytes) + 0x0000000000000005 (STRTAB) 0x610 + 0x000000000000000a (STRSZ) 72 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x5a8 contains 1 entries +Relocation section '.rel.dyn' at offset 0x658 contains 2 entries Offset Info Type Symbol's Value Symbol's Name -0000000000000258 000000020000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000258 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000470 000000020000000a R_BPF_64_32 0000000000000000 sol_create_program_address -Symbol table '.dynsym' contains 3 entries +Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1 00000000000000e8 0 NOTYPE GLOBAL DEFAULT 1 entrypoint - 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_try_find_program_address + 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_create_program_address + 3 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_try_find_program_address There are no section groups in this file. tree.so file format elf64-bpf @@ -92,31 +94,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 67 00 00 00 00 00 if r9 != 0x0 goto +0x67 + 40 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 63 00 ff 00 00 00 if r9 != 0xff goto +0x63 + 42 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 5f 00 00 00 00 00 if r9 != 0x0 goto +0x5f + 44 55 09 6f 00 00 00 00 00 if r9 != 0x0 goto +0x6f 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 5b 00 ff 00 00 00 if r9 != 0xff goto +0x5b + 46 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 57 00 0e 00 00 00 if r9 != 0xe goto +0x57 + 48 55 09 67 00 0e 00 00 00 if r9 != 0xe goto +0x67 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 53 00 ff 00 00 00 if r9 != 0xff goto +0x53 + 50 55 09 63 00 ff 00 00 00 if r9 != 0xff goto +0x63 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 4d 00 00 00 00 00 if r9 != r8 goto +0x4d + 54 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 49 00 00 00 00 00 if r9 != r8 goto +0x49 + 58 5d 89 59 00 00 00 00 00 if r9 != r8 goto +0x59 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 45 00 00 00 00 00 if r9 != r8 goto +0x45 + 62 5d 89 55 00 00 00 00 00 if r9 != r8 goto +0x55 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 42 00 00 00 00 00 if r9 != r8 goto +0x42 + 65 5d 89 52 00 00 00 00 00 if r9 != r8 goto +0x52 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 3c 00 00 00 00 00 if r9 != 0x0 goto +0x3c + 67 55 09 4c 00 00 00 00 00 if r9 != 0x0 goto +0x4c 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -127,16 +129,16 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 33 00 00 00 00 00 if r9 != r8 goto +0x33 + 78 5d 89 43 00 00 00 00 00 if r9 != r8 goto +0x43 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 30 00 00 00 00 00 if r9 != r8 goto +0x30 + 81 5d 89 40 00 00 00 00 00 if r9 != r8 goto +0x40 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 2d 00 00 00 00 00 if r9 != r8 goto +0x2d + 84 5d 89 3d 00 00 00 00 00 if r9 != r8 goto +0x3d 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 2a 00 00 00 00 00 if r9 != r8 goto +0x2a + 87 5d 89 3a 00 00 00 00 00 if r9 != r8 goto +0x3a 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -176,22 +178,38 @@ Disassembly of section .text 124 7a 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = 0x0 125 07 01 00 00 10 00 00 00 r1 += 0x10 126 7a 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = 0x0 - 127 95 00 00 00 00 00 00 00 exit - 128 b7 00 00 00 09 00 00 00 r0 = 0x9 - 129 95 00 00 00 00 00 00 00 exit - 130 b7 00 00 00 0a 00 00 00 r0 = 0xa - 131 95 00 00 00 00 00 00 00 exit - 132 b7 00 00 00 08 00 00 00 r0 = 0x8 - 133 95 00 00 00 00 00 00 00 exit - 134 b7 00 00 00 07 00 00 00 r0 = 0x7 - 135 95 00 00 00 00 00 00 00 exit - 136 b7 00 00 00 04 00 00 00 r0 = 0x4 - 137 95 00 00 00 00 00 00 00 exit - 138 b7 00 00 00 06 00 00 00 r0 = 0x6 - 139 95 00 00 00 00 00 00 00 exit - 140 b7 00 00 00 03 00 00 00 r0 = 0x3 - 141 95 00 00 00 00 00 00 00 exit - 142 b7 00 00 00 05 00 00 00 r0 = 0x5 + 127 07 04 00 00 40 01 00 00 r4 += 0x140 + 128 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 129 07 04 00 00 28 00 00 00 r4 += 0x28 + 130 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 131 07 04 00 00 a1 ff ff ff r4 += -0x5f + 132 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 133 07 04 00 00 ff 00 00 00 r4 += 0xff + 134 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 + 135 07 04 00 00 f0 ff ff ff r4 += -0x10 + 136 bf a1 00 00 00 00 00 00 r1 = r10 + 137 07 0a 00 00 d8 fe ff ff r10 += -0x128 + 138 bf a2 00 00 00 00 00 00 r2 = r10 + 139 07 0a 00 00 20 ff ff ff r10 += -0xe0 + 140 b7 03 00 00 02 00 00 00 r3 = 0x2 + 141 b7 05 00 00 01 00 00 00 r5 = 0x1 + 142 85 10 00 00 ff ff ff ff call -0x1 143 95 00 00 00 00 00 00 00 exit - 144 b7 00 00 00 02 00 00 00 r0 = 0x2 - 145 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 144 b7 00 00 00 09 00 00 00 r0 = 0x9 + 145 95 00 00 00 00 00 00 00 exit + 146 b7 00 00 00 0a 00 00 00 r0 = 0xa + 147 95 00 00 00 00 00 00 00 exit + 148 b7 00 00 00 08 00 00 00 r0 = 0x8 + 149 95 00 00 00 00 00 00 00 exit + 150 b7 00 00 00 07 00 00 00 r0 = 0x7 + 151 95 00 00 00 00 00 00 00 exit + 152 b7 00 00 00 04 00 00 00 r0 = 0x4 + 153 95 00 00 00 00 00 00 00 exit + 154 b7 00 00 00 06 00 00 00 r0 = 0x6 + 155 95 00 00 00 00 00 00 00 exit + 156 b7 00 00 00 03 00 00 00 r0 = 0x3 + 157 95 00 00 00 00 00 00 00 exit + 158 b7 00 00 00 05 00 00 00 r0 = 0x5 + 159 95 00 00 00 00 00 00 00 exit + 160 b7 00 00 00 02 00 00 00 r0 = 0x2 + 161 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 5c598bdf..0317e87b 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -110,7 +110,10 @@ .equ SF_INIT_SIGNERS_SEEDS_ADDR_OFF, -112 # Signers seeds address field. .equ SF_INIT_SIGNERS_SEEDS_LEN_OFF, -104 # Signers seeds length field. .equ SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF, -32 # System Program address. +.equ SF_INIT_INSN_PROGRAM_ID_OFF, -296 # SolInstruction program_id field. +.equ SF_INIT_INSN_ACCOUNTS_OFF, -288 # SolInstruction accounts field. .equ SF_INIT_INSN_ACCOUNT_LEN_OFF, -280 # SolInstruction account_len field. +.equ SF_INIT_INSN_DATA_OFF, -272 # SolInstruction data field. .equ SF_INIT_INSN_DATA_LEN_OFF, -264 # SolInstruction data_len field. # SolAccountMeta is_writable field for user account. .equ SF_INIT_USER_META_IS_WRITABLE_OFF, -248 @@ -140,6 +143,17 @@ .equ SF_INIT_TREE_INFO_LAMPORTS_OFF, -160 # SolAccountInfo data_len field for tree account. .equ SF_INIT_TREE_INFO_DATA_OFF, -144 +# Relative offset from PDA on stack to System Program ID. +.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 320 +# Relative offset from SolInstruction to first SolAccountMeta. +.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, 40 +# Relative offset from SolAccountMeta array to instruction data. +.equ SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM, -95 +# Relative offset from instruction data to signer seeds. +.equ SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM, 255 +# Relative offset from signer seeds to signers seeds. +.equ SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM, -16 +.equ SF_INIT_ACCT_INFOS_OFF, -224 # Account infos array. # CPI-specific constants. # ----------------------- diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 10616a2e..b3389a4f 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -1,9 +1,9 @@ # Pack SolInstruction. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] System Program ID pointer. - # - [ ] Account metas pointer. - # - [ ] Instruction data pointer. + # - [x] System Program ID pointer. + # - [x] Account metas pointer. + # - [x] Instruction data pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN @@ -75,14 +75,10 @@ # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk assign/load pointers. + # Bulk assign/load pointers for account info/addresses. # --------------------------------------------------------------------- - # Finish with: - # - [ ] r1 = pointer to instruction. - # - [ ] r2 = pointer to account infos. - # - [ ] r3 = number of account infos. - # - [ ] r4 = pointer to signer's seeds. - # - [ ] r5 = number of signers. + # Since pointers must be loaded from registers, this block steps + # through the input buffer in order to reduce intermediate loads. # --------------------------------------------------------------------- add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. @@ -104,3 +100,40 @@ add64 r1, SIZE_OF_U128 # Advance to tree data. stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + # Bulk assign/load pointers for CPI bindings. + # --------------------------------------------------------------------- + # This block steps through the stack frame, optimizing assignments in + # preparation for the impending CreateAccount CPI, which requires: + # - [x] r1 = pointer to instruction. + # - [x] r2 = pointer to account infos. + # - [x] r4 = pointer to signers seeds. + # Notably, it reuses r4 from the PDA derivation syscall to walk through + # pointers on the stack, before advancing it to its final value. + # --------------------------------------------------------------------- + # Advance to System Program ID pointer on zero-initialized stack. + add64 r4, SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 + # Advance to SolAccountMeta array pointer. + add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Advance to instruction data pointer. + add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. + # Advance to signer seeds pointer. + add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM + stxdw [r10 + SF_INIT_SIGNERS_SEEDS_ADDR_OFF], r4 + # Advance to signers seeds pointer. + add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + # Assign remaining syscall pointers. + mov64 r1, r10 + add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r2, r10 + add64 r2, SF_INIT_ACCT_INFOS_OFF + + # Invoke CPI. + # --------------------------------------------------------------------- + mov64 r3, CPI_N_ACCOUNTS + mov64 r5, CPI_N_PDA_SIGNERS + call sol_create_program_address # Create PDA. + diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index f7752b8f..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,46 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Three accounts | 5 | 7 | +2 | +40.0% | -| Five accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -warning: unused variable: `signers_seeds` - --> tree/src/program.rs:165:9 - | -165 | let signers_seeds = SolSignerSeeds { - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: function `check_success` is never used - --> tree/src/tests.rs:26:4 - | -26 | fn check_success( - | ^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 2 warnings -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 90945de3..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,123 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | -| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | -| Non-empty instruction data | 31 | 37 | +6 | +19.4% | -test tests::test_initialize_input_checks ... ok -warning: unused variable: `signers_seeds` - --> tree/src/program.rs:165:9 - | -165 | let signers_seeds = SolSignerSeeds { - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: function `check_success` is never used - --> tree/src/tests.rs:26:4 - | -26 | fn check_success( - | ^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 2 warnings -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index 986f546b..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 0b7ae552..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,46 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | -| PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | -| PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | -| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | -test tests::test_initialize_pda_checks ... ok -warning: unused variable: `signers_seeds` - --> tree/src/program.rs:165:9 - | -165 | let signers_seeds = SolSignerSeeds { - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_signers_seeds` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default -warning: function `check_success` is never used - --> tree/src/tests.rs:26:4 - | -26 | fn check_success( - | ^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default -warning: `tree` (lib test) generated 2 warnings -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1549 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 785e888f..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false); -} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 829772dc..81bda5af 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -112,8 +112,14 @@ asm_constant_group! { stack_frame_offset!(SIGNERS_SEEDS_LEN, InitStackFrame.signers_seeds[0].len), /// System Program address. stack_frame_offset!(SYSTEM_PROGRAM_ADDRESS, InitStackFrame.system_program_address), + /// SolInstruction program_id field. + stack_frame_offset!(INSN_PROGRAM_ID, InitStackFrame.instruction.program_id), + /// SolInstruction accounts field. + stack_frame_offset!(INSN_ACCOUNTS, InitStackFrame.instruction.accounts), /// SolInstruction account_len field. stack_frame_offset!(INSN_ACCOUNT_LEN, InitStackFrame.instruction.account_len), + /// SolInstruction data field. + stack_frame_offset!(INSN_DATA, InitStackFrame.instruction.data), /// SolInstruction data_len field. stack_frame_offset!(INSN_DATA_LEN, InitStackFrame.instruction.data_len), /// SolAccountMeta is_writable field for user account. @@ -186,5 +192,42 @@ asm_constant_group! { TREE_INFO_DATA, InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].data ), + /// Relative offset from PDA on stack to System Program ID. + relative_offset_immediate!( + PDA, + SYSTEM_PROGRAM_ID, + InitStackFrame.bump_seed, + InitStackFrame.system_program_address + ), + /// Relative offset from SolInstruction to first SolAccountMeta. + relative_offset_immediate!( + SYSTEM_PROGRAM_ID, + ACCT_METAS, + InitStackFrame.instruction, + InitStackFrame.account_metas + ), + /// Relative offset from SolAccountMeta array to instruction data. + relative_offset_immediate!( + ACCT_METAS, + INSN_DATA, + InitStackFrame.account_metas, + InitStackFrame.instruction_data + ), + /// Relative offset from instruction data to signer seeds. + relative_offset_immediate!( + INSN_DATA, + SIGNER_SEEDS, + InitStackFrame.instruction_data, + InitStackFrame.signer_seeds + ), + /// Relative offset from signer seeds to signers seeds. + relative_offset_immediate!( + SIGNER_SEEDS, + SIGNERS_SEEDS, + InitStackFrame.signer_seeds, + InitStackFrame.signers_seeds + ), + /// Account infos array. + stack_frame_offset!(ACCT_INFOS, InitStackFrame.account_infos), } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index fc392a62..606f4364 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -111,7 +111,10 @@ .equ SF_INIT_SIGNERS_SEEDS_ADDR_OFF, -112 # Signers seeds address field. .equ SF_INIT_SIGNERS_SEEDS_LEN_OFF, -104 # Signers seeds length field. .equ SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF, -32 # System Program address. +.equ SF_INIT_INSN_PROGRAM_ID_OFF, -296 # SolInstruction program_id field. +.equ SF_INIT_INSN_ACCOUNTS_OFF, -288 # SolInstruction accounts field. .equ SF_INIT_INSN_ACCOUNT_LEN_OFF, -280 # SolInstruction account_len field. +.equ SF_INIT_INSN_DATA_OFF, -272 # SolInstruction data field. .equ SF_INIT_INSN_DATA_LEN_OFF, -264 # SolInstruction data_len field. # SolAccountMeta is_writable field for user account. .equ SF_INIT_USER_META_IS_WRITABLE_OFF, -248 @@ -141,6 +144,17 @@ .equ SF_INIT_TREE_INFO_LAMPORTS_OFF, -160 # SolAccountInfo data_len field for tree account. .equ SF_INIT_TREE_INFO_DATA_OFF, -144 +# Relative offset from PDA on stack to System Program ID. +.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 320 +# Relative offset from SolInstruction to first SolAccountMeta. +.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, 40 +# Relative offset from SolAccountMeta array to instruction data. +.equ SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM, -95 +# Relative offset from instruction data to signer seeds. +.equ SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM, 255 +# Relative offset from signer seeds to signers seeds. +.equ SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM, -16 +.equ SF_INIT_ACCT_INFOS_OFF, -224 # Account infos array. # CPI-specific constants. # ----------------------- @@ -266,9 +280,9 @@ initialize: # Pack SolInstruction. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] System Program ID pointer. - # - [ ] Account metas pointer. - # - [ ] Instruction data pointer. + # - [x] System Program ID pointer. + # - [x] Account metas pointer. + # - [x] Instruction data pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN @@ -340,14 +354,10 @@ initialize: # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk assign/load pointers. + # Bulk assign/load pointers for account info/addresses. # --------------------------------------------------------------------- - # Finish with: - # - [ ] r1 = pointer to instruction. - # - [ ] r2 = pointer to account infos. - # - [ ] r3 = number of account infos. - # - [ ] r4 = pointer to signer's seeds. - # - [ ] r5 = number of signers. + # Since pointers must be loaded from registers, this block steps + # through the input buffer in order to reduce intermediate loads. # --------------------------------------------------------------------- add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. @@ -369,6 +379,43 @@ initialize: add64 r1, SIZE_OF_U128 # Advance to tree data. stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + # Bulk assign/load pointers for CPI bindings. + # --------------------------------------------------------------------- + # This block steps through the stack frame, optimizing assignments in + # preparation for the impending CreateAccount CPI, which requires: + # - [x] r1 = pointer to instruction. + # - [x] r2 = pointer to account infos. + # - [x] r4 = pointer to signers seeds. + # Notably, it reuses r4 from the PDA derivation syscall to walk through + # pointers on the stack, before advancing it to its final value. + # --------------------------------------------------------------------- + # Advance to System Program ID pointer on zero-initialized stack. + add64 r4, SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 + # Advance to SolAccountMeta array pointer. + add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Advance to instruction data pointer. + add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. + # Advance to signer seeds pointer. + add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM + stxdw [r10 + SF_INIT_SIGNERS_SEEDS_ADDR_OFF], r4 + # Advance to signers seeds pointer. + add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + # Assign remaining syscall pointers. + mov64 r1, r10 + add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r2, r10 + add64 r2, SF_INIT_ACCT_INFOS_OFF + + # Invoke CPI. + # --------------------------------------------------------------------- + mov64 r3, CPI_N_ACCOUNTS + mov64 r5, CPI_N_PDA_SIGNERS + call sol_create_program_address # Create PDA. + // ANCHOR_END: initialize-create-account From 5490614a0a8d2c10455ef647e78666020f6b102d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:03:29 -0800 Subject: [PATCH 125/263] Fix syscall --- .../tree/artifacts/snippets/asm/initialize-create-account.txt | 2 +- examples/tree/src/tree/tree.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index b3389a4f..ed2e0e21 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -135,5 +135,5 @@ # --------------------------------------------------------------------- mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS - call sol_create_program_address # Create PDA. + call sol_invoke_signed_c diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 606f4364..e4097814 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -414,7 +414,7 @@ initialize: # --------------------------------------------------------------------- mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS - call sol_create_program_address # Create PDA. + call sol_invoke_signed_c // ANCHOR_END: initialize-create-account From 05e24504b864723e5af99d25b4bce02dea13e99c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:11:12 -0800 Subject: [PATCH 126/263] Update program logic x2 --- .../snippets/asm/initialize-create-account.txt | 13 ++++++------- .../snippets/rs/initialize-create-account.txt | 2 +- examples/tree/src/program.rs | 2 +- examples/tree/src/tree/tree.s | 12 +++++------- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index ed2e0e21..7d23a629 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -91,14 +91,14 @@ stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. # Advance to tree address field. add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM - stdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. - stdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. - stdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. - stdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to tree data. - stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. # Bulk assign/load pointers for CPI bindings. # --------------------------------------------------------------------- @@ -135,5 +135,4 @@ # --------------------------------------------------------------------- mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS - call sol_invoke_signed_c - + call sol_invoke_signed_c \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 8bb0dca5..e27bd1fb 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -21,7 +21,7 @@ }; // Initialize signer seeds for PDA. - let signers_seeds = SolSignerSeeds { + let _signers_seeds = SolSignerSeeds { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] addr: transmute(&bump_seed), len: cpi::N_SEEDS as u64, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 9eb9d644..13f35e46 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -162,7 +162,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }; // Initialize signer seeds for PDA. - let signers_seeds = SolSignerSeeds { + let _signers_seeds = SolSignerSeeds { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] addr: transmute(&bump_seed), len: cpi::N_SEEDS as u64, diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index e4097814..748c4d29 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -370,14 +370,14 @@ initialize: stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. # Advance to tree address field. add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM - stdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. - stdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. - stdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. - stdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to tree data. - stdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. # Bulk assign/load pointers for CPI bindings. # --------------------------------------------------------------------- @@ -415,8 +415,6 @@ initialize: mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS call sol_invoke_signed_c - - // ANCHOR_END: initialize-create-account exit From 742a7b25b27ee6d5de1c4e11d2e22933dd74bca1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:12:24 -0800 Subject: [PATCH 127/263] Update deferred pointer load comment --- examples/tree/src/tree/tree.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 748c4d29..f0d24e58 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -350,7 +350,7 @@ initialize: # Initialize signers seeds for PDA. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] Signer seed pointer. + # - [x] Signer seed pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS From 4c5fe22c62d6b566575a284a6faf7850951ed758 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:29:20 -0800 Subject: [PATCH 128/263] Finalize tests --- examples/tree/artifacts/dumps/asm.txt | 40 ++--- .../tree/artifacts/snippets/asm/constants.txt | 6 +- .../asm/initialize-create-account.txt | 2 +- .../tests/entrypoint_branching/result.txt | 31 ++++ .../tests/entrypoint_branching/test.txt | 2 +- .../initialize_create_account/result.txt | 13 ++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 108 +++++++++++++ .../tests/initialize_input_checks/test.txt | 4 + .../tests/initialize_pda_checks/result.txt | 31 ++++ .../tests/initialize_pda_checks/test.txt | 4 + examples/tree/interface/src/asm.rs | 6 +- examples/tree/src/tests.rs | 43 +++-- examples/tree/src/tests/init.rs | 151 ++++++++++++++++-- examples/tree/src/tree/tree.s | 6 +- 15 files changed, 383 insertions(+), 68 deletions(-) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index ac9b0a85..3c71d112 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1704 (bytes into file) + Start of section headers 1696 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,7 +19,7 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x6a8 +There are 7 section headers, starting at offset 0x6a0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al @@ -27,9 +27,9 @@ Section Headers [ 1] .text PROGBITS 00000000000000e8 0000e8 000428 00 AX 0 0 4 [ 2] .dynamic DYNAMIC 0000000000000510 000510 0000a0 10 WA 4 0 8 [ 3] .dynsym DYNSYM 00000000000005b0 0005b0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000610 000610 000048 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000658 000658 000020 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000678 00002c 00 0 0 1 + [ 4] .dynstr STRTAB 0000000000000610 000610 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000650 000650 000020 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000670 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,7 +43,7 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000428 0x000428 R E 0x1000 - LOAD 0x0005b0 0x00000000000005b0 0x00000000000005b0 0x0000c8 0x0000c8 R 0x1000 + LOAD 0x0005b0 0x00000000000005b0 0x00000000000005b0 0x0000c0 0x0000c0 R 0x1000 DYNAMIC 0x000510 0x0000000000000510 0x0000000000000510 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping @@ -55,26 +55,26 @@ Program Headers Dynamic section at offset 0x510 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x658 + 0x0000000000000011 (REL) 0x650 0x0000000000000012 (RELSZ) 32 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) 0x0000000000000006 (SYMTAB) 0x5b0 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000005 (STRTAB) 0x610 - 0x000000000000000a (STRSZ) 72 (bytes) + 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x658 contains 2 entries +Relocation section '.rel.dyn' at offset 0x650 contains 2 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -0000000000000470 000000020000000a R_BPF_64_32 0000000000000000 sol_create_program_address +0000000000000470 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name 0 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1 00000000000000e8 0 NOTYPE GLOBAL DEFAULT 1 entrypoint - 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_create_program_address + 2 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_invoke_signed_c 3 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND sol_try_find_program_address There are no section groups in this file. @@ -170,17 +170,17 @@ Disassembly of section .text 116 07 01 00 00 10 00 00 00 r1 += 0x10 117 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 118 07 01 00 00 10 28 00 00 r1 += 0x2810 - 119 7a 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = 0x0 - 120 7a 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = 0x0 + 119 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 120 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 121 07 01 00 00 20 00 00 00 r1 += 0x20 - 122 7a 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = 0x0 + 122 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 123 07 01 00 00 20 00 00 00 r1 += 0x20 - 124 7a 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = 0x0 + 124 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 125 07 01 00 00 10 00 00 00 r1 += 0x10 - 126 7a 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = 0x0 - 127 07 04 00 00 40 01 00 00 r4 += 0x140 + 126 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 127 07 04 00 00 30 00 00 00 r4 += 0x30 128 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 129 07 04 00 00 28 00 00 00 r4 += 0x28 + 129 07 04 00 00 20 ff ff ff r4 += -0xe0 130 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 131 07 04 00 00 a1 ff ff ff r4 += -0x5f 132 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 @@ -188,9 +188,9 @@ Disassembly of section .text 134 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 135 07 04 00 00 f0 ff ff ff r4 += -0x10 136 bf a1 00 00 00 00 00 00 r1 = r10 - 137 07 0a 00 00 d8 fe ff ff r10 += -0x128 + 137 07 01 00 00 d8 fe ff ff r1 += -0x128 138 bf a2 00 00 00 00 00 00 r2 = r10 - 139 07 0a 00 00 20 ff ff ff r10 += -0xe0 + 139 07 02 00 00 20 ff ff ff r2 += -0xe0 140 b7 03 00 00 02 00 00 00 r3 = 0x2 141 b7 05 00 00 01 00 00 00 r5 = 0x1 142 85 10 00 00 ff ff ff ff call -0x1 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 0317e87b..9eb4bf5a 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -144,9 +144,9 @@ # SolAccountInfo data_len field for tree account. .equ SF_INIT_TREE_INFO_DATA_OFF, -144 # Relative offset from PDA on stack to System Program ID. -.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 320 -# Relative offset from SolInstruction to first SolAccountMeta. -.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, 40 +.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 48 +# Relative offset from System Program ID to first SolAccountMeta. +.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, -224 # Relative offset from SolAccountMeta array to instruction data. .equ SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM, -95 # Relative offset from instruction data to signer seeds. diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 7d23a629..4c2755ba 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -71,7 +71,7 @@ # Initialize signers seeds for PDA. # --------------------------------------------------------------------- # Packed later during bulk pointer load operation: - # - [ ] Signer seed pointer. + # - [x] Signer seed pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..a4015b68 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Three accounts | 5 | 7 | +2 | +40.0% | +| Five accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/test.txt b/examples/tree/artifacts/tests/entrypoint_branching/test.txt index 6cbbe3ae..cfd0f52a 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/test.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/test.txt @@ -1,4 +1,4 @@ #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES, false); + print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..0c689a3e --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,13 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| CreateAccount happy path | 2701 | 1557 | -1144 | -42.4% | + (Rust) CreateAccount happy path: owner: expected DASMAC..., got 11111111111111111111111111111111; data len: expected 16, got 0; lamports: expected 501120, got 0 +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1557 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..99462095 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, true); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..710d9f61 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,108 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | +| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | +| Non-empty instruction data | 31 | 37 | +6 | +19.4% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..24226cfc --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..7c059c13 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | +| PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | +| PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | +| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1549 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 81bda5af..27ab8370 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -196,14 +196,14 @@ asm_constant_group! { relative_offset_immediate!( PDA, SYSTEM_PROGRAM_ID, - InitStackFrame.bump_seed, + InitStackFrame.pda, InitStackFrame.system_program_address ), - /// Relative offset from SolInstruction to first SolAccountMeta. + /// Relative offset from System Program ID to first SolAccountMeta. relative_offset_immediate!( SYSTEM_PROGRAM_ID, ACCT_METAS, - InitStackFrame.instruction, + InitStackFrame.system_program_address, InitStackFrame.account_metas ), /// Relative offset from SolAccountMeta array to instruction data. diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 73862604..6be547f7 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -7,7 +7,7 @@ use solana_sdk::instruction::Instruction; use solana_sdk::program_error::ProgramError; use solana_sdk::pubkey::Pubkey; use test_utils::{setup_test, ProgramLanguage, TestSetup}; -use tree_interface::error_codes; +use tree_interface::{cpi, error_codes}; const USER_LAMPORTS: u64 = 1_000_000; @@ -23,24 +23,6 @@ struct CaseResult { error: Option, } -fn check_success( - setup: &TestSetup, - instruction: &Instruction, - accounts: &[(Pubkey, Account)], -) -> CaseResult { - let result = setup.mollusk.process_instruction(instruction, accounts); - match &result.program_result { - MolluskResult::Success => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Success, got {:?}", other)), - }, - } -} - fn check_error( setup: &TestSetup, instruction: &Instruction, @@ -66,7 +48,11 @@ trait TestCase: Copy { fn run(&self, lang: ProgramLanguage) -> CaseResult; } -fn print_comparison_table(cases: &[T], allow_asm_failures: bool) { +fn print_comparison_table( + cases: &[T], + allow_asm_failures: bool, + allow_rust_failures: bool, +) { let mut failures = Vec::new(); println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); @@ -98,7 +84,11 @@ fn print_comparison_table(cases: &[T], allow_asm_failures: bool) { } } if let Some(err) = &rs.error { - failures.push(format!(" Rust {}: {}", case.name(), err)); + if allow_rust_failures { + println!(" (Rust) {}: {}", case.name(), err); + } else { + failures.push(format!(" Rust {}: {}", case.name(), err)); + } } } @@ -111,15 +101,20 @@ fn print_comparison_table(cases: &[T], allow_asm_failures: bool) { #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES, false); + print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); } #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false); + print_comparison_table(init::InitCase::CASES, false, false); } #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false); + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} + +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, true); } diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 38cff7eb..4f916828 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -1,7 +1,10 @@ use super::*; use mollusk_svm::program; +use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; +const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; + fn init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { @@ -41,7 +44,8 @@ fn init_setup( fn pda_init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(program_language); + let mut setup = setup_test(program_language); + setup.mollusk.sysvars.rent.exemption_threshold = SIMD0194_EXEMPTION_THRESHOLD; let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) = @@ -111,6 +115,7 @@ pub(super) enum InitCase { PdaMismatchChunk1, PdaMismatchChunk2, PdaMismatchChunk3, + CreateAccountHappyPath, } impl InitCase { @@ -138,6 +143,8 @@ impl InitCase { Self::PdaMismatchChunk2, Self::PdaMismatchChunk3, ]; + + pub(super) const CPI_CASES: &'static [Self] = &[Self::CreateAccountHappyPath]; } impl TestCase for InitCase { @@ -162,6 +169,7 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", + Self::CreateAccountHappyPath => "CreateAccount happy path", } } @@ -236,14 +244,62 @@ impl TestCase for InitCase { error_codes::error::RENT_DUPLICATE, ) } - Self::RentAddressWord0 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 0, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord1 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 1, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord2 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 2, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord3 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 3, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord4 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 4, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord5 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 5, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord6 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 6, size_of::(), error_codes::error::RENT_ADDRESS), - Self::RentAddressWord7 => run_address_mismatch(lang, AccountIndex::RentSysvar as usize, 7, size_of::(), error_codes::error::RENT_ADDRESS), + Self::RentAddressWord0 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 0, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord1 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 1, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord2 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 2, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord3 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 3, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord4 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 4, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord5 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 5, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord6 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 6, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressWord7 => run_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 7, + size_of::(), + error_codes::error::RENT_ADDRESS, + ), Self::InstructionData => { let (setup, mut instruction, accounts) = init_setup(lang); instruction.data = vec![1u8; 1]; @@ -254,10 +310,79 @@ impl TestCase for InitCase { error_codes::error::INSTRUCTION_DATA, ) } - Self::PdaMismatchChunk0 => run_address_mismatch(lang, AccountIndex::Tree as usize, 0, size_of::(), error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk1 => run_address_mismatch(lang, AccountIndex::Tree as usize, 1, size_of::(), error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk2 => run_address_mismatch(lang, AccountIndex::Tree as usize, 2, size_of::(), error_codes::error::PDA_MISMATCH), - Self::PdaMismatchChunk3 => run_address_mismatch(lang, AccountIndex::Tree as usize, 3, size_of::(), error_codes::error::PDA_MISMATCH), + Self::PdaMismatchChunk0 => run_address_mismatch( + lang, + AccountIndex::Tree as usize, + 0, + size_of::(), + error_codes::error::PDA_MISMATCH, + ), + Self::PdaMismatchChunk1 => run_address_mismatch( + lang, + AccountIndex::Tree as usize, + 1, + size_of::(), + error_codes::error::PDA_MISMATCH, + ), + Self::PdaMismatchChunk2 => run_address_mismatch( + lang, + AccountIndex::Tree as usize, + 2, + size_of::(), + error_codes::error::PDA_MISMATCH, + ), + Self::PdaMismatchChunk3 => run_address_mismatch( + lang, + AccountIndex::Tree as usize, + 3, + size_of::(), + error_codes::error::PDA_MISMATCH, + ), + Self::CreateAccountHappyPath => { + let (setup, instruction, accounts) = pda_init_setup(lang); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => { + let tree = &result.resulting_accounts[AccountIndex::Tree as usize].1; + let rent_data = &accounts[AccountIndex::RentSysvar as usize].1.data; + let rent = Rent::from_bytes(rent_data).unwrap(); + let expected_lamports = + rent.try_minimum_balance(cpi::TREE_DATA_LEN).unwrap(); + let mut errors = Vec::new(); + if tree.owner != setup.program_id { + errors.push(format!( + "owner: expected {:?}, got {:?}", + setup.program_id, tree.owner + )); + } + if tree.data.len() != cpi::TREE_DATA_LEN { + errors.push(format!( + "data len: expected {}, got {}", + cpi::TREE_DATA_LEN, + tree.data.len() + )); + } + if tree.lamports != expected_lamports { + errors.push(format!( + "lamports: expected {}, got {}", + expected_lamports, tree.lamports + )); + } + CaseResult { + cu: result.compute_units_consumed, + error: if errors.is_empty() { + None + } else { + Some(errors.join("; ")) + }, + } + } + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } + } } } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index f0d24e58..2cb6c275 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -145,9 +145,9 @@ # SolAccountInfo data_len field for tree account. .equ SF_INIT_TREE_INFO_DATA_OFF, -144 # Relative offset from PDA on stack to System Program ID. -.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 320 -# Relative offset from SolInstruction to first SolAccountMeta. -.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, 40 +.equ SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM, 48 +# Relative offset from System Program ID to first SolAccountMeta. +.equ SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM, -224 # Relative offset from SolAccountMeta array to instruction data. .equ SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM, -95 # Relative offset from instruction data to signer seeds. From c3c36f31044592e8bae17046c5d32eb6b5b9fcdd Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:58:19 -0800 Subject: [PATCH 129/263] Implement rs CPI --- .../tree/artifacts/snippets/asm/constants.txt | 10 +- .../snippets/asm/initialize-input-checks.txt | 3 + .../snippets/rs/initialize-create-account.txt | 85 ++++++++++++++++- examples/tree/interface/src/common.rs | 18 +++- examples/tree/interface/src/lib.rs | 2 +- examples/tree/src/program.rs | 94 +++++++++++++++++-- examples/tree/src/tests.rs | 2 +- examples/tree/src/tree/tree.s | 11 +++ 8 files changed, 210 insertions(+), 15 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 9eb4bf5a..20c570a3 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -41,7 +41,14 @@ # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ACCOUNT_OFF, 8 # User runtime account. +.equ IB_USER_LAMPORTS_OFF, 80 # User Lamports field. +.equ IB_USER_DATA_OFF, 96 # User data field. +.equ IB_USER_OWNER_OFF, 48 # User owner field. +.equ IB_TREE_LAMPORTS_OFF, 10416 # Tree Lamports field. +.equ IB_TREE_DATA_OFF, 10432 # Tree data field. +.equ IB_TREE_OWNER_OFF, 10384 # Tree owner field. .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. +.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 .equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header. @@ -169,4 +176,5 @@ .equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. .equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. -.equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. \ No newline at end of file +.equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. +.equ CPI_RENT_EPOCH_NULL, 0 # Null rent epoch. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 071f20ee..169f2593 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -45,5 +45,8 @@ initialize: # Error if instruction data provided. # --------------------------------------------------------------------- + # Init operation discriminator is number of accounts, requires no + # instruction data. + # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index e27bd1fb..fb476d21 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,5 +1,59 @@ + let sol_account_metas = [ + SolAccountMeta { + pubkey: transmute( + input_buffer_ptr.add(input_buffer::USER_ADDRESS_OFF as usize) as *const Address, + ), + is_writable: true, + is_signer: true, + }, + SolAccountMeta { + pubkey: transmute( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize) as *const Address, + ), + is_writable: true, + is_signer: true, + }, + ]; + + let sol_account_infos = [ + SolAccountInfo { + key: input_buffer_ptr + .add(input_buffer::USER_ADDRESS_OFF as usize) + .cast(), + lamports: input_buffer_ptr + .add(input_buffer::USER_LAMPORTS_OFF as usize) + .cast(), + data_len: data::DATA_LEN_ZERO, + data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), + owner: input_buffer_ptr + .add(input_buffer::USER_OWNER_OFF as usize) + .cast(), + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + SolAccountInfo { + key: input_buffer_ptr + .add(input_buffer::TREE_ADDRESS_OFF as usize) + .cast(), + lamports: input_buffer_ptr + .add(input_buffer::TREE_LAMPORTS_OFF as usize) + .cast(), + data_len: data::DATA_LEN_ZERO, + data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), + owner: input_buffer_ptr + .add(input_buffer::TREE_OWNER_OFF as usize) + .cast(), + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + ]; + // Pack CreateAccount instruction data. - let _instruction_data = CreateAccountInstructionData { + let instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), @@ -10,8 +64,15 @@ .cast(), ), }; - #[cfg(not(target_os = "solana"))] - let _ = _instruction_data; // Silence clippy. + + let system_program_address = Address::default(); + let sol_instruction = SolInstruction { + program_id: transmute(&system_program_address), + accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, + account_len: sol_account_metas.len() as u64, + data: transmute(&instruction_data), + data_len: cpi::INSN_DATA_LEN as u64, + }; // Initialize signer seed for PDA bump. let bump_seed = SolSignerSeed { @@ -21,8 +82,24 @@ }; // Initialize signer seeds for PDA. - let _signers_seeds = SolSignerSeeds { + let signers_seeds = SolSignerSeeds { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] addr: transmute(&bump_seed), len: cpi::N_SEEDS as u64, }; + + #[cfg(target_os = "solana")] + sol_invoke_signed_c( + transmute(&sol_instruction), + transmute(&sol_account_infos), + cpi::N_ACCOUNTS as u64, + transmute(&signers_seeds), + cpi::N_PDA_SIGNERS as u64, + ); + #[cfg(not(target_os = "solana"))] + #[allow(path_statements)] + { + signers_seeds; + sol_account_infos; + sol_instruction; + } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index cd66ae6a..6bc5001b 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -36,8 +36,22 @@ constant_group! { offset!(N_ACCOUNTS, InputBufferHeader.n_accounts), /// User runtime account. offset!(USER_ACCOUNT, InputBufferHeader.user), + /// User Lamports field. + offset!(USER_LAMPORTS, InputBufferHeader.user.header.lamports), + /// User data field. + offset!(USER_DATA, InputBufferHeader.user.data), + /// User owner field. + offset!(USER_OWNER, InputBufferHeader.user.header.owner), + /// Tree Lamports field. + offset!(TREE_LAMPORTS, InputBufferHeader.tree_header.lamports), + /// Tree data field. + offset!(TREE_DATA, InitInputBuffer.header.tree.data), + /// Tree owner field. + offset!(TREE_OWNER, InputBufferHeader.tree_header.owner), /// Tree runtime account header. offset!(TREE_ACCOUNT, InputBufferHeader.tree_header), + /// Tree address field. + offset!(TREE_ADDRESS, InputBufferHeader.tree_header.address), /// System Program runtime account header. offset!(SYSTEM_PROGRAM_ACCOUNT, InitInputBuffer.header.system_program), /// Rent sysvar account header. @@ -83,6 +97,8 @@ constant_group! { USER_ACCOUNT_INDEX: usize = 0, /// Account index for tree account in CPI. TREE_ACCOUNT_INDEX: usize = 1, + /// Null rent epoch. + RENT_EPOCH_NULL: u64 = 0, } } @@ -124,7 +140,7 @@ pub struct InitInputBuffer { pub struct InitInputBufferHeader { pub _n_accounts: u64, pub _user: EmptyRuntimeAccount, - pub _tree: EmptyRuntimeAccount, + pub tree: EmptyRuntimeAccount, pub system_program: SystemProgramRuntimeAccount, pub rent: RentRuntimeAccount, } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 4df0db6f..a2d0c181 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -7,5 +7,5 @@ mod bindings; mod common; pub use asm::*; -pub use bindings::{SolSignerSeed, SolSignerSeeds}; +pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{cpi, error_codes, CreateAccountInstructionData}; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 13f35e46..00c7a9d0 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -8,11 +8,14 @@ use pinocchio::{ AccountView, Address, SUCCESS, }; use tree_interface::{ - cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData, SolSignerSeed, - SolSignerSeeds, + cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData, SolAccountInfo, + SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; #[cfg(target_os = "solana")] -use {core::mem::MaybeUninit, pinocchio::syscalls::sol_try_find_program_address}; +use { + core::mem::MaybeUninit, + pinocchio::syscalls::{sol_invoke_signed_c, sol_try_find_program_address}, +}; #[inline(always)] unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { @@ -139,8 +142,62 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR_END: initialize-pda-checks // ANCHOR: initialize-create-account + let sol_account_metas = [ + SolAccountMeta { + pubkey: transmute( + input_buffer_ptr.add(input_buffer::USER_ADDRESS_OFF as usize) as *const Address, + ), + is_writable: true, + is_signer: true, + }, + SolAccountMeta { + pubkey: transmute( + input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize) as *const Address, + ), + is_writable: true, + is_signer: true, + }, + ]; + + let sol_account_infos = [ + SolAccountInfo { + key: input_buffer_ptr + .add(input_buffer::USER_ADDRESS_OFF as usize) + .cast(), + lamports: input_buffer_ptr + .add(input_buffer::USER_LAMPORTS_OFF as usize) + .cast(), + data_len: data::DATA_LEN_ZERO, + data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), + owner: input_buffer_ptr + .add(input_buffer::USER_OWNER_OFF as usize) + .cast(), + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + SolAccountInfo { + key: input_buffer_ptr + .add(input_buffer::TREE_ADDRESS_OFF as usize) + .cast(), + lamports: input_buffer_ptr + .add(input_buffer::TREE_LAMPORTS_OFF as usize) + .cast(), + data_len: data::DATA_LEN_ZERO, + data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), + owner: input_buffer_ptr + .add(input_buffer::TREE_OWNER_OFF as usize) + .cast(), + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + ]; + // Pack CreateAccount instruction data. - let _instruction_data = CreateAccountInstructionData { + let instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), @@ -151,8 +208,15 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - .cast(), ), }; - #[cfg(not(target_os = "solana"))] - let _ = _instruction_data; // Silence clippy. + + let system_program_address = Address::default(); + let sol_instruction = SolInstruction { + program_id: transmute(&system_program_address), + accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, + account_len: sol_account_metas.len() as u64, + data: transmute(&instruction_data), + data_len: cpi::INSN_DATA_LEN as u64, + }; // Initialize signer seed for PDA bump. let bump_seed = SolSignerSeed { @@ -162,12 +226,28 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }; // Initialize signer seeds for PDA. - let _signers_seeds = SolSignerSeeds { + let signers_seeds = SolSignerSeeds { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] addr: transmute(&bump_seed), len: cpi::N_SEEDS as u64, }; + #[cfg(target_os = "solana")] + sol_invoke_signed_c( + transmute(&sol_instruction), + transmute(&sol_account_infos), + cpi::N_ACCOUNTS as u64, + transmute(&signers_seeds), + cpi::N_PDA_SIGNERS as u64, + ); + #[cfg(not(target_os = "solana"))] + #[allow(path_statements)] + { + signers_seeds; + sol_account_infos; + sol_instruction; + } + // ANCHOR_END: initialize-create-account SUCCESS diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 6be547f7..20d7cb54 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -116,5 +116,5 @@ fn test_initialize_pda_checks() { #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, true); + print_comparison_table(init::InitCase::CPI_CASES, false, false); } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 2cb6c275..82c9eb39 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -42,7 +42,14 @@ # -------------------- .equ IB_N_ACCOUNTS_OFF, 0 # Number of accounts field. .equ IB_USER_ACCOUNT_OFF, 8 # User runtime account. +.equ IB_USER_LAMPORTS_OFF, 80 # User Lamports field. +.equ IB_USER_DATA_OFF, 96 # User data field. +.equ IB_USER_OWNER_OFF, 48 # User owner field. +.equ IB_TREE_LAMPORTS_OFF, 10416 # Tree Lamports field. +.equ IB_TREE_DATA_OFF, 10432 # Tree data field. +.equ IB_TREE_OWNER_OFF, 10384 # Tree owner field. .equ IB_TREE_ACCOUNT_OFF, 10344 # Tree runtime account header. +.equ IB_TREE_ADDRESS_OFF, 10352 # Tree address field. # System Program runtime account header. .equ IB_SYSTEM_PROGRAM_ACCOUNT_OFF, 20680 .equ IB_RENT_ACCOUNT_OFF, 31032 # Rent sysvar account header. @@ -171,6 +178,7 @@ .equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. .equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. +.equ CPI_RENT_EPOCH_NULL, 0 # Null rent epoch. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -241,6 +249,9 @@ initialize: # Error if instruction data provided. # --------------------------------------------------------------------- + # Init operation discriminator is number of accounts, requires no + # instruction data. + # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks From 861c2ca5140203fd07bde0c670eb88f6834b835a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:26:15 -0800 Subject: [PATCH 130/263] Rebuild --- examples/tree/artifacts/dumps/rs.txt | 203 ++++++++++++------ examples/tree/artifacts/rs-disassembly.s | 152 +++++++++---- .../snippets/asm/initialize-input-checks.txt | 3 - .../initialize_create_account/result.txt | 7 +- .../tests/initialize_create_account/test.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 12 +- examples/tree/src/program.rs | 11 +- examples/tree/src/tree/tree.s | 3 - 8 files changed, 280 insertions(+), 113 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 85b8db44..25d75e5f 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3208 (bytes into file) + Start of section headers 3872 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xc88 +There are 8 section headers, starting at offset 0xf20 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000278 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000398 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 0003a0 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 0003a0 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 0003a0 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000718 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000756 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000510 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000630 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000638 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000638 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000638 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0009b0 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0009ee 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000278 0x000278 E 0x8 - LOAD 0x000398 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x0003a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x0003a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000510 0x000510 E 0x8 + LOAD 0x000630 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000638 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000638 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 632 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1296 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,7 +104,7 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 c0 ff ff ff add64 r10, -0x40 + 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] 10 55 03 05 00 02 00 00 00 jne r3, 0x2, +0x5 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 38 00 04 00 00 00 jne r3, 0x4, +0x38 + 40 55 03 8b 00 04 00 00 00 jne r3, 0x4, +0x8b 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 34 00 00 00 00 00 jne r3, 0x0, +0x34 + 50 55 03 87 00 00 00 00 00 jne r3, 0x0, +0x87 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + 60 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 36 00 00 00 00 00 jne r3, 0x0, +0x36 + 70 55 03 89 00 00 00 00 00 jne r3, 0x0, +0x89 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + 80 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 36 00 0e 00 00 00 jne r3, 0xe, +0x36 + 90 55 03 89 00 0e 00 00 00 jne r3, 0xe, +0x89 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 36 00 ff 00 00 00 jne r3, 0xff, +0x36 + a0 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 @@ -142,44 +142,127 @@ Disassembly of section .text 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 130 55 02 26 00 00 00 00 00 jne r2, 0x0, +0x26 - 138 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 140 07 03 00 00 b8 a1 00 00 add64 r3, 0xa1b8 + 130 55 02 79 00 00 00 00 00 jne r2, 0x0, +0x79 + 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 140 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 18 00 00 00 add64 r4, 0x18 + 150 07 04 00 00 30 00 00 00 add64 r4, 0x30 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 3f 00 00 00 add64 r5, 0x3f - 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 160 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 180 9c a1 18 00 00 00 00 00 ldxdw r1, [r10 + 0x18] - 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 190 5d 21 0a 00 00 00 00 00 jne r1, r2, +0xa - 198 9c a1 20 00 00 00 00 00 ldxdw r1, [r10 + 0x20] - 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 1a8 5d 21 07 00 00 00 00 00 jne r1, r2, +0x7 - 1b0 9c a1 28 00 00 00 00 00 ldxdw r1, [r10 + 0x28] - 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 1c0 5d 21 04 00 00 00 00 00 jne r1, r2, +0x4 - 1c8 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] - 1d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 1d8 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 1e0 1d 21 ca ff 00 00 00 00 jeq r1, r2, -0x36 - 1e8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 1f0 05 00 c8 ff 00 00 00 00 ja -0x38 - 1f8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 200 05 00 c6 ff 00 00 00 00 ja -0x3a - 208 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 210 05 00 c4 ff 00 00 00 00 ja -0x3c - 218 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 220 05 00 c2 ff 00 00 00 00 ja -0x3e - 228 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 230 05 00 c0 ff 00 00 00 00 ja -0x40 - 238 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 240 05 00 be ff 00 00 00 00 ja -0x42 - 248 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 250 05 00 bc ff 00 00 00 00 ja -0x44 - 258 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 260 05 00 ba ff 00 00 00 00 ja -0x46 - 268 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 270 05 00 b8 ff 00 00 00 00 ja -0x48 \ No newline at end of file + 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 188 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 190 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 198 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c + 1a0 9c a1 38 00 00 00 00 00 ldxdw r1, [r10 + 0x38] + 1a8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1b0 5d 21 59 00 00 00 00 00 jne r1, r2, +0x59 + 1b8 9c a1 40 00 00 00 00 00 ldxdw r1, [r10 + 0x40] + 1c0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1c8 5d 21 56 00 00 00 00 00 jne r1, r2, +0x56 + 1d0 9c a1 48 00 00 00 00 00 ldxdw r1, [r10 + 0x48] + 1d8 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 1e0 5d 21 53 00 00 00 00 00 jne r1, r2, +0x53 + 1e8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 1f0 07 02 00 00 70 28 00 00 add64 r2, 0x2870 + 1f8 9f 2a 20 00 00 00 00 00 stxdw [r10 + 0x20], r2 + 200 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 208 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 210 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 + 218 37 0a 28 00 01 01 00 00 sth [r10 + 0x28], 0x101 + 220 37 0a 18 00 01 01 00 00 sth [r10 + 0x18], 0x101 + 228 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 230 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 238 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 240 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 248 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 250 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 258 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 260 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 268 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 270 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 278 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 280 07 02 00 00 30 00 00 00 add64 r2, 0x30 + 288 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 + 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 298 07 02 00 00 60 00 00 00 add64 r2, 0x60 + 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 2a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 2b0 07 02 00 00 50 00 00 00 add64 r2, 0x50 + 2b8 9f 2a 38 00 00 00 00 00 stxdw [r10 + 0x38], r2 + 2c0 9f 1a 30 00 00 00 00 00 stxdw [r10 + 0x30], r1 + 2c8 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 2d0 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 2d8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 2e0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 2e8 27 0a 62 00 00 00 00 00 stb [r10 + 0x62], 0x0 + 2f0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 2f8 97 0a 58 00 00 00 00 00 stdw [r10 + 0x58], 0x0 + 300 97 0a 40 00 00 00 00 00 stdw [r10 + 0x40], 0x0 + 308 9c 71 90 79 00 00 00 00 ldxdw r1, [r7 + 0x7990] + 310 9c 62 18 00 00 00 00 00 ldxdw r2, [r6 + 0x18] + 318 9f 2a d0 00 00 00 00 00 stxdw [r10 + 0xd0], r2 + 320 9c 62 10 00 00 00 00 00 ldxdw r2, [r6 + 0x10] + 328 9f 2a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r2 + 330 9c 62 08 00 00 00 00 00 ldxdw r2, [r6 + 0x8] + 338 9f 2a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r2 + 340 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] + 348 9f 2a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r2 + 350 96 01 00 00 90 00 00 00 lmul64 r1, 0x90 + 358 9f 1a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r1 + 360 97 0a b0 00 10 00 00 00 stdw [r10 + 0xb0], 0x10 + 368 87 0a a4 00 00 00 00 00 stw [r10 + 0xa4], 0x0 + 370 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 378 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 380 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 388 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 390 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 398 07 01 00 00 a4 00 00 00 add64 r1, 0xa4 + 3a0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3a8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3b0 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 3b8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3c8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3d0 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 3d8 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 3e0 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3f0 07 01 00 00 0f 00 00 00 add64 r1, 0xf + 3f8 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 400 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 408 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 410 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 418 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 420 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 428 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 430 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 438 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 440 07 02 00 00 30 00 00 00 add64 r2, 0x30 + 448 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 450 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 458 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 460 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 468 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 470 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 478 05 00 77 ff 00 00 00 00 ja -0x89 + 480 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 488 05 00 75 ff 00 00 00 00 ja -0x8b + 490 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 498 05 00 73 ff 00 00 00 00 ja -0x8d + 4a0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 4a8 05 00 71 ff 00 00 00 00 ja -0x8f + 4b0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4b8 05 00 6f ff 00 00 00 00 ja -0x91 + 4c0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 4c8 05 00 6d ff 00 00 00 00 ja -0x93 + 4d0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 4d8 05 00 6b ff 00 00 00 00 ja -0x95 + 4e0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 4e8 05 00 69 ff 00 00 00 00 ja -0x97 + 4f0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 4f8 05 00 67 ff 00 00 00 00 ja -0x99 + 500 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 508 05 00 65 ff 00 00 00 00 ja -0x9b \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 25b7b247..ddfc9abc 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,7 +1,7 @@ .globl entrypoint entrypoint: - add64 r10, -64 + add64 r10, -320 ldxdw r3, [r1+0] jne r3, 2, jmp_0040 ldxdw r1, [r1+88] @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0208 + jne r3, 4, jmp_0498 ldxdw r3, [r1+88] - jne r3, 0, jmp_01f8 + jne r3, 0, jmp_0488 ldxb r3, [r1+10344] - jne r3, 255, jmp_0218 + jne r3, 255, jmp_04a8 ldxdw r3, [r1+10424] - jne r3, 0, jmp_0228 + jne r3, 0, jmp_04b8 ldxb r3, [r1+20680] - jne r3, 255, jmp_0238 + jne r3, 255, jmp_04c8 ldxdw r3, [r1+20760] - jne r3, 14, jmp_0248 + jne r3, 14, jmp_04d8 ldxb r3, [r1+31032] - jne r3, 255, jmp_0258 + jne r3, 255, jmp_04e8 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 @@ -43,62 +43,142 @@ jmp_0040: mov32 r4, -1965433885 jne r3, r4, jmp_0038 ldxdw r2, [r2-8] - jne r2, 0, jmp_0268 - mov64 r3, r1 - add64 r3, 41400 + jne r2, 0, jmp_04f8 + mov64 r6, r1 + add64 r6, 41400 mov64 r4, r10 - add64 r4, 24 + add64 r4, 48 mov64 r5, r10 - add64 r5, 63 - mov64 r6, r1 + add64 r5, 15 + mov64 r7, r1 mov64 r2, 0 + mov64 r3, r6 call sol_try_find_program_address - ldxdw r1, [r10+24] - ldxdw r2, [r6+10352] - jne r1, r2, jmp_01e8 - ldxdw r1, [r10+32] - ldxdw r2, [r6+10360] - jne r1, r2, jmp_01e8 - ldxdw r1, [r10+40] - ldxdw r2, [r6+10368] - jne r1, r2, jmp_01e8 + mov64 r0, 10 ldxdw r1, [r10+48] + ldxdw r2, [r7+10352] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+56] + ldxdw r2, [r7+10360] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+64] + ldxdw r2, [r7+10368] + jne r1, r2, jmp_0038 + ldxdw r1, [r10+72] + ldxdw r2, [r7+10376] + jne r1, r2, jmp_0038 + mov64 r2, r7 + add64 r2, 10352 + stxdw [r10+32], r2 + mov64 r1, r7 + add64 r1, 16 + stxdw [r10+16], r1 + sth [r10+40], 257 + sth [r10+24], 257 + mov64 r3, r7 + add64 r3, 10384 + stxdw [r10+136], r3 + mov64 r3, r7 + add64 r3, 10432 + stxdw [r10+128], r3 + mov64 r3, r7 + add64 r3, 10416 + stxdw [r10+112], r3 + stxdw [r10+104], r2 + mov64 r2, r7 + add64 r2, 48 + stxdw [r10+80], r2 + mov64 r2, r7 + add64 r2, 96 + stxdw [r10+72], r2 + mov64 r2, r7 + add64 r2, 80 + stxdw [r10+56], r2 + stxdw [r10+48], r1 + stb [r10+154], 0 + sth [r10+152], 257 + stdw [r10+144], 0 + stdw [r10+120], 0 + stb [r10+98], 0 + sth [r10+96], 257 + stdw [r10+88], 0 + stdw [r10+64], 0 + ldxdw r1, [r7+31120] + ldxdw r2, [r6+24] + stxdw [r10+208], r2 + ldxdw r2, [r6+16] + stxdw [r10+200], r2 + ldxdw r2, [r6+8] + stxdw [r10+192], r2 + ldxdw r2, [r6+0] + stxdw [r10+184], r2 + lmul64 r1, 144 + stxdw [r10+168], r1 + stdw [r10+176], 16 + stw [r10+164], 0 + stdw [r10+240], 0 + stdw [r10+232], 0 + stdw [r10+224], 0 + stdw [r10+216], 0 + mov64 r1, r10 + add64 r1, 164 + stxdw [r10+272], r1 + mov64 r1, r10 + add64 r1, 16 + stxdw [r10+256], r1 + mov64 r1, r10 + add64 r1, 216 + stxdw [r10+248], r1 + stdw [r10+280], 52 + stdw [r10+264], 2 + mov64 r1, r10 + add64 r1, 15 + stxdw [r10+288], r1 + stdw [r10+296], 1 + mov64 r1, r10 + add64 r1, 288 + stxdw [r10+304], r1 + stdw [r10+312], 1 + mov64 r1, r10 + add64 r1, 248 + mov64 r2, r10 + add64 r2, 48 + mov64 r4, r10 + add64 r4, 304 + mov64 r3, 2 + mov64 r5, 1 + call sol_invoke_signed_c mov64 r0, 0 - ldxdw r2, [r6+10376] - jeq r1, r2, jmp_0038 - -jmp_01e8: - mov64 r0, 10 ja jmp_0038 -jmp_01f8: +jmp_0488: mov64 r0, 2 ja jmp_0038 -jmp_0208: +jmp_0498: mov64 r0, 1 ja jmp_0038 -jmp_0218: +jmp_04a8: mov64 r0, 5 ja jmp_0038 -jmp_0228: +jmp_04b8: mov64 r0, 3 ja jmp_0038 -jmp_0238: +jmp_04c8: mov64 r0, 6 ja jmp_0038 -jmp_0248: +jmp_04d8: mov64 r0, 4 ja jmp_0038 -jmp_0258: +jmp_04e8: mov64 r0, 7 ja jmp_0038 -jmp_0268: +jmp_04f8: mov64 r0, 9 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 169f2593..071f20ee 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -45,8 +45,5 @@ initialize: # Error if instruction data provided. # --------------------------------------------------------------------- - # Init operation discriminator is number of accounts, requires no - # instruction data. - # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index 0c689a3e..aa63c0d5 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,7 +1,6 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| CreateAccount happy path | 2701 | 1557 | -1144 | -42.4% | - (Rust) CreateAccount happy path: owner: expected DASMAC..., got 11111111111111111111111111111111; data len: expected 16, got 0; lamports: expected 501120, got 0 +| CreateAccount happy path | 2701 | 2736 | +35 | +1.3% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -9,5 +8,7 @@ test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1557 of 1400000 compute units +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2736 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt index 99462095..aa2dd6c3 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, true); + print_comparison_table(init::InitCase::CPI_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 7c059c13..41aa34c8 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,27 +1,27 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1542 | 1549 | +7 | +0.5% | -| PDA mismatch chunk 2 | 1545 | 1552 | +7 | +0.5% | -| PDA mismatch chunk 3 | 1548 | 1555 | +7 | +0.5% | +| PDA mismatch chunk 1 | 1542 | 1550 | +8 | +0.5% | +| PDA mismatch chunk 2 | 1545 | 1553 | +8 | +0.5% | +| PDA mismatch chunk 3 | 1548 | 1556 | +8 | +0.5% | | PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1549 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 00c7a9d0..d0cfca33 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -14,7 +14,9 @@ use tree_interface::{ #[cfg(target_os = "solana")] use { core::mem::MaybeUninit, - pinocchio::syscalls::{sol_invoke_signed_c, sol_try_find_program_address}, + pinocchio::syscalls::{ + sol_invoke_signed_c, sol_log_compute_units_, sol_try_find_program_address, + }, }; #[inline(always)] @@ -34,6 +36,13 @@ fn is_duplicate(account: &AccountView) -> bool { account.is_borrowed() } +/// Insert a syscall to log CUs, useful for sectioning off disassembled program. +#[allow(dead_code)] +unsafe fn log_cus() { + #[cfg(target_os = "solana")] + sol_log_compute_units_(); +} + macro_rules! if_err { ($condition:expr, $error:expr) => { if unlikely($condition) { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 82c9eb39..8e93f80a 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -249,9 +249,6 @@ initialize: # Error if instruction data provided. # --------------------------------------------------------------------- - # Init operation discriminator is number of accounts, requires no - # instruction data. - # --------------------------------------------------------------------- ldxdw r9, [r2 - SIZE_OF_U64] jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks From f7150128563a945077f524ef774d4c08e486a245 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:28:46 -0800 Subject: [PATCH 131/263] Include in docs --- docs/src/examples/tree.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 1f624a88..9fe1d6dd 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -23,7 +23,9 @@ performance. -## Initialize input checks +## Initialize + +### Input checks ::: code-group @@ -39,7 +41,7 @@ performance. -## Initialize PDA checks +### PDA checks ::: code-group @@ -55,7 +57,21 @@ performance. - +### Create account + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/initialize-create-account.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/initialize-create-account.txt{rs} [Rust] + +::: + + + + ## :white_check_mark: All tests From a8b00afc4a06c04134dd3bb782819a60d25d3d2a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:47:56 -0800 Subject: [PATCH 132/263] Abstract pointer --- .../snippets/rs/initialize-create-account.txt | 38 +++++++++---------- .../tests/initialize_input_checks/result.txt | 1 + examples/tree/src/program.rs | 38 +++++++++---------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index fb476d21..04302945 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,15 +1,18 @@ + // Pack CreateAccount instruction data. + let user_key_ptr = input_buffer_ptr + .add(input_buffer::USER_ADDRESS_OFF as usize) + .cast(); + let tree_key_ptr = input_buffer_ptr + .add(input_buffer::TREE_ADDRESS_OFF as usize) + .cast(); let sol_account_metas = [ SolAccountMeta { - pubkey: transmute( - input_buffer_ptr.add(input_buffer::USER_ADDRESS_OFF as usize) as *const Address, - ), + pubkey: user_key_ptr, is_writable: true, is_signer: true, }, SolAccountMeta { - pubkey: transmute( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize) as *const Address, - ), + pubkey: tree_key_ptr, is_writable: true, is_signer: true, }, @@ -17,34 +20,30 @@ let sol_account_infos = [ SolAccountInfo { - key: input_buffer_ptr - .add(input_buffer::USER_ADDRESS_OFF as usize) + key: user_key_ptr, + owner: input_buffer_ptr + .add(input_buffer::USER_OWNER_OFF as usize) .cast(), lamports: input_buffer_ptr .add(input_buffer::USER_LAMPORTS_OFF as usize) .cast(), - data_len: data::DATA_LEN_ZERO, data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), - owner: input_buffer_ptr - .add(input_buffer::USER_OWNER_OFF as usize) - .cast(), + data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, is_writable: true, executable: false, }, SolAccountInfo { - key: input_buffer_ptr - .add(input_buffer::TREE_ADDRESS_OFF as usize) + key: tree_key_ptr, + owner: input_buffer_ptr + .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), lamports: input_buffer_ptr .add(input_buffer::TREE_LAMPORTS_OFF as usize) .cast(), - data_len: data::DATA_LEN_ZERO, data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), - owner: input_buffer_ptr - .add(input_buffer::TREE_OWNER_OFF as usize) - .cast(), + data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, is_writable: true, @@ -52,7 +51,6 @@ }, ]; - // Pack CreateAccount instruction data. let instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) @@ -67,9 +65,11 @@ let system_program_address = Address::default(); let sol_instruction = SolInstruction { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] program_id: transmute(&system_program_address), accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, account_len: sol_account_metas.len() as u64, + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] data: transmute(&instruction_data), data_len: cpi::INSN_DATA_LEN as u64, }; diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 710d9f61..3aa2d170 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -16,6 +16,7 @@ | Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | | Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok + Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index d0cfca33..aa561ca1 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -151,18 +151,21 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR_END: initialize-pda-checks // ANCHOR: initialize-create-account + // Pack CreateAccount instruction data. + let user_key_ptr = input_buffer_ptr + .add(input_buffer::USER_ADDRESS_OFF as usize) + .cast(); + let tree_key_ptr = input_buffer_ptr + .add(input_buffer::TREE_ADDRESS_OFF as usize) + .cast(); let sol_account_metas = [ SolAccountMeta { - pubkey: transmute( - input_buffer_ptr.add(input_buffer::USER_ADDRESS_OFF as usize) as *const Address, - ), + pubkey: user_key_ptr, is_writable: true, is_signer: true, }, SolAccountMeta { - pubkey: transmute( - input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF as usize) as *const Address, - ), + pubkey: tree_key_ptr, is_writable: true, is_signer: true, }, @@ -170,34 +173,30 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let sol_account_infos = [ SolAccountInfo { - key: input_buffer_ptr - .add(input_buffer::USER_ADDRESS_OFF as usize) + key: user_key_ptr, + owner: input_buffer_ptr + .add(input_buffer::USER_OWNER_OFF as usize) .cast(), lamports: input_buffer_ptr .add(input_buffer::USER_LAMPORTS_OFF as usize) .cast(), - data_len: data::DATA_LEN_ZERO, data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), - owner: input_buffer_ptr - .add(input_buffer::USER_OWNER_OFF as usize) - .cast(), + data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, is_writable: true, executable: false, }, SolAccountInfo { - key: input_buffer_ptr - .add(input_buffer::TREE_ADDRESS_OFF as usize) + key: tree_key_ptr, + owner: input_buffer_ptr + .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), lamports: input_buffer_ptr .add(input_buffer::TREE_LAMPORTS_OFF as usize) .cast(), - data_len: data::DATA_LEN_ZERO, data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), - owner: input_buffer_ptr - .add(input_buffer::TREE_OWNER_OFF as usize) - .cast(), + data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, is_writable: true, @@ -205,7 +204,6 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }, ]; - // Pack CreateAccount instruction data. let instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) @@ -220,9 +218,11 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let system_program_address = Address::default(); let sol_instruction = SolInstruction { + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] program_id: transmute(&system_program_address), accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, account_len: sol_account_metas.len() as u64, + #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] data: transmute(&instruction_data), data_len: cpi::INSN_DATA_LEN as u64, }; From 1d91fe93a8ad356f1bcc768eb96862b06c74bdc6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:52:51 -0800 Subject: [PATCH 133/263] Refactor CPI packing layout --- examples/tree/artifacts/dumps/rs.txt | 265 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 125 ++++----- .../snippets/rs/initialize-create-account.txt | 27 +- .../initialize_create_account/result.txt | 4 +- .../tests/initialize_input_checks/result.txt | 1 - examples/tree/src/program.rs | 27 +- 6 files changed, 224 insertions(+), 225 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 25d75e5f..87d48b19 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3872 (bytes into file) + Start of section headers 3864 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf20 +There are 8 section headers, starting at offset 0xf18 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000510 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000630 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000638 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000638 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000638 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0009b0 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0009ee 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000508 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000628 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000630 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000630 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000630 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0009a8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0009e6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000510 0x000510 E 0x8 - LOAD 0x000630 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000638 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000638 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000508 0x000508 E 0x8 + LOAD 0x000628 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000630 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000630 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1296 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1288 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -112,19 +112,19 @@ Disassembly of section .text 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 38 9d 00 00 00 00 00 00 00 return - 40 55 03 8b 00 04 00 00 00 jne r3, 0x4, +0x8b + 40 55 03 8a 00 04 00 00 00 jne r3, 0x4, +0x8a 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 87 00 00 00 00 00 jne r3, 0x0, +0x87 + 50 55 03 86 00 00 00 00 00 jne r3, 0x0, +0x86 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 + 60 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 89 00 00 00 00 00 jne r3, 0x0, +0x89 + 70 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 + 80 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 89 00 0e 00 00 00 jne r3, 0xe, +0x89 + 90 55 03 88 00 0e 00 00 00 jne r3, 0xe, +0x88 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 89 00 ff 00 00 00 jne r3, 0xff, +0x89 + a0 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 @@ -142,127 +142,126 @@ Disassembly of section .text 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 130 55 02 79 00 00 00 00 00 jne r2, 0x0, +0x79 + 130 55 02 78 00 00 00 00 00 jne r2, 0x0, +0x78 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 140 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 30 00 00 00 add64 r4, 0x30 + 150 07 04 00 00 68 00 00 00 add64 r4, 0x68 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 160 07 05 00 00 13 00 00 00 add64 r5, 0x13 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 188 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + 188 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] 190 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 198 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c - 1a0 9c a1 38 00 00 00 00 00 ldxdw r1, [r10 + 0x38] + 198 5d 21 5b 00 00 00 00 00 jne r1, r2, +0x5b + 1a0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] 1a8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1b0 5d 21 59 00 00 00 00 00 jne r1, r2, +0x59 - 1b8 9c a1 40 00 00 00 00 00 ldxdw r1, [r10 + 0x40] + 1b0 5d 21 58 00 00 00 00 00 jne r1, r2, +0x58 + 1b8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] 1c0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1c8 5d 21 56 00 00 00 00 00 jne r1, r2, +0x56 - 1d0 9c a1 48 00 00 00 00 00 ldxdw r1, [r10 + 0x48] + 1c8 5d 21 55 00 00 00 00 00 jne r1, r2, +0x55 + 1d0 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] 1d8 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 1e0 5d 21 53 00 00 00 00 00 jne r1, r2, +0x53 - 1e8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 1f0 07 02 00 00 70 28 00 00 add64 r2, 0x2870 - 1f8 9f 2a 20 00 00 00 00 00 stxdw [r10 + 0x20], r2 - 200 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 208 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 210 9f 1a 10 00 00 00 00 00 stxdw [r10 + 0x10], r1 - 218 37 0a 28 00 01 01 00 00 sth [r10 + 0x28], 0x101 - 220 37 0a 18 00 01 01 00 00 sth [r10 + 0x18], 0x101 - 228 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 230 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 238 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 - 240 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 248 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 250 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 - 258 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 260 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 268 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 270 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 278 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 280 07 02 00 00 30 00 00 00 add64 r2, 0x30 - 288 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 - 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 298 07 02 00 00 60 00 00 00 add64 r2, 0x60 - 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 2a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 2b0 07 02 00 00 50 00 00 00 add64 r2, 0x50 - 2b8 9f 2a 38 00 00 00 00 00 stxdw [r10 + 0x38], r2 - 2c0 9f 1a 30 00 00 00 00 00 stxdw [r10 + 0x30], r1 - 2c8 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 2d0 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 2d8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 2e0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 2e8 27 0a 62 00 00 00 00 00 stb [r10 + 0x62], 0x0 - 2f0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 2f8 97 0a 58 00 00 00 00 00 stdw [r10 + 0x58], 0x0 - 300 97 0a 40 00 00 00 00 00 stdw [r10 + 0x40], 0x0 - 308 9c 71 90 79 00 00 00 00 ldxdw r1, [r7 + 0x7990] - 310 9c 62 18 00 00 00 00 00 ldxdw r2, [r6 + 0x18] - 318 9f 2a d0 00 00 00 00 00 stxdw [r10 + 0xd0], r2 - 320 9c 62 10 00 00 00 00 00 ldxdw r2, [r6 + 0x10] - 328 9f 2a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r2 - 330 9c 62 08 00 00 00 00 00 ldxdw r2, [r6 + 0x8] - 338 9f 2a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r2 - 340 9c 62 00 00 00 00 00 00 ldxdw r2, [r6 + 0x0] - 348 9f 2a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r2 - 350 96 01 00 00 90 00 00 00 lmul64 r1, 0x90 - 358 9f 1a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r1 - 360 97 0a b0 00 10 00 00 00 stdw [r10 + 0xb0], 0x10 - 368 87 0a a4 00 00 00 00 00 stw [r10 + 0xa4], 0x0 - 370 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 378 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 380 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 388 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 390 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 398 07 01 00 00 a4 00 00 00 add64 r1, 0xa4 - 3a0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3a8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3b0 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 3b8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3d0 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 3d8 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 3e0 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3f0 07 01 00 00 0f 00 00 00 add64 r1, 0xf - 3f8 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 400 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 408 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 410 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 418 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 420 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 428 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 430 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 438 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 440 07 02 00 00 30 00 00 00 add64 r2, 0x30 - 448 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 450 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 458 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 460 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 468 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 470 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 478 05 00 77 ff 00 00 00 00 ja -0x89 - 480 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 488 05 00 75 ff 00 00 00 00 ja -0x8b - 490 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 498 05 00 73 ff 00 00 00 00 ja -0x8d - 4a0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 4a8 05 00 71 ff 00 00 00 00 ja -0x8f - 4b0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4b8 05 00 6f ff 00 00 00 00 ja -0x91 - 4c0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 4c8 05 00 6d ff 00 00 00 00 ja -0x93 - 4d0 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 4d8 05 00 6b ff 00 00 00 00 ja -0x95 - 4e0 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 4e8 05 00 69 ff 00 00 00 00 ja -0x97 - 4f0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 4f8 05 00 67 ff 00 00 00 00 ja -0x99 - 500 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 508 05 00 65 ff 00 00 00 00 ja -0x9b \ No newline at end of file + 1e0 5d 21 52 00 00 00 00 00 jne r1, r2, +0x52 + 1e8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 1f0 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 1f8 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 200 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 208 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 210 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 218 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 220 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 228 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 230 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 238 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 240 96 02 00 00 90 00 00 00 lmul64 r2, 0x90 + 248 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 250 97 0a 20 00 10 00 00 00 stdw [r10 + 0x20], 0x10 + 258 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 260 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 268 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 270 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 278 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 280 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 288 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 290 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 298 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 2a0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2a8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2b0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2b8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2c8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 2d0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 2d8 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 2e0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 2e8 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 2f0 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 2f8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 300 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 308 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 310 07 07 00 00 50 00 00 00 add64 r7, 0x50 + 318 9f 7a 70 00 00 00 00 00 stxdw [r10 + 0x70], r7 + 320 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 328 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 330 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 338 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 340 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 348 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 350 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 358 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 360 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 368 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 370 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 378 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 380 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 388 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 390 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 398 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3a0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3a8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3b0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3c0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3c8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 3d0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 3d8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 3e0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3e8 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 3f0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 3f8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 400 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 408 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 410 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 418 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 420 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 428 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 430 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 438 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 440 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 448 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 450 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 458 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 460 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 468 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 470 05 00 78 ff 00 00 00 00 ja -0x88 + 478 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 480 05 00 76 ff 00 00 00 00 ja -0x8a + 488 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 490 05 00 74 ff 00 00 00 00 ja -0x8c + 498 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 4a0 05 00 72 ff 00 00 00 00 ja -0x8e + 4a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4b0 05 00 70 ff 00 00 00 00 ja -0x90 + 4b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 4c0 05 00 6e ff 00 00 00 00 ja -0x92 + 4c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 4d0 05 00 6c ff 00 00 00 00 ja -0x94 + 4d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 4e0 05 00 6a ff 00 00 00 00 ja -0x96 + 4e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 4f0 05 00 68 ff 00 00 00 00 ja -0x98 + 4f8 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 500 05 00 66 ff 00 00 00 00 ja -0x9a \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index ddfc9abc..d59a8496 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -13,19 +13,19 @@ jmp_0038: exit jmp_0040: - jne r3, 4, jmp_0498 + jne r3, 4, jmp_0490 ldxdw r3, [r1+88] - jne r3, 0, jmp_0488 + jne r3, 0, jmp_0480 ldxb r3, [r1+10344] - jne r3, 255, jmp_04a8 + jne r3, 255, jmp_04a0 ldxdw r3, [r1+10424] - jne r3, 0, jmp_04b8 + jne r3, 0, jmp_04b0 ldxb r3, [r1+20680] - jne r3, 255, jmp_04c8 + jne r3, 255, jmp_04c0 ldxdw r3, [r1+20760] - jne r3, 14, jmp_04d8 + jne r3, 14, jmp_04d0 ldxb r3, [r1+31032] - jne r3, 255, jmp_04e8 + jne r3, 255, jmp_04e0 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 @@ -43,88 +43,87 @@ jmp_0040: mov32 r4, -1965433885 jne r3, r4, jmp_0038 ldxdw r2, [r2-8] - jne r2, 0, jmp_04f8 + jne r2, 0, jmp_04f0 mov64 r6, r1 add64 r6, 41400 mov64 r4, r10 - add64 r4, 48 + add64 r4, 104 mov64 r5, r10 - add64 r5, 15 + add64 r5, 19 mov64 r7, r1 mov64 r2, 0 mov64 r3, r6 call sol_try_find_program_address mov64 r0, 10 - ldxdw r1, [r10+48] + ldxdw r1, [r10+104] ldxdw r2, [r7+10352] jne r1, r2, jmp_0038 - ldxdw r1, [r10+56] + ldxdw r1, [r10+112] ldxdw r2, [r7+10360] jne r1, r2, jmp_0038 - ldxdw r1, [r10+64] + ldxdw r1, [r10+120] ldxdw r2, [r7+10368] jne r1, r2, jmp_0038 - ldxdw r1, [r10+72] + ldxdw r1, [r10+128] ldxdw r2, [r7+10376] jne r1, r2, jmp_0038 - mov64 r2, r7 - add64 r2, 10352 - stxdw [r10+32], r2 mov64 r1, r7 - add64 r1, 16 - stxdw [r10+16], r1 - sth [r10+40], 257 - sth [r10+24], 257 + add64 r1, 10352 + ldxdw r2, [r7+31120] + ldxdw r3, [r6+24] + stxdw [r10+64], r3 + ldxdw r3, [r6+16] + stxdw [r10+56], r3 + ldxdw r3, [r6+8] + stxdw [r10+48], r3 + ldxdw r3, [r6+0] + stxdw [r10+40], r3 + lmul64 r2, 144 + stxdw [r10+24], r2 + stdw [r10+32], 16 + stw [r10+20], 0 + stxdw [r10+88], r1 + mov64 r2, r7 + add64 r2, 16 + stxdw [r10+72], r2 + sth [r10+96], 257 + sth [r10+80], 257 mov64 r3, r7 add64 r3, 10384 - stxdw [r10+136], r3 + stxdw [r10+192], r3 mov64 r3, r7 add64 r3, 10432 - stxdw [r10+128], r3 + stxdw [r10+184], r3 mov64 r3, r7 add64 r3, 10416 - stxdw [r10+112], r3 + stxdw [r10+168], r3 + stxdw [r10+160], r1 + mov64 r1, r7 + add64 r1, 48 + stxdw [r10+136], r1 + mov64 r1, r7 + add64 r1, 96 + stxdw [r10+128], r1 + add64 r7, 80 + stxdw [r10+112], r7 stxdw [r10+104], r2 - mov64 r2, r7 - add64 r2, 48 - stxdw [r10+80], r2 - mov64 r2, r7 - add64 r2, 96 - stxdw [r10+72], r2 - mov64 r2, r7 - add64 r2, 80 - stxdw [r10+56], r2 - stxdw [r10+48], r1 + stb [r10+210], 0 + sth [r10+208], 257 + stdw [r10+200], 0 + stdw [r10+176], 0 stb [r10+154], 0 sth [r10+152], 257 stdw [r10+144], 0 stdw [r10+120], 0 - stb [r10+98], 0 - sth [r10+96], 257 - stdw [r10+88], 0 - stdw [r10+64], 0 - ldxdw r1, [r7+31120] - ldxdw r2, [r6+24] - stxdw [r10+208], r2 - ldxdw r2, [r6+16] - stxdw [r10+200], r2 - ldxdw r2, [r6+8] - stxdw [r10+192], r2 - ldxdw r2, [r6+0] - stxdw [r10+184], r2 - lmul64 r1, 144 - stxdw [r10+168], r1 - stdw [r10+176], 16 - stw [r10+164], 0 stdw [r10+240], 0 stdw [r10+232], 0 stdw [r10+224], 0 stdw [r10+216], 0 mov64 r1, r10 - add64 r1, 164 + add64 r1, 20 stxdw [r10+272], r1 mov64 r1, r10 - add64 r1, 16 + add64 r1, 72 stxdw [r10+256], r1 mov64 r1, r10 add64 r1, 216 @@ -132,7 +131,7 @@ jmp_0040: stdw [r10+280], 52 stdw [r10+264], 2 mov64 r1, r10 - add64 r1, 15 + add64 r1, 19 stxdw [r10+288], r1 stdw [r10+296], 1 mov64 r1, r10 @@ -142,7 +141,7 @@ jmp_0040: mov64 r1, r10 add64 r1, 248 mov64 r2, r10 - add64 r2, 48 + add64 r2, 104 mov64 r4, r10 add64 r4, 304 mov64 r3, 2 @@ -151,34 +150,34 @@ jmp_0040: mov64 r0, 0 ja jmp_0038 -jmp_0488: +jmp_0480: mov64 r0, 2 ja jmp_0038 -jmp_0498: +jmp_0490: mov64 r0, 1 ja jmp_0038 -jmp_04a8: +jmp_04a0: mov64 r0, 5 ja jmp_0038 -jmp_04b8: +jmp_04b0: mov64 r0, 3 ja jmp_0038 -jmp_04c8: +jmp_04c0: mov64 r0, 6 ja jmp_0038 -jmp_04d8: +jmp_04d0: mov64 r0, 4 ja jmp_0038 -jmp_04e8: +jmp_04e0: mov64 r0, 7 ja jmp_0038 -jmp_04f8: +jmp_04f0: mov64 r0, 9 ja jmp_0038 diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 04302945..bebe6d5a 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,4 +1,17 @@ // Pack CreateAccount instruction data. + let instruction_data = CreateAccountInstructionData { + discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) + * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + space: cpi::TREE_DATA_LEN as u64, + owner: read_unaligned( + input_buffer_ptr + .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) + .cast(), + ), + }; + + // Pack account metas and infos. let user_key_ptr = input_buffer_ptr .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); @@ -17,7 +30,6 @@ is_signer: true, }, ]; - let sol_account_infos = [ SolAccountInfo { key: user_key_ptr, @@ -51,18 +63,7 @@ }, ]; - let instruction_data = CreateAccountInstructionData { - discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, - lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), - space: cpi::TREE_DATA_LEN as u64, - owner: read_unaligned( - input_buffer_ptr - .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) - .cast(), - ), - }; - + // Pack instruction. let system_program_address = Address::default(); let sol_instruction = SolInstruction { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index aa63c0d5..ecfebd93 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,6 +1,6 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| -| CreateAccount happy path | 2701 | 2736 | +35 | +1.3% | +| CreateAccount happy path | 2701 | 2735 | +34 | +1.3% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -10,5 +10,5 @@ test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2736 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 3aa2d170..710d9f61 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -16,7 +16,6 @@ | Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | | Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok - Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index aa561ca1..d264c502 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -152,6 +152,19 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR: initialize-create-account // Pack CreateAccount instruction data. + let instruction_data = CreateAccountInstructionData { + discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) + * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + space: cpi::TREE_DATA_LEN as u64, + owner: read_unaligned( + input_buffer_ptr + .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) + .cast(), + ), + }; + + // Pack account metas and infos. let user_key_ptr = input_buffer_ptr .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); @@ -170,7 +183,6 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - is_signer: true, }, ]; - let sol_account_infos = [ SolAccountInfo { key: user_key_ptr, @@ -204,18 +216,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }, ]; - let instruction_data = CreateAccountInstructionData { - discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, - lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), - space: cpi::TREE_DATA_LEN as u64, - owner: read_unaligned( - input_buffer_ptr - .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) - .cast(), - ), - }; - + // Pack instruction. let system_program_address = Address::default(); let sol_instruction = SolInstruction { #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] From c7523469487703449c01c3249ba7513ebd0b0afe Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:55:46 -0800 Subject: [PATCH 134/263] Update anchor block --- .../asm/initialize-create-account.txt | 2 +- .../tests/entrypoint_branching/result.txt | 31 ----- .../initialize_create_account/result.txt | 14 --- .../tests/initialize_create_account/test.txt | 4 - .../tests/initialize_input_checks/result.txt | 108 ------------------ .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 31 ----- .../tests/initialize_pda_checks/test.txt | 4 - examples/tree/src/tree/tree.s | 2 +- 9 files changed, 2 insertions(+), 198 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 4c2755ba..7bf28e76 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -75,7 +75,7 @@ # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk assign/load pointers for account info/addresses. + # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- # Since pointers must be loaded from registers, this block steps # through the input buffer in order to reduce intermediate loads. diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index a4015b68..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Three accounts | 5 | 7 | +2 | +40.0% | -| Five accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt deleted file mode 100644 index ecfebd93..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ /dev/null @@ -1,14 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| CreateAccount happy path | 2701 | 2735 | +34 | +1.3% | -test tests::test_initialize_create_account ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt deleted file mode 100644 index aa2dd6c3..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 710d9f61..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,108 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | -| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | -| Non-empty instruction data | 31 | 37 | +6 | +19.4% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index 24226cfc..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 41aa34c8..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1542 | 1550 | +8 | +0.5% | -| PDA mismatch chunk 2 | 1545 | 1553 | +8 | +0.5% | -| PDA mismatch chunk 3 | 1548 | 1556 | +8 | +0.5% | -| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 0f682d5d..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 8e93f80a..526ba216 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -362,7 +362,7 @@ initialize: # --------------------------------------------------------------------- stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - # Bulk assign/load pointers for account info/addresses. + # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- # Since pointers must be loaded from registers, this block steps # through the input buffer in order to reduce intermediate loads. From 77aaae828406c8d4ade01d2b4cdc4901fbd45083 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 17:19:46 -0800 Subject: [PATCH 135/263] Rebuild tests --- .../tests/entrypoint_branching/result.txt | 32 ++++++ .../initialize_create_account/result.txt | 14 +++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 108 ++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 + .../tests/initialize_pda_checks/result.txt | 31 +++++ .../tests/initialize_pda_checks/test.txt | 4 + 7 files changed, 197 insertions(+) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..c18c462d --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,32 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Three accounts | 5 | 7 | +2 | +40.0% | +| Five accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok + Blocking waiting for file lock on build directory +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..ecfebd93 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,14 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| CreateAccount happy path | 2701 | 2735 | +34 | +1.3% | +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..aa2dd6c3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..710d9f61 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,108 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | +| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | +| Non-empty instruction data | 31 | 37 | +6 | +19.4% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..24226cfc --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..41aa34c8 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1542 | 1550 | +8 | +0.5% | +| PDA mismatch chunk 2 | 1545 | 1553 | +8 | +0.5% | +| PDA mismatch chunk 3 | 1548 | 1556 | +8 | +0.5% | +| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file From 5cb73b2cd604340ba3853eaccd4a40be384ce039 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 17:53:51 -0800 Subject: [PATCH 136/263] Add more test cases --- .../tests/entrypoint_branching/result.txt | 1 - .../initialize_create_account/result.txt | 22 ++++++++++ examples/tree/src/tests/init.rs | 42 ++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index c18c462d..a4015b68 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -5,7 +5,6 @@ | Three accounts | 5 | 7 | +2 | +40.0% | | Five accounts | 5 | 7 | +2 | +40.0% | test tests::test_entrypoint_branching ... ok - Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index ecfebd93..29cd1109 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,9 +1,31 @@ | Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |------|-----------|------------|----------|------------| +| User has insufficient Lamports | 2700 | 2732 | +32 | +1.2% | +| System Program is wrong address | 2550 | 2582 | +32 | +1.3% | | CreateAccount happy path | 2701 | 2735 | +34 | +1.3% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2700 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2732 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2582 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success [ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 4f916828..f348192a 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -115,6 +115,8 @@ pub(super) enum InitCase { PdaMismatchChunk1, PdaMismatchChunk2, PdaMismatchChunk3, + UserInsufficientLamports, + SystemProgramAddress, CreateAccountHappyPath, } @@ -144,7 +146,11 @@ impl InitCase { Self::PdaMismatchChunk3, ]; - pub(super) const CPI_CASES: &'static [Self] = &[Self::CreateAccountHappyPath]; + pub(super) const CPI_CASES: &'static [Self] = &[ + Self::UserInsufficientLamports, + Self::SystemProgramAddress, + Self::CreateAccountHappyPath, + ]; } impl TestCase for InitCase { @@ -169,6 +175,8 @@ impl TestCase for InitCase { Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", + Self::UserInsufficientLamports => "User has insufficient Lamports", + Self::SystemProgramAddress => "System Program is wrong address", Self::CreateAccountHappyPath => "CreateAccount happy path", } } @@ -338,6 +346,38 @@ impl TestCase for InitCase { size_of::(), error_codes::error::PDA_MISMATCH, ), + Self::UserInsufficientLamports => { + let (setup, instruction, mut accounts) = pda_init_setup(lang); + accounts[AccountIndex::User as usize].1.lamports = 0; + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Failure(_) => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Failure, got {:?}", other)), + }, + } + } + Self::SystemProgramAddress => { + let (setup, mut instruction, mut accounts) = pda_init_setup(lang); + let fake_pubkey = Pubkey::new_unique(); + accounts[AccountIndex::SystemProgram as usize].0 = fake_pubkey; + instruction.accounts[AccountIndex::SystemProgram as usize].pubkey = fake_pubkey; + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Failure(_) => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Failure, got {:?}", other)), + }, + } + } Self::CreateAccountHappyPath => { let (setup, instruction, accounts) = pda_init_setup(lang); let result = setup.mollusk.process_instruction(&instruction, &accounts); From e691e4212907229abb062a609b63a16d1e471d0a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 17:58:13 -0800 Subject: [PATCH 137/263] Add more tests --- examples/tree/src/tests/init.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index f348192a..2b1e0629 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -350,14 +350,19 @@ impl TestCase for InitCase { let (setup, instruction, mut accounts) = pda_init_setup(lang); accounts[AccountIndex::User as usize].1.lamports = 0; let result = setup.mollusk.process_instruction(&instruction, &accounts); + // SystemError::ResultWithNegativeLamports. + let expected = ProgramError::Custom(1); match &result.program_result { - MolluskResult::Failure(_) => CaseResult { + MolluskResult::Failure(err) if *err == expected => CaseResult { cu: result.compute_units_consumed, error: None, }, other => CaseResult { cu: result.compute_units_consumed, - error: Some(format!("expected Failure, got {:?}", other)), + error: Some(format!( + "expected Failure({:?}), got {:?}", + expected, other + )), }, } } @@ -367,14 +372,18 @@ impl TestCase for InitCase { accounts[AccountIndex::SystemProgram as usize].0 = fake_pubkey; instruction.accounts[AccountIndex::SystemProgram as usize].pubkey = fake_pubkey; let result = setup.mollusk.process_instruction(&instruction, &accounts); + let expected = ProgramError::NotEnoughAccountKeys; match &result.program_result { - MolluskResult::Failure(_) => CaseResult { + MolluskResult::Failure(err) if *err == expected => CaseResult { cu: result.compute_units_consumed, error: None, }, other => CaseResult { cu: result.compute_units_consumed, - error: Some(format!("expected Failure, got {:?}", other)), + error: Some(format!( + "expected Failure({:?}), got {:?}", + expected, other + )), }, } } From 88e46aba445862304066344fbcbce4e5277d8ab9 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:06:29 -0800 Subject: [PATCH 138/263] Add fixed cost reporting --- .../tests/entrypoint_branching/result.txt | 31 ----- .../initialize_create_account/result.txt | 36 ------ .../tests/initialize_create_account/test.txt | 4 - .../tests/initialize_input_checks/result.txt | 108 ------------------ .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 31 ----- .../tests/initialize_pda_checks/test.txt | 4 - examples/tree/src/tests.rs | 73 +++++++++--- examples/tree/src/tests/init.rs | 48 ++++++-- 9 files changed, 97 insertions(+), 242 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index a4015b68..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Three accounts | 5 | 7 | +2 | +40.0% | -| Five accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt deleted file mode 100644 index 29cd1109..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ /dev/null @@ -1,36 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has insufficient Lamports | 2700 | 2732 | +32 | +1.2% | -| System Program is wrong address | 2550 | 2582 | +32 | +1.3% | -| CreateAccount happy path | 2701 | 2735 | +34 | +1.3% | -test tests::test_initialize_create_account ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2700 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2732 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2582 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt deleted file mode 100644 index aa2dd6c3..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 710d9f61..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,108 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | -| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | -| Non-empty instruction data | 31 | 37 | +6 | +19.4% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index 24226cfc..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 41aa34c8..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| -| PDA mismatch chunk 1 | 1542 | 1550 | +8 | +0.5% | -| PDA mismatch chunk 2 | 1545 | 1553 | +8 | +0.5% | -| PDA mismatch chunk 3 | 1548 | 1556 | +8 | +0.5% | -| PDA mismatch chunk 4 | 1551 | 1559 | +8 | +0.5% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 0f682d5d..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 20d7cb54..36658c5e 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -11,6 +11,16 @@ use tree_interface::{cpi, error_codes}; const USER_LAMPORTS: u64 = 1_000_000; +/// Fixed costs for syscalls and CPI operations. +mod fixed_costs { + /// Cost for sol_try_find_program_address syscall. + pub const CREATE_PROGRAM_ADDRESS: u64 = 1500; + /// CPI base invocation cost (SIMD-0339). + pub const CPI_BASE: u64 = 946; + /// System Program operation cost. + pub const SYSTEM_PROGRAM: u64 = 150; +} + enum AccountIndex { User = 0, Tree = 1, @@ -46,6 +56,11 @@ fn check_error( trait TestCase: Copy { fn name(&self) -> &'static str; fn run(&self, lang: ProgramLanguage) -> CaseResult; + /// Returns the fixed syscall/CPI costs for this case. + /// These costs are identical for both ASM and Rust implementations. + fn fixed_costs(&self) -> u64 { + 0 + } } fn print_comparison_table( @@ -54,27 +69,55 @@ fn print_comparison_table( allow_rust_failures: bool, ) { let mut failures = Vec::new(); + let has_fixed_costs = cases.iter().any(|c| c.fixed_costs() > 0); - println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|------|-----------|------------|----------|------------|"); + if has_fixed_costs { + println!("| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % |"); + println!("|------|-------|-----------|------------|----------|------------|"); + } else { + println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|------|-----------|------------|----------|------------|"); + } for case in cases { let asm = case.run(ProgramLanguage::Assembly); let rs = case.run(ProgramLanguage::Rust); - let overhead = rs.cu as i64 - asm.cu as i64; - let overhead_pct = if asm.cu > 0 { - (overhead as f64 / asm.cu as f64) * 100.0 + let fixed = case.fixed_costs(); + + if has_fixed_costs { + let asm_net = asm.cu.saturating_sub(fixed); + let rs_net = rs.cu.saturating_sub(fixed); + let overhead = rs_net as i64 - asm_net as i64; + let overhead_pct = if asm_net > 0 { + format!("{:+.1}%", (overhead as f64 / asm_net as f64) * 100.0) + } else { + "N/A".to_string() + }; + println!( + "| {} | {} | {} | {} | {:+} | {} |", + case.name(), + fixed, + asm_net, + rs_net, + overhead, + overhead_pct + ); } else { - 0.0 - }; - println!( - "| {} | {} | {} | {:+} | {:+.1}% |", - case.name(), - asm.cu, - rs.cu, - overhead, - overhead_pct - ); + let overhead = rs.cu as i64 - asm.cu as i64; + let overhead_pct = if asm.cu > 0 { + (overhead as f64 / asm.cu as f64) * 100.0 + } else { + 0.0 + }; + println!( + "| {} | {} | {} | {:+} | {:+.1}% |", + case.name(), + asm.cu, + rs.cu, + overhead, + overhead_pct + ); + } if let Some(err) = &asm.error { if allow_asm_failures { diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 2b1e0629..80fcc942 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -147,8 +147,8 @@ impl InitCase { ]; pub(super) const CPI_CASES: &'static [Self] = &[ - Self::UserInsufficientLamports, Self::SystemProgramAddress, + Self::UserInsufficientLamports, Self::CreateAccountHappyPath, ]; } @@ -181,6 +181,42 @@ impl TestCase for InitCase { } } + fn fixed_costs(&self) -> u64 { + match self { + // Input checks - no syscalls. + Self::UserDataLen + | Self::TreeDuplicate + | Self::TreeDataLen + | Self::SystemProgramDuplicate + | Self::SystemProgramDataLen + | Self::RentDuplicate + | Self::RentAddressWord0 + | Self::RentAddressWord1 + | Self::RentAddressWord2 + | Self::RentAddressWord3 + | Self::RentAddressWord4 + | Self::RentAddressWord5 + | Self::RentAddressWord6 + | Self::RentAddressWord7 + | Self::InstructionData => 0, + // PDA checks - sol_try_find_program_address only. + Self::PdaMismatchChunk0 + | Self::PdaMismatchChunk1 + | Self::PdaMismatchChunk2 + | Self::PdaMismatchChunk3 => fixed_costs::CREATE_PROGRAM_ADDRESS, + // CPI with system program not found (never executes). + Self::SystemProgramAddress => { + fixed_costs::CREATE_PROGRAM_ADDRESS + fixed_costs::CPI_BASE + } + // CPI with system program executing. + Self::UserInsufficientLamports | Self::CreateAccountHappyPath => { + fixed_costs::CREATE_PROGRAM_ADDRESS + + fixed_costs::CPI_BASE + + fixed_costs::SYSTEM_PROGRAM + } + } + } + fn run(&self, lang: ProgramLanguage) -> CaseResult { match self { Self::UserDataLen => { @@ -359,10 +395,7 @@ impl TestCase for InitCase { }, other => CaseResult { cu: result.compute_units_consumed, - error: Some(format!( - "expected Failure({:?}), got {:?}", - expected, other - )), + error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), }, } } @@ -380,10 +413,7 @@ impl TestCase for InitCase { }, other => CaseResult { cu: result.compute_units_consumed, - error: Some(format!( - "expected Failure({:?}), got {:?}", - expected, other - )), + error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), }, } } From 8a0298777130cf93b17fbb9b2c050ddeebdfa43e Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:08:02 -0800 Subject: [PATCH 139/263] Check in tests --- .../tests/entrypoint_branching/result.txt | 31 +++++ .../initialize_create_account/result.txt | 36 ++++++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 108 ++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 + .../tests/initialize_pda_checks/result.txt | 31 +++++ .../tests/initialize_pda_checks/test.txt | 4 + 7 files changed, 218 insertions(+) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..a4015b68 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,31 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Three accounts | 5 | 7 | +2 | +40.0% | +| Five accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..f39d51de --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,36 @@ +| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % | +|------|-------|-----------|------------|----------|------------| +| System Program is wrong address | 2446 | 104 | 136 | +32 | +30.8% | +| User has insufficient Lamports | 2596 | 104 | 136 | +32 | +30.8% | +| CreateAccount happy path | 2596 | 105 | 139 | +34 | +32.4% | +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2582 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2700 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2732 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..aa2dd6c3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..710d9f61 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,108 @@ +| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | +| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | +| Non-empty instruction data | 31 | 37 | +6 | +19.4% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..24226cfc --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..0a7adb46 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % | +|------|-------|-----------|------------|----------|------------| +| PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | +| PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | +| PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | +| PDA mismatch chunk 4 | 1500 | 51 | 59 | +8 | +15.7% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file From c88dc247cd41df289a1fdd37fde4cb8a238b5cf1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:17:32 -0800 Subject: [PATCH 140/263] Update reporting layout --- docs/src/examples/tree.md | 26 ++++++++++++++++++- .../initialize_create_account/result.txt | 4 +-- .../tests/initialize_pda_checks/result.txt | 4 +-- examples/tree/src/tests.rs | 4 +-- examples/tree/src/tests/init.rs | 14 ++++++++++ 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 9fe1d6dd..38605d19 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -11,6 +11,8 @@ performance. ## Entrypoint branching +::: details Implementations + ::: code-group @@ -21,12 +23,18 @@ performance. ::: +::: details Benchmarking + +::: + ## Initialize ### Input checks +::: details Implementations + ::: code-group @@ -37,12 +45,18 @@ performance. ::: +::: details Benchmarking + +::: + ### PDA checks +::: details Implementations + ::: code-group @@ -53,12 +67,18 @@ performance. ::: +::: details Benchmarking + +::: + ### Create account +::: details Implementations + ::: code-group @@ -69,7 +89,11 @@ performance. ::: - +::: details Benchmarking + + + +::: diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index f39d51de..88fae32b 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,5 +1,5 @@ -| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % | -|------|-------|-----------|------------|----------|------------| +| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|------|----------------|---------------|----------------|----------|------------| | System Program is wrong address | 2446 | 104 | 136 | +32 | +30.8% | | User has insufficient Lamports | 2596 | 104 | 136 | +32 | +30.8% | | CreateAccount happy path | 2596 | 105 | 139 | +34 | +32.4% | diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 0a7adb46..de61d936 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,5 +1,5 @@ -| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % | -|------|-------|-----------|------------|----------|------------| +| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|------|----------------|---------------|----------------|----------|------------| | PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | | PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | | PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 36658c5e..2a00275f 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -72,8 +72,8 @@ fn print_comparison_table( let has_fixed_costs = cases.iter().any(|c| c.fixed_costs() > 0); if has_fixed_costs { - println!("| Case | Fixed | ASM (net) | Rust (net) | Overhead | Overhead % |"); - println!("|------|-------|-----------|------------|----------|------------|"); + println!("| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % |"); + println!("|------|----------------|---------------|----------------|----------|------------|"); } else { println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); println!("|------|-----------|------------|----------|------------|"); diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 80fcc942..b371eab2 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -1,5 +1,6 @@ use super::*; use mollusk_svm::program; +use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; @@ -447,6 +448,19 @@ impl TestCase for InitCase { expected_lamports, tree.lamports )); } + let config = Config { + panic: false, + verbose: false, + }; + if !result.run_checks( + &[Check::all_rent_exempt()], + &config, + &setup.mollusk, + ) { + errors.push( + "not all accounts are rent exempt".to_string(), + ); + } CaseResult { cu: result.compute_units_consumed, error: if errors.is_empty() { From ad225e49b7a9167566d491b8256ce7033050c016 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:31:00 -0800 Subject: [PATCH 141/263] Update docs --- docs/src/examples/tree.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 38605d19..ef7fe598 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -5,12 +5,16 @@ ## Background This example implements a [red-black tree][wikipedia tree page] in both -[SBPF assembly](../index.md) and Rust. It benchmarks various operations and code -paths side-by-side for a comprehensive breakdown of assembly vs Rust -performance. +[SBPF assembly](../index.md) and Rust. Both implementations are compared +side-by-side with as much implementation parity as possible, using C-style Rust +(raw pointers, direct [syscalls](../indices/syscalls.md)) to minimize compiler +overhead. ## Entrypoint branching +The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, +it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. + ::: details Implementations ::: code-group @@ -31,6 +35,10 @@ performance. ## Initialize +The initialize operation creates a tree [PDA] for the entire program, then +invokes a [`CreateAccount` CPI](counter#cpi-construction), with the same +[fixed costs as in the counter example](counter#compute-unit-analysis). + ### Input checks ::: details Implementations @@ -77,6 +85,10 @@ performance. ### Create account +The assembly implementation includes pointer walkthrough optimizations that are +not available in Rust, since the compiler enforces +[instruction-level parallelism][ilp]. + ::: details Implementations ::: code-group @@ -105,4 +117,9 @@ performance. ::: -[wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree \ No newline at end of file +[ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism +[compute unit]: https://solana.com/docs/references/terminology#compute-units +[pda]: https://solana.com/docs/core/pda +[wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree +[`pinocchio`]: https://github.com/anza-xyz/pinocchio +[`simd-0321`]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0321-vm-r2-instruction-data-pointer.md \ No newline at end of file From 5b24da7c4e582fb639e8b2848d81d575d5e5bb84 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:36:50 -0800 Subject: [PATCH 142/263] Update docs more --- docs/src/examples/tree.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index ef7fe598..960fb519 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -10,6 +10,36 @@ side-by-side with as much implementation parity as possible, using C-style Rust (raw pointers, direct [syscalls](../indices/syscalls.md)) to minimize compiler overhead. +## Build support + +Constants, error codes, and C bindings are derived in a shared interface using +macros, then automatically inserted into the assembly program file at build +time. + +::: details Interface + +::: code-group + +<<< ../../../examples/tree/interface/src/common.rs{rs:line-numbers} + +<<< ../../../examples/tree/interface/src/asm.rs{rs:line-numbers} + +<<< ../../../examples/tree/interface/src/bindings.rs{rs:line-numbers} + +::: + +::: details `build.rs` + +<<< ../../../examples/tree/build.rs{rs:line-numbers} + +::: + +::: details Macros + +<<< ../../../examples/tree/macros/src/lib.rs{rs:line-numbers} + +::: + ## Entrypoint branching The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, From b2d77f32b23879067a68d128f1b0d1ea5a9976aa Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:37:43 -0800 Subject: [PATCH 143/263] Update case tables --- examples/tree/src/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 2a00275f..1680d27d 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -72,11 +72,11 @@ fn print_comparison_table( let has_fixed_costs = cases.iter().any(|c| c.fixed_costs() > 0); if has_fixed_costs { - println!("| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % |"); - println!("|------|----------------|---------------|----------------|----------|------------|"); + println!("| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % |"); + println!("|-----------|----------------|---------------|----------------|----------|------------|"); } else { - println!("| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); - println!("|------|-----------|------------|----------|------------|"); + println!("| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % |"); + println!("|-----------|-----------|------------|----------|------------|"); } for case in cases { From d39559ece8291156bd20fb86d1776d911a53e6ab Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:38:27 -0800 Subject: [PATCH 144/263] Run quick-lint --- docs/src/examples/tree.md | 3 +-- examples/Cargo.toml | 4 ++-- examples/tree/interface/Cargo.toml | 10 +++++----- examples/tree/macros/Cargo.toml | 16 ++++++++-------- examples/utils/deps/build/Cargo.toml | 2 +- examples/utils/deps/program/Cargo.toml | 2 +- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 960fb519..b590b573 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -148,8 +148,7 @@ not available in Rust, since the compiler enforces ::: [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism -[compute unit]: https://solana.com/docs/references/terminology#compute-units [pda]: https://solana.com/docs/core/pda [wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree [`pinocchio`]: https://github.com/anza-xyz/pinocchio -[`simd-0321`]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0321-vm-r2-instruction-data-pointer.md \ No newline at end of file +[`simd-0321`]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0321-vm-r2-instruction-data-pointer.md diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8fbfbcb5..0df48af5 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -18,7 +18,6 @@ resolver = "2" [workspace.dependencies] cargo-manifest = "0.19.1" -tree-interface = { path = "tree/interface" } convert_case = "0.11.0" fib-rs = "1.0.0" mollusk-svm = "0.10.1" @@ -29,7 +28,8 @@ quote = "1.0.44" regex = "1.12.2" solana-rent = "3.0.0" solana-sdk = "3.0.0" -syn = { version = "2.0.114", features = ["full"] } +syn = {version = "2.0.114", features = ["full"]} +tree-interface = {path = "tree/interface"} [workspace.lints.rust] unexpected_cfgs = {level = "warn", check-cfg = ['cfg(target_os, values("solana"))']} diff --git a/examples/tree/interface/Cargo.toml b/examples/tree/interface/Cargo.toml index cbb7337f..12e2214f 100644 --- a/examples/tree/interface/Cargo.toml +++ b/examples/tree/interface/Cargo.toml @@ -1,8 +1,8 @@ -[package] -name = "tree-interface" -version = "0.1.0" -edition = "2021" - [dependencies] macros.path = "../macros" pinocchio.workspace = true + +[package] +edition = "2021" +name = "tree-interface" +version = "0.1.0" diff --git a/examples/tree/macros/Cargo.toml b/examples/tree/macros/Cargo.toml index 1adbb0ec..5405b0fa 100644 --- a/examples/tree/macros/Cargo.toml +++ b/examples/tree/macros/Cargo.toml @@ -1,13 +1,13 @@ -[package] -name = "macros" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - [dependencies] convert_case.workspace = true proc-macro2.workspace = true quote.workspace = true syn.workspace = true + +[lib] +proc-macro = true + +[package] +edition = "2021" +name = "macros" +version = "0.1.0" diff --git a/examples/utils/deps/build/Cargo.toml b/examples/utils/deps/build/Cargo.toml index f2cd1318..450be059 100644 --- a/examples/utils/deps/build/Cargo.toml +++ b/examples/utils/deps/build/Cargo.toml @@ -1,9 +1,9 @@ [dependencies] cargo-manifest.workspace = true -tree-interface.workspace = true pinocchio.workspace = true pinocchio-system.workspace = true regex.workspace = true +tree-interface.workspace = true [dev-dependencies] fib-rs.workspace = true diff --git a/examples/utils/deps/program/Cargo.toml b/examples/utils/deps/program/Cargo.toml index 44e25533..de08a813 100644 --- a/examples/utils/deps/program/Cargo.toml +++ b/examples/utils/deps/program/Cargo.toml @@ -1,7 +1,7 @@ [dependencies] -tree-interface.workspace = true pinocchio.workspace = true pinocchio-system.workspace = true +tree-interface.workspace = true [lib] crate-type = ["cdylib", "lib"] From ae103c30b6adf49e5353ffafc004e09d561817d3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:38:53 -0800 Subject: [PATCH 145/263] Re-gen results --- examples/tree/artifacts/tests/entrypoint_branching/result.txt | 4 ++-- .../tree/artifacts/tests/initialize_create_account/result.txt | 4 ++-- .../tree/artifacts/tests/initialize_input_checks/result.txt | 4 ++-- .../tree/artifacts/tests/initialize_pda_checks/result.txt | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index a4015b68..fe73f2d7 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,5 +1,5 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| | No accounts | 5 | 7 | +2 | +40.0% | | One account | 5 | 7 | +2 | +40.0% | | Three accounts | 5 | 7 | +2 | +40.0% | diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index 88fae32b..7d74f4cd 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,5 +1,5 @@ -| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|------|----------------|---------------|----------------|----------|------------| +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| | System Program is wrong address | 2446 | 104 | 136 | +32 | +30.8% | | User has insufficient Lamports | 2596 | 104 | 136 | +32 | +30.8% | | CreateAccount happy path | 2596 | 105 | 139 | +34 | +32.4% | diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 710d9f61..2d9b546e 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,5 +1,5 @@ -| Case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|------|-----------|------------|----------|------------| +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| | User has nonzero data length | 7 | 9 | +2 | +28.6% | | Tree account is duplicate | 9 | 11 | +2 | +22.2% | | Tree has nonzero data length | 11 | 13 | +2 | +18.2% | diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index de61d936..7348c78c 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,5 +1,5 @@ -| Case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|------|----------------|---------------|----------------|----------|------------| +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| | PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | | PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | | PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | From 10079a6732310c65f6967f8688307edb34f9c13b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:40:39 -0800 Subject: [PATCH 146/263] Run quick-lint --- cfg/dictionary.txt | 1 + examples/tree/macros/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cfg/dictionary.txt b/cfg/dictionary.txt index fa6d00af..6f0fffe4 100644 --- a/cfg/dictionary.txt +++ b/cfg/dictionary.txt @@ -41,6 +41,7 @@ syscalls sysvar sysvars uninit +uoff usize vitepress xffff diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index ae3d1664..aa5ed393 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -1,3 +1,5 @@ +// cspell:word strs +// cspell:word idents use convert_case::{Case, Casing}; use proc_macro::TokenStream; use quote::quote; From be214017d00f08b90ac31f00e440db514e5a365a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:31:45 -0800 Subject: [PATCH 147/263] Add tail call note --- docs/src/examples/tree.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index b590b573..a3d23058 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -43,7 +43,9 @@ time. ## Entrypoint branching The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, -it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. +it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. Note that the Rust +implementation already introduces overhead at this point in program flow due to +greedy [tail call optimizations][tail call]. ::: details Implementations @@ -149,6 +151,7 @@ not available in Rust, since the compiler enforces [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism [pda]: https://solana.com/docs/core/pda +[tail call]: https://en.wikipedia.org/wiki/Tail_call [wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree [`pinocchio`]: https://github.com/anza-xyz/pinocchio [`simd-0321`]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0321-vm-r2-instruction-data-pointer.md From 31dcf2713e3d4bffb02fbd3c407236d3b3aa8473 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:00:58 -0800 Subject: [PATCH 148/263] Add tree defs --- .../tree/artifacts/snippets/asm/constants.txt | 10 ++++- examples/tree/build.rs | 3 +- examples/tree/interface/src/asm.rs | 16 ++++++- examples/tree/interface/src/common.rs | 45 +++++++++++++++++-- examples/tree/src/tree/tree.s | 8 ++++ 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 20c570a3..3da13d50 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -177,4 +177,12 @@ .equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. .equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. -.equ CPI_RENT_EPOCH_NULL, 0 # Null rent epoch. \ No newline at end of file +.equ CPI_RENT_EPOCH_NULL, 0 # Null rent epoch. + +# Tree constants. +# --------------- +.equ TREE_N_CHILDREN, 2 # Max number of children per node. +.equ TREE_DIR_L, 0 # Left direction. +.equ TREE_DIR_R, 1 # Right direction. +.equ TREE_COLOR_B, 0 # Black color. +.equ TREE_COLOR_R, 1 # Red color. \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 0cda671a..35e7bcd1 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -19,7 +19,8 @@ fn main() { pubkey_chunk, input_buffer, init_stack_frame, - cpi + cpi, + tree ]; // Read in the assembly file. diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 27ab8370..3bb70b9a 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -3,7 +3,9 @@ extern crate alloc; use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; -use crate::common::{cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader}; +use crate::common::{ + cpi, Color, CreateAccountInstructionData, Direction, InitInputBuffer, InputBufferHeader, +}; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ entrypoint::NON_DUP_MARKER, @@ -29,6 +31,18 @@ extend_constant_group!(data { MAX_DATA_PAD = 7, }); +extend_constant_group!(tree { + prefix = "TREE", + /// Left direction. + DIR_L = Direction::Left as usize, + /// Right direction. + DIR_R = Direction::Right as usize, + /// Black color. + COLOR_B = Color::Black as u8, + /// Red color. + COLOR_R = Color::Red as u8, +}); + extend_constant_group!(input_buffer { prefix = "IB", /// User address field. diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 6bc5001b..d34fdf47 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -84,7 +84,7 @@ constant_group! { /// Number of seeds for PDA generation. N_SEEDS_TRY_FIND_PDA: u64 = 0, /// Tree account data length. - TREE_DATA_LEN: usize = size_of::(), + TREE_DATA_LEN: usize = size_of::(), /// Account data scalar for base rent calculation. ACCOUNT_DATA_SCALAR: usize = (ACCOUNT_STORAGE_OVERHEAD as usize) + TREE_DATA_LEN, /// CreateAccount discriminator for CPI. @@ -145,13 +145,50 @@ pub struct InitInputBufferHeader { pub rent: RentRuntimeAccount, } +// ANCHOR: tree-defs-common +#[repr(u8)] +pub enum Color { + Black, + Red, +} + +#[repr(usize)] +pub enum Direction { + Left, + Right, +} + +constant_group! { + /// Tree constants. + tree { + /// Max number of children per node. + N_CHILDREN: usize = 2, + } +} + #[repr(C, packed)] -struct TreeDataHeader { +/// Tree account data header. Contains pointer to tree root and top of free node stack. +struct TreeHeader { /// Pointer to tree root. - root: u64, + root: *const TreeNode, /// Pointer to stack top. - top: u64, + top: *const StackNode, +} + +#[repr(C, packed)] +struct TreeNode { + parent: *const TreeNode, + child: [*const TreeNode; tree::N_CHILDREN], + key: u16, + value: u16, + color: Color, +} + +#[repr(C, packed)] +struct StackNode { + next: *const StackNode, } +// ANCHOR_END: tree-defs-asm #[repr(C, packed)] pub struct InitInputBufferFooter { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 526ba216..a1d1c171 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -179,6 +179,14 @@ .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. .equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. .equ CPI_RENT_EPOCH_NULL, 0 # Null rent epoch. + +# Tree constants. +# --------------- +.equ TREE_N_CHILDREN, 2 # Max number of children per node. +.equ TREE_DIR_L, 0 # Left direction. +.equ TREE_DIR_R, 1 # Right direction. +.equ TREE_COLOR_B, 0 # Black color. +.equ TREE_COLOR_R, 1 # Red color. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From aa51c85c67e91bce6e65b7cd3f86b5be1e3582c0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:01:56 -0800 Subject: [PATCH 149/263] Clean up anchors --- .../asm/initialize-create-account.txt | 138 ------------------ .../snippets/asm/initialize-pda-checks.txt | 28 ---- examples/tree/interface/src/asm.rs | 2 + examples/tree/interface/src/common.rs | 2 +- 4 files changed, 3 insertions(+), 167 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/asm/initialize-create-account.txt delete mode 100644 examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt deleted file mode 100644 index 7bf28e76..00000000 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ /dev/null @@ -1,138 +0,0 @@ - # Pack SolInstruction. - # --------------------------------------------------------------------- - # Packed later during bulk pointer load operation: - # - [x] System Program ID pointer. - # - [x] Account metas pointer. - # - [x] Instruction data pointer. - # --------------------------------------------------------------------- - stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS - stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN - - # Pack CreateAccount instruction data. - # --------------------------------------------------------------------- - # - Discriminator is already set to 0 since stack is zero initialized. - # - Reuses r3 from PDA syscall. - # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_RENT_DATA_OFF] # Load lamports per byte - mul64 r9, CPI_ACCOUNT_DATA_SCALAR # Multiply to get rent-exempt cost. - # Store in instruction data. - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 - # Store new account data length. - stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN - # Copy in program ID to instruction data. - ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0], r9 - ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_1] - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1], r9 - ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_2] - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2], r9 - ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 - - # Pack SolAccountMeta for user and tree. - # --------------------------------------------------------------------- - # Packed later during bulk pointer load operation: - # - [x] User pubkey pointer. - # - [x] Tree pubkey pointer. - # --------------------------------------------------------------------- - sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER - sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER - - # Pack SolAccountInfo for user and tree. - # --------------------------------------------------------------------- - # Packed later during bulk pointer load operation: - # - [x] User pubkey pointer. - # - [x] Tree pubkey pointer. - # - [x] User lamports pointer. - # - [x] Tree lamports pointer. - # - [x] User data pointer. - # - [x] Tree data pointer. - # - [x] User owner pointer. - # - [x] Tree owner pointer. - # Skipped due to zero-initialized stack memory: - # - User data length (already checked as zero). - # - Tree data length (already checked as zero). - # - User rent epoch. - # - Tree rent epoch. - # - User executable. - # - Tree executable. - # --------------------------------------------------------------------- - sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER - sth [r10 + SF_INIT_TREE_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER - - # Initialize signer seed for PDA bump seed. - # --------------------------------------------------------------------- - # Reuses r5 from PDA derivation syscall. - # --------------------------------------------------------------------- - # Store pointer to bump seed. - stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 - stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. - - # Initialize signers seeds for PDA. - # --------------------------------------------------------------------- - # Packed later during bulk pointer load operation: - # - [x] Signer seed pointer. - # --------------------------------------------------------------------- - stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS - - # Bulk assign/load pointers for account metas and infos. - # --------------------------------------------------------------------- - # Since pointers must be loaded from registers, this block steps - # through the input buffer in order to reduce intermediate loads. - # --------------------------------------------------------------------- - add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. - stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. - stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. - add64 r1, SIZE_OF_ADDRESS # Advance to user owner. - stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. - add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. - stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. - add64 r1, SIZE_OF_U128 # Advance to user data. - stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. - # Advance to tree address field. - add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM - stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. - stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. - add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. - stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. - add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. - stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. - add64 r1, SIZE_OF_U128 # Advance to tree data. - stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. - - # Bulk assign/load pointers for CPI bindings. - # --------------------------------------------------------------------- - # This block steps through the stack frame, optimizing assignments in - # preparation for the impending CreateAccount CPI, which requires: - # - [x] r1 = pointer to instruction. - # - [x] r2 = pointer to account infos. - # - [x] r4 = pointer to signers seeds. - # Notably, it reuses r4 from the PDA derivation syscall to walk through - # pointers on the stack, before advancing it to its final value. - # --------------------------------------------------------------------- - # Advance to System Program ID pointer on zero-initialized stack. - add64 r4, SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM - # Store in SolInstruction. - stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 - # Advance to SolAccountMeta array pointer. - add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM - stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. - # Advance to instruction data pointer. - add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM - stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. - # Advance to signer seeds pointer. - add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM - stxdw [r10 + SF_INIT_SIGNERS_SEEDS_ADDR_OFF], r4 - # Advance to signers seeds pointer. - add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM - # Assign remaining syscall pointers. - mov64 r1, r10 - add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF - mov64 r2, r10 - add64 r2, SF_INIT_ACCT_INFOS_OFF - - # Invoke CPI. - # --------------------------------------------------------------------- - mov64 r3, CPI_N_ACCOUNTS - mov64 r5, CPI_N_PDA_SIGNERS - call sol_invoke_signed_c \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt deleted file mode 100644 index e7617371..00000000 --- a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt +++ /dev/null @@ -1,28 +0,0 @@ - # Compute PDA. - # --------------------------------------------------------------------- - # Skip assignment for r1, since no seeds need to be parsed and this - # argument is effectively ignored. - # --------------------------------------------------------------------- - mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. - mov64 r3, r1 # Get input buffer pointer. - add64 r3, IB_INIT_PROGRAM_ID_OFF_IMM # Point at program ID. - mov64 r4, r10 # Get stack frame pointer. - add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. - mov64 r5, r10 # Get stack frame pointer. - add64 r5, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. - call sol_try_find_program_address # Find PDA. - - # Compare computed PDA against passed account. - # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] - ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] - jne r9, r8, e_pda_mismatch - ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_1] - ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_1] - jne r9, r8, e_pda_mismatch - ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_2] - ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_2] - jne r9, r8, e_pda_mismatch - ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_3] - ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_3] - jne r9, r8, e_pda_mismatch \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 3bb70b9a..9f5a405e 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -31,6 +31,7 @@ extend_constant_group!(data { MAX_DATA_PAD = 7, }); +// ANCHOR: tree-defs-asm extend_constant_group!(tree { prefix = "TREE", /// Left direction. @@ -42,6 +43,7 @@ extend_constant_group!(tree { /// Red color. COLOR_R = Color::Red as u8, }); +// ANCHOR_END: tree-defs-asm extend_constant_group!(input_buffer { prefix = "IB", diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index d34fdf47..0fd8cfdc 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -188,7 +188,7 @@ struct TreeNode { struct StackNode { next: *const StackNode, } -// ANCHOR_END: tree-defs-asm +// ANCHOR_END: tree-defs-common #[repr(C, packed)] pub struct InitInputBufferFooter { From b24839efe8015e8c8005b0225d3c8752a6c7eaf3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:02:05 -0800 Subject: [PATCH 150/263] REbuild --- .../asm/initialize-create-account.txt | 138 ++++++++++++++++++ .../snippets/asm/initialize-pda-checks.txt | 28 ++++ 2 files changed, 166 insertions(+) create mode 100644 examples/tree/artifacts/snippets/asm/initialize-create-account.txt create mode 100644 examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt new file mode 100644 index 00000000..7bf28e76 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -0,0 +1,138 @@ + # Pack SolInstruction. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [x] System Program ID pointer. + # - [x] Account metas pointer. + # - [x] Instruction data pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN + + # Pack CreateAccount instruction data. + # --------------------------------------------------------------------- + # - Discriminator is already set to 0 since stack is zero initialized. + # - Reuses r3 from PDA syscall. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_RENT_DATA_OFF] # Load lamports per byte + mul64 r9, CPI_ACCOUNT_DATA_SCALAR # Multiply to get rent-exempt cost. + # Store in instruction data. + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + # Store new account data length. + stdw [r10 + SF_INIT_CREATE_ACCOUNT_SPACE_UOFF], CPI_TREE_DATA_LEN + # Copy in program ID to instruction data. + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_0] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_0], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_1] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_1], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_2] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_2], r9 + ldxdw r9, [r3 + PUBKEY_CHUNK_OFF_3] + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_OWNER_UOFF_3], r9 + + # Pack SolAccountMeta for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [x] User pubkey pointer. + # - [x] Tree pubkey pointer. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + + # Pack SolAccountInfo for user and tree. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [x] User pubkey pointer. + # - [x] Tree pubkey pointer. + # - [x] User lamports pointer. + # - [x] Tree lamports pointer. + # - [x] User data pointer. + # - [x] Tree data pointer. + # - [x] User owner pointer. + # - [x] Tree owner pointer. + # Skipped due to zero-initialized stack memory: + # - User data length (already checked as zero). + # - Tree data length (already checked as zero). + # - User rent epoch. + # - Tree rent epoch. + # - User executable. + # - Tree executable. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + sth [r10 + SF_INIT_TREE_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + + # Initialize signer seed for PDA bump seed. + # --------------------------------------------------------------------- + # Reuses r5 from PDA derivation syscall. + # --------------------------------------------------------------------- + # Store pointer to bump seed. + stxdw [r10 + SF_INIT_SIGNER_SEED_ADDR_OFF], r5 + stdw [r10 + SF_INIT_SIGNER_SEED_LEN_OFF], SIZE_OF_U8 # Store length. + + # Initialize signers seeds for PDA. + # --------------------------------------------------------------------- + # Packed later during bulk pointer load operation: + # - [x] Signer seed pointer. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS + + # Bulk assign/load pointers for account metas and infos. + # --------------------------------------------------------------------- + # Since pointers must be loaded from registers, this block steps + # through the input buffer in order to reduce intermediate loads. + # --------------------------------------------------------------------- + add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. + stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user owner. + stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. + stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to user data. + stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. + # Advance to tree address field. + add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM + stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. + stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. + stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to tree data. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + + # Bulk assign/load pointers for CPI bindings. + # --------------------------------------------------------------------- + # This block steps through the stack frame, optimizing assignments in + # preparation for the impending CreateAccount CPI, which requires: + # - [x] r1 = pointer to instruction. + # - [x] r2 = pointer to account infos. + # - [x] r4 = pointer to signers seeds. + # Notably, it reuses r4 from the PDA derivation syscall to walk through + # pointers on the stack, before advancing it to its final value. + # --------------------------------------------------------------------- + # Advance to System Program ID pointer on zero-initialized stack. + add64 r4, SF_INIT_PDA_TO_SYSTEM_PROGRAM_ID_REL_OFF_IMM + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 + # Advance to SolAccountMeta array pointer. + add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Advance to instruction data pointer. + add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. + # Advance to signer seeds pointer. + add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM + stxdw [r10 + SF_INIT_SIGNERS_SEEDS_ADDR_OFF], r4 + # Advance to signers seeds pointer. + add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + # Assign remaining syscall pointers. + mov64 r1, r10 + add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r2, r10 + add64 r2, SF_INIT_ACCT_INFOS_OFF + + # Invoke CPI. + # --------------------------------------------------------------------- + mov64 r3, CPI_N_ACCOUNTS + mov64 r5, CPI_N_PDA_SIGNERS + call sol_invoke_signed_c \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt new file mode 100644 index 00000000..e7617371 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/initialize-pda-checks.txt @@ -0,0 +1,28 @@ + # Compute PDA. + # --------------------------------------------------------------------- + # Skip assignment for r1, since no seeds need to be parsed and this + # argument is effectively ignored. + # --------------------------------------------------------------------- + mov64 r2, CPI_N_SEEDS_TRY_FIND_PDA # Declare no seeds to parse. + mov64 r3, r1 # Get input buffer pointer. + add64 r3, IB_INIT_PROGRAM_ID_OFF_IMM # Point at program ID. + mov64 r4, r10 # Get stack frame pointer. + add64 r4, SF_INIT_PDA_OFF # Point to PDA region on stack. + mov64 r5, r10 # Get stack frame pointer. + add64 r5, SF_INIT_BUMP_SEED_OFF # Point to bump seed region on stack. + call sol_try_find_program_address # Find PDA. + + # Compare computed PDA against passed account. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_0] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_0] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_1] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_1] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_2] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_2] + jne r9, r8, e_pda_mismatch + ldxdw r9, [r1 + IB_TREE_ADDRESS_OFF_3] + ldxdw r8, [r4 + PUBKEY_CHUNK_OFF_3] + jne r9, r8, e_pda_mismatch \ No newline at end of file From e66a8ba6e36f1f3de1acd143200644efb03d030c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:23:47 -0800 Subject: [PATCH 151/263] TIdy up constants --- .../tree/artifacts/snippets/asm/constants.txt | 4 +- examples/tree/interface/src/asm.rs | 24 ++++----- examples/tree/interface/src/common.rs | 30 +++++++---- examples/tree/interface/src/lib.rs | 4 +- examples/tree/src/program.rs | 52 ++++++++++++++++++- examples/tree/src/tree/tree.s | 2 + 6 files changed, 86 insertions(+), 30 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 3da13d50..3eb1011e 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -185,4 +185,6 @@ .equ TREE_DIR_L, 0 # Left direction. .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. -.equ TREE_COLOR_R, 1 # Red color. \ No newline at end of file +.equ TREE_COLOR_R, 1 # Red color. +.equ TREE_ROOT_OFF, 0 # Tree root. +.equ TREE_TOP_OFF, 8 # Stack top. \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 9f5a405e..78bf1d8b 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,7 +4,7 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, Color, CreateAccountInstructionData, Direction, InitInputBuffer, InputBufferHeader, + cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, TreeHeader, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -31,20 +31,6 @@ extend_constant_group!(data { MAX_DATA_PAD = 7, }); -// ANCHOR: tree-defs-asm -extend_constant_group!(tree { - prefix = "TREE", - /// Left direction. - DIR_L = Direction::Left as usize, - /// Right direction. - DIR_R = Direction::Right as usize, - /// Black color. - COLOR_B = Color::Black as u8, - /// Red color. - COLOR_R = Color::Red as u8, -}); -// ANCHOR_END: tree-defs-asm - extend_constant_group!(input_buffer { prefix = "IB", /// User address field. @@ -247,3 +233,11 @@ asm_constant_group! { stack_frame_offset!(ACCT_INFOS, InitStackFrame.account_infos), } } + +extend_constant_group!(tree { + prefix = "TREE", + /// Tree root. + offset!(ROOT, TreeHeader.root), + /// Stack top. + offset!(TOP, TreeHeader.top), +}); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0fd8cfdc..f762f3de 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -163,30 +163,38 @@ constant_group! { tree { /// Max number of children per node. N_CHILDREN: usize = 2, + /// Left direction. + DIR_L = Direction::Left as usize, + /// Right direction. + DIR_R = Direction::Right as usize, + /// Black color. + COLOR_B = Color::Black as u8, + /// Red color. + COLOR_R = Color::Red as u8, } } #[repr(C, packed)] /// Tree account data header. Contains pointer to tree root and top of free node stack. -struct TreeHeader { +pub struct TreeHeader { /// Pointer to tree root. - root: *const TreeNode, + pub root: *const TreeNode, /// Pointer to stack top. - top: *const StackNode, + pub top: *const StackNode, } #[repr(C, packed)] -struct TreeNode { - parent: *const TreeNode, - child: [*const TreeNode; tree::N_CHILDREN], - key: u16, - value: u16, - color: Color, +pub struct TreeNode { + pub parent: *const TreeNode, + pub child: [*const TreeNode; tree::N_CHILDREN], + pub key: u16, + pub value: u16, + pub color: Color, } #[repr(C, packed)] -struct StackNode { - next: *const StackNode, +pub struct StackNode { + pub next: *const StackNode, } // ANCHOR_END: tree-defs-common diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index a2d0c181..be114387 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -8,4 +8,6 @@ mod common; pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; -pub use common::{cpi, error_codes, CreateAccountInstructionData}; +pub use common::{ + cpi, error_codes, Color, CreateAccountInstructionData, Direction, TreeHeader, TreeNode, +}; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index d264c502..1812dbca 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -8,8 +8,9 @@ use pinocchio::{ AccountView, Address, SUCCESS, }; use tree_interface::{ - cpi, data, error_codes::error, input_buffer, CreateAccountInstructionData, SolAccountInfo, - SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, + cpi, data, error_codes::error, input_buffer, tree, CreateAccountInstructionData, Direction, + SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, + TreeNode, }; #[cfg(target_os = "solana")] use { @@ -262,3 +263,50 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - SUCCESS } + +/// Return the direction of the node with respect to its parent. +#[inline(always)] +unsafe fn direction(node: *const TreeNode) -> Direction { + if node == (*(*node).parent).child[tree::DIR_R] { + Direction::Right + } else { + Direction::Left + } +} + +#[inline(always)] +const fn opposite(direction: usize) -> usize { + 1 - direction +} + +/// Rotate the subtree rooted at `subtree` in the given direction, returning new root of subtree. +#[inline(always)] +unsafe fn rotate_subtree( + tree: *mut TreeHeader, + subtree: *mut TreeNode, + direction: usize, +) -> *mut TreeNode { + let subtree_parent = (*subtree).parent as *mut TreeNode; + let new_root = (*subtree).child[opposite(direction)] as *mut TreeNode; + let new_child = (*new_root).child[direction] as *mut TreeNode; + + (*subtree).child[opposite(direction)] = new_child; + + if !new_child.is_null() { + (*new_child).parent = subtree; + } + + (*new_root).child[direction] = subtree; + (*new_root).parent = subtree_parent; + (*subtree).parent = new_root; + + if !subtree_parent.is_null() { + (*subtree_parent).child + [(subtree as *const TreeNode == (*subtree_parent).child[tree::DIR_R]) as usize] = + new_root; + } else { + (*tree).root = new_root; + } + + new_root +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a1d1c171..51741109 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -187,6 +187,8 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. +.equ TREE_ROOT_OFF, 0 # Tree root. +.equ TREE_TOP_OFF, 8 # Stack top. # ANCHOR_END: constants # ANCHOR: entrypoint-branching From 6e9746349dd5e312c8eb58cfe9bdf9326028722c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:04:17 -0800 Subject: [PATCH 152/263] Begin insert layout --- .../tree/artifacts/snippets/asm/constants.txt | 7 ++- .../snippets/rs/entrypoint-branching.txt | 2 +- .../snippets/rs/initialize-create-account.txt | 5 ++ examples/tree/interface/src/common.rs | 60 +++++++++++++++++-- examples/tree/interface/src/lib.rs | 3 +- examples/tree/src/program.rs | 40 ++++++++++--- examples/tree/src/tree/tree.s | 7 ++- 7 files changed, 105 insertions(+), 19 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 3eb1011e..f626a9fe 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -14,6 +14,8 @@ .equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. .equ E_PDA_MISMATCH, 10 +.equ E_INSTRUCTION_DISCRIMINATOR, 11 # Invalid instruction discriminator. +.equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. # Type sizes. # ----------- @@ -168,9 +170,9 @@ .equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. .equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. -.equ CPI_TREE_DATA_LEN, 16 # Tree account data length. +.equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. -.equ CPI_ACCOUNT_DATA_SCALAR, 144 +.equ CPI_ACCOUNT_DATA_SCALAR, 152 # CreateAccount discriminator for CPI. .equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 .equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. @@ -186,5 +188,6 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. +.equ TREE_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 1ad539ef..86839c75 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -8,7 +8,7 @@ pub unsafe extern "C" fn entrypoint( ) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input_buffer_ptr) + general(input_buffer_ptr, instruction_data_ptr) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { initialize(input_buffer_ptr, instruction_data_ptr) } else { diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index bebe6d5a..392b9e8b 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -104,3 +104,8 @@ sol_account_infos; sol_instruction; } + + // Set next field in header. + let tree_data_ptr = tree.data_ptr(); + let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); + (*tree_data_ptr.cast::()).next = next_ptr; diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index f762f3de..ea0eab7c 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -27,6 +27,10 @@ error_codes! { INSTRUCTION_DATA, /// The passed PDA does not match the expected address. PDA_MISMATCH, + /// Invalid instruction discriminator. + INSTRUCTION_DISCRIMINATOR, + /// Invalid instruction data length. + INSTRUCTION_DATA_LEN, } constant_group! { @@ -171,6 +175,8 @@ constant_group! { COLOR_B = Color::Black as u8, /// Red color. COLOR_R = Color::Red as u8, + /// Next node field in header. + offset!(NEXT, TreeHeader.next), } } @@ -178,15 +184,17 @@ constant_group! { /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { /// Pointer to tree root. - pub root: *const TreeNode, + pub root: *mut TreeNode, /// Pointer to stack top. - pub top: *const StackNode, + pub top: *mut StackNode, + /// Pointer to where the next node should be allocated. + pub next: *mut TreeNode, } #[repr(C, packed)] pub struct TreeNode { - pub parent: *const TreeNode, - pub child: [*const TreeNode; tree::N_CHILDREN], + pub parent: *mut TreeNode, + pub child: [*mut TreeNode; tree::N_CHILDREN], pub key: u16, pub value: u16, pub color: Color, @@ -194,10 +202,52 @@ pub struct TreeNode { #[repr(C, packed)] pub struct StackNode { - pub next: *const StackNode, + pub next: *mut StackNode, } // ANCHOR_END: tree-defs-common +// ANCHOR: instructions + +#[repr(u8)] +pub enum Instruction { + /// Initialize the tree (discriminator is number of accounts). + Initialize, + /// Insert node into tree instruction. + Insert, +} + +#[repr(C, packed)] +pub struct InstructionHeader { + discriminator: u8, +} + +#[repr(C, packed)] +pub struct InsertInstruction { + pub header: InstructionHeader, + pub key: u16, + pub value: u16, +} + +#[repr(C, packed)] +/// Value in r0. +struct Return { + /// If a value is retrieved from the tree, it's encoded in high bits. + maybe_value: u16, + /// Nonzero iff error. + status: u16, +} + +constant_group! { + /// Offsets for instruction processing. + instruction { + prefix = "INSN", + /// Offset to instruction discriminator byte. + offset!(DISCRIMINATOR, InstructionHeader.discriminator), + } +} + +// ANCHOR_END: instructions + #[repr(C, packed)] pub struct InitInputBufferFooter { /// No actual instruction data follows. diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index be114387..8a3a65f5 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -9,5 +9,6 @@ mod common; pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ - cpi, error_codes, Color, CreateAccountInstructionData, Direction, TreeHeader, TreeNode, + cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, Instruction, + TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1812dbca..69663019 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -8,9 +8,9 @@ use pinocchio::{ AccountView, Address, SUCCESS, }; use tree_interface::{ - cpi, data, error_codes::error, input_buffer, tree, CreateAccountInstructionData, Direction, - SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, - TreeNode, + cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, + Direction, Instruction, SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, + SolSignerSeeds, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -25,6 +25,11 @@ unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { AccountView::new_unchecked(input_buffer_ptr.add(offset as usize).cast()) } +#[inline(always)] +unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { + read_unaligned(ptr.add(offset as usize)) +} + #[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { read_unaligned(ptr.add(offset as usize).cast()) @@ -63,7 +68,7 @@ pub unsafe extern "C" fn entrypoint( ) -> u64 { let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input_buffer_ptr) + general(input_buffer_ptr, instruction_data_ptr) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { initialize(input_buffer_ptr, instruction_data_ptr) } else { @@ -73,11 +78,19 @@ pub unsafe extern "C" fn entrypoint( // ANCHOR_END: entrypoint-branching #[inline(always)] -unsafe fn general(input_buffer_ptr: *mut u8) -> u64 { - if ldxdw(input_buffer_ptr, input_buffer::USER_DATA_LEN_OFF) == 67 { - 6677 +unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { + // Error if user has data. + let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + + // Error if tree is duplicate. + let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + + if ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8 { + insert(input_buffer_ptr, instruction_data_ptr) } else { - 666777 + error::INSTRUCTION_DISCRIMINATOR.into() } } @@ -259,11 +272,22 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - sol_instruction; } + // Set next field in header. + let tree_data_ptr = tree.data_ptr(); + let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); + (*tree_data_ptr.cast::()).next = next_ptr; + // ANCHOR_END: initialize-create-account SUCCESS } +#[inline(always)] +unsafe fn insert(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { + // Placeholder for insert instruction implementation. + SUCCESS +} + /// Return the direction of the node with respect to its parent. #[inline(always)] unsafe fn direction(node: *const TreeNode) -> Direction { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 51741109..8b4bee49 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -15,6 +15,8 @@ .equ E_INSTRUCTION_DATA, 9 # The passed PDA does not match the expected address. .equ E_PDA_MISMATCH, 10 +.equ E_INSTRUCTION_DISCRIMINATOR, 11 # Invalid instruction discriminator. +.equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. # Type sizes. # ----------- @@ -169,9 +171,9 @@ .equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. .equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. -.equ CPI_TREE_DATA_LEN, 16 # Tree account data length. +.equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. -.equ CPI_ACCOUNT_DATA_SCALAR, 144 +.equ CPI_ACCOUNT_DATA_SCALAR, 152 # CreateAccount discriminator for CPI. .equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 .equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. @@ -187,6 +189,7 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. +.equ TREE_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. # ANCHOR_END: constants From 7996a41195127097d73b150512857e17c89fde8a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:42:10 -0800 Subject: [PATCH 153/263] Add next ptr allocation --- examples/tree/artifacts/snippets/asm/constants.txt | 1 + .../artifacts/snippets/asm/initialize-create-account.txt | 9 ++++++++- .../artifacts/snippets/rs/initialize-create-account.txt | 4 ++-- examples/tree/interface/src/common.rs | 8 +++++--- examples/tree/src/program.rs | 5 ++--- examples/tree/src/tree/tree.s | 8 ++++++++ 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index f626a9fe..247829ee 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -62,6 +62,7 @@ # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. +.equ IB_TREE_HEADER_NEXT_OFF, 16 # Tree header next field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 7bf28e76..905fca4a 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -99,6 +99,7 @@ stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to tree data. stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + mov64 r6, r1 # Store tree data pointer for later. # Bulk assign/load pointers for CPI bindings. # --------------------------------------------------------------------- @@ -135,4 +136,10 @@ # --------------------------------------------------------------------- mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS - call sol_invoke_signed_c \ No newline at end of file + call sol_invoke_signed_c + + # Store next pointer in tree header. + # --------------------------------------------------------------------- + mov64 r7, r6 # Get copy of tree data pointer. + add64 r7, NEXT_OFF # Advance to next node. + stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 392b9e8b..e0530633 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -105,7 +105,7 @@ sol_instruction; } - // Set next field in header. + // Store next pointer in tree header. let tree_data_ptr = tree.data_ptr(); let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); - (*tree_data_ptr.cast::()).next = next_ptr; + (*tree.data_ptr().cast::()).next = next_ptr; \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index ea0eab7c..12f3046a 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -72,6 +72,8 @@ constant_group! { // Includes extra byte for deprecated burn_percent field that is still present in test // framework. RENT_DATA_LEN: usize = size_of::() + size_of::(), + /// Tree header next field. + offset!(TREE_HEADER_NEXT, TreeHeader.next), } } @@ -183,11 +185,11 @@ constant_group! { #[repr(C, packed)] /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { - /// Pointer to tree root. + /// Aboslute pointer to tree root in memory map. pub root: *mut TreeNode, - /// Pointer to stack top. + /// Absolute pointer to stack top in memory map. pub top: *mut StackNode, - /// Pointer to where the next node should be allocated. + /// Absolute pointer to where the next node should be allocated in memory map. pub next: *mut TreeNode, } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 69663019..b53fbcdd 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -272,11 +272,10 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - sol_instruction; } - // Set next field in header. + // Store next pointer in tree header. let tree_data_ptr = tree.data_ptr(); let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); - (*tree_data_ptr.cast::()).next = next_ptr; - + (*tree.data_ptr().cast::()).next = next_ptr; // ANCHOR_END: initialize-create-account SUCCESS diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 8b4bee49..66c1134c 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -63,6 +63,7 @@ # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. +.equ IB_TREE_HEADER_NEXT_OFF, 16 # Tree header next field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -399,6 +400,7 @@ initialize: stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. add64 r1, SIZE_OF_U128 # Advance to tree data. stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + mov64 r6, r1 # Store tree data pointer for later. # Bulk assign/load pointers for CPI bindings. # --------------------------------------------------------------------- @@ -436,6 +438,12 @@ initialize: mov64 r3, CPI_N_ACCOUNTS mov64 r5, CPI_N_PDA_SIGNERS call sol_invoke_signed_c + + # Store next pointer in tree header. + # --------------------------------------------------------------------- + mov64 r7, r6 # Get copy of tree data pointer. + add64 r7, NEXT_OFF # Advance to next node. + stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. // ANCHOR_END: initialize-create-account exit From cf472d362a39700cb1eebcc6674fe3b356c12c33 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:44:02 -0800 Subject: [PATCH 154/263] Rebuild --- examples/tree/artifacts/dumps/asm.txt | 128 ++++--- examples/tree/artifacts/dumps/rs.txt | 353 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 101 ++--- .../asm/initialize-create-account.txt | 2 +- .../tests/entrypoint_branching/result.txt | 31 -- .../initialize_create_account/result.txt | 36 -- .../tests/initialize_create_account/test.txt | 4 - .../tests/initialize_input_checks/result.txt | 108 ------ .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 31 -- .../tests/initialize_pda_checks/test.txt | 4 - examples/tree/src/tree/tree.s | 2 +- 12 files changed, 304 insertions(+), 500 deletions(-) delete mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 3c71d112..d13618ba 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1696 (bytes into file) + Start of section headers 1728 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x6a0 +There are 7 section headers, starting at offset 0x6c0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000428 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000510 000510 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000005b0 0005b0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000610 000610 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000650 000650 000020 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000670 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000448 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000530 000530 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000005d0 0005d0 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000630 000630 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000670 000670 000020 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000690 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000428 0x000428 R E 0x1000 - LOAD 0x0005b0 0x00000000000005b0 0x00000000000005b0 0x0000c0 0x0000c0 R 0x1000 - DYNAMIC 0x000510 0x0000000000000510 0x0000000000000510 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000448 0x000448 R E 0x1000 + LOAD 0x0005d0 0x00000000000005d0 0x00000000000005d0 0x0000c0 0x0000c0 R 0x1000 + DYNAMIC 0x000530 0x0000000000000530 0x0000000000000530 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,23 +52,23 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x510 contains 10 entries +Dynamic section at offset 0x530 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x650 + 0x0000000000000011 (REL) 0x670 0x0000000000000012 (RELSZ) 32 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x5b0 + 0x0000000000000006 (SYMTAB) 0x5d0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x610 + 0x0000000000000005 (STRTAB) 0x630 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x650 contains 2 entries +Relocation section '.rel.dyn' at offset 0x670 contains 2 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000258 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -0000000000000470 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000478 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -94,31 +94,31 @@ Disassembly of section .text 37 0f 19 00 00 00 00 00 00 r9 += r1 38 95 00 00 00 00 00 00 00 exit 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 + 40 55 09 7b 00 00 00 00 00 if r9 != 0x0 goto +0x7b 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 + 42 55 09 77 00 ff 00 00 00 if r9 != 0xff goto +0x77 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 6f 00 00 00 00 00 if r9 != 0x0 goto +0x6f + 44 55 09 73 00 00 00 00 00 if r9 != 0x0 goto +0x73 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b + 46 55 09 6f 00 ff 00 00 00 if r9 != 0xff goto +0x6f 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 67 00 0e 00 00 00 if r9 != 0xe goto +0x67 + 48 55 09 6b 00 0e 00 00 00 if r9 != 0xe goto +0x6b 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 63 00 ff 00 00 00 if r9 != 0xff goto +0x63 + 50 55 09 67 00 ff 00 00 00 if r9 != 0xff goto +0x67 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d + 54 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 59 00 00 00 00 00 if r9 != r8 goto +0x59 + 58 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 55 00 00 00 00 00 if r9 != r8 goto +0x55 + 62 5d 89 59 00 00 00 00 00 if r9 != r8 goto +0x59 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 52 00 00 00 00 00 if r9 != r8 goto +0x52 + 65 5d 89 56 00 00 00 00 00 if r9 != r8 goto +0x56 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 4c 00 00 00 00 00 if r9 != 0x0 goto +0x4c + 67 55 09 50 00 00 00 00 00 if r9 != 0x0 goto +0x50 68 b7 02 00 00 00 00 00 00 r2 = 0x0 69 bf 13 00 00 00 00 00 00 r3 = r1 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 @@ -129,22 +129,22 @@ Disassembly of section .text 75 85 10 00 00 ff ff ff ff call -0x1 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 43 00 00 00 00 00 if r9 != r8 goto +0x43 + 78 5d 89 47 00 00 00 00 00 if r9 != r8 goto +0x47 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 40 00 00 00 00 00 if r9 != r8 goto +0x40 + 81 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 3d 00 00 00 00 00 if r9 != r8 goto +0x3d + 84 5d 89 41 00 00 00 00 00 if r9 != r8 goto +0x41 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 3a 00 00 00 00 00 if r9 != r8 goto +0x3a + 87 5d 89 3e 00 00 00 00 00 if r9 != r8 goto +0x3e 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) - 91 27 09 00 00 90 00 00 00 r9 *= 0x90 + 91 27 09 00 00 98 00 00 00 r9 *= 0x98 92 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 - 93 7a 0a ad fe 10 00 00 00 *(u64 *)(r10 - 0x153) = 0x10 + 93 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 94 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) 95 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 96 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) @@ -178,38 +178,42 @@ Disassembly of section .text 124 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 125 07 01 00 00 10 00 00 00 r1 += 0x10 126 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 127 07 04 00 00 30 00 00 00 r4 += 0x30 - 128 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 129 07 04 00 00 20 ff ff ff r4 += -0xe0 - 130 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 131 07 04 00 00 a1 ff ff ff r4 += -0x5f - 132 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 133 07 04 00 00 ff 00 00 00 r4 += 0xff - 134 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 - 135 07 04 00 00 f0 ff ff ff r4 += -0x10 - 136 bf a1 00 00 00 00 00 00 r1 = r10 - 137 07 01 00 00 d8 fe ff ff r1 += -0x128 - 138 bf a2 00 00 00 00 00 00 r2 = r10 - 139 07 02 00 00 20 ff ff ff r2 += -0xe0 - 140 b7 03 00 00 02 00 00 00 r3 = 0x2 - 141 b7 05 00 00 01 00 00 00 r5 = 0x1 - 142 85 10 00 00 ff ff ff ff call -0x1 - 143 95 00 00 00 00 00 00 00 exit - 144 b7 00 00 00 09 00 00 00 r0 = 0x9 - 145 95 00 00 00 00 00 00 00 exit - 146 b7 00 00 00 0a 00 00 00 r0 = 0xa + 127 bf 16 00 00 00 00 00 00 r6 = r1 + 128 07 04 00 00 30 00 00 00 r4 += 0x30 + 129 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 130 07 04 00 00 20 ff ff ff r4 += -0xe0 + 131 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 132 07 04 00 00 a1 ff ff ff r4 += -0x5f + 133 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 134 07 04 00 00 ff 00 00 00 r4 += 0xff + 135 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 + 136 07 04 00 00 f0 ff ff ff r4 += -0x10 + 137 bf a1 00 00 00 00 00 00 r1 = r10 + 138 07 01 00 00 d8 fe ff ff r1 += -0x128 + 139 bf a2 00 00 00 00 00 00 r2 = r10 + 140 07 02 00 00 20 ff ff ff r2 += -0xe0 + 141 b7 03 00 00 02 00 00 00 r3 = 0x2 + 142 b7 05 00 00 01 00 00 00 r5 = 0x1 + 143 85 10 00 00 ff ff ff ff call -0x1 + 144 bf 67 00 00 00 00 00 00 r7 = r6 + 145 07 07 00 00 10 00 00 00 r7 += 0x10 + 146 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 147 95 00 00 00 00 00 00 00 exit - 148 b7 00 00 00 08 00 00 00 r0 = 0x8 + 148 b7 00 00 00 09 00 00 00 r0 = 0x9 149 95 00 00 00 00 00 00 00 exit - 150 b7 00 00 00 07 00 00 00 r0 = 0x7 + 150 b7 00 00 00 0a 00 00 00 r0 = 0xa 151 95 00 00 00 00 00 00 00 exit - 152 b7 00 00 00 04 00 00 00 r0 = 0x4 + 152 b7 00 00 00 08 00 00 00 r0 = 0x8 153 95 00 00 00 00 00 00 00 exit - 154 b7 00 00 00 06 00 00 00 r0 = 0x6 + 154 b7 00 00 00 07 00 00 00 r0 = 0x7 155 95 00 00 00 00 00 00 00 exit - 156 b7 00 00 00 03 00 00 00 r0 = 0x3 + 156 b7 00 00 00 04 00 00 00 r0 = 0x4 157 95 00 00 00 00 00 00 00 exit - 158 b7 00 00 00 05 00 00 00 r0 = 0x5 + 158 b7 00 00 00 06 00 00 00 r0 = 0x6 159 95 00 00 00 00 00 00 00 exit - 160 b7 00 00 00 02 00 00 00 r0 = 0x2 - 161 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 160 b7 00 00 00 03 00 00 00 r0 = 0x3 + 161 95 00 00 00 00 00 00 00 exit + 162 b7 00 00 00 05 00 00 00 r0 = 0x5 + 163 95 00 00 00 00 00 00 00 exit + 164 b7 00 00 00 02 00 00 00 r0 = 0x2 + 165 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 87d48b19..47103e67 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3864 (bytes into file) + Start of section headers 3936 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf18 +There are 8 section headers, starting at offset 0xf60 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000508 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000628 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000630 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000630 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000630 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0009a8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0009e6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000550 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000670 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000678 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000678 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000678 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0009f0 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000a2e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000508 0x000508 E 0x8 - LOAD 0x000628 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000630 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000630 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000550 0x000550 E 0x8 + LOAD 0x000670 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000678 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000678 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1288 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1360 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -106,162 +106,171 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 10 55 03 05 00 02 00 00 00 jne r3, 0x2, +0x5 - 18 9c 11 58 00 00 00 00 00 ldxdw r1, [r1 + 0x58] - 20 b7 00 00 00 15 1a 00 00 mov64 r0, 0x1a15 - 28 15 01 01 00 43 00 00 00 jeq r1, 0x43, +0x1 - 30 b7 00 00 00 99 2c 0a 00 mov64 r0, 0xa2c99 - 38 9d 00 00 00 00 00 00 00 return - 40 55 03 8a 00 04 00 00 00 jne r3, 0x4, +0x8a - 48 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 50 55 03 86 00 00 00 00 00 jne r3, 0x0, +0x86 - 58 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 60 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - 68 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 70 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 - 78 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - 80 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - 88 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - 90 55 03 88 00 0e 00 00 00 jne r3, 0xe, +0x88 - 98 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - a0 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - a8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - b0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 - b8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 - c0 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] - c8 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 - d0 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 - d8 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d - e0 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] - e8 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 - f0 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 - f8 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b - 100 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] - 108 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b - 110 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] - 118 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d - 120 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e - 128 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 130 55 02 78 00 00 00 00 00 jne r2, 0x0, +0x78 - 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 140 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 - 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 188 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 190 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 198 5d 21 5b 00 00 00 00 00 jne r1, r2, +0x5b - 1a0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1a8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1b0 5d 21 58 00 00 00 00 00 jne r1, r2, +0x58 - 1b8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1c0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1c8 5d 21 55 00 00 00 00 00 jne r1, r2, +0x55 - 1d0 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 1d8 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 1e0 5d 21 52 00 00 00 00 00 jne r1, r2, +0x52 - 1e8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 1f0 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 1f8 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 200 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 208 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 210 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 218 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 220 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 228 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 230 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 238 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 240 96 02 00 00 90 00 00 00 lmul64 r2, 0x90 - 248 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 250 97 0a 20 00 10 00 00 00 stdw [r10 + 0x20], 0x10 - 258 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 260 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 268 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 270 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 278 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 280 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 288 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 290 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 298 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 2a0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2a8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2b0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2b8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2c8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 2d0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 2d8 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 2e0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 2e8 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 2f0 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 2f8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 300 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 308 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 310 07 07 00 00 50 00 00 00 add64 r7, 0x50 - 318 9f 7a 70 00 00 00 00 00 stxdw [r10 + 0x70], r7 - 320 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 328 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 330 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 338 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 340 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 348 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 350 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 358 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 360 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 368 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 370 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 378 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 380 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 388 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 390 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 398 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3a0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3a8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3b0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 10 55 03 0a 00 02 00 00 00 jne r3, 0x2, +0xa + 18 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 20 55 03 93 00 00 00 00 00 jne r3, 0x0, +0x93 + 28 2c 11 68 28 00 00 00 00 ldxb w1, [r1 + 0x2868] + 30 55 01 93 00 ff 00 00 00 jne r1, 0xff, +0x93 + 38 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] + 40 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 48 bc 11 00 00 00 00 00 00 mov32 w1, w1 + 50 15 01 01 00 01 00 00 00 jeq r1, 0x1, +0x1 + 58 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 60 9d 00 00 00 00 00 00 00 return + 68 55 03 90 00 04 00 00 00 jne r3, 0x4, +0x90 + 70 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 78 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 + 80 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 88 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 + 90 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 98 55 03 8c 00 00 00 00 00 jne r3, 0x0, +0x8c + a0 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] + a8 55 03 8c 00 ff 00 00 00 jne r3, 0xff, +0x8c + b0 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] + b8 55 03 8c 00 0e 00 00 00 jne r3, 0xe, +0x8c + c0 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] + c8 55 03 8c 00 ff 00 00 00 jne r3, 0xff, +0x8c + d0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + d8 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 + e0 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 + e8 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] + f0 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 + f8 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 + 100 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d + 108 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] + 110 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 + 118 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 + 120 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b + 128 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] + 130 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b + 138 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] + 140 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d + 148 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e + 150 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] + 158 55 02 7c 00 00 00 00 00 jne r2, 0x0, +0x7c + 160 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 168 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 + 170 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 178 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 180 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 188 07 05 00 00 13 00 00 00 add64 r5, 0x13 + 190 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 198 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 1a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 1a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 1b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 1b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 1c0 5d 21 63 00 00 00 00 00 jne r1, r2, +0x63 + 1c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 1d0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1d8 5d 21 60 00 00 00 00 00 jne r1, r2, +0x60 + 1e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 1e8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1f0 5d 21 5d 00 00 00 00 00 jne r1, r2, +0x5d + 1f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 200 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 208 5d 21 5a 00 00 00 00 00 jne r1, r2, +0x5a + 210 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 218 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 220 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 228 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 230 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 238 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 240 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 248 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 250 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 258 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 260 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 268 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 270 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 278 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 + 280 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 288 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 298 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 2a8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 2b0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 2b8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2c0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 2c8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2d8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2e0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 2f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 300 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 308 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 310 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 318 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 320 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 328 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 330 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 338 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 340 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 348 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 350 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 358 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 360 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 368 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 370 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 378 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 380 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 388 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 390 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 398 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 3a0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 3a8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 3b0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3c8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 3d0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 3d8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 3e0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3e8 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 3f0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 3f8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 400 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 408 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 410 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 418 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 420 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 428 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 430 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 438 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 440 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 448 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 450 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 458 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 460 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 468 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 470 05 00 78 ff 00 00 00 00 ja -0x88 - 478 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 480 05 00 76 ff 00 00 00 00 ja -0x8a - 488 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 490 05 00 74 ff 00 00 00 00 ja -0x8c - 498 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 4a0 05 00 72 ff 00 00 00 00 ja -0x8e - 4a8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4b0 05 00 70 ff 00 00 00 00 ja -0x90 - 4b8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 4c0 05 00 6e ff 00 00 00 00 ja -0x92 - 4c8 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 4d0 05 00 6c ff 00 00 00 00 ja -0x94 - 4d8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 4e0 05 00 6a ff 00 00 00 00 ja -0x96 - 4e8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 4f0 05 00 68 ff 00 00 00 00 ja -0x98 - 4f8 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 500 05 00 66 ff 00 00 00 00 ja -0x9a \ No newline at end of file + 3c0 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 3c8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3d8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3e0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3f0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3f8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 400 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 408 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 410 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 418 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 420 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 428 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 430 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 438 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 440 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 448 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 450 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 458 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 460 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 468 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 470 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 478 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 480 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 488 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 490 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 498 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 4a0 07 01 00 00 d0 28 00 00 add64 r1, 0x28d0 + 4a8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + 4b0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 4b8 05 00 74 ff 00 00 00 00 ja -0x8c + 4c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 4c8 05 00 72 ff 00 00 00 00 ja -0x8e + 4d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4d8 05 00 70 ff 00 00 00 00 ja -0x90 + 4e0 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 4e8 05 00 6e ff 00 00 00 00 ja -0x92 + 4f0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 4f8 05 00 6c ff 00 00 00 00 ja -0x94 + 500 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 508 05 00 6a ff 00 00 00 00 ja -0x96 + 510 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 518 05 00 68 ff 00 00 00 00 ja -0x98 + 520 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 528 05 00 66 ff 00 00 00 00 ja -0x9a + 530 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 538 05 00 64 ff 00 00 00 00 ja -0x9c + 540 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 548 05 00 62 ff 00 00 00 00 ja -0x9e \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index d59a8496..5a164ef7 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -3,47 +3,52 @@ entrypoint: add64 r10, -320 ldxdw r3, [r1+0] - jne r3, 2, jmp_0040 - ldxdw r1, [r1+88] - mov64 r0, 6677 - jeq r1, 67, jmp_0038 - mov64 r0, 666777 + jne r3, 2, jmp_0068 + ldxdw r3, [r1+88] + jne r3, 0, jmp_04c8 + ldxb r1, [r1+10344] + jne r1, 255, jmp_04d8 + ldxb r1, [r2+0] + mov64 r0, 0 + mov32 r1, r1 + jeq r1, 1, jmp_0060 + mov64 r0, 11 -jmp_0038: +jmp_0060: exit -jmp_0040: - jne r3, 4, jmp_0490 +jmp_0068: + jne r3, 4, jmp_04e8 ldxdw r3, [r1+88] - jne r3, 0, jmp_0480 + jne r3, 0, jmp_04c8 ldxb r3, [r1+10344] - jne r3, 255, jmp_04a0 + jne r3, 255, jmp_04d8 ldxdw r3, [r1+10424] - jne r3, 0, jmp_04b0 + jne r3, 0, jmp_04f8 ldxb r3, [r1+20680] - jne r3, 255, jmp_04c0 + jne r3, 255, jmp_0508 ldxdw r3, [r1+20760] - jne r3, 14, jmp_04d0 + jne r3, 14, jmp_0518 ldxb r3, [r1+31032] - jne r3, 255, jmp_04e0 + jne r3, 255, jmp_0528 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 ldxdw r4, [r1+31040] - jne r4, r3, jmp_0038 + jne r4, r3, jmp_0060 mov32 r3, 1288277025 hor64 r3, 2146519613 ldxdw r4, [r1+31048] - jne r4, r3, jmp_0038 + jne r4, r3, jmp_0060 mov32 r3, 149871192 hor64 r3, 1157472667 ldxdw r4, [r1+31056] - jne r4, r3, jmp_0038 + jne r4, r3, jmp_0060 ldxdw r3, [r1+31064] mov32 r4, -1965433885 - jne r3, r4, jmp_0038 + jne r3, r4, jmp_0060 ldxdw r2, [r2-8] - jne r2, 0, jmp_04f0 + jne r2, 0, jmp_0538 mov64 r6, r1 add64 r6, 41400 mov64 r4, r10 @@ -57,16 +62,16 @@ jmp_0040: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0060 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0060 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0060 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_0038 + jne r1, r2, jmp_0060 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -78,9 +83,9 @@ jmp_0040: stxdw [r10+48], r3 ldxdw r3, [r6+0] stxdw [r10+40], r3 - lmul64 r2, 144 + lmul64 r2, 152 stxdw [r10+24], r2 - stdw [r10+32], 16 + stdw [r10+32], 24 stw [r10+20], 0 stxdw [r10+88], r1 mov64 r2, r7 @@ -104,8 +109,9 @@ jmp_0040: mov64 r1, r7 add64 r1, 96 stxdw [r10+128], r1 - add64 r7, 80 - stxdw [r10+112], r7 + mov64 r1, r7 + add64 r1, 80 + stxdw [r10+112], r1 stxdw [r10+104], r2 stb [r10+210], 0 sth [r10+208], 257 @@ -147,37 +153,40 @@ jmp_0040: mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c + mov64 r1, r7 + add64 r1, 10448 + stxdw [r7+10448], r1 mov64 r0, 0 - ja jmp_0038 + ja jmp_0060 -jmp_0480: +jmp_04c8: mov64 r0, 2 - ja jmp_0038 + ja jmp_0060 -jmp_0490: - mov64 r0, 1 - ja jmp_0038 - -jmp_04a0: +jmp_04d8: mov64 r0, 5 - ja jmp_0038 + ja jmp_0060 + +jmp_04e8: + mov64 r0, 1 + ja jmp_0060 -jmp_04b0: +jmp_04f8: mov64 r0, 3 - ja jmp_0038 + ja jmp_0060 -jmp_04c0: +jmp_0508: mov64 r0, 6 - ja jmp_0038 + ja jmp_0060 -jmp_04d0: +jmp_0518: mov64 r0, 4 - ja jmp_0038 + ja jmp_0060 -jmp_04e0: +jmp_0528: mov64 r0, 7 - ja jmp_0038 + ja jmp_0060 -jmp_04f0: +jmp_0538: mov64 r0, 9 - ja jmp_0038 + ja jmp_0060 diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 905fca4a..b447d2e7 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -141,5 +141,5 @@ # Store next pointer in tree header. # --------------------------------------------------------------------- mov64 r7, r6 # Get copy of tree data pointer. - add64 r7, NEXT_OFF # Advance to next node. + add64 r7, TREE_NEXT_OFF # Advance to next node. stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt deleted file mode 100644 index fe73f2d7..00000000 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Three accounts | 5 | 7 | +2 | +40.0% | -| Five accounts | 5 | 7 | +2 | +40.0% | -test tests::test_entrypoint_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt deleted file mode 100644 index 7d74f4cd..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ /dev/null @@ -1,36 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 104 | 136 | +32 | +30.8% | -| User has insufficient Lamports | 2596 | 104 | 136 | +32 | +30.8% | -| CreateAccount happy path | 2596 | 105 | 139 | +34 | +32.4% | -test tests::test_initialize_create_account ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2582 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2700 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 501120 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2732 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt deleted file mode 100644 index aa2dd6c3..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index 2d9b546e..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,108 +0,0 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | -| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | -| Non-empty instruction data | 31 | 37 | +6 | +19.4% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index 24226cfc..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 7348c78c..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | -| PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | -| PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | -| PDA mismatch chunk 4 | 1500 | 51 | 59 | +8 | +15.7% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 0f682d5d..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 66c1134c..0541e1af 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -442,7 +442,7 @@ initialize: # Store next pointer in tree header. # --------------------------------------------------------------------- mov64 r7, r6 # Get copy of tree data pointer. - add64 r7, NEXT_OFF # Advance to next node. + add64 r7, TREE_NEXT_OFF # Advance to next node. stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. // ANCHOR_END: initialize-create-account From ebc3fb5eaa728b843d5b4e20ca42b69d72db84a4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:49:44 -0800 Subject: [PATCH 155/263] Fix next impl --- examples/tree/artifacts/snippets/asm/constants.txt | 4 ++-- .../artifacts/snippets/asm/initialize-create-account.txt | 4 ++-- .../artifacts/snippets/rs/initialize-create-account.txt | 2 +- examples/tree/interface/src/asm.rs | 1 + examples/tree/interface/src/common.rs | 4 +--- examples/tree/src/program.rs | 2 +- examples/tree/src/tree/tree.s | 8 ++++---- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 247829ee..91967fa3 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -23,6 +23,7 @@ .equ SIZE_OF_U64, 8 # Size of u64. .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. +.equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. # Data layout constants. # ---------------------- @@ -62,7 +63,6 @@ # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. -.equ IB_TREE_HEADER_NEXT_OFF, 16 # Tree header next field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -189,6 +189,6 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. -.equ TREE_NEXT_OFF, 16 # Next node field in header. +.equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index b447d2e7..a041fab8 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -141,5 +141,5 @@ # Store next pointer in tree header. # --------------------------------------------------------------------- mov64 r7, r6 # Get copy of tree data pointer. - add64 r7, TREE_NEXT_OFF # Advance to next node. - stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. \ No newline at end of file + add64 r7, SIZE_OF_TREE_HEADER # Advance to next node. + stxdw [r6 + TREE_HEADER_NEXT_OFF], r7 # Store in next field. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index e0530633..60c1d813 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -107,5 +107,5 @@ // Store next pointer in tree header. let tree_data_ptr = tree.data_ptr(); - let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); + let next_ptr = tree_data_ptr.add(size_of::()).cast(); (*tree.data_ptr().cast::()).next = next_ptr; \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 78bf1d8b..24080726 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -20,6 +20,7 @@ sizes! { u64, Address, u128, + TreeHeader, } extend_constant_group!(data { diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 12f3046a..1ba18981 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -72,8 +72,6 @@ constant_group! { // Includes extra byte for deprecated burn_percent field that is still present in test // framework. RENT_DATA_LEN: usize = size_of::() + size_of::(), - /// Tree header next field. - offset!(TREE_HEADER_NEXT, TreeHeader.next), } } @@ -178,7 +176,7 @@ constant_group! { /// Red color. COLOR_R = Color::Red as u8, /// Next node field in header. - offset!(NEXT, TreeHeader.next), + offset!(HEADER_NEXT, TreeHeader.next), } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index b53fbcdd..056add91 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -274,7 +274,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // Store next pointer in tree header. let tree_data_ptr = tree.data_ptr(); - let next_ptr = tree_data_ptr.add(tree::NEXT_OFF as usize).cast(); + let next_ptr = tree_data_ptr.add(size_of::()).cast(); (*tree.data_ptr().cast::()).next = next_ptr; // ANCHOR_END: initialize-create-account diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 0541e1af..3e788f92 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -24,6 +24,7 @@ .equ SIZE_OF_U64, 8 # Size of u64. .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. +.equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. # Data layout constants. # ---------------------- @@ -63,7 +64,6 @@ # Expected data length of system program account. .equ IB_SYSTEM_PROGRAM_DATA_LEN, 14 .equ IB_RENT_DATA_LEN, 17 # Expected data length of rent sysvar account. -.equ IB_TREE_HEADER_NEXT_OFF, 16 # Tree header next field. .equ IB_USER_ADDRESS_OFF, 16 # User address field. .equ IB_USER_DATA_LEN_OFF, 88 # User data length field. .equ IB_NON_DUP_MARKER, 255 # Non-duplicate marker value. @@ -190,7 +190,7 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. -.equ TREE_NEXT_OFF, 16 # Next node field in header. +.equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. # ANCHOR_END: constants @@ -442,8 +442,8 @@ initialize: # Store next pointer in tree header. # --------------------------------------------------------------------- mov64 r7, r6 # Get copy of tree data pointer. - add64 r7, TREE_NEXT_OFF # Advance to next node. - stxdw [r6 + IB_TREE_HEADER_NEXT_OFF], r7 # Store in next field. + add64 r7, SIZE_OF_TREE_HEADER # Advance to next node. + stxdw [r6 + TREE_HEADER_NEXT_OFF], r7 # Store in next field. // ANCHOR_END: initialize-create-account exit From 676785805d82d41ba922b73f5cb62aee728e617d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:01:54 -0800 Subject: [PATCH 156/263] Finalize testing --- examples/tree/artifacts/dumps/asm.txt | 2 +- examples/tree/artifacts/dumps/rs.txt | 2 +- examples/tree/artifacts/rs-disassembly.s | 2 +- .../snippets/rs/initialize-create-account.txt | 3 +- .../tests/entrypoint_branching/result.txt | 31 +++++ .../initialize_create_account/result.txt | 36 ++++++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 109 ++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 + .../tests/initialize_pda_checks/result.txt | 31 +++++ .../tests/initialize_pda_checks/test.txt | 4 + examples/tree/interface/src/lib.rs | 1 + examples/tree/src/lib.rs | 1 + examples/tree/src/program.rs | 9 +- examples/tree/src/tests/init.rs | 27 +++-- 15 files changed, 248 insertions(+), 18 deletions(-) create mode 100644 examples/tree/artifacts/tests/entrypoint_branching/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index d13618ba..90c5fcd6 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -196,7 +196,7 @@ Disassembly of section .text 142 b7 05 00 00 01 00 00 00 r5 = 0x1 143 85 10 00 00 ff ff ff ff call -0x1 144 bf 67 00 00 00 00 00 00 r7 = r6 - 145 07 07 00 00 10 00 00 00 r7 += 0x10 + 145 07 07 00 00 18 00 00 00 r7 += 0x18 146 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 147 95 00 00 00 00 00 00 00 exit 148 b7 00 00 00 09 00 00 00 r0 = 0x9 diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 47103e67..3ec943a0 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -252,7 +252,7 @@ Disassembly of section .text 488 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 490 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b 498 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 4a0 07 01 00 00 d0 28 00 00 add64 r1, 0x28d0 + 4a0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 4a8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 4b0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 4b8 05 00 74 ff 00 00 00 00 ja -0x8c diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 5a164ef7..4b553abc 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -154,7 +154,7 @@ jmp_0068: mov64 r5, 1 call sol_invoke_signed_c mov64 r1, r7 - add64 r1, 10448 + add64 r1, 10456 stxdw [r7+10448], r1 mov64 r0, 0 ja jmp_0060 diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 60c1d813..4fc91c2a 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -106,6 +106,5 @@ } // Store next pointer in tree header. - let tree_data_ptr = tree.data_ptr(); - let next_ptr = tree_data_ptr.add(size_of::()).cast(); + let next_ptr = tree.data_ptr().add(size_of::()).cast(); (*tree.data_ptr().cast::()).next = next_ptr; \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt new file mode 100644 index 00000000..fe73f2d7 --- /dev/null +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -0,0 +1,31 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| No accounts | 5 | 7 | +2 | +40.0% | +| One account | 5 | 7 | +2 | +40.0% | +| Three accounts | 5 | 7 | +2 | +40.0% | +| Five accounts | 5 | 7 | +2 | +40.0% | +test tests::test_entrypoint_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..15b5199e --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,36 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| System Program is wrong address | 2446 | 105 | 137 | +32 | +30.5% | +| User has insufficient Lamports | 2596 | 105 | 137 | +32 | +30.5% | +| CreateAccount happy path | 2596 | 109 | 143 | +34 | +31.2% | +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2551 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2583 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2733 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2705 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2739 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..aa2dd6c3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..e2a93dc5 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,109 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| User has nonzero data length | 7 | 9 | +2 | +28.6% | +| Tree account is duplicate | 9 | 11 | +2 | +22.2% | +| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | +| System program is duplicate | 13 | 15 | +2 | +15.4% | +| System program wrong data length | 15 | 17 | +2 | +13.3% | +| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | +| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | +| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | +| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | +| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | +| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | +| Non-empty instruction data | 31 | 37 | +6 | +19.4% | +test tests::test_initialize_input_checks ... ok + Blocking waiting for file lock on build directory +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..24226cfc --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..7348c78c --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | +| PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | +| PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | +| PDA mismatch chunk 4 | 1500 | 51 | 59 | +8 | +15.7% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 8a3a65f5..ddb1a643 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unused)] extern crate alloc; diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs index 569ef2f5..4690eac5 100644 --- a/examples/tree/src/lib.rs +++ b/examples/tree/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), no_std)] +#![allow(unused)] mod program; #[cfg(test)] diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 056add91..fcf4c0fc 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -273,8 +273,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - } // Store next pointer in tree header. - let tree_data_ptr = tree.data_ptr(); - let next_ptr = tree_data_ptr.add(size_of::()).cast(); + let next_ptr = tree.data_ptr().add(size_of::()).cast(); (*tree.data_ptr().cast::()).next = next_ptr; // ANCHOR_END: initialize-create-account @@ -309,9 +308,9 @@ unsafe fn rotate_subtree( subtree: *mut TreeNode, direction: usize, ) -> *mut TreeNode { - let subtree_parent = (*subtree).parent as *mut TreeNode; - let new_root = (*subtree).child[opposite(direction)] as *mut TreeNode; - let new_child = (*new_root).child[direction] as *mut TreeNode; + let subtree_parent = (*subtree).parent; + let new_root = (*subtree).child[opposite(direction)]; + let new_child = (*new_root).child[direction]; (*subtree).child[opposite(direction)] = new_child; diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index b371eab2..90541fc6 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -3,9 +3,14 @@ use mollusk_svm::program; use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; +use tree_interface::{input_buffer, tree, TreeHeader}; const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; +/// Virtual address of the input buffer in the SVM memory map. +/// See `solana_sbpf::ebpf::MM_INPUT_START`. +const MM_INPUT_START: u64 = 0x400000000; + fn init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { @@ -448,18 +453,24 @@ impl TestCase for InitCase { expected_lamports, tree.lamports )); } + let expected_next = MM_INPUT_START + + input_buffer::TREE_DATA_OFF as u64 + + size_of::() as u64; + let header = unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; + let actual_next = header.next as u64; + if actual_next != expected_next { + errors.push(format!( + "next: expected {:#x}, got {:#x}", + expected_next, actual_next + )); + } let config = Config { panic: false, verbose: false, }; - if !result.run_checks( - &[Check::all_rent_exempt()], - &config, - &setup.mollusk, - ) { - errors.push( - "not all accounts are rent exempt".to_string(), - ); + if !result.run_checks(&[Check::all_rent_exempt()], &config, &setup.mollusk) + { + errors.push("not all accounts are rent exempt".to_string()); } CaseResult { cu: result.compute_units_consumed, From 47aee4f59dc01593dcfcfdb704a62adf036e47c0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:02:27 -0800 Subject: [PATCH 157/263] Check in results --- examples/tree/artifacts/tests/initialize_input_checks/result.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index e2a93dc5..2d9b546e 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -16,7 +16,6 @@ | Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | | Non-empty instruction data | 31 | 37 | +6 | +19.4% | test tests::test_initialize_input_checks ... ok - Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 From 64f0fd7a45aa3a5eea89583574c3885413dba4c0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:19:45 -0800 Subject: [PATCH 158/263] Begin insert logic --- .../tree/artifacts/snippets/asm/constants.txt | 4 ++- .../snippets/asm/general-branching.txt | 18 ++++++++++ .../asm/initialize-create-account.txt | 4 ++- .../tree/artifacts/snippets/asm/insert.txt | 3 ++ .../snippets/rs/general-branching.txt | 18 ++++++++++ .../tree/artifacts/snippets/rs/insert.txt | 12 +++++++ examples/tree/interface/src/asm.rs | 6 +++- examples/tree/interface/src/lib.rs | 4 +-- examples/tree/src/program.rs | 31 ++++++++++++----- examples/tree/src/tree/tree.s | 34 ++++++++++++++++--- 10 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/general-branching.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert.txt create mode 100644 examples/tree/artifacts/snippets/rs/general-branching.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert.txt diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 91967fa3..d29469f7 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -24,6 +24,7 @@ .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. +.equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. # Data layout constants. # ---------------------- @@ -191,4 +192,5 @@ .equ TREE_COLOR_R, 1 # Red color. .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. -.equ TREE_TOP_OFF, 8 # Stack top. \ No newline at end of file +.equ TREE_TOP_OFF, 8 # Stack top. +.equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/general-branching.txt b/examples/tree/artifacts/snippets/asm/general-branching.txt new file mode 100644 index 00000000..53218617 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/general-branching.txt @@ -0,0 +1,18 @@ +general: + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + + # Get instruction data length, check instruction discriminator. + # --------------------------------------------------------------------- + ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. + ldxb r8, [r2 + OFFSET_ZERO] # Get discriminator. + jeq r8, TREE_DISCRIMINATOR_INSERT, insert # Fast path to insert. + mov64 r0, E_INSTRUCTION_DISCRIMINATOR # Else fail. + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index a041fab8..2ed7626a 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -142,4 +142,6 @@ # --------------------------------------------------------------------- mov64 r7, r6 # Get copy of tree data pointer. add64 r7, SIZE_OF_TREE_HEADER # Advance to next node. - stxdw [r6 + TREE_HEADER_NEXT_OFF], r7 # Store in next field. \ No newline at end of file + stxdw [r6 + TREE_HEADER_NEXT_OFF], r7 # Store in next field. + + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert.txt b/examples/tree/artifacts/snippets/asm/insert.txt new file mode 100644 index 00000000..2138eb5c --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert.txt @@ -0,0 +1,3 @@ +insert: + jne r8, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/general-branching.txt b/examples/tree/artifacts/snippets/rs/general-branching.txt new file mode 100644 index 00000000..376784c2 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/general-branching.txt @@ -0,0 +1,18 @@ +#[inline(always)] +unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { + // Error if user has data. + let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + + // Error if tree is duplicate. + let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + + // Get instruction data length and discriminator, branch to instruction. + let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); + if ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8 { + insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) + } else { + error::INSTRUCTION_DISCRIMINATOR.into() + } +} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt new file mode 100644 index 00000000..4cfa4d3d --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -0,0 +1,12 @@ +#[inline(always)] +unsafe fn insert( + input_buffer_ptr: *mut u8, + instruction_data_ptr: *mut u8, + instruction_data_len: u64, +) -> u64 { + if_err!( + instruction_data_len != size_of::() as u64, + error::INSTRUCTION_DATA_LEN + ); + SUCCESS +} \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 24080726..e5ff8ae8 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,7 +4,8 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, TreeHeader, + cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, InsertInstruction, + Instruction, TreeHeader, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -21,6 +22,7 @@ sizes! { Address, u128, TreeHeader, + InsertInstruction, } extend_constant_group!(data { @@ -241,4 +243,6 @@ extend_constant_group!(tree { offset!(ROOT, TreeHeader.root), /// Stack top. offset!(TOP, TreeHeader.top), + /// Discriminator for insert instruction. + DISCRIMINATOR_INSERT = Instruction::Insert as u8, }); diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index ddb1a643..19396831 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -10,6 +10,6 @@ mod common; pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ - cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, Instruction, - TreeHeader, TreeNode, + cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, + InsertInstruction, Instruction, TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index fcf4c0fc..c1eccc1d 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,8 +9,8 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, - Direction, Instruction, SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, - SolSignerSeeds, TreeHeader, TreeNode, + Direction, InsertInstruction, Instruction, SolAccountInfo, SolAccountMeta, SolInstruction, + SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -77,6 +77,7 @@ pub unsafe extern "C" fn entrypoint( } // ANCHOR_END: entrypoint-branching +// ANCHOR: general-branching #[inline(always)] unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { // Error if user has data. @@ -87,12 +88,30 @@ unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + // Get instruction data length and discriminator, branch to instruction. + let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); if ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8 { - insert(input_buffer_ptr, instruction_data_ptr) + insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() } } +// ANCHOR_END: general-branching + +// ANCHOR: insert +#[inline(always)] +unsafe fn insert( + input_buffer_ptr: *mut u8, + instruction_data_ptr: *mut u8, + instruction_data_len: u64, +) -> u64 { + if_err!( + instruction_data_len != size_of::() as u64, + error::INSTRUCTION_DATA_LEN + ); + SUCCESS +} +// ANCHOR_END: insert // ANCHOR: initialize-input-checks #[inline(always)] @@ -280,12 +299,6 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - SUCCESS } -#[inline(always)] -unsafe fn insert(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { - // Placeholder for insert instruction implementation. - SUCCESS -} - /// Return the direction of the node with respect to its parent. #[inline(always)] unsafe fn direction(node: *const TreeNode) -> Direction { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 3e788f92..0fa175c5 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -25,6 +25,7 @@ .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. +.equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. # Data layout constants. # ---------------------- @@ -193,6 +194,7 @@ .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. +.equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -208,12 +210,26 @@ entrypoint: exit # ANCHOR_END: entrypoint-branching +# ANCHOR: general-branching general: - ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. - add64 r9, MAX_DATA_PAD # Speculatively add max possible padding. - and64 r9, DATA_LEN_AND_MASK # Get data length plus required padding. - add64 r9, r1 # Get input buffer pointer shifted for tree data. + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + + # Get instruction data length, check instruction discriminator. + # --------------------------------------------------------------------- + ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. + ldxb r8, [r2 + OFFSET_ZERO] # Get discriminator. + jeq r8, TREE_DISCRIMINATOR_INSERT, insert # Fast path to insert. + mov64 r0, E_INSTRUCTION_DISCRIMINATOR # Else fail. exit +# ANCHOR_END: general-branching # ANCHOR: initialize-input-checks initialize: @@ -444,14 +460,24 @@ initialize: mov64 r7, r6 # Get copy of tree data pointer. add64 r7, SIZE_OF_TREE_HEADER # Advance to next node. stxdw [r6 + TREE_HEADER_NEXT_OFF], r7 # Store in next field. + + exit // ANCHOR_END: initialize-create-account +# ANCHOR: insert +insert: + jne r8, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len exit +# ANCHOR_END: insert e_instruction_data: mov64 r0, E_INSTRUCTION_DATA exit +e_instruction_data_len: + mov64 r0, E_INSTRUCTION_DATA_LEN + exit + e_pda_mismatch: mov64 r0, E_PDA_MISMATCH exit From 8cfe63778ad60fa3c7d5d2853ec4d1af6221d57c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:37:29 -0800 Subject: [PATCH 159/263] Add common handler, expected failure tests --- docs/src/examples/tree.md | 60 ++- examples/tree/artifacts/dumps/asm.txt | 290 +++++++------- examples/tree/artifacts/dumps/rs.txt | 363 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 87 +++-- .../snippets/asm/initialize-input-checks.txt | 1 - .../tree/artifacts/snippets/asm/insert.txt | 2 +- .../snippets/interface/instructions.txt | 38 ++ .../snippets/interface/tree-defs-common.txt | 54 +++ .../tests/general_branching/result.txt | 24 ++ .../tests/general_branching/test.txt | 4 + .../tree/artifacts/tests/insert/result.txt | 24 ++ examples/tree/artifacts/tests/insert/test.txt | 4 + examples/tree/build.rs | 4 + examples/tree/src/tests.rs | 12 + examples/tree/src/tests/general.rs | 95 +++++ examples/tree/src/tests/insert.rs | 109 ++++++ examples/tree/src/tree/tree.s | 3 +- 17 files changed, 807 insertions(+), 367 deletions(-) create mode 100644 examples/tree/artifacts/snippets/interface/instructions.txt create mode 100644 examples/tree/artifacts/snippets/interface/tree-defs-common.txt create mode 100644 examples/tree/artifacts/tests/general_branching/result.txt create mode 100644 examples/tree/artifacts/tests/general_branching/test.txt create mode 100644 examples/tree/artifacts/tests/insert/result.txt create mode 100644 examples/tree/artifacts/tests/insert/test.txt create mode 100644 examples/tree/src/tests/general.rs create mode 100644 examples/tree/src/tests/insert.rs diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index a3d23058..92e663dd 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -10,6 +10,12 @@ side-by-side with as much implementation parity as possible, using C-style Rust (raw pointers, direct [syscalls](../indices/syscalls.md)) to minimize compiler overhead. +::: details Core data structures + +<<< ../../../examples/tree/artifacts/snippets/interface/tree-defs-common.txt{rs} + +::: + ## Build support Constants, error codes, and C bindings are derived in a shared interface using @@ -40,7 +46,9 @@ time. ::: -## Entrypoint branching +## Branching + +### Entrypoint The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. Note that the Rust @@ -65,6 +73,36 @@ greedy [tail call optimizations][tail call]. ::: +### General + +If the user passes the number of accounts required for a general operation (all +instructions besides the [initialize](#initialize) instruction), the program +branches to a common instruction handler. + +::: details Instruction definitions + +<<< ../../../examples/tree/artifacts/snippets/interface/instructions.txt{rs} + +::: + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/general-branching.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/general-branching.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + ## Initialize The initialize operation creates a tree [PDA] for the entire program, then @@ -141,6 +179,26 @@ not available in Rust, since the compiler enforces +## Insert + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/insert.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + ## :white_check_mark: All tests ::: details `tests.rs` diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 90c5fcd6..246d589c 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1728 (bytes into file) + Start of section headers 1792 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x6c0 +There are 7 section headers, starting at offset 0x700 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000448 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000530 000530 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000005d0 0005d0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000630 000630 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000670 000670 000020 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000690 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000488 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000570 000570 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000610 000610 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000670 000670 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000006b0 0006b0 000020 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0006d0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000448 0x000448 R E 0x1000 - LOAD 0x0005d0 0x00000000000005d0 0x00000000000005d0 0x0000c0 0x0000c0 R 0x1000 - DYNAMIC 0x000530 0x0000000000000530 0x0000000000000530 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000488 0x000488 R E 0x1000 + LOAD 0x000610 0x0000000000000610 0x0000000000000610 0x0000c0 0x0000c0 R 0x1000 + DYNAMIC 0x000570 0x0000000000000570 0x0000000000000570 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,23 +52,23 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x530 contains 10 entries +Dynamic section at offset 0x570 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x670 + 0x0000000000000011 (REL) 0x6b0 0x0000000000000012 (RELSZ) 32 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x5d0 + 0x0000000000000006 (SYMTAB) 0x610 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x630 + 0x0000000000000005 (STRTAB) 0x670 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x670 contains 2 entries +Relocation section '.rel.dyn' at offset 0x6b0 contains 2 entries Offset Info Type Symbol's Value Symbol's Name -0000000000000258 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -0000000000000478 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000278 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000498 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -85,135 +85,143 @@ Disassembly of section .text 00000000000000e8 29 79 19 00 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x0) 30 15 09 03 00 02 00 00 00 if r9 == 0x2 goto +0x3 - 31 15 09 07 00 04 00 00 00 if r9 == 0x4 goto +0x7 + 31 15 09 0b 00 04 00 00 00 if r9 == 0x4 goto +0xb 32 b7 00 00 00 01 00 00 00 r0 = 0x1 33 95 00 00 00 00 00 00 00 exit - 34 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 35 07 09 00 00 07 00 00 00 r9 += 0x7 - 36 57 09 00 00 f8 ff ff ff r9 &= -0x8 - 37 0f 19 00 00 00 00 00 00 r9 += r1 - 38 95 00 00 00 00 00 00 00 exit - 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 7b 00 00 00 00 00 if r9 != 0x0 goto +0x7b - 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 77 00 ff 00 00 00 if r9 != 0xff goto +0x77 - 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 73 00 00 00 00 00 if r9 != 0x0 goto +0x73 - 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 6f 00 ff 00 00 00 if r9 != 0xff goto +0x6f - 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 6b 00 0e 00 00 00 if r9 != 0xe goto +0x6b - 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 67 00 ff 00 00 00 if r9 != 0xff goto +0x67 - 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) - 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 - 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) - 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d - 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) - 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 59 00 00 00 00 00 if r9 != r8 goto +0x59 - 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) - 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 56 00 00 00 00 00 if r9 != r8 goto +0x56 - 66 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 67 55 09 50 00 00 00 00 00 if r9 != 0x0 goto +0x50 - 68 b7 02 00 00 00 00 00 00 r2 = 0x0 - 69 bf 13 00 00 00 00 00 00 r3 = r1 - 70 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 - 71 bf a4 00 00 00 00 00 00 r4 = r10 - 72 07 04 00 00 b0 ff ff ff r4 += -0x50 - 73 bf a5 00 00 00 00 00 00 r5 = r10 - 74 07 05 00 00 a0 fe ff ff r5 += -0x160 - 75 85 10 00 00 ff ff ff ff call -0x1 - 76 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) - 77 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 78 5d 89 47 00 00 00 00 00 if r9 != r8 goto +0x47 - 79 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) - 80 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 81 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 - 82 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) - 83 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 84 5d 89 41 00 00 00 00 00 if r9 != r8 goto +0x41 - 85 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) - 86 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 87 5d 89 3e 00 00 00 00 00 if r9 != r8 goto +0x3e - 88 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 - 89 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 - 90 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) - 91 27 09 00 00 98 00 00 00 r9 *= 0x98 - 92 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 - 93 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 - 94 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 95 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 - 96 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) - 97 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 - 98 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) - 99 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 - 100 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) - 101 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 - 102 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 - 103 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 - 104 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 - 105 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 - 106 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 - 107 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 - 108 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 - 109 07 01 00 00 10 00 00 00 r1 += 0x10 - 110 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 - 111 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 - 112 07 01 00 00 20 00 00 00 r1 += 0x20 - 113 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 - 114 07 01 00 00 20 00 00 00 r1 += 0x20 - 115 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 - 116 07 01 00 00 10 00 00 00 r1 += 0x10 - 117 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 118 07 01 00 00 10 28 00 00 r1 += 0x2810 - 119 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 - 120 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 - 121 07 01 00 00 20 00 00 00 r1 += 0x20 - 122 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 - 123 07 01 00 00 20 00 00 00 r1 += 0x20 - 124 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 - 125 07 01 00 00 10 00 00 00 r1 += 0x10 - 126 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 127 bf 16 00 00 00 00 00 00 r6 = r1 - 128 07 04 00 00 30 00 00 00 r4 += 0x30 - 129 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 130 07 04 00 00 20 ff ff ff r4 += -0xe0 - 131 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 132 07 04 00 00 a1 ff ff ff r4 += -0x5f - 133 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 134 07 04 00 00 ff 00 00 00 r4 += 0xff - 135 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 - 136 07 04 00 00 f0 ff ff ff r4 += -0x10 - 137 bf a1 00 00 00 00 00 00 r1 = r10 - 138 07 01 00 00 d8 fe ff ff r1 += -0x128 - 139 bf a2 00 00 00 00 00 00 r2 = r10 - 140 07 02 00 00 20 ff ff ff r2 += -0xe0 - 141 b7 03 00 00 02 00 00 00 r3 = 0x2 - 142 b7 05 00 00 01 00 00 00 r5 = 0x1 - 143 85 10 00 00 ff ff ff ff call -0x1 - 144 bf 67 00 00 00 00 00 00 r7 = r6 - 145 07 07 00 00 18 00 00 00 r7 += 0x18 - 146 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 - 147 95 00 00 00 00 00 00 00 exit - 148 b7 00 00 00 09 00 00 00 r0 = 0x9 - 149 95 00 00 00 00 00 00 00 exit - 150 b7 00 00 00 0a 00 00 00 r0 = 0xa + 34 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 35 55 09 88 00 00 00 00 00 if r9 != 0x0 goto +0x88 + 36 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 37 55 09 84 00 ff 00 00 00 if r9 != 0xff goto +0x84 + 38 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 39 71 28 00 00 00 00 00 00 r8 = *(u8 *)(r2 + 0x0) + 40 15 08 6f 00 01 00 00 00 if r8 == 0x1 goto +0x6f + 41 b7 00 00 00 0b 00 00 00 r0 = 0xb + 42 95 00 00 00 00 00 00 00 exit + 43 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 44 55 09 7f 00 00 00 00 00 if r9 != 0x0 goto +0x7f + 45 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 46 55 09 7b 00 ff 00 00 00 if r9 != 0xff goto +0x7b + 47 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 48 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 + 49 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) + 50 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 + 51 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) + 52 55 09 6f 00 0e 00 00 00 if r9 != 0xe goto +0x6f + 53 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) + 54 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b + 55 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) + 56 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll + 58 5d 89 65 00 00 00 00 00 if r9 != r8 goto +0x65 + 59 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) + 60 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll + 62 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 + 63 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) + 64 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll + 66 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d + 67 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) + 68 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d + 69 5d 89 5a 00 00 00 00 00 if r9 != r8 goto +0x5a + 70 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 71 55 09 52 00 00 00 00 00 if r9 != 0x0 goto +0x52 + 72 b7 02 00 00 00 00 00 00 r2 = 0x0 + 73 bf 13 00 00 00 00 00 00 r3 = r1 + 74 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 + 75 bf a4 00 00 00 00 00 00 r4 = r10 + 76 07 04 00 00 b0 ff ff ff r4 += -0x50 + 77 bf a5 00 00 00 00 00 00 r5 = r10 + 78 07 05 00 00 a0 fe ff ff r5 += -0x160 + 79 85 10 00 00 ff ff ff ff call -0x1 + 80 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) + 81 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) + 82 5d 89 4b 00 00 00 00 00 if r9 != r8 goto +0x4b + 83 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) + 84 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) + 85 5d 89 48 00 00 00 00 00 if r9 != r8 goto +0x48 + 86 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) + 87 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 88 5d 89 45 00 00 00 00 00 if r9 != r8 goto +0x45 + 89 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) + 90 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) + 91 5d 89 42 00 00 00 00 00 if r9 != r8 goto +0x42 + 92 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 93 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 + 94 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) + 95 27 09 00 00 98 00 00 00 r9 *= 0x98 + 96 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 + 97 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 + 98 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 99 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 + 100 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 101 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 + 102 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 103 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 + 104 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 105 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 + 106 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 107 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 + 108 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 109 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 + 110 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 + 111 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 + 112 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 + 113 07 01 00 00 10 00 00 00 r1 += 0x10 + 114 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 115 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 116 07 01 00 00 20 00 00 00 r1 += 0x20 + 117 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 118 07 01 00 00 20 00 00 00 r1 += 0x20 + 119 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 120 07 01 00 00 10 00 00 00 r1 += 0x10 + 121 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 122 07 01 00 00 10 28 00 00 r1 += 0x2810 + 123 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 124 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 + 125 07 01 00 00 20 00 00 00 r1 += 0x20 + 126 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 127 07 01 00 00 20 00 00 00 r1 += 0x20 + 128 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 129 07 01 00 00 10 00 00 00 r1 += 0x10 + 130 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 131 bf 16 00 00 00 00 00 00 r6 = r1 + 132 07 04 00 00 30 00 00 00 r4 += 0x30 + 133 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 134 07 04 00 00 20 ff ff ff r4 += -0xe0 + 135 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 136 07 04 00 00 a1 ff ff ff r4 += -0x5f + 137 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 138 07 04 00 00 ff 00 00 00 r4 += 0xff + 139 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 + 140 07 04 00 00 f0 ff ff ff r4 += -0x10 + 141 bf a1 00 00 00 00 00 00 r1 = r10 + 142 07 01 00 00 d8 fe ff ff r1 += -0x128 + 143 bf a2 00 00 00 00 00 00 r2 = r10 + 144 07 02 00 00 20 ff ff ff r2 += -0xe0 + 145 b7 03 00 00 02 00 00 00 r3 = 0x2 + 146 b7 05 00 00 01 00 00 00 r5 = 0x1 + 147 85 10 00 00 ff ff ff ff call -0x1 + 148 bf 67 00 00 00 00 00 00 r7 = r6 + 149 07 07 00 00 18 00 00 00 r7 += 0x18 + 150 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 151 95 00 00 00 00 00 00 00 exit - 152 b7 00 00 00 08 00 00 00 r0 = 0x8 + 152 55 09 03 00 05 00 00 00 if r9 != 0x5 goto +0x3 153 95 00 00 00 00 00 00 00 exit - 154 b7 00 00 00 07 00 00 00 r0 = 0x7 + 154 b7 00 00 00 09 00 00 00 r0 = 0x9 155 95 00 00 00 00 00 00 00 exit - 156 b7 00 00 00 04 00 00 00 r0 = 0x4 + 156 b7 00 00 00 0c 00 00 00 r0 = 0xc 157 95 00 00 00 00 00 00 00 exit - 158 b7 00 00 00 06 00 00 00 r0 = 0x6 + 158 b7 00 00 00 0a 00 00 00 r0 = 0xa 159 95 00 00 00 00 00 00 00 exit - 160 b7 00 00 00 03 00 00 00 r0 = 0x3 + 160 b7 00 00 00 08 00 00 00 r0 = 0x8 161 95 00 00 00 00 00 00 00 exit - 162 b7 00 00 00 05 00 00 00 r0 = 0x5 + 162 b7 00 00 00 07 00 00 00 r0 = 0x7 163 95 00 00 00 00 00 00 00 exit - 164 b7 00 00 00 02 00 00 00 r0 = 0x2 - 165 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 164 b7 00 00 00 04 00 00 00 r0 = 0x4 + 165 95 00 00 00 00 00 00 00 exit + 166 b7 00 00 00 06 00 00 00 r0 = 0x6 + 167 95 00 00 00 00 00 00 00 exit + 168 b7 00 00 00 03 00 00 00 r0 = 0x3 + 169 95 00 00 00 00 00 00 00 exit + 170 b7 00 00 00 05 00 00 00 r0 = 0x5 + 171 95 00 00 00 00 00 00 00 exit + 172 b7 00 00 00 02 00 00 00 r0 = 0x2 + 173 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 3ec943a0..18a60ce8 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3936 (bytes into file) + Start of section headers 3960 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf60 +There are 8 section headers, starting at offset 0xf78 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000550 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000670 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000678 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000678 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000678 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0009f0 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000a2e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000568 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000688 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000690 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000690 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000690 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000a08 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000a46 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000550 0x000550 E 0x8 - LOAD 0x000670 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000678 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000678 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000568 0x000568 E 0x8 + LOAD 0x000688 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000690 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000690 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1360 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1384 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -106,171 +106,174 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 10 55 03 0a 00 02 00 00 00 jne r3, 0x2, +0xa + 10 55 03 0b 00 02 00 00 00 jne r3, 0x2, +0xb 18 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 20 55 03 93 00 00 00 00 00 jne r3, 0x0, +0x93 + 20 55 03 94 00 00 00 00 00 jne r3, 0x0, +0x94 28 2c 11 68 28 00 00 00 00 ldxb w1, [r1 + 0x2868] - 30 55 01 93 00 ff 00 00 00 jne r1, 0xff, +0x93 - 38 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] - 40 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 48 bc 11 00 00 00 00 00 00 mov32 w1, w1 - 50 15 01 01 00 01 00 00 00 jeq r1, 0x1, +0x1 - 58 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 60 9d 00 00 00 00 00 00 00 return - 68 55 03 90 00 04 00 00 00 jne r3, 0x4, +0x90 - 70 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 78 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 - 80 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 88 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - 90 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 98 55 03 8c 00 00 00 00 00 jne r3, 0x0, +0x8c - a0 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - a8 55 03 8c 00 ff 00 00 00 jne r3, 0xff, +0x8c - b0 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - b8 55 03 8c 00 0e 00 00 00 jne r3, 0xe, +0x8c - c0 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - c8 55 03 8c 00 ff 00 00 00 jne r3, 0xff, +0x8c - d0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - d8 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 - e0 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 - e8 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] - f0 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 - f8 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 - 100 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d - 108 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] - 110 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 - 118 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 - 120 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b - 128 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] - 130 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b - 138 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] - 140 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d - 148 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e - 150 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 158 55 02 7c 00 00 00 00 00 jne r2, 0x0, +0x7c - 160 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 168 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 - 170 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 178 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 180 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 188 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 190 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 198 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 1a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 1a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 1b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 1b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 1c0 5d 21 63 00 00 00 00 00 jne r1, r2, +0x63 - 1c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1d0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1d8 5d 21 60 00 00 00 00 00 jne r1, r2, +0x60 - 1e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1e8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1f0 5d 21 5d 00 00 00 00 00 jne r1, r2, +0x5d - 1f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 200 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 208 5d 21 5a 00 00 00 00 00 jne r1, r2, +0x5a - 210 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 218 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 220 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 228 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 230 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 238 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 240 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 248 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 250 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 258 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 260 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 268 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 270 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 278 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 - 280 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 288 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 298 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 2a8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 2b0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 2b8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2c0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 2c8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2d8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2e0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 2f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 300 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 308 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 310 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 318 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 320 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 328 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 330 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 338 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 340 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 348 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 350 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 358 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 360 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 368 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 370 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 378 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 380 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 388 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 390 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 398 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 3a0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 3a8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 3b0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c0 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 3c8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3d8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3e0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3f0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3f8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 400 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 408 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 410 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 418 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 420 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 428 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 430 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 438 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 440 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 448 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 450 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 458 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 460 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 468 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 470 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 478 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 480 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 488 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 490 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 498 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 4a0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 4a8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - 4b0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 4b8 05 00 74 ff 00 00 00 00 ja -0x8c - 4c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 4c8 05 00 72 ff 00 00 00 00 ja -0x8e - 4d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4d8 05 00 70 ff 00 00 00 00 ja -0x90 - 4e0 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 4e8 05 00 6e ff 00 00 00 00 ja -0x92 - 4f0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 4f8 05 00 6c ff 00 00 00 00 ja -0x94 - 500 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 508 05 00 6a ff 00 00 00 00 ja -0x96 - 510 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 518 05 00 68 ff 00 00 00 00 ja -0x98 - 520 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 528 05 00 66 ff 00 00 00 00 ja -0x9a - 530 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 538 05 00 64 ff 00 00 00 00 ja -0x9c - 540 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 548 05 00 62 ff 00 00 00 00 ja -0x9e \ No newline at end of file + 30 55 01 94 00 ff 00 00 00 jne r1, 0xff, +0x94 + 38 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 40 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] + 48 55 01 03 00 01 00 00 00 jne r1, 0x1, +0x3 + 50 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 58 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] + 60 55 01 90 00 05 00 00 00 jne r1, 0x5, +0x90 + 68 9d 00 00 00 00 00 00 00 return + 70 55 03 92 00 04 00 00 00 jne r3, 0x4, +0x92 + 78 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 80 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 + 88 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 90 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 + 98 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + a0 55 03 8e 00 00 00 00 00 jne r3, 0x0, +0x8e + a8 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] + b0 55 03 8e 00 ff 00 00 00 jne r3, 0xff, +0x8e + b8 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] + c0 55 03 8e 00 0e 00 00 00 jne r3, 0xe, +0x8e + c8 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] + d0 55 03 8e 00 ff 00 00 00 jne r3, 0xff, +0x8e + d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + e0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 + e8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 + f0 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] + f8 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 + 100 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 + 108 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d + 110 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] + 118 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 + 120 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 + 128 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b + 130 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] + 138 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b + 140 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] + 148 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d + 150 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e + 158 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] + 160 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e + 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 170 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 + 178 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 180 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 188 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 190 07 05 00 00 13 00 00 00 add64 r5, 0x13 + 198 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 1a0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 1a8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 1b0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 1b8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 1c0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 1c8 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 + 1d0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 1d8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1e0 5d 21 62 00 00 00 00 00 jne r1, r2, +0x62 + 1e8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 1f0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1f8 5d 21 5f 00 00 00 00 00 jne r1, r2, +0x5f + 200 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 208 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 210 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c + 218 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 220 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 228 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 230 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 238 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 240 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 248 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 250 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 258 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 260 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 268 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 270 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 278 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 280 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 + 288 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 290 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 298 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 2a0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 2a8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 2b0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 2b8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2c8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 2d0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2d8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2e0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2e8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2f0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2f8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 300 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 308 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 310 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 318 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 320 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 328 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 330 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 338 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 340 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 348 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 350 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 358 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 360 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 368 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 370 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 378 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 380 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 388 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 390 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 398 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 3a0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 3a8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 3b0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 3b8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3c8 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 3d0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3d8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3e0 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3e8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3f0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3f8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 400 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 408 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 410 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 418 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 420 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 428 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 430 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 438 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 440 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 448 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 450 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 458 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 460 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 468 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 470 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 478 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 480 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 488 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 490 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 498 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 4a0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 4a8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 4b0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + 4b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 4c0 05 00 74 ff 00 00 00 00 ja -0x8c + 4c8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 4d0 05 00 72 ff 00 00 00 00 ja -0x8e + 4d8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4e0 05 00 70 ff 00 00 00 00 ja -0x90 + 4e8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 4f0 05 00 6e ff 00 00 00 00 ja -0x92 + 4f8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 500 05 00 6c ff 00 00 00 00 ja -0x94 + 508 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 510 05 00 6a ff 00 00 00 00 ja -0x96 + 518 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 520 05 00 68 ff 00 00 00 00 ja -0x98 + 528 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 530 05 00 66 ff 00 00 00 00 ja -0x9a + 538 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 540 05 00 64 ff 00 00 00 00 ja -0x9c + 548 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 550 05 00 62 ff 00 00 00 00 ja -0x9e + 558 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 560 05 00 60 ff 00 00 00 00 ja -0xa0 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 4b553abc..91047769 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -3,52 +3,53 @@ entrypoint: add64 r10, -320 ldxdw r3, [r1+0] - jne r3, 2, jmp_0068 + jne r3, 2, jmp_0070 ldxdw r3, [r1+88] - jne r3, 0, jmp_04c8 + jne r3, 0, jmp_04d0 ldxb r1, [r1+10344] - jne r1, 255, jmp_04d8 + jne r1, 255, jmp_04e0 + mov64 r0, 11 ldxb r1, [r2+0] + jne r1, 1, jmp_0068 mov64 r0, 0 - mov32 r1, r1 - jeq r1, 1, jmp_0060 - mov64 r0, 11 + ldxdw r1, [r2-8] + jne r1, 5, jmp_04f0 -jmp_0060: +jmp_0068: exit -jmp_0068: - jne r3, 4, jmp_04e8 +jmp_0070: + jne r3, 4, jmp_0500 ldxdw r3, [r1+88] - jne r3, 0, jmp_04c8 + jne r3, 0, jmp_04d0 ldxb r3, [r1+10344] - jne r3, 255, jmp_04d8 + jne r3, 255, jmp_04e0 ldxdw r3, [r1+10424] - jne r3, 0, jmp_04f8 + jne r3, 0, jmp_0510 ldxb r3, [r1+20680] - jne r3, 255, jmp_0508 + jne r3, 255, jmp_0520 ldxdw r3, [r1+20760] - jne r3, 14, jmp_0518 + jne r3, 14, jmp_0530 ldxb r3, [r1+31032] - jne r3, 255, jmp_0528 + jne r3, 255, jmp_0540 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 ldxdw r4, [r1+31040] - jne r4, r3, jmp_0060 + jne r4, r3, jmp_0068 mov32 r3, 1288277025 hor64 r3, 2146519613 ldxdw r4, [r1+31048] - jne r4, r3, jmp_0060 + jne r4, r3, jmp_0068 mov32 r3, 149871192 hor64 r3, 1157472667 ldxdw r4, [r1+31056] - jne r4, r3, jmp_0060 + jne r4, r3, jmp_0068 ldxdw r3, [r1+31064] mov32 r4, -1965433885 - jne r3, r4, jmp_0060 + jne r3, r4, jmp_0068 ldxdw r2, [r2-8] - jne r2, 0, jmp_0538 + jne r2, 0, jmp_0550 mov64 r6, r1 add64 r6, 41400 mov64 r4, r10 @@ -62,16 +63,16 @@ jmp_0068: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_0060 + jne r1, r2, jmp_0068 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_0060 + jne r1, r2, jmp_0068 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_0060 + jne r1, r2, jmp_0068 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_0060 + jne r1, r2, jmp_0068 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -157,36 +158,40 @@ jmp_0068: add64 r1, 10456 stxdw [r7+10448], r1 mov64 r0, 0 - ja jmp_0060 + ja jmp_0068 -jmp_04c8: +jmp_04d0: mov64 r0, 2 - ja jmp_0060 + ja jmp_0068 -jmp_04d8: +jmp_04e0: mov64 r0, 5 - ja jmp_0060 + ja jmp_0068 + +jmp_04f0: + mov64 r0, 12 + ja jmp_0068 -jmp_04e8: +jmp_0500: mov64 r0, 1 - ja jmp_0060 + ja jmp_0068 -jmp_04f8: +jmp_0510: mov64 r0, 3 - ja jmp_0060 + ja jmp_0068 -jmp_0508: +jmp_0520: mov64 r0, 6 - ja jmp_0060 + ja jmp_0068 -jmp_0518: +jmp_0530: mov64 r0, 4 - ja jmp_0060 + ja jmp_0068 -jmp_0528: +jmp_0540: mov64 r0, 7 - ja jmp_0060 + ja jmp_0068 -jmp_0538: +jmp_0550: mov64 r0, 9 - ja jmp_0060 + ja jmp_0068 diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 071f20ee..8a3c8fe0 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -1,5 +1,4 @@ initialize: - # Error if user has data. # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] diff --git a/examples/tree/artifacts/snippets/asm/insert.txt b/examples/tree/artifacts/snippets/asm/insert.txt index 2138eb5c..7ab74eb6 100644 --- a/examples/tree/artifacts/snippets/asm/insert.txt +++ b/examples/tree/artifacts/snippets/asm/insert.txt @@ -1,3 +1,3 @@ insert: - jne r8, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len + jne r9, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt new file mode 100644 index 00000000..f18c4906 --- /dev/null +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -0,0 +1,38 @@ + +#[repr(u8)] +pub enum Instruction { + /// Initialize the tree (discriminator is number of accounts). + Initialize, + /// Insert node into tree instruction. + Insert, +} + +#[repr(C, packed)] +pub struct InstructionHeader { + discriminator: u8, +} + +#[repr(C, packed)] +pub struct InsertInstruction { + pub header: InstructionHeader, + pub key: u16, + pub value: u16, +} + +#[repr(C, packed)] +/// Value in r0. +struct Return { + /// If a value is retrieved from the tree, it's encoded in high bits. + maybe_value: u16, + /// Nonzero iff error. + status: u16, +} + +constant_group! { + /// Offsets for instruction processing. + instruction { + prefix = "INSN", + /// Offset to instruction discriminator byte. + offset!(DISCRIMINATOR, InstructionHeader.discriminator), + } +} diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt new file mode 100644 index 00000000..6a7c5864 --- /dev/null +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -0,0 +1,54 @@ +#[repr(u8)] +pub enum Color { + Black, + Red, +} + +#[repr(usize)] +pub enum Direction { + Left, + Right, +} + +constant_group! { + /// Tree constants. + tree { + /// Max number of children per node. + N_CHILDREN: usize = 2, + /// Left direction. + DIR_L = Direction::Left as usize, + /// Right direction. + DIR_R = Direction::Right as usize, + /// Black color. + COLOR_B = Color::Black as u8, + /// Red color. + COLOR_R = Color::Red as u8, + /// Next node field in header. + offset!(HEADER_NEXT, TreeHeader.next), + } +} + +#[repr(C, packed)] +/// Tree account data header. Contains pointer to tree root and top of free node stack. +pub struct TreeHeader { + /// Aboslute pointer to tree root in memory map. + pub root: *mut TreeNode, + /// Absolute pointer to stack top in memory map. + pub top: *mut StackNode, + /// Absolute pointer to where the next node should be allocated in memory map. + pub next: *mut TreeNode, +} + +#[repr(C, packed)] +pub struct TreeNode { + pub parent: *mut TreeNode, + pub child: [*mut TreeNode; tree::N_CHILDREN], + pub key: u16, + pub value: u16, + pub color: Color, +} + +#[repr(C, packed)] +pub struct StackNode { + pub next: *mut StackNode, +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/general_branching/result.txt b/examples/tree/artifacts/tests/general_branching/result.txt new file mode 100644 index 00000000..d8c774c3 --- /dev/null +++ b/examples/tree/artifacts/tests/general_branching/result.txt @@ -0,0 +1,24 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| User has nonzero data length | 6 | 8 | +2 | +33.3% | +| Tree account is duplicate | 8 | 10 | +2 | +25.0% | +| Invalid instruction discriminator | 11 | 11 | +0 | +0.0% | +test tests::test_general_branching ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/general_branching/test.txt b/examples/tree/artifacts/tests/general_branching/test.txt new file mode 100644 index 00000000..1383597b --- /dev/null +++ b/examples/tree/artifacts/tests/general_branching/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_general_branching() { + print_comparison_table(general::GeneralCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt new file mode 100644 index 00000000..465c5bf4 --- /dev/null +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -0,0 +1,24 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Instruction data too short | 12 | 16 | +4 | +33.3% | +| Instruction data too long | 12 | 16 | +4 | +33.3% | +| Insert happy path | 11 | 14 | +3 | +27.3% | +test tests::test_insert ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/test.txt b/examples/tree/artifacts/tests/insert/test.txt new file mode 100644 index 00000000..ee37483c --- /dev/null +++ b/examples/tree/artifacts/tests/insert/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert() { + print_comparison_table(insert::InsertCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 35e7bcd1..4c0c45a0 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -71,6 +71,10 @@ fn main() { let rs_path = manifest_path.join("src/program.rs"); let rs_content = fs::read_to_string(&rs_path).unwrap(); extract_snippets(&rs_content, manifest_path, "rs"); + + let common_path = manifest_path.join("interface/src/common.rs"); + let common_content = fs::read_to_string(&common_path).unwrap(); + extract_snippets(&common_content, manifest_path, "interface"); } /// Extract ANCHOR snippets from source content and write to artifacts/snippets/{kind}/. diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 1680d27d..68507b4a 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,5 +1,7 @@ mod entrypoint; +mod general; mod init; +mod insert; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_sdk::account::Account; @@ -147,6 +149,16 @@ fn test_entrypoint_branching() { print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); } +#[test] +fn test_general_branching() { + print_comparison_table(general::GeneralCase::CASES, false, false); +} + +#[test] +fn test_insert() { + print_comparison_table(insert::InsertCase::CASES, false, false); +} + #[test] fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES, false, false); diff --git a/examples/tree/src/tests/general.rs b/examples/tree/src/tests/general.rs new file mode 100644 index 00000000..45de6755 --- /dev/null +++ b/examples/tree/src/tests/general.rs @@ -0,0 +1,95 @@ +use super::*; +use mollusk_svm::program; +use solana_sdk::instruction::AccountMeta; + +fn general_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[], + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::default()), + ]; + + (setup, instruction, accounts) +} + +#[derive(Clone, Copy)] +pub(super) enum GeneralCase { + UserDataLen, + TreeDuplicate, + InstructionDiscriminator, +} + +impl GeneralCase { + pub(super) const CASES: &'static [Self] = &[ + Self::UserDataLen, + Self::TreeDuplicate, + Self::InstructionDiscriminator, + ]; +} + +impl TestCase for GeneralCase { + fn name(&self) -> &'static str { + match self { + Self::UserDataLen => "User has nonzero data length", + Self::TreeDuplicate => "Tree account is duplicate", + Self::InstructionDiscriminator => "Invalid instruction discriminator", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + Self::UserDataLen => { + let (setup, instruction, mut accounts) = general_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::USER_DATA_LEN, + ) + } + Self::TreeDuplicate => { + let (setup, mut instruction, mut accounts) = general_setup(lang); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::TREE_DUPLICATE, + ) + } + Self::InstructionDiscriminator => { + let (setup, mut instruction, accounts) = general_setup(lang); + instruction.data = vec![255]; // Invalid discriminator. + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DISCRIMINATOR, + ) + } + } + } +} diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs new file mode 100644 index 00000000..9316e65e --- /dev/null +++ b/examples/tree/src/tests/insert.rs @@ -0,0 +1,109 @@ +use super::*; +use mollusk_svm::program; +use solana_sdk::instruction::AccountMeta; +use tree_interface::{cpi, Instruction as TreeInstruction}; + +fn insert_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(program_language); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + // Valid InsertInstruction: discriminator (1) + key (u16) + value (u16) = 5 bytes. + let instruction_data: [u8; 5] = [ + TreeInstruction::Insert as u8, + 42, 0, // key + 1, 0, // value + ]; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &instruction_data, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + ( + tree_pubkey, + Account::new(0, cpi::TREE_DATA_LEN, &setup.program_id), + ), + ]; + + (setup, instruction, accounts) +} + +#[derive(Clone, Copy)] +pub(super) enum InsertCase { + InstructionDataLenShort, + InstructionDataLenLong, + InsertHappyPath, +} + +impl InsertCase { + pub(super) const CASES: &'static [Self] = &[ + Self::InstructionDataLenShort, + Self::InstructionDataLenLong, + Self::InsertHappyPath, + ]; +} + +impl TestCase for InsertCase { + fn name(&self) -> &'static str { + match self { + Self::InstructionDataLenShort => "Instruction data too short", + Self::InstructionDataLenLong => "Instruction data too long", + Self::InsertHappyPath => "Insert happy path", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + Self::InstructionDataLenShort => { + let (setup, mut instruction, accounts) = insert_setup(lang); + // Correct discriminator but wrong length (1 byte instead of 5). + instruction.data = vec![TreeInstruction::Insert as u8]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA_LEN, + ) + } + Self::InstructionDataLenLong => { + let (setup, mut instruction, accounts) = insert_setup(lang); + // Correct discriminator but wrong length (6 bytes instead of 5). + instruction.data = vec![TreeInstruction::Insert as u8, 0, 0, 0, 0, 0]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA_LEN, + ) + } + Self::InsertHappyPath => { + let (setup, instruction, accounts) = insert_setup(lang); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } + } + } + } +} diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 0fa175c5..fd03c347 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -233,7 +233,6 @@ general: # ANCHOR: initialize-input-checks initialize: - # Error if user has data. # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] @@ -466,7 +465,7 @@ initialize: # ANCHOR: insert insert: - jne r8, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len + jne r9, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len exit # ANCHOR_END: insert From bd9579d5f7e4deea8b1e00e12315ba25006a00cf Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:42:10 -0800 Subject: [PATCH 160/263] Add general branching optimization --- examples/tree/artifacts/dumps/rs.txt | 367 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 89 +++-- .../snippets/rs/general-branching.txt | 4 +- .../tests/general_branching/result.txt | 4 +- .../tree/artifacts/tests/insert/result.txt | 12 +- examples/tree/src/program.rs | 4 +- 6 files changed, 244 insertions(+), 236 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 18a60ce8..01505c90 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3960 (bytes into file) + Start of section headers 3968 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf78 +There are 8 section headers, starting at offset 0xf80 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000568 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000688 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000690 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000690 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000690 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000a08 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000a46 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000570 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000690 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000698 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000698 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000698 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000a10 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000a4e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000568 0x000568 E 0x8 - LOAD 0x000688 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000690 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000690 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000570 0x000570 E 0x8 + LOAD 0x000690 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000698 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000698 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1384 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1392 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -106,174 +106,175 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 10 55 03 0b 00 02 00 00 00 jne r3, 0x2, +0xb + 10 55 03 0a 00 02 00 00 00 jne r3, 0x2, +0xa 18 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 20 55 03 94 00 00 00 00 00 jne r3, 0x0, +0x94 + 20 55 03 93 00 00 00 00 00 jne r3, 0x0, +0x93 28 2c 11 68 28 00 00 00 00 ldxb w1, [r1 + 0x2868] - 30 55 01 94 00 ff 00 00 00 jne r1, 0xff, +0x94 - 38 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 40 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] - 48 55 01 03 00 01 00 00 00 jne r1, 0x1, +0x3 - 50 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 58 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] - 60 55 01 90 00 05 00 00 00 jne r1, 0x5, +0x90 - 68 9d 00 00 00 00 00 00 00 return - 70 55 03 92 00 04 00 00 00 jne r3, 0x4, +0x92 - 78 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 80 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 - 88 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 90 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - 98 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - a0 55 03 8e 00 00 00 00 00 jne r3, 0x0, +0x8e - a8 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - b0 55 03 8e 00 ff 00 00 00 jne r3, 0xff, +0x8e - b8 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - c0 55 03 8e 00 0e 00 00 00 jne r3, 0xe, +0x8e - c8 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - d0 55 03 8e 00 ff 00 00 00 jne r3, 0xff, +0x8e - d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - e0 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 - e8 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 - f0 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] - f8 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 - 100 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 - 108 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d - 110 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] - 118 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 - 120 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 - 128 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b - 130 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] - 138 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b - 140 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] - 148 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d - 150 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e - 158 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 160 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e - 168 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 170 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 - 178 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 180 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 188 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 190 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 198 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 1a0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 1a8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 1b0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 1b8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 1c0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 1c8 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 - 1d0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1d8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1e0 5d 21 62 00 00 00 00 00 jne r1, r2, +0x62 - 1e8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1f0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1f8 5d 21 5f 00 00 00 00 00 jne r1, r2, +0x5f - 200 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 208 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 210 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c - 218 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 220 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 228 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 230 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 238 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 240 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 248 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 250 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 258 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 260 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 268 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 270 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 278 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 280 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 - 288 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 290 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 298 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 2a0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 2a8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 2b0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 2b8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2c8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 2d0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2d8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2e0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2e8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2f0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2f8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 300 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 308 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 310 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 318 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 320 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 328 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 330 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 338 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 340 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 348 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 350 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 358 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 360 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 368 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 370 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 378 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 380 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 388 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 390 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 398 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 3a0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 3a8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 3b0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 3b8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c8 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 3d0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3d8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3e0 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3e8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3f0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3f8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 400 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 408 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 410 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 418 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 420 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 428 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 430 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 438 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 440 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 448 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 450 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 458 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 460 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 468 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 470 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 478 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 480 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 488 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 490 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 498 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 4a0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 4a8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 4b0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - 4b8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 4c0 05 00 74 ff 00 00 00 00 ja -0x8c - 4c8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 4d0 05 00 72 ff 00 00 00 00 ja -0x8e - 4d8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4e0 05 00 70 ff 00 00 00 00 ja -0x90 - 4e8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - 4f0 05 00 6e ff 00 00 00 00 ja -0x92 - 4f8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 500 05 00 6c ff 00 00 00 00 ja -0x94 - 508 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 510 05 00 6a ff 00 00 00 00 ja -0x96 - 518 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 520 05 00 68 ff 00 00 00 00 ja -0x98 - 528 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 530 05 00 66 ff 00 00 00 00 ja -0x9a - 538 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 540 05 00 64 ff 00 00 00 00 ja -0x9c - 548 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 550 05 00 62 ff 00 00 00 00 ja -0x9e - 558 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 560 05 00 60 ff 00 00 00 00 ja -0xa0 \ No newline at end of file + 30 55 01 93 00 ff 00 00 00 jne r1, 0xff, +0x93 + 38 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] + 40 55 01 93 00 01 00 00 00 jne r1, 0x1, +0x93 + 48 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 50 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] + 58 55 01 92 00 05 00 00 00 jne r1, 0x5, +0x92 + 60 9d 00 00 00 00 00 00 00 return + 68 55 03 94 00 04 00 00 00 jne r3, 0x4, +0x94 + 70 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 78 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 + 80 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 88 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 + 90 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 98 55 03 90 00 00 00 00 00 jne r3, 0x0, +0x90 + a0 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] + a8 55 03 90 00 ff 00 00 00 jne r3, 0xff, +0x90 + b0 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] + b8 55 03 90 00 0e 00 00 00 jne r3, 0xe, +0x90 + c0 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] + c8 55 03 90 00 ff 00 00 00 jne r3, 0xff, +0x90 + d0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + d8 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 + e0 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 + e8 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] + f0 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 + f8 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 + 100 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d + 108 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] + 110 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 + 118 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 + 120 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b + 128 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] + 130 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b + 138 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] + 140 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d + 148 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e + 150 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] + 158 55 02 80 00 00 00 00 00 jne r2, 0x0, +0x80 + 160 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 168 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 + 170 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 178 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 180 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 188 07 05 00 00 13 00 00 00 add64 r5, 0x13 + 190 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 198 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 1a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 1a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 1b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 1b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 1c0 5d 21 67 00 00 00 00 00 jne r1, r2, +0x67 + 1c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 1d0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1d8 5d 21 64 00 00 00 00 00 jne r1, r2, +0x64 + 1e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 1e8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1f0 5d 21 61 00 00 00 00 00 jne r1, r2, +0x61 + 1f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 200 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 208 5d 21 5e 00 00 00 00 00 jne r1, r2, +0x5e + 210 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 218 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 220 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 228 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 230 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 238 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 240 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 248 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 250 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 258 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 260 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 268 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 270 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 278 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 + 280 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 288 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 298 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 2a8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 2b0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 2b8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2c0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 2c8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2d8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2e0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 2f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 300 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 308 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 310 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 318 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 320 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 328 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 330 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 338 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 340 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 348 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 350 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 358 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 360 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 368 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 370 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 378 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 380 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 388 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 390 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 398 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 3a0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 3a8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 3b0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3c0 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 3c8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3d8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3e0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3f0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3f8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 400 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 408 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 410 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 418 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 420 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 428 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 430 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 438 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 440 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 448 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 450 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 458 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 460 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 468 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 470 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 478 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 480 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 488 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 490 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 498 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 4a0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 4a8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + 4b0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 4b8 05 00 74 ff 00 00 00 00 ja -0x8c + 4c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 4c8 05 00 72 ff 00 00 00 00 ja -0x8e + 4d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4d8 05 00 70 ff 00 00 00 00 ja -0x90 + 4e0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 4e8 05 00 6e ff 00 00 00 00 ja -0x92 + 4f0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 4f8 05 00 6c ff 00 00 00 00 ja -0x94 + 500 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 508 05 00 6a ff 00 00 00 00 ja -0x96 + 510 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 518 05 00 68 ff 00 00 00 00 ja -0x98 + 520 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 528 05 00 66 ff 00 00 00 00 ja -0x9a + 530 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 538 05 00 64 ff 00 00 00 00 ja -0x9c + 540 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 548 05 00 62 ff 00 00 00 00 ja -0x9e + 550 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 558 05 00 60 ff 00 00 00 00 ja -0xa0 + 560 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 + 568 05 00 5e ff 00 00 00 00 ja -0xa2 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 91047769..7462f209 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -3,53 +3,52 @@ entrypoint: add64 r10, -320 ldxdw r3, [r1+0] - jne r3, 2, jmp_0070 + jne r3, 2, jmp_0068 ldxdw r3, [r1+88] - jne r3, 0, jmp_04d0 + jne r3, 0, jmp_04c8 ldxb r1, [r1+10344] - jne r1, 255, jmp_04e0 - mov64 r0, 11 + jne r1, 255, jmp_04d8 ldxb r1, [r2+0] - jne r1, 1, jmp_0068 + jne r1, 1, jmp_04e8 mov64 r0, 0 ldxdw r1, [r2-8] - jne r1, 5, jmp_04f0 + jne r1, 5, jmp_04f8 -jmp_0068: +jmp_0060: exit -jmp_0070: - jne r3, 4, jmp_0500 +jmp_0068: + jne r3, 4, jmp_0508 ldxdw r3, [r1+88] - jne r3, 0, jmp_04d0 + jne r3, 0, jmp_04c8 ldxb r3, [r1+10344] - jne r3, 255, jmp_04e0 + jne r3, 255, jmp_04d8 ldxdw r3, [r1+10424] - jne r3, 0, jmp_0510 + jne r3, 0, jmp_0518 ldxb r3, [r1+20680] - jne r3, 255, jmp_0520 + jne r3, 255, jmp_0528 ldxdw r3, [r1+20760] - jne r3, 14, jmp_0530 + jne r3, 14, jmp_0538 ldxb r3, [r1+31032] - jne r3, 255, jmp_0540 + jne r3, 255, jmp_0548 mov64 r0, 8 mov32 r3, 399877894 hor64 r3, 1364995097 ldxdw r4, [r1+31040] - jne r4, r3, jmp_0068 + jne r4, r3, jmp_0060 mov32 r3, 1288277025 hor64 r3, 2146519613 ldxdw r4, [r1+31048] - jne r4, r3, jmp_0068 + jne r4, r3, jmp_0060 mov32 r3, 149871192 hor64 r3, 1157472667 ldxdw r4, [r1+31056] - jne r4, r3, jmp_0068 + jne r4, r3, jmp_0060 ldxdw r3, [r1+31064] mov32 r4, -1965433885 - jne r3, r4, jmp_0068 + jne r3, r4, jmp_0060 ldxdw r2, [r2-8] - jne r2, 0, jmp_0550 + jne r2, 0, jmp_0558 mov64 r6, r1 add64 r6, 41400 mov64 r4, r10 @@ -63,16 +62,16 @@ jmp_0070: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_0068 + jne r1, r2, jmp_0060 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_0068 + jne r1, r2, jmp_0060 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_0068 + jne r1, r2, jmp_0060 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_0068 + jne r1, r2, jmp_0060 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -158,40 +157,44 @@ jmp_0070: add64 r1, 10456 stxdw [r7+10448], r1 mov64 r0, 0 - ja jmp_0068 + ja jmp_0060 -jmp_04d0: +jmp_04c8: mov64 r0, 2 - ja jmp_0068 + ja jmp_0060 -jmp_04e0: +jmp_04d8: mov64 r0, 5 - ja jmp_0068 + ja jmp_0060 + +jmp_04e8: + mov64 r0, 11 + ja jmp_0060 -jmp_04f0: +jmp_04f8: mov64 r0, 12 - ja jmp_0068 + ja jmp_0060 -jmp_0500: +jmp_0508: mov64 r0, 1 - ja jmp_0068 + ja jmp_0060 -jmp_0510: +jmp_0518: mov64 r0, 3 - ja jmp_0068 + ja jmp_0060 -jmp_0520: +jmp_0528: mov64 r0, 6 - ja jmp_0068 + ja jmp_0060 -jmp_0530: +jmp_0538: mov64 r0, 4 - ja jmp_0068 + ja jmp_0060 -jmp_0540: +jmp_0548: mov64 r0, 7 - ja jmp_0068 + ja jmp_0060 -jmp_0550: +jmp_0558: mov64 r0, 9 - ja jmp_0068 + ja jmp_0060 diff --git a/examples/tree/artifacts/snippets/rs/general-branching.txt b/examples/tree/artifacts/snippets/rs/general-branching.txt index 376784c2..0fcf9fc5 100644 --- a/examples/tree/artifacts/snippets/rs/general-branching.txt +++ b/examples/tree/artifacts/snippets/rs/general-branching.txt @@ -10,7 +10,9 @@ unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u // Get instruction data length and discriminator, branch to instruction. let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); - if ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8 { + if likely( + ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, + ) { insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() diff --git a/examples/tree/artifacts/tests/general_branching/result.txt b/examples/tree/artifacts/tests/general_branching/result.txt index d8c774c3..288c168e 100644 --- a/examples/tree/artifacts/tests/general_branching/result.txt +++ b/examples/tree/artifacts/tests/general_branching/result.txt @@ -2,7 +2,7 @@ |-----------|-----------|------------|----------|------------| | User has nonzero data length | 6 | 8 | +2 | +33.3% | | Tree account is duplicate | 8 | 10 | +2 | +25.0% | -| Invalid instruction discriminator | 11 | 11 | +0 | +0.0% | +| Invalid instruction discriminator | 11 | 12 | +1 | +9.1% | test tests::test_general_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units @@ -20,5 +20,5 @@ test tests::test_general_branching ... ok [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index 465c5bf4..857c793b 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Instruction data too short | 12 | 16 | +4 | +33.3% | -| Instruction data too long | 12 | 16 | +4 | +33.3% | -| Insert happy path | 11 | 14 | +3 | +27.3% | +| Instruction data too short | 12 | 15 | +3 | +25.0% | +| Instruction data too long | 12 | 15 | +3 | +25.0% | +| Insert happy path | 11 | 13 | +2 | +18.2% | test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index c1eccc1d..12fcdcc2 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -90,7 +90,9 @@ unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u // Get instruction data length and discriminator, branch to instruction. let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); - if ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8 { + if likely( + ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, + ) { insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() From f2597e098a0fc1e89d2070c3f17bc8eaec9e3bd8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 17:18:19 -0800 Subject: [PATCH 161/263] Begin insert algo --- examples/tree/artifacts/snippets/rs/insert.txt | 7 +++++++ examples/tree/src/program.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 4cfa4d3d..0b55c13e 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -8,5 +8,12 @@ unsafe fn insert( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN ); + + let tree_header_ptr: *mut TreeHeader = + transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); + + if (*tree_header_ptr).top.is_null() { // If stack is empty, need to allocate a node. + } + SUCCESS } \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 12fcdcc2..cad07e47 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -111,6 +111,13 @@ unsafe fn insert( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN ); + + let tree_header_ptr: *mut TreeHeader = + transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); + + if (*tree_header_ptr).top.is_null() { // If stack is empty, need to allocate a node. + } + SUCCESS } // ANCHOR_END: insert From d9fe96bd1221332d19bb4874e33aac8aaf0b630a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 17:22:21 -0800 Subject: [PATCH 162/263] Use _ptr --- .../snippets/interface/tree-defs-common.txt | 14 ++++---- .../snippets/rs/initialize-create-account.txt | 2 +- .../tree/artifacts/snippets/rs/insert.txt | 2 +- examples/tree/interface/src/asm.rs | 4 +-- examples/tree/interface/src/common.rs | 14 ++++---- examples/tree/src/program.rs | 32 +++++++++---------- examples/tree/src/tests/init.rs | 2 +- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index 6a7c5864..65c2f1b5 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -24,7 +24,7 @@ constant_group! { /// Red color. COLOR_R = Color::Red as u8, /// Next node field in header. - offset!(HEADER_NEXT, TreeHeader.next), + offset!(HEADER_NEXT, TreeHeader.next_ptr), } } @@ -32,17 +32,17 @@ constant_group! { /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { /// Aboslute pointer to tree root in memory map. - pub root: *mut TreeNode, + pub root_ptr: *mut TreeNode, /// Absolute pointer to stack top in memory map. - pub top: *mut StackNode, + pub top_ptr: *mut StackNode, /// Absolute pointer to where the next node should be allocated in memory map. - pub next: *mut TreeNode, + pub next_ptr: *mut TreeNode, } #[repr(C, packed)] pub struct TreeNode { - pub parent: *mut TreeNode, - pub child: [*mut TreeNode; tree::N_CHILDREN], + pub parent_ptr: *mut TreeNode, + pub child_ptr: [*mut TreeNode; tree::N_CHILDREN], pub key: u16, pub value: u16, pub color: Color, @@ -50,5 +50,5 @@ pub struct TreeNode { #[repr(C, packed)] pub struct StackNode { - pub next: *mut StackNode, + pub next_ptr: *mut StackNode, } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 4fc91c2a..0013540f 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -107,4 +107,4 @@ // Store next pointer in tree header. let next_ptr = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next = next_ptr; \ No newline at end of file + (*tree.data_ptr().cast::()).next_ptr = next_ptr; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 0b55c13e..6a02e0ad 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -12,7 +12,7 @@ unsafe fn insert( let tree_header_ptr: *mut TreeHeader = transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); - if (*tree_header_ptr).top.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header_ptr).top_ptr.is_null() { // If stack is empty, need to allocate a node. } SUCCESS diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index e5ff8ae8..3cefcb80 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -240,9 +240,9 @@ asm_constant_group! { extend_constant_group!(tree { prefix = "TREE", /// Tree root. - offset!(ROOT, TreeHeader.root), + offset!(ROOT, TreeHeader.root_ptr), /// Stack top. - offset!(TOP, TreeHeader.top), + offset!(TOP, TreeHeader.top_ptr), /// Discriminator for insert instruction. DISCRIMINATOR_INSERT = Instruction::Insert as u8, }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1ba18981..d9d9d3c9 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -176,7 +176,7 @@ constant_group! { /// Red color. COLOR_R = Color::Red as u8, /// Next node field in header. - offset!(HEADER_NEXT, TreeHeader.next), + offset!(HEADER_NEXT, TreeHeader.next_ptr), } } @@ -184,17 +184,17 @@ constant_group! { /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { /// Aboslute pointer to tree root in memory map. - pub root: *mut TreeNode, + pub root_ptr: *mut TreeNode, /// Absolute pointer to stack top in memory map. - pub top: *mut StackNode, + pub top_ptr: *mut StackNode, /// Absolute pointer to where the next node should be allocated in memory map. - pub next: *mut TreeNode, + pub next_ptr: *mut TreeNode, } #[repr(C, packed)] pub struct TreeNode { - pub parent: *mut TreeNode, - pub child: [*mut TreeNode; tree::N_CHILDREN], + pub parent_ptr: *mut TreeNode, + pub child_ptr: [*mut TreeNode; tree::N_CHILDREN], pub key: u16, pub value: u16, pub color: Color, @@ -202,7 +202,7 @@ pub struct TreeNode { #[repr(C, packed)] pub struct StackNode { - pub next: *mut StackNode, + pub next_ptr: *mut StackNode, } // ANCHOR_END: tree-defs-common diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index cad07e47..21a615e5 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -115,7 +115,7 @@ unsafe fn insert( let tree_header_ptr: *mut TreeHeader = transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); - if (*tree_header_ptr).top.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header_ptr).top_ptr.is_null() { // If stack is empty, need to allocate a node. } SUCCESS @@ -302,7 +302,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // Store next pointer in tree header. let next_ptr = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next = next_ptr; + (*tree.data_ptr().cast::()).next_ptr = next_ptr; // ANCHOR_END: initialize-create-account SUCCESS @@ -311,7 +311,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - /// Return the direction of the node with respect to its parent. #[inline(always)] unsafe fn direction(node: *const TreeNode) -> Direction { - if node == (*(*node).parent).child[tree::DIR_R] { + if node == (*(*node).parent_ptr).child_ptrs[tree::DIR_R] { Direction::Right } else { Direction::Left @@ -330,26 +330,26 @@ unsafe fn rotate_subtree( subtree: *mut TreeNode, direction: usize, ) -> *mut TreeNode { - let subtree_parent = (*subtree).parent; - let new_root = (*subtree).child[opposite(direction)]; - let new_child = (*new_root).child[direction]; + let parent_ptr = (*subtree).parent_ptr; + let new_root = (*subtree).child_ptrs[opposite(direction)]; + let new_child_ptr = (*new_root).child_ptrs[direction]; - (*subtree).child[opposite(direction)] = new_child; + (*subtree).child_ptrs[opposite(direction)] = new_child_ptr; - if !new_child.is_null() { - (*new_child).parent = subtree; + if !new_child_ptr.is_null() { + (*new_child_ptr).parent_ptr = subtree; } - (*new_root).child[direction] = subtree; - (*new_root).parent = subtree_parent; - (*subtree).parent = new_root; + (*new_root).child_ptrs[direction] = subtree; + (*new_root).parent_ptr = parent_ptr; + (*subtree).parent_ptr = new_root; - if !subtree_parent.is_null() { - (*subtree_parent).child - [(subtree as *const TreeNode == (*subtree_parent).child[tree::DIR_R]) as usize] = + if !parent_ptr.is_null() { + (*parent_ptr).child_ptrs + [(subtree as *const TreeNode == (*parent_ptr).child_ptrs[tree::DIR_R]) as usize] = new_root; } else { - (*tree).root = new_root; + (*tree).root_ptr = new_root; } new_root diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 90541fc6..8b526118 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -457,7 +457,7 @@ impl TestCase for InitCase { + input_buffer::TREE_DATA_OFF as u64 + size_of::() as u64; let header = unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; - let actual_next = header.next as u64; + let actual_next = header.next_ptr as u64; if actual_next != expected_next { errors.push(format!( "next: expected {:#x}, got {:#x}", From 359773e747de4687b133b91a1b0dd557d8596280 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 12 Feb 2026 18:24:13 -0800 Subject: [PATCH 163/263] Use _ptrs --- examples/tree/src/program.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 21a615e5..9c39d274 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -311,7 +311,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - /// Return the direction of the node with respect to its parent. #[inline(always)] unsafe fn direction(node: *const TreeNode) -> Direction { - if node == (*(*node).parent_ptr).child_ptrs[tree::DIR_R] { + if node == (*(*node).parent_ptr).child_ptr[tree::DIR_R] { Direction::Right } else { Direction::Left @@ -331,22 +331,22 @@ unsafe fn rotate_subtree( direction: usize, ) -> *mut TreeNode { let parent_ptr = (*subtree).parent_ptr; - let new_root = (*subtree).child_ptrs[opposite(direction)]; - let new_child_ptr = (*new_root).child_ptrs[direction]; + let new_root = (*subtree).child_ptr[opposite(direction)]; + let new_child_ptr = (*new_root).child_ptr[direction]; - (*subtree).child_ptrs[opposite(direction)] = new_child_ptr; + (*subtree).child_ptr[opposite(direction)] = new_child_ptr; if !new_child_ptr.is_null() { (*new_child_ptr).parent_ptr = subtree; } - (*new_root).child_ptrs[direction] = subtree; + (*new_root).child_ptr[direction] = subtree; (*new_root).parent_ptr = parent_ptr; (*subtree).parent_ptr = new_root; if !parent_ptr.is_null() { - (*parent_ptr).child_ptrs - [(subtree as *const TreeNode == (*parent_ptr).child_ptrs[tree::DIR_R]) as usize] = + (*parent_ptr).child_ptr + [(subtree as *const TreeNode == (*parent_ptr).child_ptr[tree::DIR_R]) as usize] = new_root; } else { (*tree).root_ptr = new_root; From b2126975383bffa6705178313fb767be5b43ac7e Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:51:14 -0800 Subject: [PATCH 164/263] Take out _ptr --- .../snippets/interface/tree-defs-common.txt | 14 +++--- .../snippets/rs/initialize-create-account.txt | 16 +++---- .../tree/artifacts/snippets/rs/insert.txt | 4 +- examples/tree/interface/src/asm.rs | 4 +- examples/tree/interface/src/common.rs | 14 +++--- examples/tree/src/program.rs | 48 +++++++++---------- examples/tree/src/tests/init.rs | 2 +- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index 65c2f1b5..6a7c5864 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -24,7 +24,7 @@ constant_group! { /// Red color. COLOR_R = Color::Red as u8, /// Next node field in header. - offset!(HEADER_NEXT, TreeHeader.next_ptr), + offset!(HEADER_NEXT, TreeHeader.next), } } @@ -32,17 +32,17 @@ constant_group! { /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { /// Aboslute pointer to tree root in memory map. - pub root_ptr: *mut TreeNode, + pub root: *mut TreeNode, /// Absolute pointer to stack top in memory map. - pub top_ptr: *mut StackNode, + pub top: *mut StackNode, /// Absolute pointer to where the next node should be allocated in memory map. - pub next_ptr: *mut TreeNode, + pub next: *mut TreeNode, } #[repr(C, packed)] pub struct TreeNode { - pub parent_ptr: *mut TreeNode, - pub child_ptr: [*mut TreeNode; tree::N_CHILDREN], + pub parent: *mut TreeNode, + pub child: [*mut TreeNode; tree::N_CHILDREN], pub key: u16, pub value: u16, pub color: Color, @@ -50,5 +50,5 @@ pub struct TreeNode { #[repr(C, packed)] pub struct StackNode { - pub next_ptr: *mut StackNode, + pub next: *mut StackNode, } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 0013540f..5df270f0 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -12,27 +12,27 @@ }; // Pack account metas and infos. - let user_key_ptr = input_buffer_ptr + let user_key = input_buffer_ptr .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); - let tree_key_ptr = input_buffer_ptr + let tree_key = input_buffer_ptr .add(input_buffer::TREE_ADDRESS_OFF as usize) .cast(); let sol_account_metas = [ SolAccountMeta { - pubkey: user_key_ptr, + pubkey: user_key, is_writable: true, is_signer: true, }, SolAccountMeta { - pubkey: tree_key_ptr, + pubkey: tree_key, is_writable: true, is_signer: true, }, ]; let sol_account_infos = [ SolAccountInfo { - key: user_key_ptr, + key: user_key, owner: input_buffer_ptr .add(input_buffer::USER_OWNER_OFF as usize) .cast(), @@ -47,7 +47,7 @@ executable: false, }, SolAccountInfo { - key: tree_key_ptr, + key: tree_key, owner: input_buffer_ptr .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), @@ -106,5 +106,5 @@ } // Store next pointer in tree header. - let next_ptr = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next_ptr = next_ptr; \ No newline at end of file + let next = tree.data_ptr().add(size_of::()).cast(); + (*tree.data_ptr().cast::()).next = next; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 6a02e0ad..4b40b712 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -9,10 +9,10 @@ unsafe fn insert( error::INSTRUCTION_DATA_LEN ); - let tree_header_ptr: *mut TreeHeader = + let tree_header: *mut TreeHeader = transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); - if (*tree_header_ptr).top_ptr.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } SUCCESS diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 3cefcb80..e5ff8ae8 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -240,9 +240,9 @@ asm_constant_group! { extend_constant_group!(tree { prefix = "TREE", /// Tree root. - offset!(ROOT, TreeHeader.root_ptr), + offset!(ROOT, TreeHeader.root), /// Stack top. - offset!(TOP, TreeHeader.top_ptr), + offset!(TOP, TreeHeader.top), /// Discriminator for insert instruction. DISCRIMINATOR_INSERT = Instruction::Insert as u8, }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index d9d9d3c9..1ba18981 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -176,7 +176,7 @@ constant_group! { /// Red color. COLOR_R = Color::Red as u8, /// Next node field in header. - offset!(HEADER_NEXT, TreeHeader.next_ptr), + offset!(HEADER_NEXT, TreeHeader.next), } } @@ -184,17 +184,17 @@ constant_group! { /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { /// Aboslute pointer to tree root in memory map. - pub root_ptr: *mut TreeNode, + pub root: *mut TreeNode, /// Absolute pointer to stack top in memory map. - pub top_ptr: *mut StackNode, + pub top: *mut StackNode, /// Absolute pointer to where the next node should be allocated in memory map. - pub next_ptr: *mut TreeNode, + pub next: *mut TreeNode, } #[repr(C, packed)] pub struct TreeNode { - pub parent_ptr: *mut TreeNode, - pub child_ptr: [*mut TreeNode; tree::N_CHILDREN], + pub parent: *mut TreeNode, + pub child: [*mut TreeNode; tree::N_CHILDREN], pub key: u16, pub value: u16, pub color: Color, @@ -202,7 +202,7 @@ pub struct TreeNode { #[repr(C, packed)] pub struct StackNode { - pub next_ptr: *mut StackNode, + pub next: *mut StackNode, } // ANCHOR_END: tree-defs-common diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 9c39d274..c39b684c 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -112,10 +112,10 @@ unsafe fn insert( error::INSTRUCTION_DATA_LEN ); - let tree_header_ptr: *mut TreeHeader = + let tree_header: *mut TreeHeader = transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); - if (*tree_header_ptr).top_ptr.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } SUCCESS @@ -207,27 +207,27 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }; // Pack account metas and infos. - let user_key_ptr = input_buffer_ptr + let user_key = input_buffer_ptr .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); - let tree_key_ptr = input_buffer_ptr + let tree_key = input_buffer_ptr .add(input_buffer::TREE_ADDRESS_OFF as usize) .cast(); let sol_account_metas = [ SolAccountMeta { - pubkey: user_key_ptr, + pubkey: user_key, is_writable: true, is_signer: true, }, SolAccountMeta { - pubkey: tree_key_ptr, + pubkey: tree_key, is_writable: true, is_signer: true, }, ]; let sol_account_infos = [ SolAccountInfo { - key: user_key_ptr, + key: user_key, owner: input_buffer_ptr .add(input_buffer::USER_OWNER_OFF as usize) .cast(), @@ -242,7 +242,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - executable: false, }, SolAccountInfo { - key: tree_key_ptr, + key: tree_key, owner: input_buffer_ptr .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), @@ -301,8 +301,8 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - } // Store next pointer in tree header. - let next_ptr = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next_ptr = next_ptr; + let next = tree.data_ptr().add(size_of::()).cast(); + (*tree.data_ptr().cast::()).next = next; // ANCHOR_END: initialize-create-account SUCCESS @@ -311,7 +311,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - /// Return the direction of the node with respect to its parent. #[inline(always)] unsafe fn direction(node: *const TreeNode) -> Direction { - if node == (*(*node).parent_ptr).child_ptr[tree::DIR_R] { + if node == (*(*node).parent).child[tree::DIR_R] { Direction::Right } else { Direction::Left @@ -330,26 +330,26 @@ unsafe fn rotate_subtree( subtree: *mut TreeNode, direction: usize, ) -> *mut TreeNode { - let parent_ptr = (*subtree).parent_ptr; - let new_root = (*subtree).child_ptr[opposite(direction)]; - let new_child_ptr = (*new_root).child_ptr[direction]; + let parent = (*subtree).parent; + let new_root = (*subtree).child[opposite(direction)]; + let new_child = (*new_root).child[direction]; - (*subtree).child_ptr[opposite(direction)] = new_child_ptr; + (*subtree).child[opposite(direction)] = new_child; - if !new_child_ptr.is_null() { - (*new_child_ptr).parent_ptr = subtree; + if !new_child.is_null() { + (*new_child).parent = subtree; } - (*new_root).child_ptr[direction] = subtree; - (*new_root).parent_ptr = parent_ptr; - (*subtree).parent_ptr = new_root; + (*new_root).child[direction] = subtree; + (*new_root).parent = parent; + (*subtree).parent = new_root; - if !parent_ptr.is_null() { - (*parent_ptr).child_ptr - [(subtree as *const TreeNode == (*parent_ptr).child_ptr[tree::DIR_R]) as usize] = + if !parent.is_null() { + (*parent).child + [(subtree as *const TreeNode == (*parent).child[tree::DIR_R]) as usize] = new_root; } else { - (*tree).root_ptr = new_root; + (*tree).root = new_root; } new_root diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 8b526118..90541fc6 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -457,7 +457,7 @@ impl TestCase for InitCase { + input_buffer::TREE_DATA_OFF as u64 + size_of::() as u64; let header = unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; - let actual_next = header.next_ptr as u64; + let actual_next = header.next as u64; if actual_next != expected_next { errors.push(format!( "next: expected {:#x}, got {:#x}", From 9d3cf57bc39858109c83c0061cbc453906ca36df Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:02:24 -0800 Subject: [PATCH 165/263] Take out more _ptr --- .../snippets/rs/entrypoint-branching.txt | 10 +-- .../snippets/rs/general-branching.txt | 12 +-- .../snippets/rs/initialize-create-account.txt | 24 +++--- .../snippets/rs/initialize-input-checks.txt | 12 +-- .../snippets/rs/initialize-pda-checks.txt | 6 +- .../tree/artifacts/snippets/rs/insert.txt | 6 +- examples/tree/src/program.rs | 74 +++++++++---------- 7 files changed, 72 insertions(+), 72 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 86839c75..ee1cb315 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -3,14 +3,14 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint( - input_buffer_ptr: *mut u8, - instruction_data_ptr: *mut u8, + input: *mut u8, + instruction_data: *mut u8, ) -> u64 { - let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input_buffer_ptr, instruction_data_ptr) + general(input, instruction_data) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr, instruction_data_ptr) + initialize(input, instruction_data) } else { error::N_ACCOUNTS.into() } diff --git a/examples/tree/artifacts/snippets/rs/general-branching.txt b/examples/tree/artifacts/snippets/rs/general-branching.txt index 0fcf9fc5..b4e283ac 100644 --- a/examples/tree/artifacts/snippets/rs/general-branching.txt +++ b/examples/tree/artifacts/snippets/rs/general-branching.txt @@ -1,19 +1,19 @@ #[inline(always)] -unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { +unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. - let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate. - let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); // Get instruction data length and discriminator, branch to instruction. - let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); if likely( - ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, + ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, ) { - insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) + insert(input, instruction_data, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() } diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index 5df270f0..b8e4f463 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,21 +1,21 @@ // Pack CreateAccount instruction data. - let instruction_data = CreateAccountInstructionData { + let create_account_instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + * ldxdw(input, input_buffer::RENT_DATA_OFF), space: cpi::TREE_DATA_LEN as u64, owner: read_unaligned( - input_buffer_ptr + input .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) .cast(), ), }; // Pack account metas and infos. - let user_key = input_buffer_ptr + let user_key = input .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); - let tree_key = input_buffer_ptr + let tree_key = input .add(input_buffer::TREE_ADDRESS_OFF as usize) .cast(); let sol_account_metas = [ @@ -33,13 +33,13 @@ let sol_account_infos = [ SolAccountInfo { key: user_key, - owner: input_buffer_ptr + owner: input .add(input_buffer::USER_OWNER_OFF as usize) .cast(), - lamports: input_buffer_ptr + lamports: input .add(input_buffer::USER_LAMPORTS_OFF as usize) .cast(), - data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), + data: input.add(input_buffer::USER_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, @@ -48,13 +48,13 @@ }, SolAccountInfo { key: tree_key, - owner: input_buffer_ptr + owner: input .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), - lamports: input_buffer_ptr + lamports: input .add(input_buffer::TREE_LAMPORTS_OFF as usize) .cast(), - data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), + data: input.add(input_buffer::TREE_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, @@ -71,7 +71,7 @@ accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, account_len: sol_account_metas.len() as u64, #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - data: transmute(&instruction_data), + data: transmute(&create_account_instruction_data), data_len: cpi::INSN_DATA_LEN as u64, }; diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 4912538c..992696a4 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,16 +1,16 @@ #[inline(always)] -unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { +unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. - let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate or has data. - let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - let system_program = account_at(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); + let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); if_err!( is_duplicate(&system_program), error::SYSTEM_PROGRAM_DUPLICATE @@ -21,7 +21,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); + let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( !address_eq(rent_sysvar.address(), &RENT_ID), @@ -29,7 +29,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // Error if instruction data provided. - let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); if_err!( instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 7808d48f..55281c70 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -6,9 +6,9 @@ // Get input buffer footer pointer. sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. - input_buffer_ptr, + input, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), + input.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); @@ -22,7 +22,7 @@ !address_eq( &pda, #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] - transmute(input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) + transmute(input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) ), error::PDA_MISMATCH ); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 4b40b712..33675283 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -1,7 +1,7 @@ #[inline(always)] unsafe fn insert( - input_buffer_ptr: *mut u8, - instruction_data_ptr: *mut u8, + input: *mut u8, + instruction_data: *mut u8, instruction_data_len: u64, ) -> u64 { if_err!( @@ -10,7 +10,7 @@ unsafe fn insert( ); let tree_header: *mut TreeHeader = - transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); + transmute(input.add(input_buffer::TREE_DATA_OFF as usize)); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index c39b684c..19bd6bfc 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -21,8 +21,8 @@ use { }; #[inline(always)] -unsafe fn account_at(input_buffer_ptr: *mut u8, offset: i16) -> AccountView { - AccountView::new_unchecked(input_buffer_ptr.add(offset as usize).cast()) +unsafe fn account_at(input: *mut u8, offset: i16) -> AccountView { + AccountView::new_unchecked(input.add(offset as usize).cast()) } #[inline(always)] @@ -63,14 +63,14 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint( - input_buffer_ptr: *mut u8, - instruction_data_ptr: *mut u8, + input: *mut u8, + instruction_data: *mut u8, ) -> u64 { - let n_accounts = ldxdw(input_buffer_ptr, input_buffer::N_ACCOUNTS_OFF); + let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input_buffer_ptr, instruction_data_ptr) + general(input, instruction_data) } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input_buffer_ptr, instruction_data_ptr) + initialize(input, instruction_data) } else { error::N_ACCOUNTS.into() } @@ -79,21 +79,21 @@ pub unsafe extern "C" fn entrypoint( // ANCHOR: general-branching #[inline(always)] -unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { +unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. - let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate. - let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); // Get instruction data length and discriminator, branch to instruction. - let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); if likely( - ldxb(instruction_data_ptr, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, + ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, ) { - insert(input_buffer_ptr, instruction_data_ptr, instruction_data_len) + insert(input, instruction_data, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() } @@ -103,8 +103,8 @@ unsafe fn general(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u // ANCHOR: insert #[inline(always)] unsafe fn insert( - input_buffer_ptr: *mut u8, - instruction_data_ptr: *mut u8, + input: *mut u8, + instruction_data: *mut u8, instruction_data_len: u64, ) -> u64 { if_err!( @@ -113,7 +113,7 @@ unsafe fn insert( ); let tree_header: *mut TreeHeader = - transmute(input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize)); + transmute(input.add(input_buffer::TREE_DATA_OFF as usize)); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } @@ -124,18 +124,18 @@ unsafe fn insert( // ANCHOR: initialize-input-checks #[inline(always)] -unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) -> u64 { +unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. - let user = account_at(input_buffer_ptr, input_buffer::USER_ACCOUNT_OFF); + let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!(!user.is_data_empty(), error::USER_DATA_LEN); // Error if tree is duplicate or has data. - let tree = account_at(input_buffer_ptr, input_buffer::TREE_ACCOUNT_OFF); + let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - let system_program = account_at(input_buffer_ptr, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); + let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); if_err!( is_duplicate(&system_program), error::SYSTEM_PROGRAM_DUPLICATE @@ -146,7 +146,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = account_at(input_buffer_ptr, input_buffer::RENT_ACCOUNT_OFF); + let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); if_err!( !address_eq(rent_sysvar.address(), &RENT_ID), @@ -154,7 +154,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - ); // Error if instruction data provided. - let instruction_data_len = ldxdw(instruction_data_ptr, -(size_of::() as i16)); + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); if_err!( instruction_data_len != data::DATA_LEN_ZERO, error::INSTRUCTION_DATA @@ -170,9 +170,9 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // Get input buffer footer pointer. sol_try_find_program_address( // Pass a declared pointer instead of null to prevent unnecessary register assignment. - input_buffer_ptr, + input, cpi::N_SEEDS_TRY_FIND_PDA, - input_buffer_ptr.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), + input.add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize), pda.as_mut_ptr().cast(), bump.as_mut_ptr(), ); @@ -186,7 +186,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - !address_eq( &pda, #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] - transmute(input_buffer_ptr.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) + transmute(input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) ), error::PDA_MISMATCH ); @@ -194,23 +194,23 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - // ANCHOR: initialize-create-account // Pack CreateAccount instruction data. - let instruction_data = CreateAccountInstructionData { + let create_account_instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input_buffer_ptr, input_buffer::RENT_DATA_OFF), + * ldxdw(input, input_buffer::RENT_DATA_OFF), space: cpi::TREE_DATA_LEN as u64, owner: read_unaligned( - input_buffer_ptr + input .add(input_buffer::INIT_PROGRAM_ID_OFF_IMM as usize) .cast(), ), }; // Pack account metas and infos. - let user_key = input_buffer_ptr + let user_key = input .add(input_buffer::USER_ADDRESS_OFF as usize) .cast(); - let tree_key = input_buffer_ptr + let tree_key = input .add(input_buffer::TREE_ADDRESS_OFF as usize) .cast(); let sol_account_metas = [ @@ -228,13 +228,13 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - let sol_account_infos = [ SolAccountInfo { key: user_key, - owner: input_buffer_ptr + owner: input .add(input_buffer::USER_OWNER_OFF as usize) .cast(), - lamports: input_buffer_ptr + lamports: input .add(input_buffer::USER_LAMPORTS_OFF as usize) .cast(), - data: input_buffer_ptr.add(input_buffer::USER_DATA_OFF as usize), + data: input.add(input_buffer::USER_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, @@ -243,13 +243,13 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - }, SolAccountInfo { key: tree_key, - owner: input_buffer_ptr + owner: input .add(input_buffer::TREE_OWNER_OFF as usize) .cast(), - lamports: input_buffer_ptr + lamports: input .add(input_buffer::TREE_LAMPORTS_OFF as usize) .cast(), - data: input_buffer_ptr.add(input_buffer::TREE_DATA_OFF as usize), + data: input.add(input_buffer::TREE_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, is_signer: true, @@ -266,7 +266,7 @@ unsafe fn initialize(input_buffer_ptr: *mut u8, instruction_data_ptr: *mut u8) - accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, account_len: sol_account_metas.len() as u64, #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - data: transmute(&instruction_data), + data: transmute(&create_account_instruction_data), data_len: cpi::INSN_DATA_LEN as u64, }; From 71851f7197d13baf386b16d27bdb2a62e67a2352 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:40:06 -0800 Subject: [PATCH 166/263] Clean up ptr style --- .../snippets/rs/entrypoint-branching.txt | 5 +- .../snippets/rs/general-branching.txt | 8 +- .../snippets/rs/initialize-create-account.txt | 51 +++----- .../snippets/rs/initialize-input-checks.txt | 15 ++- .../snippets/rs/initialize-pda-checks.txt | 5 +- .../tree/artifacts/snippets/rs/insert.txt | 9 +- examples/tree/src/program.rs | 121 ++++++++---------- 7 files changed, 83 insertions(+), 131 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index ee1cb315..1ecbee2c 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -2,10 +2,7 @@ no_allocator!(); nostd_panic_handler!(); #[no_mangle] -pub unsafe extern "C" fn entrypoint( - input: *mut u8, - instruction_data: *mut u8, -) -> u64 { +pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { general(input, instruction_data) diff --git a/examples/tree/artifacts/snippets/rs/general-branching.txt b/examples/tree/artifacts/snippets/rs/general-branching.txt index b4e283ac..fc70e7e2 100644 --- a/examples/tree/artifacts/snippets/rs/general-branching.txt +++ b/examples/tree/artifacts/snippets/rs/general-branching.txt @@ -2,17 +2,15 @@ unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + if_err!((*user).data_len != 0, error::USER_DATA_LEN); // Error if tree is duplicate. let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + if_err!(is_duplicate(tree), error::TREE_DUPLICATE); // Get instruction data length and discriminator, branch to instruction. let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if likely( - ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, - ) { + if likely(ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8) { insert(input, instruction_data, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index b8e4f463..a18fbeca 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -1,8 +1,7 @@ // Pack CreateAccount instruction data. let create_account_instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, - lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input, input_buffer::RENT_DATA_OFF), + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input, input_buffer::RENT_DATA_OFF), space: cpi::TREE_DATA_LEN as u64, owner: read_unaligned( input @@ -12,12 +11,8 @@ }; // Pack account metas and infos. - let user_key = input - .add(input_buffer::USER_ADDRESS_OFF as usize) - .cast(); - let tree_key = input - .add(input_buffer::TREE_ADDRESS_OFF as usize) - .cast(); + let user_key = input.add(input_buffer::USER_ADDRESS_OFF as usize).cast(); + let tree_key = input.add(input_buffer::TREE_ADDRESS_OFF as usize).cast(); let sol_account_metas = [ SolAccountMeta { pubkey: user_key, @@ -33,12 +28,8 @@ let sol_account_infos = [ SolAccountInfo { key: user_key, - owner: input - .add(input_buffer::USER_OWNER_OFF as usize) - .cast(), - lamports: input - .add(input_buffer::USER_LAMPORTS_OFF as usize) - .cast(), + owner: input.add(input_buffer::USER_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::USER_LAMPORTS_OFF as usize).cast(), data: input.add(input_buffer::USER_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, @@ -48,12 +39,8 @@ }, SolAccountInfo { key: tree_key, - owner: input - .add(input_buffer::TREE_OWNER_OFF as usize) - .cast(), - lamports: input - .add(input_buffer::TREE_LAMPORTS_OFF as usize) - .cast(), + owner: input.add(input_buffer::TREE_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::TREE_LAMPORTS_OFF as usize).cast(), data: input.add(input_buffer::TREE_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, @@ -66,35 +53,31 @@ // Pack instruction. let system_program_address = Address::default(); let sol_instruction = SolInstruction { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - program_id: transmute(&system_program_address), - accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, + program_id: addr_of!(system_program_address).cast_mut().cast(), + accounts: sol_account_metas.as_ptr().cast_mut().cast(), account_len: sol_account_metas.len() as u64, - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - data: transmute(&create_account_instruction_data), + data: addr_of!(create_account_instruction_data).cast_mut().cast(), data_len: cpi::INSN_DATA_LEN as u64, }; // Initialize signer seed for PDA bump. let bump_seed = SolSignerSeed { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - addr: transmute(&bump), + addr: addr_of!(bump).cast(), len: size_of::() as u64, }; // Initialize signer seeds for PDA. let signers_seeds = SolSignerSeeds { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - addr: transmute(&bump_seed), + addr: addr_of!(bump_seed).cast(), len: cpi::N_SEEDS as u64, }; #[cfg(target_os = "solana")] sol_invoke_signed_c( - transmute(&sol_instruction), - transmute(&sol_account_infos), + addr_of!(sol_instruction).cast(), + addr_of!(sol_account_infos).cast(), cpi::N_ACCOUNTS as u64, - transmute(&signers_seeds), + addr_of!(signers_seeds).cast(), cpi::N_PDA_SIGNERS as u64, ); #[cfg(not(target_os = "solana"))] @@ -106,5 +89,5 @@ } // Store next pointer in tree header. - let next = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next = next; \ No newline at end of file + let tree_data: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); + (*tree_data).next = tree_data.add(1).cast(); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 992696a4..2937d7dc 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -2,29 +2,30 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + if_err!((*user).data_len != 0, error::USER_DATA_LEN); // Error if tree is duplicate or has data. let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); - if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); + if_err!(is_duplicate(tree), error::TREE_DUPLICATE); + if_err!((*tree).data_len != 0, error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); if_err!( - is_duplicate(&system_program), + is_duplicate(system_program), error::SYSTEM_PROGRAM_DUPLICATE ); if_err!( - system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, + (*system_program).data_len as usize != input_buffer::SYSTEM_PROGRAM_DATA_LEN, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if Rent account is duplicate or has incorrect address. let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); - if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); + if_err!(is_duplicate(rent_sysvar), error::RENT_DUPLICATE); + let rent_id = RENT_ID; if_err!( - !address_eq(rent_sysvar.address(), &RENT_ID), + !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), error::RENT_ADDRESS ); diff --git a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt index 55281c70..99e7e8a4 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-pda-checks.txt @@ -20,9 +20,8 @@ // Compare result with passed PDA. if_err!( !address_eq( - &pda, - #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] - transmute(input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) + addr_of!(pda), + input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize).cast() ), error::PDA_MISMATCH ); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 33675283..70be4634 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -1,16 +1,11 @@ #[inline(always)] -unsafe fn insert( - input: *mut u8, - instruction_data: *mut u8, - instruction_data_len: u64, -) -> u64 { +unsafe fn insert(input: *mut u8, instruction_data: *mut u8, instruction_data_len: u64) -> u64 { if_err!( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN ); - let tree_header: *mut TreeHeader = - transmute(input.add(input_buffer::TREE_DATA_OFF as usize)); + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 19bd6bfc..303659f8 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,11 +1,11 @@ -use core::mem::transmute; -use core::ptr::read_unaligned; +use core::ptr::{addr_of, read_unaligned}; use pinocchio::{ - address::address_eq, + account::RuntimeAccount, + entrypoint::NON_DUP_MARKER, hint::{likely, unlikely}, no_allocator, nostd_panic_handler, sysvars::rent::RENT_ID, - AccountView, Address, SUCCESS, + Address, SUCCESS, }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, @@ -21,8 +21,8 @@ use { }; #[inline(always)] -unsafe fn account_at(input: *mut u8, offset: i16) -> AccountView { - AccountView::new_unchecked(input.add(offset as usize).cast()) +unsafe fn account_at(input: *mut u8, offset: i16) -> *mut RuntimeAccount { + input.add(offset as usize).cast() } #[inline(always)] @@ -38,8 +38,16 @@ unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { /// Checks if the account is a duplicate by checking if it's borrowed, since this is equivalent /// via the underlying API due to the borrow state implementation. #[inline(always)] -fn is_duplicate(account: &AccountView) -> bool { - account.is_borrowed() +unsafe fn is_duplicate(account: *const RuntimeAccount) -> bool { + (*account).borrow_state != NON_DUP_MARKER +} + +/// Compares two addresses by pointer, avoiding references in calling code while harnessing +/// the underlying `address_eq` implementation which is assembly-optimal. +#[inline(always)] +unsafe fn address_eq(a: *const Address, b: *const Address) -> bool { + use pinocchio::address::address_eq as eq; + eq(&*a, &*b) } /// Insert a syscall to log CUs, useful for sectioning off disassembled program. @@ -62,10 +70,7 @@ no_allocator!(); nostd_panic_handler!(); #[no_mangle] -pub unsafe extern "C" fn entrypoint( - input: *mut u8, - instruction_data: *mut u8, -) -> u64 { +pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { general(input, instruction_data) @@ -82,17 +87,15 @@ pub unsafe extern "C" fn entrypoint( unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + if_err!((*user).data_len != 0, error::USER_DATA_LEN); // Error if tree is duplicate. let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); + if_err!(is_duplicate(tree), error::TREE_DUPLICATE); // Get instruction data length and discriminator, branch to instruction. let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if likely( - ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8, - ) { + if likely(ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8) { insert(input, instruction_data, instruction_data_len) } else { error::INSTRUCTION_DISCRIMINATOR.into() @@ -102,18 +105,13 @@ unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { // ANCHOR: insert #[inline(always)] -unsafe fn insert( - input: *mut u8, - instruction_data: *mut u8, - instruction_data_len: u64, -) -> u64 { +unsafe fn insert(input: *mut u8, instruction_data: *mut u8, instruction_data_len: u64) -> u64 { if_err!( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN ); - let tree_header: *mut TreeHeader = - transmute(input.add(input_buffer::TREE_DATA_OFF as usize)); + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. } @@ -127,29 +125,30 @@ unsafe fn insert( unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!(!user.is_data_empty(), error::USER_DATA_LEN); + if_err!((*user).data_len != 0, error::USER_DATA_LEN); // Error if tree is duplicate or has data. let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(&tree), error::TREE_DUPLICATE); - if_err!(!tree.is_data_empty(), error::TREE_DATA_LEN); + if_err!(is_duplicate(tree), error::TREE_DUPLICATE); + if_err!((*tree).data_len != 0, error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); if_err!( - is_duplicate(&system_program), + is_duplicate(system_program), error::SYSTEM_PROGRAM_DUPLICATE ); if_err!( - system_program.data_len() != input_buffer::SYSTEM_PROGRAM_DATA_LEN, + (*system_program).data_len as usize != input_buffer::SYSTEM_PROGRAM_DATA_LEN, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if Rent account is duplicate or has incorrect address. let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); - if_err!(is_duplicate(&rent_sysvar), error::RENT_DUPLICATE); + if_err!(is_duplicate(rent_sysvar), error::RENT_DUPLICATE); + let rent_id = RENT_ID; if_err!( - !address_eq(rent_sysvar.address(), &RENT_ID), + !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), error::RENT_ADDRESS ); @@ -184,9 +183,8 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Compare result with passed PDA. if_err!( !address_eq( - &pda, - #[allow(clippy::transmute_ptr_to_ref, clippy::missing_transmute_annotations)] - transmute(input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize)) + addr_of!(pda), + input.add(input_buffer::TREE_ADDRESS_OFF_0 as usize).cast() ), error::PDA_MISMATCH ); @@ -196,8 +194,7 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Pack CreateAccount instruction data. let create_account_instruction_data = CreateAccountInstructionData { discriminator: cpi::CREATE_ACCOUNT_DISCRIMINATOR, - lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) - * ldxdw(input, input_buffer::RENT_DATA_OFF), + lamports: (cpi::ACCOUNT_DATA_SCALAR as u64) * ldxdw(input, input_buffer::RENT_DATA_OFF), space: cpi::TREE_DATA_LEN as u64, owner: read_unaligned( input @@ -207,12 +204,8 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { }; // Pack account metas and infos. - let user_key = input - .add(input_buffer::USER_ADDRESS_OFF as usize) - .cast(); - let tree_key = input - .add(input_buffer::TREE_ADDRESS_OFF as usize) - .cast(); + let user_key = input.add(input_buffer::USER_ADDRESS_OFF as usize).cast(); + let tree_key = input.add(input_buffer::TREE_ADDRESS_OFF as usize).cast(); let sol_account_metas = [ SolAccountMeta { pubkey: user_key, @@ -228,12 +221,8 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { let sol_account_infos = [ SolAccountInfo { key: user_key, - owner: input - .add(input_buffer::USER_OWNER_OFF as usize) - .cast(), - lamports: input - .add(input_buffer::USER_LAMPORTS_OFF as usize) - .cast(), + owner: input.add(input_buffer::USER_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::USER_LAMPORTS_OFF as usize).cast(), data: input.add(input_buffer::USER_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, @@ -243,12 +232,8 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { }, SolAccountInfo { key: tree_key, - owner: input - .add(input_buffer::TREE_OWNER_OFF as usize) - .cast(), - lamports: input - .add(input_buffer::TREE_LAMPORTS_OFF as usize) - .cast(), + owner: input.add(input_buffer::TREE_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::TREE_LAMPORTS_OFF as usize).cast(), data: input.add(input_buffer::TREE_DATA_OFF as usize), data_len: data::DATA_LEN_ZERO, rent_epoch: cpi::RENT_EPOCH_NULL, @@ -261,35 +246,31 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { // Pack instruction. let system_program_address = Address::default(); let sol_instruction = SolInstruction { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - program_id: transmute(&system_program_address), - accounts: sol_account_metas.as_ptr() as *mut SolAccountMeta, + program_id: addr_of!(system_program_address).cast_mut().cast(), + accounts: sol_account_metas.as_ptr().cast_mut().cast(), account_len: sol_account_metas.len() as u64, - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - data: transmute(&create_account_instruction_data), + data: addr_of!(create_account_instruction_data).cast_mut().cast(), data_len: cpi::INSN_DATA_LEN as u64, }; // Initialize signer seed for PDA bump. let bump_seed = SolSignerSeed { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - addr: transmute(&bump), + addr: addr_of!(bump).cast(), len: size_of::() as u64, }; // Initialize signer seeds for PDA. let signers_seeds = SolSignerSeeds { - #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] - addr: transmute(&bump_seed), + addr: addr_of!(bump_seed).cast(), len: cpi::N_SEEDS as u64, }; #[cfg(target_os = "solana")] sol_invoke_signed_c( - transmute(&sol_instruction), - transmute(&sol_account_infos), + addr_of!(sol_instruction).cast(), + addr_of!(sol_account_infos).cast(), cpi::N_ACCOUNTS as u64, - transmute(&signers_seeds), + addr_of!(signers_seeds).cast(), cpi::N_PDA_SIGNERS as u64, ); #[cfg(not(target_os = "solana"))] @@ -301,8 +282,8 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { } // Store next pointer in tree header. - let next = tree.data_ptr().add(size_of::()).cast(); - (*tree.data_ptr().cast::()).next = next; + let tree_data: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); + (*tree_data).next = tree_data.add(1).cast(); // ANCHOR_END: initialize-create-account SUCCESS @@ -345,9 +326,7 @@ unsafe fn rotate_subtree( (*subtree).parent = new_root; if !parent.is_null() { - (*parent).child - [(subtree as *const TreeNode == (*parent).child[tree::DIR_R]) as usize] = - new_root; + (*parent).child[(subtree == (*parent).child[tree::DIR_R]) as usize] = new_root; } else { (*tree).root = new_root; } From cb41b73f94eac20e82b18db06e628b23f0fabc97 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:12:59 -0800 Subject: [PATCH 167/263] Update RS impl, tests --- examples/tree/artifacts/dumps/asm.txt | 2 +- examples/tree/artifacts/dumps/rs.txt | 365 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 187 +++++---- .../tree/artifacts/snippets/asm/constants.txt | 2 +- .../snippets/interface/instructions.txt | 9 +- .../snippets/rs/entrypoint-branching.txt | 15 +- .../snippets/rs/general-branching.txt | 18 - .../snippets/rs/initialize-input-checks.txt | 26 +- .../tree/artifacts/snippets/rs/insert.txt | 8 +- .../tests/entrypoint_branching/result.txt | 31 +- .../tests/general_branching/result.txt | 24 -- .../tests/general_branching/test.txt | 4 - .../initialize_create_account/result.txt | 33 +- .../tests/initialize_create_account/test.txt | 2 +- .../tests/initialize_input_checks/result.txt | 81 ++-- .../tests/initialize_input_checks/test.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 36 +- .../tests/initialize_pda_checks/test.txt | 2 +- .../tree/artifacts/tests/insert/result.txt | 12 +- examples/tree/interface/src/common.rs | 11 +- examples/tree/interface/src/lib.rs | 2 +- examples/tree/src/program.rs | 74 ++-- examples/tree/src/tests.rs | 12 +- examples/tree/src/tests/entrypoint.rs | 77 ++-- examples/tree/src/tests/general.rs | 95 ----- examples/tree/src/tests/init.rs | 73 +++- examples/tree/src/tree/tree.s | 2 +- 27 files changed, 544 insertions(+), 661 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/rs/general-branching.txt delete mode 100644 examples/tree/artifacts/tests/general_branching/result.txt delete mode 100644 examples/tree/artifacts/tests/general_branching/test.txt delete mode 100644 examples/tree/src/tests/general.rs diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 246d589c..b7775ced 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -125,7 +125,7 @@ Disassembly of section .text 71 55 09 52 00 00 00 00 00 if r9 != 0x0 goto +0x52 72 b7 02 00 00 00 00 00 00 r2 = 0x0 73 bf 13 00 00 00 00 00 00 r3 = r1 - 74 07 03 00 00 b8 a1 00 00 r3 += 0xa1b8 + 74 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 75 bf a4 00 00 00 00 00 00 r4 = r10 76 07 04 00 00 b0 ff ff ff r4 += -0x50 77 bf a5 00 00 00 00 00 00 r5 = r10 diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 01505c90..dee5ee54 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3968 (bytes into file) + Start of section headers 3912 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf80 +There are 8 section headers, starting at offset 0xf48 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000570 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000690 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000698 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000698 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000698 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000a10 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000a4e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000538 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000658 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000660 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000660 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000660 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 0009d8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000a16 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000570 0x000570 E 0x8 - LOAD 0x000690 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000698 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000698 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000538 0x000538 E 0x8 + LOAD 0x000658 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000660 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000660 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1392 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 1336 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -105,176 +105,169 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 - 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 10 55 03 0a 00 02 00 00 00 jne r3, 0x2, +0xa - 18 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 20 55 03 93 00 00 00 00 00 jne r3, 0x0, +0x93 - 28 2c 11 68 28 00 00 00 00 ldxb w1, [r1 + 0x2868] - 30 55 01 93 00 ff 00 00 00 jne r1, 0xff, +0x93 - 38 2c 21 00 00 00 00 00 00 ldxb w1, [r2 + 0x0] - 40 55 01 93 00 01 00 00 00 jne r1, 0x1, +0x93 - 48 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 50 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] - 58 55 01 92 00 05 00 00 00 jne r1, 0x5, +0x92 - 60 9d 00 00 00 00 00 00 00 return - 68 55 03 94 00 04 00 00 00 jne r3, 0x4, +0x94 - 70 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 78 55 03 88 00 00 00 00 00 jne r3, 0x0, +0x88 - 80 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 88 55 03 88 00 ff 00 00 00 jne r3, 0xff, +0x88 - 90 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 98 55 03 90 00 00 00 00 00 jne r3, 0x0, +0x90 - a0 2c 13 c8 50 00 00 00 00 ldxb w3, [r1 + 0x50c8] - a8 55 03 90 00 ff 00 00 00 jne r3, 0xff, +0x90 - b0 9c 13 18 51 00 00 00 00 ldxdw r3, [r1 + 0x5118] - b8 55 03 90 00 0e 00 00 00 jne r3, 0xe, +0x90 - c0 2c 13 38 79 00 00 00 00 ldxb w3, [r1 + 0x7938] - c8 55 03 90 00 ff 00 00 00 jne r3, 0xff, +0x90 - d0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - d8 b4 03 00 00 06 a7 d5 17 mov32 w3, 0x17d5a706 - e0 f7 03 00 00 19 2c 5c 51 hor64 r3, 0x515c2c19 - e8 9c 14 40 79 00 00 00 00 ldxdw r4, [r1 + 0x7940] - f0 5d 34 ed ff 00 00 00 00 jne r4, r3, -0x13 - f8 b4 03 00 00 21 8c c9 4c mov32 w3, 0x4cc98c21 - 100 f7 03 00 00 3d 4a f1 7f hor64 r3, 0x7ff14a3d - 108 9c 14 48 79 00 00 00 00 ldxdw r4, [r1 + 0x7948] - 110 5d 34 e9 ff 00 00 00 00 jne r4, r3, -0x17 - 118 b4 03 00 00 58 da ee 08 mov32 w3, 0x8eeda58 - 120 f7 03 00 00 9b a1 fd 44 hor64 r3, 0x44fda19b - 128 9c 14 50 79 00 00 00 00 ldxdw r4, [r1 + 0x7950] - 130 5d 34 e5 ff 00 00 00 00 jne r4, r3, -0x1b - 138 9c 13 58 79 00 00 00 00 ldxdw r3, [r1 + 0x7958] - 140 b4 04 00 00 e3 db d9 8a mov32 w4, -0x7526241d - 148 5d 43 e2 ff 00 00 00 00 jne r3, r4, -0x1e - 150 9c 22 f8 ff 00 00 00 00 ldxdw r2, [r2 - 0x8] - 158 55 02 80 00 00 00 00 00 jne r2, 0x0, +0x80 - 160 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 168 07 06 00 00 b8 a1 00 00 add64 r6, 0xa1b8 - 170 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 178 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 180 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 188 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 190 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 198 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 1a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 1a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 1b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 1b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 1c0 5d 21 67 00 00 00 00 00 jne r1, r2, +0x67 - 1c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1d0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1d8 5d 21 64 00 00 00 00 00 jne r1, r2, +0x64 - 1e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1e8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1f0 5d 21 61 00 00 00 00 00 jne r1, r2, +0x61 - 1f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 200 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 208 5d 21 5e 00 00 00 00 00 jne r1, r2, +0x5e - 210 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 218 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 220 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 228 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 230 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 238 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 240 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 248 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 250 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 258 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 260 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 268 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 270 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 278 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 - 280 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 288 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 290 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 298 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 2a0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 2a8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 2b0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 2b8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2c0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 2c8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2d8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2e0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 2f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 300 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 308 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 310 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 318 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 320 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 328 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 330 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 338 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 340 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 348 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 350 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 358 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 360 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 368 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 370 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 378 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 380 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 388 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 390 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 398 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 3a0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 3a8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 3b0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 8 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 10 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] + 18 2c 22 00 00 00 00 00 00 ldxb w2, [r2 + 0x0] + 20 15 02 8d 00 01 00 00 00 jeq r2, 0x1, +0x8d + 28 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 30 55 02 8d 00 00 00 00 00 jne r2, 0x0, +0x8d + 38 55 01 8f 00 01 00 00 00 jne r1, 0x1, +0x8f + 40 9c 61 00 00 00 00 00 00 ldxdw r1, [r6 + 0x0] + 48 55 01 8f 00 04 00 00 00 jne r1, 0x4, +0x8f + 50 9c 61 58 00 00 00 00 00 ldxdw r1, [r6 + 0x58] + 58 55 01 8f 00 00 00 00 00 jne r1, 0x0, +0x8f + 60 2c 61 68 28 00 00 00 00 ldxb w1, [r6 + 0x2868] + 68 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f + 70 9c 61 b8 28 00 00 00 00 ldxdw r1, [r6 + 0x28b8] + 78 55 01 8f 00 00 00 00 00 jne r1, 0x0, +0x8f + 80 2c 61 c8 50 00 00 00 00 ldxb w1, [r6 + 0x50c8] + 88 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f + 90 9c 61 18 51 00 00 00 00 ldxdw r1, [r6 + 0x5118] + 98 55 01 8f 00 0e 00 00 00 jne r1, 0xe, +0x8f + a0 2c 61 38 79 00 00 00 00 ldxb w1, [r6 + 0x7938] + a8 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f + b0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + b8 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 + c0 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 + c8 9c 62 40 79 00 00 00 00 ldxdw r2, [r6 + 0x7940] + d0 5d 12 79 00 00 00 00 00 jne r2, r1, +0x79 + d8 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 + e0 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d + e8 9c 62 48 79 00 00 00 00 ldxdw r2, [r6 + 0x7948] + f0 5d 12 75 00 00 00 00 00 jne r2, r1, +0x75 + f8 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 + 100 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b + 108 9c 62 50 79 00 00 00 00 ldxdw r2, [r6 + 0x7950] + 110 5d 12 71 00 00 00 00 00 jne r2, r1, +0x71 + 118 9c 61 58 79 00 00 00 00 ldxdw r1, [r6 + 0x7958] + 120 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d + 128 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 130 bf 67 00 00 00 00 00 00 mov64 r7, r6 + 138 07 07 00 00 b9 a1 00 00 add64 r7, 0xa1b9 + 140 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 148 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 150 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 158 07 05 00 00 13 00 00 00 add64 r5, 0x13 + 160 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 168 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 170 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 180 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] + 190 5d 21 62 00 00 00 00 00 jne r1, r2, +0x62 + 198 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] + 1a8 5d 21 5f 00 00 00 00 00 jne r1, r2, +0x5f + 1b0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] + 1c0 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c + 1c8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 1d0 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] + 1d8 5d 21 59 00 00 00 00 00 jne r1, r2, +0x59 + 1e0 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 1e8 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 1f0 9c 62 90 79 00 00 00 00 ldxdw r2, [r6 + 0x7990] + 1f8 9c 73 18 00 00 00 00 00 ldxdw r3, [r7 + 0x18] + 200 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 208 9c 73 10 00 00 00 00 00 ldxdw r3, [r7 + 0x10] + 210 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 218 9c 73 08 00 00 00 00 00 ldxdw r3, [r7 + 0x8] + 220 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 228 9c 73 00 00 00 00 00 00 ldxdw r3, [r7 + 0x0] + 230 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 238 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 240 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 248 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 + 250 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 258 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 260 bf 62 00 00 00 00 00 00 mov64 r2, r6 + 268 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 270 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 278 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 280 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 288 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 290 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 298 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 2a8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2b0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2b8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 2c0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 2c8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 2d0 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 2d8 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 2e0 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 2e8 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 2f0 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 2f8 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 300 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 308 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 310 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 318 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 320 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 328 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 330 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 338 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 340 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 348 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 350 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 358 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 360 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 368 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 370 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 378 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 380 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 388 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 390 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 398 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3a0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3a8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3b0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c0 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 3c8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3d8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3e0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3f0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3f8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 400 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 408 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 410 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 418 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 420 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 428 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 430 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 438 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 440 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 448 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 450 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 458 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 460 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 468 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 470 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 478 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 480 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 488 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 490 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 498 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 4a0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 4a8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - 4b0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 4b8 05 00 74 ff 00 00 00 00 ja -0x8c - 4c0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 4c8 05 00 72 ff 00 00 00 00 ja -0x8e - 4d0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4d8 05 00 70 ff 00 00 00 00 ja -0x90 - 4e0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 4e8 05 00 6e ff 00 00 00 00 ja -0x92 - 4f0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - 4f8 05 00 6c ff 00 00 00 00 ja -0x94 - 500 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 508 05 00 6a ff 00 00 00 00 ja -0x96 - 510 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 518 05 00 68 ff 00 00 00 00 ja -0x98 - 520 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 528 05 00 66 ff 00 00 00 00 ja -0x9a - 530 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 538 05 00 64 ff 00 00 00 00 ja -0x9c - 540 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 548 05 00 62 ff 00 00 00 00 ja -0x9e - 550 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 558 05 00 60 ff 00 00 00 00 ja -0xa0 - 560 b7 00 00 00 09 00 00 00 mov64 r0, 0x9 - 568 05 00 5e ff 00 00 00 00 ja -0xa2 \ No newline at end of file + 3c0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3c8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 3d0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 3d8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 3e0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3e8 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 3f0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 3f8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 400 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 408 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 410 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 418 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 420 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 428 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 430 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 438 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 440 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 448 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 450 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 458 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 460 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 468 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 470 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 478 9f 16 d0 28 00 00 00 00 stxdw [r6 + 0x28d0], r1 + 480 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 488 05 00 02 00 00 00 00 00 ja +0x2 + 490 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 498 55 01 03 00 05 00 00 00 jne r1, 0x5, +0x3 + 4a0 9d 00 00 00 00 00 00 00 return + 4a8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 4b0 05 00 fd ff 00 00 00 00 ja -0x3 + 4b8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 4c0 05 00 fb ff 00 00 00 00 ja -0x5 + 4c8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 4d0 05 00 f9 ff 00 00 00 00 ja -0x7 + 4d8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 4e0 05 00 f7 ff 00 00 00 00 ja -0x9 + 4e8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 4f0 05 00 f5 ff 00 00 00 00 ja -0xb + 4f8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 500 05 00 f3 ff 00 00 00 00 ja -0xd + 508 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 510 05 00 f1 ff 00 00 00 00 ja -0xf + 518 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 520 05 00 ef ff 00 00 00 00 ja -0x11 + 528 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 530 05 00 ed ff 00 00 00 00 ja -0x13 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 7462f209..eb9db260 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,114 +2,104 @@ entrypoint: add64 r10, -320 - ldxdw r3, [r1+0] - jne r3, 2, jmp_0068 - ldxdw r3, [r1+88] - jne r3, 0, jmp_04c8 - ldxb r1, [r1+10344] - jne r1, 255, jmp_04d8 - ldxb r1, [r2+0] - jne r1, 1, jmp_04e8 - mov64 r0, 0 + mov64 r6, r1 ldxdw r1, [r2-8] - jne r1, 5, jmp_04f8 - -jmp_0060: - exit - -jmp_0068: - jne r3, 4, jmp_0508 - ldxdw r3, [r1+88] - jne r3, 0, jmp_04c8 - ldxb r3, [r1+10344] - jne r3, 255, jmp_04d8 - ldxdw r3, [r1+10424] - jne r3, 0, jmp_0518 - ldxb r3, [r1+20680] - jne r3, 255, jmp_0528 - ldxdw r3, [r1+20760] - jne r3, 14, jmp_0538 - ldxb r3, [r1+31032] - jne r3, 255, jmp_0548 + ldxb r2, [r2+0] + jeq r2, 1, jmp_0498 + mov64 r0, 11 + jne r2, 0, jmp_04a8 + jne r1, 1, jmp_04b0 + ldxdw r1, [r6+0] + jne r1, 4, jmp_04c0 + ldxdw r1, [r6+88] + jne r1, 0, jmp_04d0 + ldxb r1, [r6+10344] + jne r1, 255, jmp_04e0 + ldxdw r1, [r6+10424] + jne r1, 0, jmp_04f0 + ldxb r1, [r6+20680] + jne r1, 255, jmp_0500 + ldxdw r1, [r6+20760] + jne r1, 14, jmp_0510 + ldxb r1, [r6+31032] + jne r1, 255, jmp_0520 mov64 r0, 8 - mov32 r3, 399877894 - hor64 r3, 1364995097 - ldxdw r4, [r1+31040] - jne r4, r3, jmp_0060 - mov32 r3, 1288277025 - hor64 r3, 2146519613 - ldxdw r4, [r1+31048] - jne r4, r3, jmp_0060 - mov32 r3, 149871192 - hor64 r3, 1157472667 - ldxdw r4, [r1+31056] - jne r4, r3, jmp_0060 - ldxdw r3, [r1+31064] - mov32 r4, -1965433885 - jne r3, r4, jmp_0060 - ldxdw r2, [r2-8] - jne r2, 0, jmp_0558 - mov64 r6, r1 - add64 r6, 41400 + mov32 r1, 399877894 + hor64 r1, 1364995097 + ldxdw r2, [r6+31040] + jne r2, r1, jmp_04a8 + mov32 r1, 1288277025 + hor64 r1, 2146519613 + ldxdw r2, [r6+31048] + jne r2, r1, jmp_04a8 + mov32 r1, 149871192 + hor64 r1, 1157472667 + ldxdw r2, [r6+31056] + jne r2, r1, jmp_04a8 + ldxdw r1, [r6+31064] + mov32 r2, -1965433885 + jne r1, r2, jmp_04a8 + mov64 r7, r6 + add64 r7, 41401 mov64 r4, r10 add64 r4, 104 mov64 r5, r10 add64 r5, 19 - mov64 r7, r1 + mov64 r1, r6 mov64 r2, 0 - mov64 r3, r6 + mov64 r3, r7 call sol_try_find_program_address mov64 r0, 10 ldxdw r1, [r10+104] - ldxdw r2, [r7+10352] - jne r1, r2, jmp_0060 + ldxdw r2, [r6+10352] + jne r1, r2, jmp_04a8 ldxdw r1, [r10+112] - ldxdw r2, [r7+10360] - jne r1, r2, jmp_0060 + ldxdw r2, [r6+10360] + jne r1, r2, jmp_04a8 ldxdw r1, [r10+120] - ldxdw r2, [r7+10368] - jne r1, r2, jmp_0060 + ldxdw r2, [r6+10368] + jne r1, r2, jmp_04a8 ldxdw r1, [r10+128] - ldxdw r2, [r7+10376] - jne r1, r2, jmp_0060 - mov64 r1, r7 + ldxdw r2, [r6+10376] + jne r1, r2, jmp_04a8 + mov64 r1, r6 add64 r1, 10352 - ldxdw r2, [r7+31120] - ldxdw r3, [r6+24] + ldxdw r2, [r6+31120] + ldxdw r3, [r7+24] stxdw [r10+64], r3 - ldxdw r3, [r6+16] + ldxdw r3, [r7+16] stxdw [r10+56], r3 - ldxdw r3, [r6+8] + ldxdw r3, [r7+8] stxdw [r10+48], r3 - ldxdw r3, [r6+0] + ldxdw r3, [r7+0] stxdw [r10+40], r3 lmul64 r2, 152 stxdw [r10+24], r2 stdw [r10+32], 24 stw [r10+20], 0 stxdw [r10+88], r1 - mov64 r2, r7 + mov64 r2, r6 add64 r2, 16 stxdw [r10+72], r2 sth [r10+96], 257 sth [r10+80], 257 - mov64 r3, r7 + mov64 r3, r6 add64 r3, 10384 stxdw [r10+192], r3 - mov64 r3, r7 + mov64 r3, r6 add64 r3, 10432 stxdw [r10+184], r3 - mov64 r3, r7 + mov64 r3, r6 add64 r3, 10416 stxdw [r10+168], r3 stxdw [r10+160], r1 - mov64 r1, r7 + mov64 r1, r6 add64 r1, 48 stxdw [r10+136], r1 - mov64 r1, r7 + mov64 r1, r6 add64 r1, 96 stxdw [r10+128], r1 - mov64 r1, r7 + mov64 r1, r6 add64 r1, 80 stxdw [r10+112], r1 stxdw [r10+104], r2 @@ -153,48 +143,47 @@ jmp_0068: mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c - mov64 r1, r7 + mov64 r1, r6 add64 r1, 10456 - stxdw [r7+10448], r1 + stxdw [r6+10448], r1 mov64 r0, 0 - ja jmp_0060 - -jmp_04c8: - mov64 r0, 2 - ja jmp_0060 + ja jmp_04a8 -jmp_04d8: - mov64 r0, 5 - ja jmp_0060 +jmp_0498: + mov64 r0, 0 + jne r1, 5, jmp_04b0 -jmp_04e8: - mov64 r0, 11 - ja jmp_0060 +jmp_04a8: + exit -jmp_04f8: +jmp_04b0: mov64 r0, 12 - ja jmp_0060 + ja jmp_04a8 -jmp_0508: +jmp_04c0: mov64 r0, 1 - ja jmp_0060 + ja jmp_04a8 + +jmp_04d0: + mov64 r0, 2 + ja jmp_04a8 -jmp_0518: +jmp_04e0: + mov64 r0, 5 + ja jmp_04a8 + +jmp_04f0: mov64 r0, 3 - ja jmp_0060 + ja jmp_04a8 -jmp_0528: +jmp_0500: mov64 r0, 6 - ja jmp_0060 + ja jmp_04a8 -jmp_0538: +jmp_0510: mov64 r0, 4 - ja jmp_0060 + ja jmp_04a8 -jmp_0548: +jmp_0520: mov64 r0, 7 - ja jmp_0060 - -jmp_0558: - mov64 r0, 9 - ja jmp_0060 + ja jmp_04a8 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index d29469f7..6fb2af51 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -96,7 +96,7 @@ .equ IB_RENT_ID_CHUNK_3_LO, -1965433885 # Rent sysvar ID (chunk 3 lo). .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41401 # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index f18c4906..3209df97 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -1,9 +1,9 @@ #[repr(u8)] pub enum Instruction { - /// Initialize the tree (discriminator is number of accounts). + /// Initialize the tree. Initialize, - /// Insert node into tree instruction. + /// Insert key-value pair. Insert, } @@ -12,6 +12,11 @@ pub struct InstructionHeader { discriminator: u8, } +#[repr(C, packed)] +pub struct InitializeInstruction { + pub header: InstructionHeader, +} + #[repr(C, packed)] pub struct InsertInstruction { pub header: InstructionHeader, diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 1ecbee2c..69d294cf 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -3,12 +3,15 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); - if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input, instruction_data) - } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input, instruction_data) - } else { - error::N_ACCOUNTS.into() + match ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) { + x if x == Instruction::Initialize as u8 => { + initialize(input, instruction_data, instruction_data_len, n_accounts) + } + x if x == Instruction::Insert as u8 => { + insert(input, instruction_data, instruction_data_len, n_accounts) + } + _ => error::INSTRUCTION_DISCRIMINATOR.into(), } } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/general-branching.txt b/examples/tree/artifacts/snippets/rs/general-branching.txt deleted file mode 100644 index fc70e7e2..00000000 --- a/examples/tree/artifacts/snippets/rs/general-branching.txt +++ /dev/null @@ -1,18 +0,0 @@ -#[inline(always)] -unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { - // Error if user has data. - let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!((*user).data_len != 0, error::USER_DATA_LEN); - - // Error if tree is duplicate. - let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(tree), error::TREE_DUPLICATE); - - // Get instruction data length and discriminator, branch to instruction. - let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if likely(ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8) { - insert(input, instruction_data, instruction_data_len) - } else { - error::INSTRUCTION_DISCRIMINATOR.into() - } -} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 2937d7dc..536d9a18 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,5 +1,22 @@ #[inline(always)] -unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { +unsafe fn initialize( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + // Error if instruction data provided. + if_err!( + instruction_data_len != size_of::() as u64, + error::INSTRUCTION_DATA_LEN + ); + + // Error if incorrect number of accounts. + if_err!( + n_accounts != input_buffer::N_ACCOUNTS_INIT, + error::N_ACCOUNTS + ); + // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!((*user).data_len != 0, error::USER_DATA_LEN); @@ -27,11 +44,4 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { if_err!( !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), error::RENT_ADDRESS - ); - - // Error if instruction data provided. - let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if_err!( - instruction_data_len != data::DATA_LEN_ZERO, - error::INSTRUCTION_DATA ); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 70be4634..5d0d3373 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -1,5 +1,11 @@ #[inline(always)] -unsafe fn insert(input: *mut u8, instruction_data: *mut u8, instruction_data_len: u64) -> u64 { +unsafe fn insert( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + // Error if invalid instruction data length. if_err!( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index fe73f2d7..68376696 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,31 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| No accounts | 5 | 7 | +2 | +40.0% | -| One account | 5 | 7 | +2 | +40.0% | -| Three accounts | 5 | 7 | +2 | +40.0% | -| Five accounts | 5 | 7 | +2 | +40.0% | +| Invalid instruction discriminator | 11 | 8 | -3 | -27.3% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 5 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/general_branching/result.txt b/examples/tree/artifacts/tests/general_branching/result.txt deleted file mode 100644 index 288c168e..00000000 --- a/examples/tree/artifacts/tests/general_branching/result.txt +++ /dev/null @@ -1,24 +0,0 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| User has nonzero data length | 6 | 8 | +2 | +33.3% | -| Tree account is duplicate | 8 | 10 | +2 | +25.0% | -| Invalid instruction discriminator | 11 | 12 | +1 | +9.1% | -test tests::test_general_branching ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/general_branching/test.txt b/examples/tree/artifacts/tests/general_branching/test.txt deleted file mode 100644 index 1383597b..00000000 --- a/examples/tree/artifacts/tests/general_branching/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_general_branching() { - print_comparison_table(general::GeneralCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index 15b5199e..d5650d28 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,36 +1,33 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 105 | 137 | +32 | +30.5% | -| User has insufficient Lamports | 2596 | 105 | 137 | +32 | +30.5% | -| CreateAccount happy path | 2596 | 109 | 143 | +34 | +31.2% | +| System Program is wrong address | 2446 | 0 | 141 | +141 | N/A | + (ASM) System Program is wrong address: expected Failure(NotEnoughAccountKeys), got Failure(Custom(9)) +| User has insufficient Lamports | 2596 | 0 | 141 | +141 | N/A | + (ASM) User has insufficient Lamports: expected Failure(Custom(1)), got Failure(Custom(9)) +| CreateAccount happy path | 2596 | 0 | 147 | +147 | N/A | + (ASM) CreateAccount happy path: expected Success, got Failure(Custom(9)) test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2583 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2587 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2701 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 [ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2733 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2737 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2705 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2739 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2743 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt index aa2dd6c3..4c771911 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); + print_comparison_table(init::InitCase::CPI_CASES, true, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 2d9b546e..0908a4ea 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,108 +1,117 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| User has nonzero data length | 7 | 9 | +2 | +28.6% | -| Tree account is duplicate | 9 | 11 | +2 | +22.2% | -| Tree has nonzero data length | 11 | 13 | +2 | +18.2% | -| System program is duplicate | 13 | 15 | +2 | +15.4% | -| System program wrong data length | 15 | 17 | +2 | +13.3% | -| Rent sysvar is duplicate | 17 | 19 | +2 | +11.8% | -| Rent address mismatch word 0 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 1 | 20 | 22 | +2 | +10.0% | -| Rent address mismatch word 2 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 3 | 23 | 26 | +3 | +13.0% | -| Rent address mismatch word 4 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 5 | 26 | 30 | +4 | +15.4% | -| Rent address mismatch word 6 | 29 | 33 | +4 | +13.8% | -| Rent address mismatch word 7 | 29 | 33 | +4 | +13.8% | -| Non-empty instruction data | 31 | 37 | +6 | +19.4% | +| Invalid instruction data length | 31 | 11 | -20 | -64.5% | + (ASM) Invalid instruction data length: expected Failure(Custom(12)), got Failure(Custom(9)) +| Incorrect number of accounts | 11 | 13 | +2 | +18.2% | + (ASM) Incorrect number of accounts: expected Failure(Custom(1)), got Failure(Custom(11)) +| User has nonzero data length | 7 | 15 | +8 | +114.3% | +| Tree account is duplicate | 9 | 17 | +8 | +88.9% | +| Tree has nonzero data length | 11 | 19 | +8 | +72.7% | +| System program is duplicate | 13 | 21 | +8 | +61.5% | +| System program wrong data length | 15 | 23 | +8 | +53.3% | +| Rent sysvar is duplicate | 17 | 25 | +8 | +47.1% | +| Rent address mismatch word 0 | 20 | 28 | +8 | +40.0% | +| Rent address mismatch word 1 | 20 | 28 | +8 | +40.0% | +| Rent address mismatch word 2 | 23 | 32 | +9 | +39.1% | +| Rent address mismatch word 3 | 23 | 32 | +9 | +39.1% | +| Rent address mismatch word 4 | 26 | 36 | +10 | +38.5% | +| Rent address mismatch word 5 | 26 | 36 | +10 | +38.5% | +| Rent address mismatch word 6 | 29 | 39 | +10 | +34.5% | +| Rent address mismatch word 7 | 29 | 39 | +10 | +34.5% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt index 24226cfc..94e043d8 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); + print_comparison_table(init::InitCase::CASES, true, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 7348c78c..243d1001 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,31 +1,35 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 42 | 50 | +8 | +19.0% | -| PDA mismatch chunk 2 | 1500 | 45 | 53 | +8 | +17.8% | -| PDA mismatch chunk 3 | 1500 | 48 | 56 | +8 | +16.7% | -| PDA mismatch chunk 4 | 1500 | 51 | 59 | +8 | +15.7% | +| PDA mismatch chunk 1 | 1500 | 0 | 54 | +54 | N/A | + (ASM) PDA mismatch chunk 1: expected Failure(Custom(10)), got Failure(Custom(9)) +| PDA mismatch chunk 2 | 1500 | 0 | 57 | +57 | N/A | + (ASM) PDA mismatch chunk 2: expected Failure(Custom(10)), got Failure(Custom(9)) +| PDA mismatch chunk 3 | 1500 | 0 | 60 | +60 | N/A | + (ASM) PDA mismatch chunk 3: expected Failure(Custom(10)), got Failure(Custom(9)) +| PDA mismatch chunk 4 | 1500 | 0 | 63 | +63 | N/A | + (ASM) PDA mismatch chunk 4: expected Failure(Custom(10)), got Failure(Custom(9)) test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1542 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1554 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1557 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1560 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1563 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt index 0f682d5d..fc7859a4 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); + print_comparison_table(init::InitCase::PDA_CASES, true, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index 857c793b..df93c555 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Instruction data too short | 12 | 15 | +3 | +25.0% | -| Instruction data too long | 12 | 15 | +3 | +25.0% | -| Insert happy path | 11 | 13 | +2 | +18.2% | +| Instruction data too short | 12 | 10 | -2 | -16.7% | +| Instruction data too long | 12 | 10 | -2 | -16.7% | +| Insert happy path | 11 | 8 | -3 | -27.3% | test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1ba18981..a6b7a303 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -210,9 +210,9 @@ pub struct StackNode { #[repr(u8)] pub enum Instruction { - /// Initialize the tree (discriminator is number of accounts). + /// Initialize the tree. Initialize, - /// Insert node into tree instruction. + /// Insert key-value pair. Insert, } @@ -221,6 +221,11 @@ pub struct InstructionHeader { discriminator: u8, } +#[repr(C, packed)] +pub struct InitializeInstruction { + pub header: InstructionHeader, +} + #[repr(C, packed)] pub struct InsertInstruction { pub header: InstructionHeader, @@ -250,8 +255,8 @@ constant_group! { #[repr(C, packed)] pub struct InitInputBufferFooter { - /// No actual instruction data follows. pub instruction_data_len: u64, + pub instruction: InitializeInstruction, pub program_id: Address, } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 19396831..d749687a 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -11,5 +11,5 @@ pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, - InsertInstruction, Instruction, TreeHeader, TreeNode, + InitializeInstruction, InsertInstruction, Instruction, TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 303659f8..2cfbf97a 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,8 +9,8 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, - Direction, InsertInstruction, Instruction, SolAccountInfo, SolAccountMeta, SolInstruction, - SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, + Direction, InitializeInstruction, InsertInstruction, Instruction, SolAccountInfo, + SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -71,41 +71,29 @@ nostd_panic_handler!(); #[no_mangle] pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { + let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); - if likely(n_accounts == input_buffer::N_ACCOUNTS_GENERAL) { - general(input, instruction_data) - } else if likely(n_accounts == input_buffer::N_ACCOUNTS_INIT) { - initialize(input, instruction_data) - } else { - error::N_ACCOUNTS.into() + match ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) { + x if x == Instruction::Initialize as u8 => { + initialize(input, instruction_data, instruction_data_len, n_accounts) + } + x if x == Instruction::Insert as u8 => { + insert(input, instruction_data, instruction_data_len, n_accounts) + } + _ => error::INSTRUCTION_DISCRIMINATOR.into(), } } // ANCHOR_END: entrypoint-branching -// ANCHOR: general-branching -#[inline(always)] -unsafe fn general(input: *mut u8, instruction_data: *mut u8) -> u64 { - // Error if user has data. - let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!((*user).data_len != 0, error::USER_DATA_LEN); - - // Error if tree is duplicate. - let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(tree), error::TREE_DUPLICATE); - - // Get instruction data length and discriminator, branch to instruction. - let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if likely(ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) == Instruction::Insert as u8) { - insert(input, instruction_data, instruction_data_len) - } else { - error::INSTRUCTION_DISCRIMINATOR.into() - } -} -// ANCHOR_END: general-branching - // ANCHOR: insert #[inline(always)] -unsafe fn insert(input: *mut u8, instruction_data: *mut u8, instruction_data_len: u64) -> u64 { +unsafe fn insert( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + // Error if invalid instruction data length. if_err!( instruction_data_len != size_of::() as u64, error::INSTRUCTION_DATA_LEN @@ -122,7 +110,24 @@ unsafe fn insert(input: *mut u8, instruction_data: *mut u8, instruction_data_len // ANCHOR: initialize-input-checks #[inline(always)] -unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { +unsafe fn initialize( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + // Error if instruction data provided. + if_err!( + instruction_data_len != size_of::() as u64, + error::INSTRUCTION_DATA_LEN + ); + + // Error if incorrect number of accounts. + if_err!( + n_accounts != input_buffer::N_ACCOUNTS_INIT, + error::N_ACCOUNTS + ); + // Error if user has data. let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); if_err!((*user).data_len != 0, error::USER_DATA_LEN); @@ -151,13 +156,6 @@ unsafe fn initialize(input: *mut u8, instruction_data: *mut u8) -> u64 { !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), error::RENT_ADDRESS ); - - // Error if instruction data provided. - let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); - if_err!( - instruction_data_len != data::DATA_LEN_ZERO, - error::INSTRUCTION_DATA - ); // ANCHOR_END: initialize-input-checks // ANCHOR: initialize-pda-checks diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 68507b4a..025f5079 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,5 +1,4 @@ mod entrypoint; -mod general; mod init; mod insert; @@ -149,11 +148,6 @@ fn test_entrypoint_branching() { print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); } -#[test] -fn test_general_branching() { - print_comparison_table(general::GeneralCase::CASES, false, false); -} - #[test] fn test_insert() { print_comparison_table(insert::InsertCase::CASES, false, false); @@ -161,15 +155,15 @@ fn test_insert() { #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); + print_comparison_table(init::InitCase::CASES, true, false); } #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); + print_comparison_table(init::InitCase::PDA_CASES, true, false); } #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); + print_comparison_table(init::InitCase::CPI_CASES, true, false); } diff --git a/examples/tree/src/tests/entrypoint.rs b/examples/tree/src/tests/entrypoint.rs index 7219d20d..4c047be2 100644 --- a/examples/tree/src/tests/entrypoint.rs +++ b/examples/tree/src/tests/entrypoint.rs @@ -1,59 +1,56 @@ use super::*; +use mollusk_svm::program; use solana_sdk::instruction::AccountMeta; #[derive(Clone, Copy)] pub(super) enum EntrypointCase { - NoAccounts, - OneAccount, - ThreeAccounts, - FiveAccounts, + InvalidDiscriminator, } impl EntrypointCase { - pub(super) const CASES: &'static [Self] = &[ - Self::NoAccounts, - Self::OneAccount, - Self::ThreeAccounts, - Self::FiveAccounts, - ]; - - const fn n_accounts(&self) -> usize { - match self { - Self::NoAccounts => 0, - Self::OneAccount => 1, - Self::ThreeAccounts => 3, - Self::FiveAccounts => 5, - } - } + pub(super) const CASES: &'static [Self] = &[Self::InvalidDiscriminator]; } impl TestCase for EntrypointCase { fn name(&self) -> &'static str { match self { - Self::NoAccounts => "No accounts", - Self::OneAccount => "One account", - Self::ThreeAccounts => "Three accounts", - Self::FiveAccounts => "Five accounts", + Self::InvalidDiscriminator => "Invalid instruction discriminator", } } fn run(&self, lang: ProgramLanguage) -> CaseResult { - let setup = setup_test(lang); - - let account_metas: Vec = (0..self.n_accounts()) - .map(|_| AccountMeta::new(Pubkey::new_unique(), false)) - .collect(); - let accounts: Vec<(Pubkey, Account)> = account_metas - .iter() - .map(|meta| (meta.pubkey, Account::default())) - .collect(); - - let instruction = Instruction::new_with_bytes(setup.program_id, &[], account_metas); - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::N_ACCOUNTS, - ) + match self { + Self::InvalidDiscriminator => { + let setup = setup_test(lang); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &[255], // Invalid discriminator. + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, Account::default()), + ]; + + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DISCRIMINATOR, + ) + } + } } } diff --git a/examples/tree/src/tests/general.rs b/examples/tree/src/tests/general.rs deleted file mode 100644 index 45de6755..00000000 --- a/examples/tree/src/tests/general.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::*; -use mollusk_svm::program; -use solana_sdk::instruction::AccountMeta; - -fn general_setup( - program_language: ProgramLanguage, -) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(program_language); - let (system_program_pubkey, _) = program::keyed_account_for_system_program(); - - let user_pubkey = Pubkey::new_unique(); - let tree_pubkey = Pubkey::new_unique(); - - let instruction = Instruction::new_with_bytes( - setup.program_id, - &[], - vec![ - AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pubkey, false), - ], - ); - - let accounts = vec![ - ( - user_pubkey, - Account::new(USER_LAMPORTS, 0, &system_program_pubkey), - ), - (tree_pubkey, Account::default()), - ]; - - (setup, instruction, accounts) -} - -#[derive(Clone, Copy)] -pub(super) enum GeneralCase { - UserDataLen, - TreeDuplicate, - InstructionDiscriminator, -} - -impl GeneralCase { - pub(super) const CASES: &'static [Self] = &[ - Self::UserDataLen, - Self::TreeDuplicate, - Self::InstructionDiscriminator, - ]; -} - -impl TestCase for GeneralCase { - fn name(&self) -> &'static str { - match self { - Self::UserDataLen => "User has nonzero data length", - Self::TreeDuplicate => "Tree account is duplicate", - Self::InstructionDiscriminator => "Invalid instruction discriminator", - } - } - - fn run(&self, lang: ProgramLanguage) -> CaseResult { - match self { - Self::UserDataLen => { - let (setup, instruction, mut accounts) = general_setup(lang); - accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::USER_DATA_LEN, - ) - } - Self::TreeDuplicate => { - let (setup, mut instruction, mut accounts) = general_setup(lang); - instruction.accounts[AccountIndex::Tree as usize] = - instruction.accounts[AccountIndex::User as usize].clone(); - accounts[AccountIndex::Tree as usize] = - accounts[AccountIndex::User as usize].clone(); - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::TREE_DUPLICATE, - ) - } - Self::InstructionDiscriminator => { - let (setup, mut instruction, accounts) = general_setup(lang); - instruction.data = vec![255]; // Invalid discriminator. - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::INSTRUCTION_DISCRIMINATOR, - ) - } - } - } -} diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 90541fc6..4b57646e 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -3,7 +3,7 @@ use mollusk_svm::program; use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; -use tree_interface::{input_buffer, tree, TreeHeader}; +use tree_interface::{input_buffer, tree, Instruction as TreeInstruction, TreeHeader}; const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; @@ -25,7 +25,7 @@ fn init_setup( let instruction = Instruction::new_with_bytes( setup.program_id, - &[], + &[TreeInstruction::Initialize as u8], vec![ AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), @@ -62,7 +62,7 @@ fn pda_init_setup( let instruction = Instruction::new_with_bytes( setup.program_id, - &[], + &[TreeInstruction::Initialize as u8], vec![ AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), @@ -102,6 +102,9 @@ fn run_address_mismatch( #[derive(Clone, Copy)] pub(super) enum InitCase { + InstructionData, + NAccountsTooFew, + NAccountsTooMany, UserDataLen, TreeDuplicate, TreeDataLen, @@ -116,7 +119,6 @@ pub(super) enum InitCase { RentAddressWord5, RentAddressWord6, RentAddressWord7, - InstructionData, PdaMismatchChunk0, PdaMismatchChunk1, PdaMismatchChunk2, @@ -128,6 +130,9 @@ pub(super) enum InitCase { impl InitCase { pub(super) const CASES: &'static [Self] = &[ + Self::InstructionData, + Self::NAccountsTooFew, + Self::NAccountsTooMany, Self::UserDataLen, Self::TreeDuplicate, Self::TreeDataLen, @@ -142,7 +147,6 @@ impl InitCase { Self::RentAddressWord5, Self::RentAddressWord6, Self::RentAddressWord7, - Self::InstructionData, ]; pub(super) const PDA_CASES: &'static [Self] = &[ @@ -162,6 +166,9 @@ impl InitCase { impl TestCase for InitCase { fn name(&self) -> &'static str { match self { + Self::InstructionData => "Invalid instruction data length", + Self::NAccountsTooFew => "Too few accounts", + Self::NAccountsTooMany => "Too many accounts", Self::UserDataLen => "User has nonzero data length", Self::TreeDuplicate => "Tree account is duplicate", Self::TreeDataLen => "Tree has nonzero data length", @@ -176,7 +183,6 @@ impl TestCase for InitCase { Self::RentAddressWord5 => "Rent address mismatch word 5", Self::RentAddressWord6 => "Rent address mismatch word 6", Self::RentAddressWord7 => "Rent address mismatch word 7", - Self::InstructionData => "Non-empty instruction data", Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", @@ -190,7 +196,10 @@ impl TestCase for InitCase { fn fixed_costs(&self) -> u64 { match self { // Input checks - no syscalls. - Self::UserDataLen + Self::InstructionData + | Self::NAccountsTooFew + | Self::NAccountsTooMany + | Self::UserDataLen | Self::TreeDuplicate | Self::TreeDataLen | Self::SystemProgramDuplicate @@ -203,8 +212,7 @@ impl TestCase for InitCase { | Self::RentAddressWord4 | Self::RentAddressWord5 | Self::RentAddressWord6 - | Self::RentAddressWord7 - | Self::InstructionData => 0, + | Self::RentAddressWord7 => 0, // PDA checks - sol_try_find_program_address only. Self::PdaMismatchChunk0 | Self::PdaMismatchChunk1 @@ -225,6 +233,43 @@ impl TestCase for InitCase { fn run(&self, lang: ProgramLanguage) -> CaseResult { match self { + Self::InstructionData => { + let (setup, mut instruction, accounts) = init_setup(lang); + instruction.data = vec![TreeInstruction::Initialize as u8, 0]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA_LEN, + ) + } + Self::NAccountsTooFew => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + // Remove rent sysvar (3 accounts instead of 4). + instruction.accounts.pop(); + accounts.pop(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS, + ) + } + Self::NAccountsTooMany => { + let (setup, mut instruction, mut accounts) = init_setup(lang); + // Add a bogus account (5 accounts instead of 4). + let bogus_pubkey = Pubkey::new_unique(); + instruction + .accounts + .push(AccountMeta::new_readonly(bogus_pubkey, false)); + accounts.push((bogus_pubkey, Account::default())); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS, + ) + } Self::UserDataLen => { let (setup, instruction, mut accounts) = init_setup(lang); accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; @@ -350,16 +395,6 @@ impl TestCase for InitCase { size_of::(), error_codes::error::RENT_ADDRESS, ), - Self::InstructionData => { - let (setup, mut instruction, accounts) = init_setup(lang); - instruction.data = vec![1u8; 1]; - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::INSTRUCTION_DATA, - ) - } Self::PdaMismatchChunk0 => run_address_mismatch( lang, AccountIndex::Tree as usize, diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index fd03c347..8c21258e 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -97,7 +97,7 @@ .equ IB_RENT_ID_CHUNK_3_LO, -1965433885 # Rent sysvar ID (chunk 3 lo). .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. -.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41400 +.equ IB_INIT_PROGRAM_ID_OFF_IMM, 41401 # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 From dc245e94a8a1898cbe106e128ca29ef904d75cd3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:49:45 -0800 Subject: [PATCH 168/263] Rebuild examples --- examples/tree/artifacts/dumps/asm.txt | 311 +++++++++-------- examples/tree/artifacts/dumps/rs.txt | 316 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 158 ++++----- .../tree/artifacts/snippets/asm/constants.txt | 8 + .../snippets/asm/entrypoint-branching.txt | 16 +- .../snippets/asm/general-branching.txt | 18 - .../snippets/asm/initialize-input-checks.txt | 15 +- .../snippets/interface/instructions.txt | 4 + .../snippets/rs/entrypoint-branching.txt | 15 +- .../tests/entrypoint_branching/result.txt | 4 +- .../initialize_create_account/result.txt | 33 +- .../tests/initialize_create_account/test.txt | 2 +- .../tests/initialize_input_checks/result.txt | 107 +++--- .../tests/initialize_input_checks/test.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 36 +- .../tests/initialize_pda_checks/test.txt | 2 +- .../tree/artifacts/tests/insert/result.txt | 18 +- examples/tree/build.rs | 1 + examples/tree/interface/src/asm.rs | 5 +- examples/tree/interface/src/common.rs | 4 + examples/tree/src/program.rs | 19 +- examples/tree/src/tests.rs | 6 +- examples/tree/src/tree/tree.s | 58 ++-- 23 files changed, 583 insertions(+), 575 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/asm/general-branching.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index b7775ced..4866c10f 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1792 (bytes into file) + Start of section headers 1752 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x700 +There are 7 section headers, starting at offset 0x6d8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000488 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000570 000570 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000610 000610 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000670 000670 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000006b0 0006b0 000020 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0006d0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000460 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000548 000548 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000005e8 0005e8 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000648 000648 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000688 000688 000020 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0006a8 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000488 0x000488 R E 0x1000 - LOAD 0x000610 0x0000000000000610 0x0000000000000610 0x0000c0 0x0000c0 R 0x1000 - DYNAMIC 0x000570 0x0000000000000570 0x0000000000000570 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000460 0x000460 R E 0x1000 + LOAD 0x0005e8 0x00000000000005e8 0x00000000000005e8 0x0000c0 0x0000c0 R 0x1000 + DYNAMIC 0x000548 0x0000000000000548 0x0000000000000548 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,23 +52,23 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x570 contains 10 entries +Dynamic section at offset 0x548 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x6b0 + 0x0000000000000011 (REL) 0x688 0x0000000000000012 (RELSZ) 32 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x610 + 0x0000000000000006 (SYMTAB) 0x5e8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x670 + 0x0000000000000005 (STRTAB) 0x648 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x6b0 contains 2 entries +Relocation section '.rel.dyn' at offset 0x688 contains 2 entries Offset Info Type Symbol's Value Symbol's Name -0000000000000278 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -0000000000000498 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -83,145 +83,140 @@ tree.so file format elf64-bpf Disassembly of section .text 00000000000000e8 - 29 79 19 00 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x0) - 30 15 09 03 00 02 00 00 00 if r9 == 0x2 goto +0x3 - 31 15 09 0b 00 04 00 00 00 if r9 == 0x4 goto +0xb - 32 b7 00 00 00 01 00 00 00 r0 = 0x1 - 33 95 00 00 00 00 00 00 00 exit - 34 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 35 55 09 88 00 00 00 00 00 if r9 != 0x0 goto +0x88 - 36 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 37 55 09 84 00 ff 00 00 00 if r9 != 0xff goto +0x84 - 38 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 39 71 28 00 00 00 00 00 00 r8 = *(u8 *)(r2 + 0x0) - 40 15 08 6f 00 01 00 00 00 if r8 == 0x1 goto +0x6f - 41 b7 00 00 00 0b 00 00 00 r0 = 0xb - 42 95 00 00 00 00 00 00 00 exit - 43 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 44 55 09 7f 00 00 00 00 00 if r9 != 0x0 goto +0x7f - 45 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 46 55 09 7b 00 ff 00 00 00 if r9 != 0xff goto +0x7b - 47 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 48 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 - 49 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 50 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 - 51 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 52 55 09 6f 00 0e 00 00 00 if r9 != 0xe goto +0x6f - 53 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 54 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b - 55 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) - 56 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 58 5d 89 65 00 00 00 00 00 if r9 != r8 goto +0x65 - 59 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) - 60 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 62 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 - 63 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) - 64 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 66 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d - 67 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) - 68 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 69 5d 89 5a 00 00 00 00 00 if r9 != r8 goto +0x5a - 70 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) - 71 55 09 52 00 00 00 00 00 if r9 != 0x0 goto +0x52 - 72 b7 02 00 00 00 00 00 00 r2 = 0x0 - 73 bf 13 00 00 00 00 00 00 r3 = r1 - 74 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 - 75 bf a4 00 00 00 00 00 00 r4 = r10 - 76 07 04 00 00 b0 ff ff ff r4 += -0x50 - 77 bf a5 00 00 00 00 00 00 r5 = r10 - 78 07 05 00 00 a0 fe ff ff r5 += -0x160 - 79 85 10 00 00 ff ff ff ff call -0x1 - 80 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) - 81 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 82 5d 89 4b 00 00 00 00 00 if r9 != r8 goto +0x4b - 83 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) - 84 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 85 5d 89 48 00 00 00 00 00 if r9 != r8 goto +0x48 - 86 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) - 87 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 88 5d 89 45 00 00 00 00 00 if r9 != r8 goto +0x45 - 89 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) - 90 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 91 5d 89 42 00 00 00 00 00 if r9 != r8 goto +0x42 - 92 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 - 93 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 - 94 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) - 95 27 09 00 00 98 00 00 00 r9 *= 0x98 - 96 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 - 97 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 - 98 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 99 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 - 100 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) - 101 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 - 102 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) - 103 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 - 104 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) - 105 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 - 106 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 - 107 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 - 108 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 - 109 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 - 110 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 - 111 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 - 112 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 + 29 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) + 30 79 18 00 00 00 00 00 00 r8 = *(u64 *)(r1 + 0x0) + 31 71 27 00 00 00 00 00 00 r7 = *(u8 *)(r2 + 0x0) + 32 15 07 70 00 01 00 00 00 if r7 == 0x1 goto +0x70 + 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 34 b7 00 00 00 0b 00 00 00 r0 = 0xb + 35 95 00 00 00 00 00 00 00 exit + 36 55 09 70 00 01 00 00 00 if r9 != 0x1 goto +0x70 + 37 55 08 71 00 04 00 00 00 if r8 != 0x4 goto +0x71 + 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 39 55 09 7f 00 00 00 00 00 if r9 != 0x0 goto +0x7f + 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 41 55 09 7b 00 ff 00 00 00 if r9 != 0xff goto +0x7b + 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 43 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 + 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) + 45 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 + 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) + 47 55 09 6f 00 0e 00 00 00 if r9 != 0xe goto +0x6f + 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) + 49 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b + 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) + 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll + 53 5d 89 65 00 00 00 00 00 if r9 != r8 goto +0x65 + 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) + 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll + 57 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 + 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) + 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll + 61 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d + 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) + 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d + 64 5d 89 5a 00 00 00 00 00 if r9 != r8 goto +0x5a + 65 b7 02 00 00 00 00 00 00 r2 = 0x0 + 66 bf 13 00 00 00 00 00 00 r3 = r1 + 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 + 68 bf a4 00 00 00 00 00 00 r4 = r10 + 69 07 04 00 00 b0 ff ff ff r4 += -0x50 + 70 bf a5 00 00 00 00 00 00 r5 = r10 + 71 07 05 00 00 a0 fe ff ff r5 += -0x160 + 72 85 10 00 00 ff ff ff ff call -0x1 + 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) + 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) + 75 5d 89 4d 00 00 00 00 00 if r9 != r8 goto +0x4d + 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) + 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) + 78 5d 89 4a 00 00 00 00 00 if r9 != r8 goto +0x4a + 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) + 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 81 5d 89 47 00 00 00 00 00 if r9 != r8 goto +0x47 + 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) + 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) + 84 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 + 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 + 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) + 88 27 09 00 00 98 00 00 00 r9 *= 0x98 + 89 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 + 90 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 + 91 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 92 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 + 93 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 94 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 + 95 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 96 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 + 97 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 98 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 + 99 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 100 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 + 101 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 102 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 + 103 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 + 104 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 + 105 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 + 106 07 01 00 00 10 00 00 00 r1 += 0x10 + 107 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 108 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 109 07 01 00 00 20 00 00 00 r1 += 0x20 + 110 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 111 07 01 00 00 20 00 00 00 r1 += 0x20 + 112 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 113 07 01 00 00 10 00 00 00 r1 += 0x10 - 114 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 - 115 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 - 116 07 01 00 00 20 00 00 00 r1 += 0x20 - 117 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 114 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 115 07 01 00 00 10 28 00 00 r1 += 0x2810 + 116 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 117 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 118 07 01 00 00 20 00 00 00 r1 += 0x20 - 119 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 - 120 07 01 00 00 10 00 00 00 r1 += 0x10 - 121 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 122 07 01 00 00 10 28 00 00 r1 += 0x2810 - 123 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 - 124 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 - 125 07 01 00 00 20 00 00 00 r1 += 0x20 - 126 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 - 127 07 01 00 00 20 00 00 00 r1 += 0x20 - 128 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 - 129 07 01 00 00 10 00 00 00 r1 += 0x10 - 130 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 131 bf 16 00 00 00 00 00 00 r6 = r1 - 132 07 04 00 00 30 00 00 00 r4 += 0x30 - 133 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 134 07 04 00 00 20 ff ff ff r4 += -0xe0 - 135 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 136 07 04 00 00 a1 ff ff ff r4 += -0x5f - 137 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 138 07 04 00 00 ff 00 00 00 r4 += 0xff - 139 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 - 140 07 04 00 00 f0 ff ff ff r4 += -0x10 - 141 bf a1 00 00 00 00 00 00 r1 = r10 - 142 07 01 00 00 d8 fe ff ff r1 += -0x128 - 143 bf a2 00 00 00 00 00 00 r2 = r10 - 144 07 02 00 00 20 ff ff ff r2 += -0xe0 - 145 b7 03 00 00 02 00 00 00 r3 = 0x2 - 146 b7 05 00 00 01 00 00 00 r5 = 0x1 - 147 85 10 00 00 ff ff ff ff call -0x1 - 148 bf 67 00 00 00 00 00 00 r7 = r6 - 149 07 07 00 00 18 00 00 00 r7 += 0x18 - 150 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 - 151 95 00 00 00 00 00 00 00 exit - 152 55 09 03 00 05 00 00 00 if r9 != 0x5 goto +0x3 - 153 95 00 00 00 00 00 00 00 exit - 154 b7 00 00 00 09 00 00 00 r0 = 0x9 - 155 95 00 00 00 00 00 00 00 exit - 156 b7 00 00 00 0c 00 00 00 r0 = 0xc - 157 95 00 00 00 00 00 00 00 exit - 158 b7 00 00 00 0a 00 00 00 r0 = 0xa - 159 95 00 00 00 00 00 00 00 exit - 160 b7 00 00 00 08 00 00 00 r0 = 0x8 - 161 95 00 00 00 00 00 00 00 exit - 162 b7 00 00 00 07 00 00 00 r0 = 0x7 - 163 95 00 00 00 00 00 00 00 exit - 164 b7 00 00 00 04 00 00 00 r0 = 0x4 - 165 95 00 00 00 00 00 00 00 exit - 166 b7 00 00 00 06 00 00 00 r0 = 0x6 - 167 95 00 00 00 00 00 00 00 exit - 168 b7 00 00 00 03 00 00 00 r0 = 0x3 - 169 95 00 00 00 00 00 00 00 exit - 170 b7 00 00 00 05 00 00 00 r0 = 0x5 - 171 95 00 00 00 00 00 00 00 exit - 172 b7 00 00 00 02 00 00 00 r0 = 0x2 - 173 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 119 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 120 07 01 00 00 20 00 00 00 r1 += 0x20 + 121 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 122 07 01 00 00 10 00 00 00 r1 += 0x10 + 123 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 124 bf 16 00 00 00 00 00 00 r6 = r1 + 125 07 04 00 00 30 00 00 00 r4 += 0x30 + 126 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 127 07 04 00 00 20 ff ff ff r4 += -0xe0 + 128 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 129 07 04 00 00 a1 ff ff ff r4 += -0x5f + 130 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 131 07 04 00 00 ff 00 00 00 r4 += 0xff + 132 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 + 133 07 04 00 00 f0 ff ff ff r4 += -0x10 + 134 bf a1 00 00 00 00 00 00 r1 = r10 + 135 07 01 00 00 d8 fe ff ff r1 += -0x128 + 136 bf a2 00 00 00 00 00 00 r2 = r10 + 137 07 02 00 00 20 ff ff ff r2 += -0xe0 + 138 b7 03 00 00 02 00 00 00 r3 = 0x2 + 139 b7 05 00 00 01 00 00 00 r5 = 0x1 + 140 85 10 00 00 ff ff ff ff call -0x1 + 141 bf 67 00 00 00 00 00 00 r7 = r6 + 142 07 07 00 00 18 00 00 00 r7 += 0x18 + 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 + 144 95 00 00 00 00 00 00 00 exit + 145 55 09 03 00 05 00 00 00 if r9 != 0x5 goto +0x3 + 146 95 00 00 00 00 00 00 00 exit + 147 b7 00 00 00 09 00 00 00 r0 = 0x9 + 148 95 00 00 00 00 00 00 00 exit + 149 b7 00 00 00 0c 00 00 00 r0 = 0xc + 150 95 00 00 00 00 00 00 00 exit + 151 b7 00 00 00 01 00 00 00 r0 = 0x1 + 152 95 00 00 00 00 00 00 00 exit + 153 b7 00 00 00 0a 00 00 00 r0 = 0xa + 154 95 00 00 00 00 00 00 00 exit + 155 b7 00 00 00 08 00 00 00 r0 = 0x8 + 156 95 00 00 00 00 00 00 00 exit + 157 b7 00 00 00 07 00 00 00 r0 = 0x7 + 158 95 00 00 00 00 00 00 00 exit + 159 b7 00 00 00 04 00 00 00 r0 = 0x4 + 160 95 00 00 00 00 00 00 00 exit + 161 b7 00 00 00 06 00 00 00 r0 = 0x6 + 162 95 00 00 00 00 00 00 00 exit + 163 b7 00 00 00 03 00 00 00 r0 = 0x3 + 164 95 00 00 00 00 00 00 00 exit + 165 b7 00 00 00 05 00 00 00 r0 = 0x5 + 166 95 00 00 00 00 00 00 00 exit + 167 b7 00 00 00 02 00 00 00 r0 = 0x2 + 168 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index dee5ee54..6ad9c733 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -105,169 +105,169 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 - 8 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 10 9c 21 f8 ff 00 00 00 00 ldxdw r1, [r2 - 0x8] - 18 2c 22 00 00 00 00 00 00 ldxb w2, [r2 + 0x0] - 20 15 02 8d 00 01 00 00 00 jeq r2, 0x1, +0x8d - 28 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 30 55 02 8d 00 00 00 00 00 jne r2, 0x0, +0x8d - 38 55 01 8f 00 01 00 00 00 jne r1, 0x1, +0x8f - 40 9c 61 00 00 00 00 00 00 ldxdw r1, [r6 + 0x0] - 48 55 01 8f 00 04 00 00 00 jne r1, 0x4, +0x8f - 50 9c 61 58 00 00 00 00 00 ldxdw r1, [r6 + 0x58] - 58 55 01 8f 00 00 00 00 00 jne r1, 0x0, +0x8f - 60 2c 61 68 28 00 00 00 00 ldxb w1, [r6 + 0x2868] - 68 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f - 70 9c 61 b8 28 00 00 00 00 ldxdw r1, [r6 + 0x28b8] - 78 55 01 8f 00 00 00 00 00 jne r1, 0x0, +0x8f - 80 2c 61 c8 50 00 00 00 00 ldxb w1, [r6 + 0x50c8] - 88 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f - 90 9c 61 18 51 00 00 00 00 ldxdw r1, [r6 + 0x5118] - 98 55 01 8f 00 0e 00 00 00 jne r1, 0xe, +0x8f - a0 2c 61 38 79 00 00 00 00 ldxb w1, [r6 + 0x7938] - a8 55 01 8f 00 ff 00 00 00 jne r1, 0xff, +0x8f - b0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - b8 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 - c0 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 - c8 9c 62 40 79 00 00 00 00 ldxdw r2, [r6 + 0x7940] - d0 5d 12 79 00 00 00 00 00 jne r2, r1, +0x79 - d8 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 - e0 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d - e8 9c 62 48 79 00 00 00 00 ldxdw r2, [r6 + 0x7948] - f0 5d 12 75 00 00 00 00 00 jne r2, r1, +0x75 - f8 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 - 100 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b - 108 9c 62 50 79 00 00 00 00 ldxdw r2, [r6 + 0x7950] - 110 5d 12 71 00 00 00 00 00 jne r2, r1, +0x71 - 118 9c 61 58 79 00 00 00 00 ldxdw r1, [r6 + 0x7958] - 120 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d - 128 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 130 bf 67 00 00 00 00 00 00 mov64 r7, r6 - 138 07 07 00 00 b9 a1 00 00 add64 r7, 0xa1b9 - 140 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 148 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 150 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 158 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 160 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 168 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 170 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 178 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 180 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 188 9c 62 70 28 00 00 00 00 ldxdw r2, [r6 + 0x2870] - 190 5d 21 62 00 00 00 00 00 jne r1, r2, +0x62 - 198 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1a0 9c 62 78 28 00 00 00 00 ldxdw r2, [r6 + 0x2878] - 1a8 5d 21 5f 00 00 00 00 00 jne r1, r2, +0x5f - 1b0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1b8 9c 62 80 28 00 00 00 00 ldxdw r2, [r6 + 0x2880] - 1c0 5d 21 5c 00 00 00 00 00 jne r1, r2, +0x5c - 1c8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 1d0 9c 62 88 28 00 00 00 00 ldxdw r2, [r6 + 0x2888] - 1d8 5d 21 59 00 00 00 00 00 jne r1, r2, +0x59 - 1e0 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 1e8 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 1f0 9c 62 90 79 00 00 00 00 ldxdw r2, [r6 + 0x7990] - 1f8 9c 73 18 00 00 00 00 00 ldxdw r3, [r7 + 0x18] - 200 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 208 9c 73 10 00 00 00 00 00 ldxdw r3, [r7 + 0x10] - 210 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 218 9c 73 08 00 00 00 00 00 ldxdw r3, [r7 + 0x8] - 220 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 228 9c 73 00 00 00 00 00 00 ldxdw r3, [r7 + 0x0] - 230 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 238 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 240 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 248 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 - 250 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 258 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 260 bf 62 00 00 00 00 00 00 mov64 r2, r6 - 268 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 270 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 278 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 280 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 288 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 290 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 298 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 2a8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2b0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2b8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 2c0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 2c8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 2d0 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 2d8 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 2e0 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 2e8 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 2f0 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 2f8 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 300 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 308 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 310 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 318 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 320 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 328 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 330 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 338 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 340 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 348 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 350 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 358 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 360 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 368 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 370 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 378 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 380 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 388 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 390 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 398 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3a0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3a8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3b0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3b8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3c8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 3d0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 3d8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 3e0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3e8 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 3f0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 3f8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 400 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 408 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 410 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 418 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 420 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 428 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 430 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 438 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 440 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 448 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 450 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 458 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 460 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 468 bf 61 00 00 00 00 00 00 mov64 r1, r6 - 470 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 478 9f 16 d0 28 00 00 00 00 stxdw [r6 + 0x28d0], r1 - 480 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 488 05 00 02 00 00 00 00 00 ja +0x2 - 490 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 498 55 01 03 00 05 00 00 00 jne r1, 0x5, +0x3 - 4a0 9d 00 00 00 00 00 00 00 return + 8 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] + 10 2c 22 00 00 00 00 00 00 ldxb w2, [r2 + 0x0] + 18 55 02 03 00 01 00 00 00 jne r2, 0x1, +0x3 + 20 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 28 55 03 8d 00 05 00 00 00 jne r3, 0x5, +0x8d + 30 9d 00 00 00 00 00 00 00 return + 38 55 02 8f 00 00 00 00 00 jne r2, 0x0, +0x8f + 40 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a + 48 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 50 55 02 8e 00 04 00 00 00 jne r2, 0x4, +0x8e + 58 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 60 55 02 8e 00 00 00 00 00 jne r2, 0x0, +0x8e + 68 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 70 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e + 78 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 80 55 02 8e 00 00 00 00 00 jne r2, 0x0, +0x8e + 88 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 90 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e + 98 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + a0 55 02 8e 00 0e 00 00 00 jne r2, 0xe, +0x8e + a8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + b0 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e + b8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + c0 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + c8 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + d0 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + d8 5d 23 ea ff 00 00 00 00 jne r3, r2, -0x16 + e0 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + e8 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + f0 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + f8 5d 23 e6 ff 00 00 00 00 jne r3, r2, -0x1a + 100 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 108 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 110 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 118 5d 23 e2 ff 00 00 00 00 jne r3, r2, -0x1e + 120 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 128 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 130 5d 32 df ff 00 00 00 00 jne r2, r3, -0x21 + 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 140 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 150 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 160 07 05 00 00 13 00 00 00 add64 r5, 0x13 + 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 188 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 190 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 198 5d 21 61 00 00 00 00 00 jne r1, r2, +0x61 + 1a0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 1a8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 1b0 5d 21 5e 00 00 00 00 00 jne r1, r2, +0x5e + 1b8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 1c0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 1c8 5d 21 5b 00 00 00 00 00 jne r1, r2, +0x5b + 1d0 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 1d8 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 1e0 5d 21 58 00 00 00 00 00 jne r1, r2, +0x58 + 1e8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 1f0 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 1f8 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 200 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 208 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 + 210 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 218 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 220 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 228 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 + 230 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 238 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 240 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 248 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 250 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 + 258 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 + 260 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 268 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 270 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 278 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 280 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 288 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 290 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 298 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 2a0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 2a8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2b0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 2b8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 2c8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 2d0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 2d8 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 2e0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 2e8 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 2f0 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 2f8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 300 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 308 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 310 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 318 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 320 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 328 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 330 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 338 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 340 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 348 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 350 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 358 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 360 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 368 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 370 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 378 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 380 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 388 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 390 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 398 07 01 00 00 14 00 00 00 add64 r1, 0x14 + 3a0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 3a8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3b0 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 3b8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3c8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 3d0 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 3d8 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 3e0 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 3f0 07 01 00 00 13 00 00 00 add64 r1, 0x13 + 3f8 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 400 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 408 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 410 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 418 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 420 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 428 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 430 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 438 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 440 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 448 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 450 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 458 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 460 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 468 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 470 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 478 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 480 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + 488 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 490 05 00 73 ff 00 00 00 00 ja -0x8d + 498 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 4a0 05 00 71 ff 00 00 00 00 ja -0x8f 4a8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 4b0 05 00 fd ff 00 00 00 00 ja -0x3 - 4b8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - 4c0 05 00 fb ff 00 00 00 00 ja -0x5 + 4b0 05 00 6f ff 00 00 00 00 ja -0x91 + 4b8 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 4c0 05 00 6d ff 00 00 00 00 ja -0x93 4c8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 4d0 05 00 f9 ff 00 00 00 00 ja -0x7 + 4d0 05 00 6b ff 00 00 00 00 ja -0x95 4d8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 4e0 05 00 f7 ff 00 00 00 00 ja -0x9 + 4e0 05 00 69 ff 00 00 00 00 ja -0x97 4e8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4f0 05 00 f5 ff 00 00 00 00 ja -0xb + 4f0 05 00 67 ff 00 00 00 00 ja -0x99 4f8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 500 05 00 f3 ff 00 00 00 00 ja -0xd + 500 05 00 65 ff 00 00 00 00 ja -0x9b 508 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 510 05 00 f1 ff 00 00 00 00 ja -0xf + 510 05 00 63 ff 00 00 00 00 ja -0x9d 518 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 520 05 00 ef ff 00 00 00 00 ja -0x11 + 520 05 00 61 ff 00 00 00 00 ja -0x9f 528 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 530 05 00 ed ff 00 00 00 00 ja -0x13 \ No newline at end of file + 530 05 00 5f ff 00 00 00 00 ja -0xa1 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index eb9db260..d2689712 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,104 +2,109 @@ entrypoint: add64 r10, -320 - mov64 r6, r1 - ldxdw r1, [r2-8] + ldxdw r3, [r2-8] ldxb r2, [r2+0] - jeq r2, 1, jmp_0498 - mov64 r0, 11 - jne r2, 0, jmp_04a8 - jne r1, 1, jmp_04b0 - ldxdw r1, [r6+0] - jne r1, 4, jmp_04c0 - ldxdw r1, [r6+88] - jne r1, 0, jmp_04d0 - ldxb r1, [r6+10344] - jne r1, 255, jmp_04e0 - ldxdw r1, [r6+10424] - jne r1, 0, jmp_04f0 - ldxb r1, [r6+20680] - jne r1, 255, jmp_0500 - ldxdw r1, [r6+20760] - jne r1, 14, jmp_0510 - ldxb r1, [r6+31032] - jne r1, 255, jmp_0520 + jne r2, 1, jmp_0038 + mov64 r0, 0 + jne r3, 5, jmp_04a0 + +jmp_0030: + exit + +jmp_0038: + jne r2, 0, jmp_04b0 + jne r3, 1, jmp_04a0 + ldxdw r2, [r1+0] + jne r2, 4, jmp_04c0 + ldxdw r2, [r1+88] + jne r2, 0, jmp_04d0 + ldxb r2, [r1+10344] + jne r2, 255, jmp_04e0 + ldxdw r2, [r1+10424] + jne r2, 0, jmp_04f0 + ldxb r2, [r1+20680] + jne r2, 255, jmp_0500 + ldxdw r2, [r1+20760] + jne r2, 14, jmp_0510 + ldxb r2, [r1+31032] + jne r2, 255, jmp_0520 mov64 r0, 8 - mov32 r1, 399877894 - hor64 r1, 1364995097 - ldxdw r2, [r6+31040] - jne r2, r1, jmp_04a8 - mov32 r1, 1288277025 - hor64 r1, 2146519613 - ldxdw r2, [r6+31048] - jne r2, r1, jmp_04a8 - mov32 r1, 149871192 - hor64 r1, 1157472667 - ldxdw r2, [r6+31056] - jne r2, r1, jmp_04a8 - ldxdw r1, [r6+31064] - mov32 r2, -1965433885 - jne r1, r2, jmp_04a8 - mov64 r7, r6 - add64 r7, 41401 + mov32 r2, 399877894 + hor64 r2, 1364995097 + ldxdw r3, [r1+31040] + jne r3, r2, jmp_0030 + mov32 r2, 1288277025 + hor64 r2, 2146519613 + ldxdw r3, [r1+31048] + jne r3, r2, jmp_0030 + mov32 r2, 149871192 + hor64 r2, 1157472667 + ldxdw r3, [r1+31056] + jne r3, r2, jmp_0030 + ldxdw r2, [r1+31064] + mov32 r3, -1965433885 + jne r2, r3, jmp_0030 + mov64 r6, r1 + add64 r6, 41401 mov64 r4, r10 add64 r4, 104 mov64 r5, r10 add64 r5, 19 - mov64 r1, r6 + mov64 r7, r1 mov64 r2, 0 - mov64 r3, r7 + mov64 r3, r6 call sol_try_find_program_address mov64 r0, 10 ldxdw r1, [r10+104] - ldxdw r2, [r6+10352] - jne r1, r2, jmp_04a8 + ldxdw r2, [r7+10352] + jne r1, r2, jmp_0030 ldxdw r1, [r10+112] - ldxdw r2, [r6+10360] - jne r1, r2, jmp_04a8 + ldxdw r2, [r7+10360] + jne r1, r2, jmp_0030 ldxdw r1, [r10+120] - ldxdw r2, [r6+10368] - jne r1, r2, jmp_04a8 + ldxdw r2, [r7+10368] + jne r1, r2, jmp_0030 ldxdw r1, [r10+128] - ldxdw r2, [r6+10376] - jne r1, r2, jmp_04a8 - mov64 r1, r6 + ldxdw r2, [r7+10376] + jne r1, r2, jmp_0030 + mov64 r1, r7 add64 r1, 10352 - ldxdw r2, [r6+31120] - ldxdw r3, [r7+24] + ldxdw r2, [r7+31120] + ldxdw r3, [r6+24] stxdw [r10+64], r3 - ldxdw r3, [r7+16] + ldxdw r3, [r6+16] stxdw [r10+56], r3 - ldxdw r3, [r7+8] + ldxdw r3, [r6+8] stxdw [r10+48], r3 - ldxdw r3, [r7+0] + ldxdw r3, [r6+0] stxdw [r10+40], r3 lmul64 r2, 152 stxdw [r10+24], r2 stdw [r10+32], 24 stw [r10+20], 0 stxdw [r10+88], r1 - mov64 r2, r6 + mov64 r2, r7 add64 r2, 16 stxdw [r10+72], r2 sth [r10+96], 257 sth [r10+80], 257 - mov64 r3, r6 + mov64 r3, r7 add64 r3, 10384 stxdw [r10+192], r3 - mov64 r3, r6 + mov64 r3, r7 add64 r3, 10432 stxdw [r10+184], r3 - mov64 r3, r6 + mov64 r3, r7 add64 r3, 10416 stxdw [r10+168], r3 stxdw [r10+160], r1 - mov64 r1, r6 + mov64 r1, r7 add64 r1, 48 stxdw [r10+136], r1 - mov64 r1, r6 + mov64 r1, r7 add64 r1, 96 stxdw [r10+128], r1 - mov64 r1, r6 + mov64 r1, r7 add64 r1, 80 stxdw [r10+112], r1 stxdw [r10+104], r2 @@ -143,47 +148,44 @@ entrypoint: mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c - mov64 r1, r6 + mov64 r1, r7 add64 r1, 10456 - stxdw [r6+10448], r1 - mov64 r0, 0 - ja jmp_04a8 - -jmp_0498: + stxdw [r7+10448], r1 mov64 r0, 0 - jne r1, 5, jmp_04b0 + ja jmp_0030 -jmp_04a8: - exit +jmp_04a0: + mov64 r0, 12 + ja jmp_0030 jmp_04b0: - mov64 r0, 12 - ja jmp_04a8 + mov64 r0, 11 + ja jmp_0030 jmp_04c0: mov64 r0, 1 - ja jmp_04a8 + ja jmp_0030 jmp_04d0: mov64 r0, 2 - ja jmp_04a8 + ja jmp_0030 jmp_04e0: mov64 r0, 5 - ja jmp_04a8 + ja jmp_0030 jmp_04f0: mov64 r0, 3 - ja jmp_04a8 + ja jmp_0030 jmp_0500: mov64 r0, 6 - ja jmp_04a8 + ja jmp_0030 jmp_0510: mov64 r0, 4 - ja jmp_04a8 + ja jmp_0030 jmp_0520: mov64 r0, 7 - ja jmp_04a8 + ja jmp_0030 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 6fb2af51..23b53ad0 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -24,6 +24,7 @@ .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. +.equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. # Data layout constants. @@ -100,6 +101,13 @@ # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 +# Offsets for instruction processing. +# ----------------------------------- +.equ INSN_DISCRIMINATOR_OFF, 0 # Offset to instruction discriminator byte. +# Initialize instruction discriminator. +.equ INSN_DISCRIMINATOR_INITIALIZE, 0 +.equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. + # Init stack frame layout. # ------------------------ .equ SF_INIT_BUMP_SEED_OFF, -352 # Bump seed. diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt index c1c13eff..6761dffc 100644 --- a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt @@ -1,10 +1,16 @@ .globl entrypoint entrypoint: - # Check input buffer accounts. + # Read instruction data length and discriminator. # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. - mov64 r0, E_N_ACCOUNTS # Else fail. + ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. + ldxdw r8, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + ldxb r7, [r2 + OFFSET_ZERO] # Get discriminator. + + # Jump to branch for given discriminator. + # --------------------------------------------------------------------- + jeq r7, INSN_DISCRIMINATOR_INSERT, insert + jeq r7, INSN_DISCRIMINATOR_INITIALIZE, initialize + # Error if invalid discriminator provided. + mov64 r0, E_INSTRUCTION_DISCRIMINATOR exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/general-branching.txt b/examples/tree/artifacts/snippets/asm/general-branching.txt deleted file mode 100644 index 53218617..00000000 --- a/examples/tree/artifacts/snippets/asm/general-branching.txt +++ /dev/null @@ -1,18 +0,0 @@ -general: - # Error if user has data. - # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] - jne r9, DATA_LEN_ZERO, e_user_data_len - - # Error if tree is duplicate. - # --------------------------------------------------------------------- - ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_tree_duplicate - - # Get instruction data length, check instruction discriminator. - # --------------------------------------------------------------------- - ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. - ldxb r8, [r2 + OFFSET_ZERO] # Get discriminator. - jeq r8, TREE_DISCRIMINATOR_INSERT, insert # Fast path to insert. - mov64 r0, E_INSTRUCTION_DISCRIMINATOR # Else fail. - exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt index 8a3c8fe0..ff67dcfc 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-input-checks.txt @@ -1,4 +1,12 @@ initialize: + # Error if invalid instruction data length. + # --------------------------------------------------------------------- + jne r9, SIZE_OF_INITIALIZE_INSTRUCTION, e_instruction_data_len + + # Error if invalid number of accounts. + # --------------------------------------------------------------------- + jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts + # Error if user has data. # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] @@ -40,9 +48,4 @@ initialize: # Instead, replace with mov32, which only loads one 32-bit immediate, # since the rent sysvar address has all chunk 3 hi bits unset. mov32 r8, IB_RENT_ID_CHUNK_3_LO - jne r9, r8, e_rent_address - - # Error if instruction data provided. - # --------------------------------------------------------------------- - ldxdw r9, [r2 - SIZE_OF_U64] - jne r9, DATA_LEN_ZERO, e_instruction_data \ No newline at end of file + jne r9, r8, e_rent_address \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index 3209df97..01201380 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -39,5 +39,9 @@ constant_group! { prefix = "INSN", /// Offset to instruction discriminator byte. offset!(DISCRIMINATOR, InstructionHeader.discriminator), + /// Initialize instruction discriminator. + DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, + /// Insert instruction discriminator. + DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, } } diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 69d294cf..4739d93d 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -5,13 +5,12 @@ nostd_panic_handler!(); pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); - match ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) { - x if x == Instruction::Initialize as u8 => { - initialize(input, instruction_data, instruction_data_len, n_accounts) - } - x if x == Instruction::Insert as u8 => { - insert(input, instruction_data, instruction_data_len, n_accounts) - } - _ => error::INSTRUCTION_DISCRIMINATOR.into(), + let instruction_discriminator = ldxb(instruction_data, instruction::DISCRIMINATOR_OFF); + if likely(instruction_discriminator == instruction::DISCRIMINATOR_INSERT) { + insert(input, instruction_data, instruction_data_len, n_accounts) + } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_INITIALIZE) { + initialize(input, instruction_data, instruction_data_len, n_accounts) + } else { + error::INSTRUCTION_DISCRIMINATOR.into() } } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 68376696..d2aa128b 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,9 +1,9 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction discriminator | 11 | 8 | -3 | -27.3% | +| Invalid instruction discriminator | 7 | 8 | +1 | +14.3% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index d5650d28..ac84fbbb 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,33 +1,36 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 0 | 141 | +141 | N/A | - (ASM) System Program is wrong address: expected Failure(NotEnoughAccountKeys), got Failure(Custom(9)) -| User has insufficient Lamports | 2596 | 0 | 141 | +141 | N/A | - (ASM) User has insufficient Lamports: expected Failure(Custom(1)), got Failure(Custom(9)) -| CreateAccount happy path | 2596 | 0 | 147 | +147 | N/A | - (ASM) CreateAccount happy path: expected Success, got Failure(Custom(9)) +| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | +| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | +| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2587 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 [ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2737 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2743 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt index 4c771911..aa2dd6c3 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, true, false); + print_comparison_table(init::InitCase::CPI_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 0908a4ea..547baf75 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,117 +1,122 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 31 | 11 | -20 | -64.5% | - (ASM) Invalid instruction data length: expected Failure(Custom(12)), got Failure(Custom(9)) -| Incorrect number of accounts | 11 | 13 | +2 | +18.2% | - (ASM) Incorrect number of accounts: expected Failure(Custom(1)), got Failure(Custom(11)) -| User has nonzero data length | 7 | 15 | +8 | +114.3% | -| Tree account is duplicate | 9 | 17 | +8 | +88.9% | -| Tree has nonzero data length | 11 | 19 | +8 | +72.7% | -| System program is duplicate | 13 | 21 | +8 | +61.5% | -| System program wrong data length | 15 | 23 | +8 | +53.3% | -| Rent sysvar is duplicate | 17 | 25 | +8 | +47.1% | -| Rent address mismatch word 0 | 20 | 28 | +8 | +40.0% | -| Rent address mismatch word 1 | 20 | 28 | +8 | +40.0% | -| Rent address mismatch word 2 | 23 | 32 | +9 | +39.1% | -| Rent address mismatch word 3 | 23 | 32 | +9 | +39.1% | -| Rent address mismatch word 4 | 26 | 36 | +10 | +38.5% | -| Rent address mismatch word 5 | 26 | 36 | +10 | +38.5% | -| Rent address mismatch word 6 | 29 | 39 | +10 | +34.5% | -| Rent address mismatch word 7 | 29 | 39 | +10 | +34.5% | +| Invalid instruction data length | 8 | 9 | +1 | +12.5% | +| Too few accounts | 9 | 11 | +2 | +22.2% | +| Too many accounts | 9 | 11 | +2 | +22.2% | +| User has nonzero data length | 11 | 13 | +2 | +18.2% | +| Tree account is duplicate | 13 | 15 | +2 | +15.4% | +| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | +| System program is duplicate | 17 | 19 | +2 | +11.8% | +| System program wrong data length | 19 | 21 | +2 | +10.5% | +| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | +| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | +| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt index 94e043d8..24226cfc 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, true, false); + print_comparison_table(init::InitCase::CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 243d1001..49588334 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,35 +1,31 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 0 | 54 | +54 | N/A | - (ASM) PDA mismatch chunk 1: expected Failure(Custom(10)), got Failure(Custom(9)) -| PDA mismatch chunk 2 | 1500 | 0 | 57 | +57 | N/A | - (ASM) PDA mismatch chunk 2: expected Failure(Custom(10)), got Failure(Custom(9)) -| PDA mismatch chunk 3 | 1500 | 0 | 60 | +60 | N/A | - (ASM) PDA mismatch chunk 3: expected Failure(Custom(10)), got Failure(Custom(9)) -| PDA mismatch chunk 4 | 1500 | 0 | 63 | +63 | N/A | - (ASM) PDA mismatch chunk 4: expected Failure(Custom(10)), got Failure(Custom(9)) +| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | +| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | +| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | +| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1554 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1557 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1560 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9 +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1563 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt index fc7859a4..0f682d5d 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, true, false); + print_comparison_table(init::InitCase::PDA_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index df93c555..ffc545f7 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Instruction data too short | 12 | 10 | -2 | -16.7% | -| Instruction data too long | 12 | 10 | -2 | -16.7% | -| Insert happy path | 11 | 8 | -3 | -27.3% | +| Instruction data too short | 7 | 9 | +2 | +28.6% | +| Instruction data too long | 7 | 9 | +2 | +28.6% | +| Insert happy path | 6 | 7 | +1 | +16.7% | test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/build.rs b/examples/tree/build.rs index 4c0c45a0..ed64ea76 100644 --- a/examples/tree/build.rs +++ b/examples/tree/build.rs @@ -18,6 +18,7 @@ fn main() { data, pubkey_chunk, input_buffer, + instruction, init_stack_frame, cpi, tree diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index e5ff8ae8..ee90c2b5 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,8 +4,8 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, CreateAccountInstructionData, InitInputBuffer, InputBufferHeader, InsertInstruction, - Instruction, TreeHeader, + cpi, CreateAccountInstructionData, InitInputBuffer, InitializeInstruction, InputBufferHeader, + InsertInstruction, Instruction, TreeHeader, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -22,6 +22,7 @@ sizes! { Address, u128, TreeHeader, + InitializeInstruction, InsertInstruction, } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index a6b7a303..9e25ae86 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -248,6 +248,10 @@ constant_group! { prefix = "INSN", /// Offset to instruction discriminator byte. offset!(DISCRIMINATOR, InstructionHeader.discriminator), + /// Initialize instruction discriminator. + DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, + /// Insert instruction discriminator. + DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 2cfbf97a..0e535a5c 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,8 +9,8 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, - Direction, InitializeInstruction, InsertInstruction, Instruction, SolAccountInfo, - SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, + Direction, InitializeInstruction, InsertInstruction, SolAccountInfo, SolAccountMeta, + SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -73,14 +73,13 @@ nostd_panic_handler!(); pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) -> u64 { let instruction_data_len = ldxdw(instruction_data, -(size_of::() as i16)); let n_accounts = ldxdw(input, input_buffer::N_ACCOUNTS_OFF); - match ldxb(instruction_data, instruction::DISCRIMINATOR_OFF) { - x if x == Instruction::Initialize as u8 => { - initialize(input, instruction_data, instruction_data_len, n_accounts) - } - x if x == Instruction::Insert as u8 => { - insert(input, instruction_data, instruction_data_len, n_accounts) - } - _ => error::INSTRUCTION_DISCRIMINATOR.into(), + let instruction_discriminator = ldxb(instruction_data, instruction::DISCRIMINATOR_OFF); + if likely(instruction_discriminator == instruction::DISCRIMINATOR_INSERT) { + insert(input, instruction_data, instruction_data_len, n_accounts) + } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_INITIALIZE) { + initialize(input, instruction_data, instruction_data_len, n_accounts) + } else { + error::INSTRUCTION_DISCRIMINATOR.into() } } // ANCHOR_END: entrypoint-branching diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 025f5079..97f5d495 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -155,15 +155,15 @@ fn test_insert() { #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, true, false); + print_comparison_table(init::InitCase::CASES, false, false); } #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, true, false); + print_comparison_table(init::InitCase::PDA_CASES, false, false); } #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, true, false); + print_comparison_table(init::InitCase::CPI_CASES, false, false); } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 8c21258e..42d0d2e5 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -25,6 +25,7 @@ .equ SIZE_OF_ADDRESS, 32 # Size of Address. .equ SIZE_OF_U128, 16 # Size of u128. .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. +.equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. # Data layout constants. @@ -101,6 +102,13 @@ # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 +# Offsets for instruction processing. +# ----------------------------------- +.equ INSN_DISCRIMINATOR_OFF, 0 # Offset to instruction discriminator byte. +# Initialize instruction discriminator. +.equ INSN_DISCRIMINATOR_INITIALIZE, 0 +.equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. + # Init stack frame layout. # ------------------------ .equ SF_INIT_BUMP_SEED_OFF, -352 # Bump seed. @@ -201,38 +209,31 @@ .globl entrypoint entrypoint: - # Check input buffer accounts. + # Read instruction data length and discriminator. + # --------------------------------------------------------------------- + ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. + ldxdw r8, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. + ldxb r7, [r2 + OFFSET_ZERO] # Get discriminator. + + # Jump to branch for given discriminator. # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_N_ACCOUNTS_OFF] # Get n input buffer accounts. - jeq r9, IB_N_ACCOUNTS_GENERAL, general # Fast path to general case. - jeq r9, IB_N_ACCOUNTS_INIT, initialize # Branch to init case. - mov64 r0, E_N_ACCOUNTS # Else fail. + jeq r7, INSN_DISCRIMINATOR_INSERT, insert + jeq r7, INSN_DISCRIMINATOR_INITIALIZE, initialize + # Error if invalid discriminator provided. + mov64 r0, E_INSTRUCTION_DISCRIMINATOR exit # ANCHOR_END: entrypoint-branching -# ANCHOR: general-branching -general: - # Error if user has data. +# ANCHOR: initialize-input-checks +initialize: + # Error if invalid instruction data length. # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] - jne r9, DATA_LEN_ZERO, e_user_data_len + jne r9, SIZE_OF_INITIALIZE_INSTRUCTION, e_instruction_data_len - # Error if tree is duplicate. + # Error if invalid number of accounts. # --------------------------------------------------------------------- - ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts - # Get instruction data length, check instruction discriminator. - # --------------------------------------------------------------------- - ldxdw r9, [r2 - SIZE_OF_U64] # Get instruction data length. - ldxb r8, [r2 + OFFSET_ZERO] # Get discriminator. - jeq r8, TREE_DISCRIMINATOR_INSERT, insert # Fast path to insert. - mov64 r0, E_INSTRUCTION_DISCRIMINATOR # Else fail. - exit -# ANCHOR_END: general-branching - -# ANCHOR: initialize-input-checks -initialize: # Error if user has data. # --------------------------------------------------------------------- ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] @@ -275,11 +276,6 @@ initialize: # since the rent sysvar address has all chunk 3 hi bits unset. mov32 r8, IB_RENT_ID_CHUNK_3_LO jne r9, r8, e_rent_address - - # Error if instruction data provided. - # --------------------------------------------------------------------- - ldxdw r9, [r2 - SIZE_OF_U64] - jne r9, DATA_LEN_ZERO, e_instruction_data # ANCHOR_END: initialize-input-checks # ANCHOR: initialize-pda-checks @@ -477,6 +473,10 @@ e_instruction_data_len: mov64 r0, E_INSTRUCTION_DATA_LEN exit +e_n_accounts: + mov64 r0, E_N_ACCOUNTS + exit + e_pda_mismatch: mov64 r0, E_PDA_MISMATCH exit From d0aa1b59157a7047cac9e2971d7b7d611ef708e5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:54:34 -0800 Subject: [PATCH 169/263] Update docs for branching flow --- docs/src/examples/tree.md | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 92e663dd..a15352be 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -46,9 +46,7 @@ time. ::: -## Branching - -### Entrypoint +## Entrypoint branching The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. Note that the Rust @@ -69,37 +67,7 @@ greedy [tail call optimizations][tail call]. ::: details Benchmarking - - -::: - -### General - -If the user passes the number of accounts required for a general operation (all -instructions besides the [initialize](#initialize) instruction), the program -branches to a common instruction handler. - -::: details Instruction definitions - -<<< ../../../examples/tree/artifacts/snippets/interface/instructions.txt{rs} - -::: - -::: details Implementations - -::: code-group - - - -<<< ../../../examples/tree/artifacts/snippets/asm/general-branching.txt{asm} [Assembly] - -<<< ../../../examples/tree/artifacts/snippets/rs/general-branching.txt{rs} [Rust] - -::: - -::: details Benchmarking - - + ::: @@ -125,7 +93,7 @@ invokes a [`CreateAccount` CPI](counter#cpi-construction), with the same ::: details Benchmarking - + ::: From 00d2ea75a52a121f845b8ab8998409180f3708c3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:19:38 -0800 Subject: [PATCH 170/263] Abstract macros for accounts --- .../snippets/rs/initialize-input-checks.txt | 29 +++----- .../tree/artifacts/snippets/rs/insert.txt | 11 ++- examples/tree/src/program.rs | 74 ++++++++++++++----- 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 536d9a18..1cfa5fbb 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -5,11 +5,7 @@ unsafe fn initialize( instruction_data_len: u64, n_accounts: u64, ) -> u64 { - // Error if instruction data provided. - if_err!( - instruction_data_len != size_of::() as u64, - error::INSTRUCTION_DATA_LEN - ); + check_instruction_data_len!(instruction_data_len, InitializeInstruction); // Error if incorrect number of accounts. if_err!( @@ -18,28 +14,27 @@ unsafe fn initialize( ); // Error if user has data. - let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!((*user).data_len != 0, error::USER_DATA_LEN); + let user = user_account!(input); // Error if tree is duplicate or has data. - let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(tree), error::TREE_DUPLICATE); - if_err!((*tree).data_len != 0, error::TREE_DATA_LEN); + let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + check_data_len!(tree, data::DATA_LEN_ZERO, error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); - if_err!( - is_duplicate(system_program), + let system_program = account_non_dup!( + input, + input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF, error::SYSTEM_PROGRAM_DUPLICATE ); - if_err!( - (*system_program).data_len as usize != input_buffer::SYSTEM_PROGRAM_DATA_LEN, + check_data_len!( + system_program, + input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); - if_err!(is_duplicate(rent_sysvar), error::RENT_DUPLICATE); + let rent_sysvar = + account_non_dup!(input, input_buffer::RENT_ACCOUNT_OFF, error::RENT_DUPLICATE); let rent_id = RENT_ID; if_err!( !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 5d0d3373..f586d292 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -5,12 +5,17 @@ unsafe fn insert( instruction_data_len: u64, n_accounts: u64, ) -> u64 { - // Error if invalid instruction data length. + check_instruction_data_len!(instruction_data_len, InsertInstruction); + + // Error if too few accounts. if_err!( - instruction_data_len != size_of::() as u64, - error::INSTRUCTION_DATA_LEN + n_accounts < input_buffer::N_ACCOUNTS_GENERAL, + error::N_ACCOUNTS ); + let user = user_account!(input); + let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 0e535a5c..139a17f4 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -65,6 +65,40 @@ macro_rules! if_err { }; } +macro_rules! check_instruction_data_len { + ($instruction_data_len:expr, $type:ty) => { + if_err!( + $instruction_data_len != size_of::<$type>() as u64, + error::INSTRUCTION_DATA_LEN + ); + }; +} + +macro_rules! user_account { + ($input:expr) => {{ + let user = account_at($input, input_buffer::USER_ACCOUNT_OFF); + if_err!( + (*user).data_len != data::DATA_LEN_ZERO, + error::USER_DATA_LEN + ); + user + }}; +} + +macro_rules! check_data_len { + ($account:expr, $expected:expr, $error:expr) => { + if_err!((*$account).data_len != $expected, $error); + }; +} + +macro_rules! account_non_dup { + ($input:expr, $offset:expr, $error:expr) => {{ + let account = account_at($input, $offset); + if_err!(is_duplicate(account), $error); + account + }}; +} + // ANCHOR: entrypoint-branching no_allocator!(); nostd_panic_handler!(); @@ -92,12 +126,17 @@ unsafe fn insert( instruction_data_len: u64, n_accounts: u64, ) -> u64 { - // Error if invalid instruction data length. + check_instruction_data_len!(instruction_data_len, InsertInstruction); + + // Error if too few accounts. if_err!( - instruction_data_len != size_of::() as u64, - error::INSTRUCTION_DATA_LEN + n_accounts < input_buffer::N_ACCOUNTS_GENERAL, + error::N_ACCOUNTS ); + let user = user_account!(input); + let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. @@ -115,11 +154,7 @@ unsafe fn initialize( instruction_data_len: u64, n_accounts: u64, ) -> u64 { - // Error if instruction data provided. - if_err!( - instruction_data_len != size_of::() as u64, - error::INSTRUCTION_DATA_LEN - ); + check_instruction_data_len!(instruction_data_len, InitializeInstruction); // Error if incorrect number of accounts. if_err!( @@ -128,28 +163,27 @@ unsafe fn initialize( ); // Error if user has data. - let user = account_at(input, input_buffer::USER_ACCOUNT_OFF); - if_err!((*user).data_len != 0, error::USER_DATA_LEN); + let user = user_account!(input); // Error if tree is duplicate or has data. - let tree = account_at(input, input_buffer::TREE_ACCOUNT_OFF); - if_err!(is_duplicate(tree), error::TREE_DUPLICATE); - if_err!((*tree).data_len != 0, error::TREE_DATA_LEN); + let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + check_data_len!(tree, data::DATA_LEN_ZERO, error::TREE_DATA_LEN); // Error if System Program is duplicate or has invalid data length. - let system_program = account_at(input, input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF); - if_err!( - is_duplicate(system_program), + let system_program = account_non_dup!( + input, + input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF, error::SYSTEM_PROGRAM_DUPLICATE ); - if_err!( - (*system_program).data_len as usize != input_buffer::SYSTEM_PROGRAM_DATA_LEN, + check_data_len!( + system_program, + input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, error::SYSTEM_PROGRAM_DATA_LEN ); // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = account_at(input, input_buffer::RENT_ACCOUNT_OFF); - if_err!(is_duplicate(rent_sysvar), error::RENT_DUPLICATE); + let rent_sysvar = + account_non_dup!(input, input_buffer::RENT_ACCOUNT_OFF, error::RENT_DUPLICATE); let rent_id = RENT_ID; if_err!( !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), From 5c1c962da10246bc6937d87d7ea3a5f1d8d42aa4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:23:22 -0800 Subject: [PATCH 171/263] Begin insert allocatin logic --- examples/tree/artifacts/snippets/rs/insert.txt | 8 ++++++-- examples/tree/src/program.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index f586d292..164f76e1 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -13,12 +13,16 @@ unsafe fn insert( error::N_ACCOUNTS ); + // Error if user has data. let user = user_account!(input); + + // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + // Allocate a node if the stack is empty. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - - if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header).top.is_null() { + let tree_data_len = (*tree).data_len; } SUCCESS diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 139a17f4..5d3c20cd 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -134,12 +134,16 @@ unsafe fn insert( error::N_ACCOUNTS ); + // Error if user has data. let user = user_account!(input); + + // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + // Allocate a node if the stack is empty. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - - if (*tree_header).top.is_null() { // If stack is empty, need to allocate a node. + if (*tree_header).top.is_null() { + let tree_data_len = (*tree).data_len; } SUCCESS From 5b203f6087a55570be44f75e8d2d39232c651616 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:38:39 -0800 Subject: [PATCH 172/263] Begin insert allocation path --- .../tree/artifacts/snippets/asm/constants.txt | 2 + .../snippets/rs/initialize-input-checks.txt | 21 +------ .../tree/artifacts/snippets/rs/insert.txt | 12 ++++ examples/tree/interface/src/common.rs | 2 + examples/tree/src/program.rs | 61 +++++++++++++------ examples/tree/src/tests/insert.rs | 11 ++-- examples/tree/src/tree/tree.s | 2 + 7 files changed, 67 insertions(+), 44 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 23b53ad0..3bef1a1f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -16,6 +16,8 @@ .equ E_PDA_MISMATCH, 10 .equ E_INSTRUCTION_DISCRIMINATOR, 11 # Invalid instruction discriminator. .equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. +# Not enough accounts passed for insertion allocation. +.equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 # Type sizes. # ----------- diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index 1cfa5fbb..ee9aeb59 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -20,23 +20,4 @@ unsafe fn initialize( let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); check_data_len!(tree, data::DATA_LEN_ZERO, error::TREE_DATA_LEN); - // Error if System Program is duplicate or has invalid data length. - let system_program = account_non_dup!( - input, - input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF, - error::SYSTEM_PROGRAM_DUPLICATE - ); - check_data_len!( - system_program, - input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, - error::SYSTEM_PROGRAM_DATA_LEN - ); - - // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = - account_non_dup!(input, input_buffer::RENT_ACCOUNT_OFF, error::RENT_DUPLICATE); - let rent_id = RENT_ID; - if_err!( - !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), - error::RENT_ADDRESS - ); \ No newline at end of file + check_cpi_accounts!(input); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 164f76e1..f188100c 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -22,7 +22,19 @@ unsafe fn insert( // Allocate a node if the stack is empty. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { + // Error if wrong number of accounts passed, since need extra accounts to allocate space. + if_err!( + n_accounts != input_buffer::N_ACCOUNTS_INIT, + error::N_ACCOUNTS_INSERT_ALLOCATION + ); + + // Get shifted input buffer pointer based on tree data length. let tree_data_len = (*tree).data_len; + let shifted_input = + input.add(tree_data_len.next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); + + // Check system program and rent sysvar accounts using shifted input buffer pointer. + check_cpi_accounts!(shifted_input); } SUCCESS diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 9e25ae86..c0b7eaa4 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -31,6 +31,8 @@ error_codes! { INSTRUCTION_DISCRIMINATOR, /// Invalid instruction data length. INSTRUCTION_DATA_LEN, + /// Not enough accounts passed for insertion allocation. + N_ACCOUNTS_INSERT_ALLOCATION, } constant_group! { diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 5d3c20cd..359e6b8f 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -99,6 +99,34 @@ macro_rules! account_non_dup { }}; } +/// Checks the System Program and Rent sysvar accounts relative to a given input buffer pointer. +/// In `initialize`, this is the base `input`; in `insert`, it is `shifted_input` which accounts +/// for the tree's existing data length. +macro_rules! check_cpi_accounts { + ($input:expr) => { + let system_program = account_non_dup!( + $input, + input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF, + error::SYSTEM_PROGRAM_DUPLICATE + ); + check_data_len!( + system_program, + input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, + error::SYSTEM_PROGRAM_DATA_LEN + ); + let rent_sysvar = account_non_dup!( + $input, + input_buffer::RENT_ACCOUNT_OFF, + error::RENT_DUPLICATE + ); + let rent_id = RENT_ID; + if_err!( + !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), + error::RENT_ADDRESS + ); + }; +} + // ANCHOR: entrypoint-branching no_allocator!(); nostd_panic_handler!(); @@ -143,7 +171,19 @@ unsafe fn insert( // Allocate a node if the stack is empty. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); if (*tree_header).top.is_null() { + // Error if wrong number of accounts passed, since need extra accounts to allocate space. + if_err!( + n_accounts != input_buffer::N_ACCOUNTS_INIT, + error::N_ACCOUNTS_INSERT_ALLOCATION + ); + + // Get shifted input buffer pointer based on tree data length. let tree_data_len = (*tree).data_len; + let shifted_input = + input.add(tree_data_len.next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); + + // Check system program and rent sysvar accounts using shifted input buffer pointer. + check_cpi_accounts!(shifted_input); } SUCCESS @@ -173,26 +213,7 @@ unsafe fn initialize( let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); check_data_len!(tree, data::DATA_LEN_ZERO, error::TREE_DATA_LEN); - // Error if System Program is duplicate or has invalid data length. - let system_program = account_non_dup!( - input, - input_buffer::SYSTEM_PROGRAM_ACCOUNT_OFF, - error::SYSTEM_PROGRAM_DUPLICATE - ); - check_data_len!( - system_program, - input_buffer::SYSTEM_PROGRAM_DATA_LEN as u64, - error::SYSTEM_PROGRAM_DATA_LEN - ); - - // Error if Rent account is duplicate or has incorrect address. - let rent_sysvar = - account_non_dup!(input, input_buffer::RENT_ACCOUNT_OFF, error::RENT_DUPLICATE); - let rent_id = RENT_ID; - if_err!( - !address_eq(addr_of!((*rent_sysvar).address), addr_of!(rent_id)), - error::RENT_ADDRESS - ); + check_cpi_accounts!(input); // ANCHOR_END: initialize-input-checks // ANCHOR: initialize-pda-checks diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 9316e65e..abeffc89 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -28,15 +28,18 @@ fn insert_setup( ], ); + // Initialize tree account with non-null `top` pointer so insert skips allocation. + let mut tree_data = vec![0u8; cpi::TREE_DATA_LEN]; + tree_data[8..16].copy_from_slice(&1u64.to_le_bytes()); // top != null + let mut tree_account = Account::new(0, cpi::TREE_DATA_LEN, &setup.program_id); + tree_account.data = tree_data; + let accounts = vec![ ( user_pubkey, Account::new(USER_LAMPORTS, 0, &system_program_pubkey), ), - ( - tree_pubkey, - Account::new(0, cpi::TREE_DATA_LEN, &setup.program_id), - ), + (tree_pubkey, tree_account), ]; (setup, instruction, accounts) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 42d0d2e5..a1b3ebeb 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -17,6 +17,8 @@ .equ E_PDA_MISMATCH, 10 .equ E_INSTRUCTION_DISCRIMINATOR, 11 # Invalid instruction discriminator. .equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. +# Not enough accounts passed for insertion allocation. +.equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 # Type sizes. # ----------- From f8ad3174dff104d09500aa2196792ee6fd1df322 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:47:30 -0800 Subject: [PATCH 173/263] Begin allocation refactor --- examples/tree/artifacts/snippets/rs/insert.txt | 4 ++-- examples/tree/src/program.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index f188100c..1c034e92 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -29,9 +29,9 @@ unsafe fn insert( ); // Get shifted input buffer pointer based on tree data length. - let tree_data_len = (*tree).data_len; + let tree_data_len: *mut u64 = addr_of_mut!((*tree).data_len); let shifted_input = - input.add(tree_data_len.next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); + input.add((*tree_data_len).next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); // Check system program and rent sysvar accounts using shifted input buffer pointer. check_cpi_accounts!(shifted_input); diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 359e6b8f..228588ed 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,4 @@ -use core::ptr::{addr_of, read_unaligned}; +use core::ptr::{addr_of, addr_of_mut, read_unaligned}; use pinocchio::{ account::RuntimeAccount, entrypoint::NON_DUP_MARKER, @@ -178,9 +178,9 @@ unsafe fn insert( ); // Get shifted input buffer pointer based on tree data length. - let tree_data_len = (*tree).data_len; + let tree_data_len: *mut u64 = addr_of_mut!((*tree).data_len); let shifted_input = - input.add(tree_data_len.next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); + input.add((*tree_data_len).next_multiple_of(data::BPF_ALIGN_OF_U128 as u64) as usize); // Check system program and rent sysvar accounts using shifted input buffer pointer. check_cpi_accounts!(shifted_input); From c76f812b1f1d8577a4e98f2591ee23dad874a214 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 17:21:46 -0800 Subject: [PATCH 174/263] Update allocations block --- .../tree/artifacts/snippets/asm/constants.txt | 16 +- .../snippets/interface/tree-defs-common.txt | 2 + .../snippets/rs/initialize-create-account.txt | 4 +- .../tree/artifacts/snippets/rs/insert.txt | 104 ++++++++++- examples/tree/interface/src/asm.rs | 2 +- examples/tree/interface/src/common.rs | 25 ++- examples/tree/interface/src/lib.rs | 3 +- examples/tree/src/program.rs | 110 ++++++++++- examples/tree/src/tests.rs | 2 +- examples/tree/src/tests/insert.rs | 173 ++++++++++++++++-- examples/tree/src/tree/tree.s | 16 +- 11 files changed, 417 insertions(+), 40 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 3bef1a1f..adae7916 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -178,16 +178,23 @@ # CPI-specific constants. # ----------------------- -.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign CPI. -.equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. -.equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts. +# The tree account is a PDA for CreateAccount CPI. +.equ CPI_N_PDA_SIGNERS, 1 +# Number of seeds for CreateAccount PDA signer (bump only). +.equ CPI_N_SEEDS_CREATE_ACCOUNT, 1 +# Number of signers for Transfer CPI (none — user is already a signer). +.equ CPI_N_SIGNERS_TRANSFER, 0 .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. .equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. .equ CPI_ACCOUNT_DATA_SCALAR, 152 # CreateAccount discriminator for CPI. .equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 -.equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. +# Length of CreateAccount instruction data. +.equ CPI_CREATE_ACCOUNT_INSN_DATA_LEN, 52 +.equ CPI_TRANSFER_DISCRIMINATOR, 2 # Transfer discriminator for CPI. +.equ CPI_TRANSFER_INSN_DATA_LEN, 12 # Length of Transfer instruction data. .equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. .equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. @@ -200,6 +207,7 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. +.equ TREE_HEADER_TOP_OFF, 8 # Stack top field in header. .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index 6a7c5864..9cc5fe41 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -23,6 +23,8 @@ constant_group! { COLOR_B = Color::Black as u8, /// Red color. COLOR_R = Color::Red as u8, + /// Stack top field in header. + offset!(HEADER_TOP, TreeHeader.top), /// Next node field in header. offset!(HEADER_NEXT, TreeHeader.next), } diff --git a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt index a18fbeca..441f2914 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-create-account.txt @@ -57,7 +57,7 @@ accounts: sol_account_metas.as_ptr().cast_mut().cast(), account_len: sol_account_metas.len() as u64, data: addr_of!(create_account_instruction_data).cast_mut().cast(), - data_len: cpi::INSN_DATA_LEN as u64, + data_len: cpi::CREATE_ACCOUNT_INSN_DATA_LEN as u64, }; // Initialize signer seed for PDA bump. @@ -69,7 +69,7 @@ // Initialize signer seeds for PDA. let signers_seeds = SolSignerSeeds { addr: addr_of!(bump_seed).cast(), - len: cpi::N_SEEDS as u64, + len: cpi::N_SEEDS_CREATE_ACCOUNT as u64, }; #[cfg(target_os = "solana")] diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 1c034e92..936c8b1c 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -19,9 +19,9 @@ unsafe fn insert( // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); - // Allocate a node if the stack is empty. + // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - if (*tree_header).top.is_null() { + let _node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, @@ -35,7 +35,105 @@ unsafe fn insert( // Check system program and rent sysvar accounts using shifted input buffer pointer. check_cpi_accounts!(shifted_input); - } + + // Calculate additional lamports for rent exemption of one TreeNode. + let lamports_per_byte = ldxdw(shifted_input, input_buffer::RENT_DATA_OFF); + let transfer_lamports = size_of::() as u64 * lamports_per_byte; + + // Pack Transfer instruction data. + let transfer_instruction_data = TransferInstructionData { + discriminator: cpi::TRANSFER_DISCRIMINATOR, + lamports: transfer_lamports, + }; + + // Pack account metas and infos. + let user_key = input.add(input_buffer::USER_ADDRESS_OFF as usize).cast(); + let tree_key = input.add(input_buffer::TREE_ADDRESS_OFF as usize).cast(); + let sol_account_metas = [ + SolAccountMeta { + pubkey: user_key, + is_writable: true, + is_signer: true, + }, + SolAccountMeta { + pubkey: tree_key, + is_writable: true, + is_signer: false, + }, + ]; + let sol_account_infos = [ + SolAccountInfo { + key: user_key, + owner: input.add(input_buffer::USER_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::USER_LAMPORTS_OFF as usize).cast(), + data: input.add(input_buffer::USER_DATA_OFF as usize), + data_len: data::DATA_LEN_ZERO, + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + SolAccountInfo { + key: tree_key, + owner: input.add(input_buffer::TREE_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::TREE_LAMPORTS_OFF as usize).cast(), + data: input.add(input_buffer::TREE_DATA_OFF as usize), + data_len: *tree_data_len, + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: false, + is_writable: true, + executable: false, + }, + ]; + + // Pack instruction. + let system_program_address = Address::default(); + let sol_instruction = SolInstruction { + program_id: addr_of!(system_program_address).cast_mut().cast(), + accounts: sol_account_metas.as_ptr().cast_mut().cast(), + account_len: sol_account_metas.len() as u64, + data: addr_of!(transfer_instruction_data).cast_mut().cast(), + data_len: cpi::TRANSFER_INSN_DATA_LEN as u64, + }; + + // No signers needed, since user is already a signer on the transaction. + let empty_signers = SolSignerSeeds { + addr: core::ptr::null(), + len: 0, + }; + + #[cfg(target_os = "solana")] + sol_invoke_signed_c( + addr_of!(sol_instruction).cast(), + addr_of!(sol_account_infos).cast(), + cpi::N_ACCOUNTS as u64, + addr_of!(empty_signers).cast(), + cpi::N_SIGNERS_TRANSFER, + ); + #[cfg(not(target_os = "solana"))] + #[allow(path_statements)] + { + empty_signers; + sol_account_infos; + sol_instruction; + } + + // Save pointer to newly allocated node (current next). + let node = (*tree_header).next; + + // Increase tree data length by size of one TreeNode. + *tree_data_len += size_of::() as u64; + + // Advance next pointer by one TreeNode. + (*tree_header).next = (*tree_header).next.add(1); + + node + } else { + // Pop node from free stack. + let node = (*tree_header).top.cast::(); + (*tree_header).top = (*(*tree_header).top).next; + node + }; SUCCESS } \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index ee90c2b5..ec900ac4 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -81,7 +81,7 @@ struct InitStackFrame { account_metas: [SolAccountMeta; cpi::N_ACCOUNTS], account_infos: [SolAccountInfo; cpi::N_ACCOUNTS], signers_seeds: [SolSignerSeeds; cpi::N_PDA_SIGNERS], - signer_seeds: [SolSignerSeed; cpi::N_SEEDS], + signer_seeds: [SolSignerSeed; cpi::N_SEEDS_CREATE_ACCOUNT], pda: Address, rent: Rent, /// Zero-initialized on stack. diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index c0b7eaa4..1e0fccda 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -81,12 +81,14 @@ constant_group! { /// CPI-specific constants. cpi { prefix = "CPI", - /// User and tree accounts must sign CPI. + /// User and tree accounts. N_ACCOUNTS: usize = 2, - /// The tree account is a PDA. + /// The tree account is a PDA for CreateAccount CPI. N_PDA_SIGNERS: usize = 1, - /// The bump seed is required for tree PDA signer. - N_SEEDS: usize = 1, + /// Number of seeds for CreateAccount PDA signer (bump only). + N_SEEDS_CREATE_ACCOUNT: usize = 1, + /// Number of signers for Transfer CPI (none — user is already a signer). + N_SIGNERS_TRANSFER: u64 = 0, /// Number of seeds for PDA generation. N_SEEDS_TRY_FIND_PDA: u64 = 0, /// Tree account data length. @@ -96,7 +98,11 @@ constant_group! { /// CreateAccount discriminator for CPI. CREATE_ACCOUNT_DISCRIMINATOR: u32 = 0, /// Length of CreateAccount instruction data. - INSN_DATA_LEN: usize = size_of::(), + CREATE_ACCOUNT_INSN_DATA_LEN: usize = size_of::(), + /// Transfer discriminator for CPI. + TRANSFER_DISCRIMINATOR: u32 = 2, + /// Length of Transfer instruction data. + TRANSFER_INSN_DATA_LEN: usize = size_of::(), /// Mask for writable signer. WRITABLE_SIGNER: u64 = 0x0101, /// Account index for user account in CPI. @@ -117,6 +123,13 @@ pub struct CreateAccountInstructionData { pub owner: Address, } +#[repr(C, packed)] +/// For CPI to transfer lamports. +pub struct TransferInstructionData { + pub discriminator: u32, + pub lamports: u64, +} + constant_group! { /// Data layout constants. data { @@ -177,6 +190,8 @@ constant_group! { COLOR_B = Color::Black as u8, /// Red color. COLOR_R = Color::Red as u8, + /// Stack top field in header. + offset!(HEADER_TOP, TreeHeader.top), /// Next node field in header. offset!(HEADER_NEXT, TreeHeader.next), } diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index d749687a..3122603e 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -11,5 +11,6 @@ pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, - InitializeInstruction, InsertInstruction, Instruction, TreeHeader, TreeNode, + InitializeInstruction, InsertInstruction, Instruction, StackNode, TransferInstructionData, + TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 228588ed..0dfcce62 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -10,7 +10,7 @@ use pinocchio::{ use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, Direction, InitializeInstruction, InsertInstruction, SolAccountInfo, SolAccountMeta, - SolInstruction, SolSignerSeed, SolSignerSeeds, TreeHeader, TreeNode, + SolInstruction, SolSignerSeed, SolSignerSeeds, TransferInstructionData, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -168,9 +168,9 @@ unsafe fn insert( // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); - // Allocate a node if the stack is empty. + // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - if (*tree_header).top.is_null() { + let _node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, @@ -184,7 +184,105 @@ unsafe fn insert( // Check system program and rent sysvar accounts using shifted input buffer pointer. check_cpi_accounts!(shifted_input); - } + + // Calculate additional lamports for rent exemption of one TreeNode. + let lamports_per_byte = ldxdw(shifted_input, input_buffer::RENT_DATA_OFF); + let transfer_lamports = size_of::() as u64 * lamports_per_byte; + + // Pack Transfer instruction data. + let transfer_instruction_data = TransferInstructionData { + discriminator: cpi::TRANSFER_DISCRIMINATOR, + lamports: transfer_lamports, + }; + + // Pack account metas and infos. + let user_key = input.add(input_buffer::USER_ADDRESS_OFF as usize).cast(); + let tree_key = input.add(input_buffer::TREE_ADDRESS_OFF as usize).cast(); + let sol_account_metas = [ + SolAccountMeta { + pubkey: user_key, + is_writable: true, + is_signer: true, + }, + SolAccountMeta { + pubkey: tree_key, + is_writable: true, + is_signer: false, + }, + ]; + let sol_account_infos = [ + SolAccountInfo { + key: user_key, + owner: input.add(input_buffer::USER_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::USER_LAMPORTS_OFF as usize).cast(), + data: input.add(input_buffer::USER_DATA_OFF as usize), + data_len: data::DATA_LEN_ZERO, + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: true, + is_writable: true, + executable: false, + }, + SolAccountInfo { + key: tree_key, + owner: input.add(input_buffer::TREE_OWNER_OFF as usize).cast(), + lamports: input.add(input_buffer::TREE_LAMPORTS_OFF as usize).cast(), + data: input.add(input_buffer::TREE_DATA_OFF as usize), + data_len: *tree_data_len, + rent_epoch: cpi::RENT_EPOCH_NULL, + is_signer: false, + is_writable: true, + executable: false, + }, + ]; + + // Pack instruction. + let system_program_address = Address::default(); + let sol_instruction = SolInstruction { + program_id: addr_of!(system_program_address).cast_mut().cast(), + accounts: sol_account_metas.as_ptr().cast_mut().cast(), + account_len: sol_account_metas.len() as u64, + data: addr_of!(transfer_instruction_data).cast_mut().cast(), + data_len: cpi::TRANSFER_INSN_DATA_LEN as u64, + }; + + // No signers needed, since user is already a signer on the transaction. + let empty_signers = SolSignerSeeds { + addr: core::ptr::null(), + len: 0, + }; + + #[cfg(target_os = "solana")] + sol_invoke_signed_c( + addr_of!(sol_instruction).cast(), + addr_of!(sol_account_infos).cast(), + cpi::N_ACCOUNTS as u64, + addr_of!(empty_signers).cast(), + cpi::N_SIGNERS_TRANSFER, + ); + #[cfg(not(target_os = "solana"))] + #[allow(path_statements)] + { + empty_signers; + sol_account_infos; + sol_instruction; + } + + // Save pointer to newly allocated node (current next). + let node = (*tree_header).next; + + // Increase tree data length by size of one TreeNode. + *tree_data_len += size_of::() as u64; + + // Advance next pointer by one TreeNode. + (*tree_header).next = (*tree_header).next.add(1); + + node + } else { + // Pop node from free stack. + let node = (*tree_header).top.cast::(); + (*tree_header).top = (*(*tree_header).top).next; + node + }; SUCCESS } @@ -306,7 +404,7 @@ unsafe fn initialize( accounts: sol_account_metas.as_ptr().cast_mut().cast(), account_len: sol_account_metas.len() as u64, data: addr_of!(create_account_instruction_data).cast_mut().cast(), - data_len: cpi::INSN_DATA_LEN as u64, + data_len: cpi::CREATE_ACCOUNT_INSN_DATA_LEN as u64, }; // Initialize signer seed for PDA bump. @@ -318,7 +416,7 @@ unsafe fn initialize( // Initialize signer seeds for PDA. let signers_seeds = SolSignerSeeds { addr: addr_of!(bump_seed).cast(), - len: cpi::N_SEEDS as u64, + len: cpi::N_SEEDS_CREATE_ACCOUNT as u64, }; #[cfg(target_os = "solana")] diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 97f5d495..a8aff13b 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -150,7 +150,7 @@ fn test_entrypoint_branching() { #[test] fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, false, false); + print_comparison_table(insert::InsertCase::CASES, true, false); } #[test] diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index abeffc89..f6b4ffe2 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -1,10 +1,75 @@ use super::*; use mollusk_svm::program; +use mollusk_svm::result::{Check, Config}; +use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; -use tree_interface::{cpi, Instruction as TreeInstruction}; +use tree_interface::{ + cpi, input_buffer, tree, Instruction as TreeInstruction, StackNode, TreeHeader, TreeNode, +}; + +/// Virtual address of the input buffer in the SVM memory map. +/// See `solana_sbpf::ebpf::MM_INPUT_START`. +const MM_INPUT_START: u64 = 0x400000000; +const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; fn insert_setup( program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let mut setup = setup_test(program_language); + setup.mollusk.sysvars.rent.exemption_threshold = SIMD0194_EXEMPTION_THRESHOLD; + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); + let (rent_sysvar_pubkey, rent_sysvar_account) = + setup.mollusk.sysvars.keyed_account_for_rent_sysvar(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + // Valid InsertInstruction: discriminator (1) + key (u16) + value (u16) = 5 bytes. + let instruction_data: [u8; 5] = [ + TreeInstruction::Insert as u8, + 42, 0, // key + 1, 0, // value + ]; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &instruction_data, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), + AccountMeta::new_readonly(rent_sysvar_pubkey, false), + ], + ); + + // Tree starts with TREE_DATA_LEN (header only), top = null to trigger allocation. + let rent = Rent::from_bytes(&rent_sysvar_account.data).unwrap(); + let tree_lamports = rent.try_minimum_balance(cpi::TREE_DATA_LEN).unwrap(); + let mut tree_account = Account::new(tree_lamports, cpi::TREE_DATA_LEN, &setup.program_id); + // top is null (zeroed) — triggers allocation path. + // next pointer must point to the first allocation slot (right after header). + let next_ptr = + MM_INPUT_START + input_buffer::TREE_DATA_OFF as u64 + size_of::() as u64; + let next_off = tree::HEADER_NEXT_OFF as usize; + tree_account.data[next_off..next_off + size_of::<*mut TreeNode>()] + .copy_from_slice(&next_ptr.to_le_bytes()); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account), + (system_program_pubkey, system_program_account), + (rent_sysvar_pubkey, rent_sysvar_account), + ]; + + (setup, instruction, accounts) +} + +fn insert_skip_alloc_setup( + program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { let setup = setup_test(program_language); let (system_program_pubkey, _) = program::keyed_account_for_system_program(); @@ -12,7 +77,6 @@ fn insert_setup( let user_pubkey = Pubkey::new_unique(); let tree_pubkey = Pubkey::new_unique(); - // Valid InsertInstruction: discriminator (1) + key (u16) + value (u16) = 5 bytes. let instruction_data: [u8; 5] = [ TreeInstruction::Insert as u8, 42, 0, // key @@ -28,10 +92,17 @@ fn insert_setup( ], ); - // Initialize tree account with non-null `top` pointer so insert skips allocation. - let mut tree_data = vec![0u8; cpi::TREE_DATA_LEN]; - tree_data[8..16].copy_from_slice(&1u64.to_le_bytes()); // top != null - let mut tree_account = Account::new(0, cpi::TREE_DATA_LEN, &setup.program_id); + // Initialize tree account with a free node on the stack so insert pops instead of allocating. + let tree_data_len = cpi::TREE_DATA_LEN + size_of::(); + let mut tree_data = vec![0u8; tree_data_len]; + // top points to the free node (right after header in memory map). + let top_ptr = + MM_INPUT_START + input_buffer::TREE_DATA_OFF as u64 + size_of::() as u64; + let top_off = tree::HEADER_TOP_OFF as usize; + tree_data[top_off..top_off + size_of::<*mut StackNode>()] + .copy_from_slice(&top_ptr.to_le_bytes()); + // Free node's next is null (zeroed) — only one free node on the stack. + let mut tree_account = Account::new(0, tree_data_len, &setup.program_id); tree_account.data = tree_data; let accounts = vec![ @@ -49,14 +120,16 @@ fn insert_setup( pub(super) enum InsertCase { InstructionDataLenShort, InstructionDataLenLong, - InsertHappyPath, + InsertSkipAlloc, + InsertAllocHappyPath, } impl InsertCase { pub(super) const CASES: &'static [Self] = &[ Self::InstructionDataLenShort, Self::InstructionDataLenLong, - Self::InsertHappyPath, + Self::InsertSkipAlloc, + Self::InsertAllocHappyPath, ]; } @@ -65,14 +138,24 @@ impl TestCase for InsertCase { match self { Self::InstructionDataLenShort => "Instruction data too short", Self::InstructionDataLenLong => "Instruction data too long", - Self::InsertHappyPath => "Insert happy path", + Self::InsertSkipAlloc => "Insert skip alloc", + Self::InsertAllocHappyPath => "Insert alloc happy path", + } + } + + fn fixed_costs(&self) -> u64 { + match self { + Self::InsertAllocHappyPath => { + fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM + } + _ => 0, } } fn run(&self, lang: ProgramLanguage) -> CaseResult { match self { Self::InstructionDataLenShort => { - let (setup, mut instruction, accounts) = insert_setup(lang); + let (setup, mut instruction, accounts) = insert_skip_alloc_setup(lang); // Correct discriminator but wrong length (1 byte instead of 5). instruction.data = vec![TreeInstruction::Insert as u8]; check_error( @@ -83,7 +166,7 @@ impl TestCase for InsertCase { ) } Self::InstructionDataLenLong => { - let (setup, mut instruction, accounts) = insert_setup(lang); + let (setup, mut instruction, accounts) = insert_skip_alloc_setup(lang); // Correct discriminator but wrong length (6 bytes instead of 5). instruction.data = vec![TreeInstruction::Insert as u8, 0, 0, 0, 0, 0]; check_error( @@ -93,8 +176,8 @@ impl TestCase for InsertCase { error_codes::error::INSTRUCTION_DATA_LEN, ) } - Self::InsertHappyPath => { - let (setup, instruction, accounts) = insert_setup(lang); + Self::InsertSkipAlloc => { + let (setup, instruction, accounts) = insert_skip_alloc_setup(lang); let result = setup.mollusk.process_instruction(&instruction, &accounts); match &result.program_result { MolluskResult::Success => CaseResult { @@ -107,6 +190,70 @@ impl TestCase for InsertCase { }, } } + Self::InsertAllocHappyPath => { + let (setup, instruction, accounts) = insert_setup(lang); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => { + let tree = &result.resulting_accounts[AccountIndex::Tree as usize].1; + let rent_data = &accounts[AccountIndex::RentSysvar as usize].1.data; + let rent = Rent::from_bytes(rent_data).unwrap(); + let expected_data_len = + cpi::TREE_DATA_LEN + size_of::(); + let expected_lamports = + rent.try_minimum_balance(expected_data_len).unwrap(); + let mut errors = Vec::new(); + if tree.data.len() != expected_data_len { + errors.push(format!( + "data len: expected {}, got {}", + expected_data_len, + tree.data.len() + )); + } + if tree.lamports != expected_lamports { + errors.push(format!( + "lamports: expected {}, got {}", + expected_lamports, tree.lamports + )); + } + // Verify next pointer advanced by one TreeNode. + let expected_next = MM_INPUT_START + + input_buffer::TREE_DATA_OFF as u64 + + size_of::() as u64 + + size_of::() as u64; + let header = + unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; + let actual_next = header.next as u64; + if actual_next != expected_next { + errors.push(format!( + "next: expected {:#x}, got {:#x}", + expected_next, actual_next + )); + } + let config = Config { + panic: false, + verbose: false, + }; + if !result + .run_checks(&[Check::all_rent_exempt()], &config, &setup.mollusk) + { + errors.push("not all accounts are rent exempt".to_string()); + } + CaseResult { + cu: result.compute_units_consumed, + error: if errors.is_empty() { + None + } else { + Some(errors.join("; ")) + }, + } + } + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } + } } } } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a1b3ebeb..b58f41d6 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -179,16 +179,23 @@ # CPI-specific constants. # ----------------------- -.equ CPI_N_ACCOUNTS, 2 # User and tree accounts must sign CPI. -.equ CPI_N_PDA_SIGNERS, 1 # The tree account is a PDA. -.equ CPI_N_SEEDS, 1 # The bump seed is required for tree PDA signer. +.equ CPI_N_ACCOUNTS, 2 # User and tree accounts. +# The tree account is a PDA for CreateAccount CPI. +.equ CPI_N_PDA_SIGNERS, 1 +# Number of seeds for CreateAccount PDA signer (bump only). +.equ CPI_N_SEEDS_CREATE_ACCOUNT, 1 +# Number of signers for Transfer CPI (none — user is already a signer). +.equ CPI_N_SIGNERS_TRANSFER, 0 .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. .equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. .equ CPI_ACCOUNT_DATA_SCALAR, 152 # CreateAccount discriminator for CPI. .equ CPI_CREATE_ACCOUNT_DISCRIMINATOR, 0 -.equ CPI_INSN_DATA_LEN, 52 # Length of CreateAccount instruction data. +# Length of CreateAccount instruction data. +.equ CPI_CREATE_ACCOUNT_INSN_DATA_LEN, 52 +.equ CPI_TRANSFER_DISCRIMINATOR, 2 # Transfer discriminator for CPI. +.equ CPI_TRANSFER_INSN_DATA_LEN, 12 # Length of Transfer instruction data. .equ CPI_WRITABLE_SIGNER, 0x0101 # Mask for writable signer. .equ CPI_USER_ACCOUNT_INDEX, 0 # Account index for user account in CPI. .equ CPI_TREE_ACCOUNT_INDEX, 1 # Account index for tree account in CPI. @@ -201,6 +208,7 @@ .equ TREE_DIR_R, 1 # Right direction. .equ TREE_COLOR_B, 0 # Black color. .equ TREE_COLOR_R, 1 # Red color. +.equ TREE_HEADER_TOP_OFF, 8 # Stack top field in header. .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. From 0bf5db85a3a900b83b3874c637e2f84effb30e0d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 17:59:44 -0800 Subject: [PATCH 175/263] Update init behavor, test harness --- .../tree/artifacts/snippets/asm/constants.txt | 6 +- .../asm/initialize-create-account.txt | 2 +- .../snippets/interface/instructions.txt | 4 ++ .../tree/artifacts/snippets/rs/insert.txt | 30 ++++++--- examples/tree/interface/src/common.rs | 8 ++- examples/tree/src/program.rs | 30 ++++++--- examples/tree/src/tests.rs | 7 +++ examples/tree/src/tests/init.rs | 6 -- examples/tree/src/tests/insert.rs | 61 +++++++++++-------- examples/tree/src/tree/tree.s | 8 ++- 10 files changed, 105 insertions(+), 57 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index adae7916..b6c3dd39 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -109,6 +109,8 @@ # Initialize instruction discriminator. .equ INSN_DISCRIMINATOR_INITIALIZE, 0 .equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. +.equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. +.equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. # Init stack frame layout. # ------------------------ @@ -183,8 +185,8 @@ .equ CPI_N_PDA_SIGNERS, 1 # Number of seeds for CreateAccount PDA signer (bump only). .equ CPI_N_SEEDS_CREATE_ACCOUNT, 1 -# Number of signers for Transfer CPI (none — user is already a signer). -.equ CPI_N_SIGNERS_TRANSFER, 0 +# PDA signers for Transfer CPI (none — user is already a signer). +.equ CPI_N_PDA_SIGNERS_TRANSFER, 0 .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. .equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index 2ed7626a..bc4fbf46 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -73,7 +73,7 @@ # Packed later during bulk pointer load operation: # - [x] Signer seed pointer. # --------------------------------------------------------------------- - stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS + stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS_CREATE_ACCOUNT # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index 01201380..ecaa1b40 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -43,5 +43,9 @@ constant_group! { DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, /// Insert instruction discriminator. DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, + /// Key field in insert instruction. + offset!(INSERT_KEY, InsertInstruction.key), + /// Value field in insert instruction. + offset!(INSERT_VALUE, InsertInstruction.value), } } diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert.txt index 936c8b1c..eed8def5 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert.txt @@ -21,7 +21,7 @@ unsafe fn insert( // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let _node: *mut TreeNode = if (*tree_header).top.is_null() { + let node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, @@ -108,7 +108,7 @@ unsafe fn insert( addr_of!(sol_account_infos).cast(), cpi::N_ACCOUNTS as u64, addr_of!(empty_signers).cast(), - cpi::N_SIGNERS_TRANSFER, + cpi::N_PDA_SIGNERS_TRANSFER, ); #[cfg(not(target_os = "solana"))] #[allow(path_statements)] @@ -118,22 +118,34 @@ unsafe fn insert( sol_instruction; } - // Save pointer to newly allocated node (current next). - let node = (*tree_header).next; - // Increase tree data length by size of one TreeNode. *tree_data_len += size_of::() as u64; // Advance next pointer by one TreeNode. + let node = (*tree_header).next; (*tree_header).next = (*tree_header).next.add(1); - node } else { // Pop node from free stack. - let node = (*tree_header).top.cast::(); - (*tree_header).top = (*(*tree_header).top).next; - node + let top = (*tree_header).top; + (*tree_header).top = (*top).next; + top.cast() }; + // Initialize node as root of tree. + (*tree_header).root = node; + + // Set key and value from instruction data. Parent, children, and color are already null/zero. + (*node).key = read_unaligned( + instruction_data + .add(instruction::INSERT_KEY_OFF as usize) + .cast(), + ); + (*node).value = read_unaligned( + instruction_data + .add(instruction::INSERT_VALUE_OFF as usize) + .cast(), + ); + SUCCESS } \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1e0fccda..1aa0836e 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -87,8 +87,8 @@ constant_group! { N_PDA_SIGNERS: usize = 1, /// Number of seeds for CreateAccount PDA signer (bump only). N_SEEDS_CREATE_ACCOUNT: usize = 1, - /// Number of signers for Transfer CPI (none — user is already a signer). - N_SIGNERS_TRANSFER: u64 = 0, + /// PDA signers for Transfer CPI (none — user is already a signer). + N_PDA_SIGNERS_TRANSFER: u64 = 0, /// Number of seeds for PDA generation. N_SEEDS_TRY_FIND_PDA: u64 = 0, /// Tree account data length. @@ -269,6 +269,10 @@ constant_group! { DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, /// Insert instruction discriminator. DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, + /// Key field in insert instruction. + offset!(INSERT_KEY, InsertInstruction.key), + /// Value field in insert instruction. + offset!(INSERT_VALUE, InsertInstruction.value), } } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 0dfcce62..bedfdce0 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -170,7 +170,7 @@ unsafe fn insert( // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let _node: *mut TreeNode = if (*tree_header).top.is_null() { + let node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, @@ -257,7 +257,7 @@ unsafe fn insert( addr_of!(sol_account_infos).cast(), cpi::N_ACCOUNTS as u64, addr_of!(empty_signers).cast(), - cpi::N_SIGNERS_TRANSFER, + cpi::N_PDA_SIGNERS_TRANSFER, ); #[cfg(not(target_os = "solana"))] #[allow(path_statements)] @@ -267,23 +267,35 @@ unsafe fn insert( sol_instruction; } - // Save pointer to newly allocated node (current next). - let node = (*tree_header).next; - // Increase tree data length by size of one TreeNode. *tree_data_len += size_of::() as u64; // Advance next pointer by one TreeNode. + let node = (*tree_header).next; (*tree_header).next = (*tree_header).next.add(1); - node } else { // Pop node from free stack. - let node = (*tree_header).top.cast::(); - (*tree_header).top = (*(*tree_header).top).next; - node + let top = (*tree_header).top; + (*tree_header).top = (*top).next; + top.cast() }; + // Initialize node as root of tree. + (*tree_header).root = node; + + // Set key and value from instruction data. Parent, children, and color are already null/zero. + (*node).key = read_unaligned( + instruction_data + .add(instruction::INSERT_KEY_OFF as usize) + .cast(), + ); + (*node).value = read_unaligned( + instruction_data + .add(instruction::INSERT_VALUE_OFF as usize) + .cast(), + ); + SUCCESS } // ANCHOR_END: insert diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index a8aff13b..f0298370 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -12,6 +12,13 @@ use tree_interface::{cpi, error_codes}; const USER_LAMPORTS: u64 = 1_000_000; +/// Virtual address of the input buffer in the SVM memory map. +/// See `solana_sbpf::ebpf::MM_INPUT_START`. +const MM_INPUT_START: u64 = 0x400000000; + +/// Rent exemption threshold per SIMD-0194. +const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; + /// Fixed costs for syscalls and CPI operations. mod fixed_costs { /// Cost for sol_try_find_program_address syscall. diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 4b57646e..7f731958 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -5,12 +5,6 @@ use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; use tree_interface::{input_buffer, tree, Instruction as TreeInstruction, TreeHeader}; -const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; - -/// Virtual address of the input buffer in the SVM memory map. -/// See `solana_sbpf::ebpf::MM_INPUT_START`. -const MM_INPUT_START: u64 = 0x400000000; - fn init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index f6b4ffe2..3c0b9b60 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -7,11 +7,6 @@ use tree_interface::{ cpi, input_buffer, tree, Instruction as TreeInstruction, StackNode, TreeHeader, TreeNode, }; -/// Virtual address of the input buffer in the SVM memory map. -/// See `solana_sbpf::ebpf::MM_INPUT_START`. -const MM_INPUT_START: u64 = 0x400000000; -const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; - fn insert_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { @@ -28,8 +23,10 @@ fn insert_setup( // Valid InsertInstruction: discriminator (1) + key (u16) + value (u16) = 5 bytes. let instruction_data: [u8; 5] = [ TreeInstruction::Insert as u8, - 42, 0, // key - 1, 0, // value + 42, + 0, // key + 1, + 0, // value ]; let instruction = Instruction::new_with_bytes( @@ -79,8 +76,10 @@ fn insert_skip_alloc_setup( let instruction_data: [u8; 5] = [ TreeInstruction::Insert as u8, - 42, 0, // key - 1, 0, // value + 42, + 0, // key + 1, + 0, // value ]; let instruction = Instruction::new_with_bytes( @@ -145,9 +144,7 @@ impl TestCase for InsertCase { fn fixed_costs(&self) -> u64 { match self { - Self::InsertAllocHappyPath => { - fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM - } + Self::InsertAllocHappyPath => fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM, _ => 0, } } @@ -198,8 +195,7 @@ impl TestCase for InsertCase { let tree = &result.resulting_accounts[AccountIndex::Tree as usize].1; let rent_data = &accounts[AccountIndex::RentSysvar as usize].1.data; let rent = Rent::from_bytes(rent_data).unwrap(); - let expected_data_len = - cpi::TREE_DATA_LEN + size_of::(); + let expected_data_len = cpi::TREE_DATA_LEN + size_of::(); let expected_lamports = rent.try_minimum_balance(expected_data_len).unwrap(); let mut errors = Vec::new(); @@ -216,26 +212,41 @@ impl TestCase for InsertCase { expected_lamports, tree.lamports )); } - // Verify next pointer advanced by one TreeNode. - let expected_next = MM_INPUT_START + // Verify header pointers. + let header = unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; + let node_addr = MM_INPUT_START + input_buffer::TREE_DATA_OFF as u64 - + size_of::() as u64 - + size_of::() as u64; - let header = - unsafe { &*(tree.data.as_ptr() as *const TreeHeader) }; - let actual_next = header.next as u64; - if actual_next != expected_next { + + size_of::() as u64; + let expected_next = node_addr + size_of::() as u64; + if header.next as u64 != expected_next { errors.push(format!( "next: expected {:#x}, got {:#x}", - expected_next, actual_next + expected_next, header.next as u64 )); } + if header.root as u64 != node_addr { + errors.push(format!( + "root: expected {:#x}, got {:#x}", + node_addr, header.root as u64 + )); + } + // Verify node key and value. + let node = unsafe { + &*(tree.data.as_ptr().add(size_of::()) as *const TreeNode) + }; + let key = node.key; + let value = node.value; + if key != 42 { + errors.push(format!("key: expected 42, got {}", key)); + } + if value != 1 { + errors.push(format!("value: expected 1, got {}", value)); + } let config = Config { panic: false, verbose: false, }; - if !result - .run_checks(&[Check::all_rent_exempt()], &config, &setup.mollusk) + if !result.run_checks(&[Check::all_rent_exempt()], &config, &setup.mollusk) { errors.push("not all accounts are rent exempt".to_string()); } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index b58f41d6..4c8833c2 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -110,6 +110,8 @@ # Initialize instruction discriminator. .equ INSN_DISCRIMINATOR_INITIALIZE, 0 .equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. +.equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. +.equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. # Init stack frame layout. # ------------------------ @@ -184,8 +186,8 @@ .equ CPI_N_PDA_SIGNERS, 1 # Number of seeds for CreateAccount PDA signer (bump only). .equ CPI_N_SEEDS_CREATE_ACCOUNT, 1 -# Number of signers for Transfer CPI (none — user is already a signer). -.equ CPI_N_SIGNERS_TRANSFER, 0 +# PDA signers for Transfer CPI (none — user is already a signer). +.equ CPI_N_PDA_SIGNERS_TRANSFER, 0 .equ CPI_N_SEEDS_TRY_FIND_PDA, 0 # Number of seeds for PDA generation. .equ CPI_TREE_DATA_LEN, 24 # Tree account data length. # Account data scalar for base rent calculation. @@ -395,7 +397,7 @@ initialize: # Packed later during bulk pointer load operation: # - [x] Signer seed pointer. # --------------------------------------------------------------------- - stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS + stdw [r10 + SF_INIT_SIGNERS_SEEDS_LEN_OFF], CPI_N_SEEDS_CREATE_ACCOUNT # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- From cb5577c6e4382f9fd1721694492e135ca0076307 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:06:56 -0800 Subject: [PATCH 176/263] Clean up new allocation path --- .../snippets/interface/instructions.txt | 2 +- .../rs/{insert.txt => insert-allocate.txt} | 41 +-------------- .../snippets/rs/insert-input-checks.txt | 20 ++++++++ examples/tree/interface/src/common.rs | 2 +- examples/tree/interface/src/lib.rs | 3 +- examples/tree/src/program.rs | 6 ++- examples/tree/src/tests.rs | 12 +++++ examples/tree/src/tests/init.rs | 3 +- examples/tree/src/tests/insert.rs | 50 +++++++++---------- 9 files changed, 66 insertions(+), 73 deletions(-) rename examples/tree/artifacts/snippets/rs/{insert.txt => insert-allocate.txt} (81%) create mode 100644 examples/tree/artifacts/snippets/rs/insert-input-checks.txt diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index ecaa1b40..9baf5c58 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -9,7 +9,7 @@ pub enum Instruction { #[repr(C, packed)] pub struct InstructionHeader { - discriminator: u8, + pub discriminator: u8, } #[repr(C, packed)] diff --git a/examples/tree/artifacts/snippets/rs/insert.txt b/examples/tree/artifacts/snippets/rs/insert-allocate.txt similarity index 81% rename from examples/tree/artifacts/snippets/rs/insert.txt rename to examples/tree/artifacts/snippets/rs/insert-allocate.txt index eed8def5..8fec731f 100644 --- a/examples/tree/artifacts/snippets/rs/insert.txt +++ b/examples/tree/artifacts/snippets/rs/insert-allocate.txt @@ -1,24 +1,3 @@ -#[inline(always)] -unsafe fn insert( - input: *mut u8, - instruction_data: *mut u8, - instruction_data_len: u64, - n_accounts: u64, -) -> u64 { - check_instruction_data_len!(instruction_data_len, InsertInstruction); - - // Error if too few accounts. - if_err!( - n_accounts < input_buffer::N_ACCOUNTS_GENERAL, - error::N_ACCOUNTS - ); - - // Error if user has data. - let user = user_account!(input); - - // Error if tree is duplicate. - let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); - // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); let node: *mut TreeNode = if (*tree_header).top.is_null() { @@ -130,22 +109,4 @@ unsafe fn insert( let top = (*tree_header).top; (*tree_header).top = (*top).next; top.cast() - }; - - // Initialize node as root of tree. - (*tree_header).root = node; - - // Set key and value from instruction data. Parent, children, and color are already null/zero. - (*node).key = read_unaligned( - instruction_data - .add(instruction::INSERT_KEY_OFF as usize) - .cast(), - ); - (*node).value = read_unaligned( - instruction_data - .add(instruction::INSERT_VALUE_OFF as usize) - .cast(), - ); - - SUCCESS -} \ No newline at end of file + }; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-input-checks.txt b/examples/tree/artifacts/snippets/rs/insert-input-checks.txt new file mode 100644 index 00000000..48969685 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-input-checks.txt @@ -0,0 +1,20 @@ +#[inline(always)] +unsafe fn insert( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + check_instruction_data_len!(instruction_data_len, InsertInstruction); + + // Error if too few accounts. + if_err!( + n_accounts < input_buffer::N_ACCOUNTS_GENERAL, + error::N_ACCOUNTS + ); + + // Error if user has data. + let user = user_account!(input); + + // Error if tree is duplicate. + let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 1aa0836e..3566dcb5 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -235,7 +235,7 @@ pub enum Instruction { #[repr(C, packed)] pub struct InstructionHeader { - discriminator: u8, + pub discriminator: u8, } #[repr(C, packed)] diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 3122603e..1b73368f 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -11,6 +11,7 @@ pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, - InitializeInstruction, InsertInstruction, Instruction, StackNode, TransferInstructionData, + InitializeInstruction, InstructionHeader, InsertInstruction, Instruction, StackNode, + TransferInstructionData, TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index bedfdce0..6b98d88b 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -146,7 +146,7 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) - } // ANCHOR_END: entrypoint-branching -// ANCHOR: insert +// ANCHOR: insert-input-checks #[inline(always)] unsafe fn insert( input: *mut u8, @@ -167,7 +167,9 @@ unsafe fn insert( // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + // ANCHOR_END: insert-input-checks + // ANCHOR: insert-allocate // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); let node: *mut TreeNode = if (*tree_header).top.is_null() { @@ -280,6 +282,7 @@ unsafe fn insert( (*tree_header).top = (*top).next; top.cast() }; + // ANCHOR_END: insert-allocate // Initialize node as root of tree. (*tree_header).root = node; @@ -298,7 +301,6 @@ unsafe fn insert( SUCCESS } -// ANCHOR_END: insert // ANCHOR: initialize-input-checks #[inline(always)] diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index f0298370..6d1f0479 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -19,6 +19,18 @@ const MM_INPUT_START: u64 = 0x400000000; /// Rent exemption threshold per SIMD-0194. const SIMD0194_EXEMPTION_THRESHOLD: f64 = 1.0; +/// Set up a test with SIMD-0194 rent exemption threshold. +fn setup_test_with_rent(lang: ProgramLanguage) -> TestSetup { + let mut setup = setup_test(lang); + setup.mollusk.sysvars.rent.exemption_threshold = SIMD0194_EXEMPTION_THRESHOLD; + setup +} + +/// Cast a sized value to its raw byte representation. +unsafe fn as_bytes(val: &T) -> &[u8] { + core::slice::from_raw_parts(val as *const T as *const u8, size_of::()) +} + /// Fixed costs for syscalls and CPI operations. mod fixed_costs { /// Cost for sol_try_find_program_address syscall. diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 7f731958..f68785d5 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -44,8 +44,7 @@ fn init_setup( fn pda_init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let mut setup = setup_test(program_language); - setup.mollusk.sysvars.rent.exemption_threshold = SIMD0194_EXEMPTION_THRESHOLD; + let mut setup = setup_test_with_rent(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) = diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 3c0b9b60..2efd9caa 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -4,14 +4,27 @@ use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; use tree_interface::{ - cpi, input_buffer, tree, Instruction as TreeInstruction, StackNode, TreeHeader, TreeNode, + cpi, input_buffer, tree, InstructionHeader, Instruction as TreeInstruction, InsertInstruction, + StackNode, TreeHeader, TreeNode, }; +const TEST_KEY: u16 = 42; +const TEST_VALUE: u16 = 1; + +fn insert_instruction_data() -> InsertInstruction { + InsertInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Insert as u8, + }, + key: TEST_KEY, + value: TEST_VALUE, + } +} + fn insert_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let mut setup = setup_test(program_language); - setup.mollusk.sysvars.rent.exemption_threshold = SIMD0194_EXEMPTION_THRESHOLD; + let mut setup = setup_test_with_rent(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) = @@ -20,18 +33,10 @@ fn insert_setup( let user_pubkey = Pubkey::new_unique(); let tree_pubkey = Pubkey::new_unique(); - // Valid InsertInstruction: discriminator (1) + key (u16) + value (u16) = 5 bytes. - let instruction_data: [u8; 5] = [ - TreeInstruction::Insert as u8, - 42, - 0, // key - 1, - 0, // value - ]; - + let insn_data = insert_instruction_data(); let instruction = Instruction::new_with_bytes( setup.program_id, - &instruction_data, + unsafe { as_bytes(&insn_data) }, vec![ AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), @@ -74,17 +79,10 @@ fn insert_skip_alloc_setup( let user_pubkey = Pubkey::new_unique(); let tree_pubkey = Pubkey::new_unique(); - let instruction_data: [u8; 5] = [ - TreeInstruction::Insert as u8, - 42, - 0, // key - 1, - 0, // value - ]; - + let insn_data = insert_instruction_data(); let instruction = Instruction::new_with_bytes( setup.program_id, - &instruction_data, + unsafe { as_bytes(&insn_data) }, vec![ AccountMeta::new(user_pubkey, true), AccountMeta::new(tree_pubkey, false), @@ -236,11 +234,11 @@ impl TestCase for InsertCase { }; let key = node.key; let value = node.value; - if key != 42 { - errors.push(format!("key: expected 42, got {}", key)); + if key != TEST_KEY { + errors.push(format!("key: expected {}, got {}", TEST_KEY, key)); } - if value != 1 { - errors.push(format!("value: expected 1, got {}", value)); + if value != TEST_VALUE { + errors.push(format!("value: expected {}, got {}", TEST_VALUE, value)); } let config = Config { panic: false, From 429c338df9d17b6cc8cedb2d7dba6489b5d1bec0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:09:19 -0800 Subject: [PATCH 177/263] Rebuild examples --- examples/tree/artifacts/dumps/rs.txt | 482 +++++++++++------- examples/tree/artifacts/rs-disassembly.s | 246 ++++++--- .../asm/initialize-create-account.txt | 2 +- .../tests/entrypoint_branching/result.txt | 4 +- .../tests/initialize_input_checks/result.txt | 4 +- .../tree/artifacts/tests/insert/result.txt | 22 +- examples/tree/artifacts/tests/insert/test.txt | 2 +- examples/tree/src/tree/tree.s | 2 +- 8 files changed, 513 insertions(+), 251 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 6ad9c733..89f70694 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 3912 (bytes into file) + Start of section headers 4888 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0xf48 +There are 8 section headers, starting at offset 0x1318 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000538 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000658 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000660 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000660 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000660 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 0009d8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000a16 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000908 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000a28 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000a30 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000a30 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000a30 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 000da8 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 000de6 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000538 0x000538 E 0x8 - LOAD 0x000658 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000660 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000660 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000908 0x000908 E 0x8 + LOAD 0x000a28 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000a30 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000a30 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 1336 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 2312 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -105,169 +105,291 @@ Disassembly of section .text 0000000000000000 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 - 8 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] - 10 2c 22 00 00 00 00 00 00 ldxb w2, [r2 + 0x0] - 18 55 02 03 00 01 00 00 00 jne r2, 0x1, +0x3 - 20 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 28 55 03 8d 00 05 00 00 00 jne r3, 0x5, +0x8d - 30 9d 00 00 00 00 00 00 00 return - 38 55 02 8f 00 00 00 00 00 jne r2, 0x0, +0x8f - 40 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a - 48 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 50 55 02 8e 00 04 00 00 00 jne r2, 0x4, +0x8e - 58 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 60 55 02 8e 00 00 00 00 00 jne r2, 0x0, +0x8e - 68 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 70 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e - 78 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 80 55 02 8e 00 00 00 00 00 jne r2, 0x0, +0x8e - 88 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 90 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e - 98 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - a0 55 02 8e 00 0e 00 00 00 jne r2, 0xe, +0x8e - a8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - b0 55 02 8e 00 ff 00 00 00 jne r2, 0xff, +0x8e - b8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - c0 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - c8 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - d0 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - d8 5d 23 ea ff 00 00 00 00 jne r3, r2, -0x16 - e0 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - e8 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - f0 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - f8 5d 23 e6 ff 00 00 00 00 jne r3, r2, -0x1a - 100 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 108 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 110 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 118 5d 23 e2 ff 00 00 00 00 jne r3, r2, -0x1e - 120 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 128 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 130 5d 32 df ff 00 00 00 00 jne r2, r3, -0x21 - 138 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 140 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 148 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 150 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 158 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 160 07 05 00 00 13 00 00 00 add64 r5, 0x13 - 168 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 170 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 178 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 180 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 188 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 190 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 198 5d 21 61 00 00 00 00 00 jne r1, r2, +0x61 - 1a0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 1a8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 1b0 5d 21 5e 00 00 00 00 00 jne r1, r2, +0x5e - 1b8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 1c0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 1c8 5d 21 5b 00 00 00 00 00 jne r1, r2, +0x5b - 1d0 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 1d8 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 1e0 5d 21 58 00 00 00 00 00 jne r1, r2, +0x58 - 1e8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 1f0 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 1f8 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 200 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 208 9f 3a 40 00 00 00 00 00 stxdw [r10 + 0x40], r3 - 210 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 218 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 220 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 228 9f 3a 30 00 00 00 00 00 stxdw [r10 + 0x30], r3 - 230 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 238 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 240 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 248 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 250 97 0a 20 00 18 00 00 00 stdw [r10 + 0x20], 0x18 - 258 87 0a 14 00 00 00 00 00 stw [r10 + 0x14], 0x0 - 260 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 268 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 270 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 278 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 280 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 288 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 290 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 298 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 2a0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 2a8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2b0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 2b8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 2c0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 2c8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 2d0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 2d8 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 2e0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 2e8 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 2f0 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 2f8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 300 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 308 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 310 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 318 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 320 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 328 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 330 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 338 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 340 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 348 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 350 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 358 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 360 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 368 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 370 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 378 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 380 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 388 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 390 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 398 07 01 00 00 14 00 00 00 add64 r1, 0x14 - 3a0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 3a8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3b0 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 3b8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 3c0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3c8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 3d0 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 3d8 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 3e0 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 3e8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 3f0 07 01 00 00 13 00 00 00 add64 r1, 0x13 - 3f8 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 400 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 408 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 410 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 418 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 420 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 428 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 430 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 438 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 440 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 448 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 450 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 458 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 460 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 468 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 470 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 478 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 480 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - 488 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 490 05 00 73 ff 00 00 00 00 ja -0x8d - 498 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - 4a0 05 00 71 ff 00 00 00 00 ja -0x8f - 4a8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 4b0 05 00 6f ff 00 00 00 00 ja -0x91 - 4b8 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 4c0 05 00 6d ff 00 00 00 00 ja -0x93 - 4c8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 4d0 05 00 6b ff 00 00 00 00 ja -0x95 - 4d8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 4e0 05 00 69 ff 00 00 00 00 ja -0x97 - 4e8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 4f0 05 00 67 ff 00 00 00 00 ja -0x99 - 4f8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 500 05 00 65 ff 00 00 00 00 ja -0x9b - 508 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 510 05 00 63 ff 00 00 00 00 ja -0x9d - 518 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 520 05 00 61 ff 00 00 00 00 ja -0x9f - 528 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 530 05 00 5f ff 00 00 00 00 ja -0xa1 \ No newline at end of file + 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] + 10 9c 24 f8 ff 00 00 00 00 ldxdw r4, [r2 - 0x8] + 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] + 20 55 05 7c 00 01 00 00 00 jne r5, 0x1, +0x7c + 28 55 04 05 01 05 00 00 00 jne r4, 0x5, +0x105 + 30 a5 03 06 01 02 00 00 00 jlt r3, 0x2, +0x106 + 38 9c 14 58 00 00 00 00 00 ldxdw r4, [r1 + 0x58] + 40 55 04 06 01 00 00 00 00 jne r4, 0x0, +0x106 + 48 2c 14 68 28 00 00 00 00 ldxb w4, [r1 + 0x2868] + 50 55 04 06 01 ff 00 00 00 jne r4, 0xff, +0x106 + 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 + 68 9c 14 c8 28 00 00 00 00 ldxdw r4, [r1 + 0x28c8] + 70 15 04 03 00 00 00 00 00 jeq r4, 0x0, +0x3 + 78 9c 43 00 00 00 00 00 00 ldxdw r3, [r4 + 0x0] + 80 9f 31 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r3 + 88 05 00 68 00 00 00 00 00 ja +0x68 + 90 55 03 04 01 04 00 00 00 jne r3, 0x4, +0x104 + 98 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + a0 bf 35 00 00 00 00 00 00 mov64 r5, r3 + a8 07 05 00 00 07 00 00 00 add64 r5, 0x7 + b0 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + b8 bf 14 00 00 00 00 00 00 mov64 r4, r1 + c0 0f 54 00 00 00 00 00 00 add64 r4, r5 + c8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + d0 55 05 f8 00 ff 00 00 00 jne r5, 0xff, +0xf8 + d8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + e0 55 05 f8 00 0e 00 00 00 jne r5, 0xe, +0xf8 + e8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + f0 55 05 fa 00 ff 00 00 00 jne r5, 0xff, +0xfa + f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 100 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 108 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 110 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 118 5d 57 5c 00 00 00 00 00 jne r7, r5, +0x5c + 120 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 128 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 130 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 138 5d 57 58 00 00 00 00 00 jne r7, r5, +0x58 + 140 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 148 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 150 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 158 5d 57 54 00 00 00 00 00 jne r7, r5, +0x54 + 160 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 168 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 170 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 178 5d 52 50 00 00 00 00 00 jne r2, r5, +0x50 + 180 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 188 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 190 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 + 198 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 1a0 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 1a8 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 1b0 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 1b8 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 1c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 1c8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 + 1d0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 + 1d8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 1e0 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 1e8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 1f0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 + 1f8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 + 200 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 208 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 210 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 218 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 220 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 + 228 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 230 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 238 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 240 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 248 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 250 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 258 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 260 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 268 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 270 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 278 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 280 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 + 288 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 290 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 298 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 2a0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 2a8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 2b0 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 + 2b8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 2c0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 + 2c8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 + 2d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 2d8 07 02 00 00 30 01 00 00 add64 r2, 0x130 + 2e0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 2e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 2f0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 + 2f8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 300 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 308 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 + 310 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 + 318 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc + 320 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 + 328 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 + 330 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 338 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 340 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 348 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 350 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 358 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 360 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 368 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 370 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 378 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 380 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 388 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 390 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 398 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 3a0 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 3a8 9c 84 d0 28 00 00 00 00 ldxdw r4, [r8 + 0x28d0] + 3b0 bf 41 00 00 00 00 00 00 mov64 r1, r4 + 3b8 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 3c0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 3c8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 3d0 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + 3d8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] + 3e0 3f 14 18 00 00 00 00 00 stxh [r4 + 0x18], w1 + 3e8 3c 21 03 00 00 00 00 00 ldxh w1, [r2 + 0x3] + 3f0 3f 14 1a 00 00 00 00 00 stxh [r4 + 0x1a], w1 + 3f8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 400 9d 00 00 00 00 00 00 00 return + 408 55 05 9b 00 00 00 00 00 jne r5, 0x0, +0x9b + 410 55 04 88 00 01 00 00 00 jne r4, 0x1, +0x88 + 418 55 03 89 00 04 00 00 00 jne r3, 0x4, +0x89 + 420 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 428 55 02 89 00 00 00 00 00 jne r2, 0x0, +0x89 + 430 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 438 55 02 89 00 ff 00 00 00 jne r2, 0xff, +0x89 + 440 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 448 55 02 95 00 00 00 00 00 jne r2, 0x0, +0x95 + 450 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 458 55 02 87 00 ff 00 00 00 jne r2, 0xff, +0x87 + 460 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 468 55 02 87 00 0e 00 00 00 jne r2, 0xe, +0x87 + 470 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 478 55 02 89 00 ff 00 00 00 jne r2, 0xff, +0x89 + 480 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 488 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 490 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 498 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 4a0 5d 23 eb ff 00 00 00 00 jne r3, r2, -0x15 + 4a8 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 4b0 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 4b8 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 4c0 5d 23 e7 ff 00 00 00 00 jne r3, r2, -0x19 + 4c8 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 4d0 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 4d8 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 4e0 5d 23 e3 ff 00 00 00 00 jne r3, r2, -0x1d + 4e8 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 4f0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 4f8 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 + 500 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 508 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 510 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 518 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 520 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 528 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 530 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 538 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 540 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 548 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 550 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 558 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 560 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 568 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 570 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 578 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b + 580 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 588 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 590 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 + 598 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 5a0 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 5a8 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 + 5b0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 5b8 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 5c0 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 5c8 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 5d0 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + 5d8 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 5e0 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + 5e8 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 5f0 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + 5f8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 600 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + 608 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 610 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + 618 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + 620 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + 628 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 630 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 638 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 640 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 648 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 650 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 658 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 660 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 668 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 670 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 678 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 680 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 688 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 690 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 698 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 6a0 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + 6a8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 6b0 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 6b8 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + 6c0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 6c8 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 6d0 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + 6d8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 6e0 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 6e8 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + 6f0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 6f8 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 700 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + 708 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 710 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + 718 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 720 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 728 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 730 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 738 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 740 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + 748 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + 750 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + 758 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 760 07 01 00 00 10 00 00 00 add64 r1, 0x10 + 768 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + 770 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 778 07 01 00 00 48 00 00 00 add64 r1, 0x48 + 780 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + 788 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 790 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + 798 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + 7a0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + 7a8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + 7b0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 7b8 07 01 00 00 0f 00 00 00 add64 r1, 0xf + 7c0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + 7c8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + 7d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 7d8 07 01 00 00 20 01 00 00 add64 r1, 0x120 + 7e0 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + 7e8 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + 7f0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 7f8 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + 800 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 808 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 810 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 818 07 04 00 00 30 01 00 00 add64 r4, 0x130 + 820 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 828 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 830 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 838 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 840 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 848 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + 850 05 00 74 ff 00 00 00 00 ja -0x8c + 858 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 860 05 00 73 ff 00 00 00 00 ja -0x8d + 868 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 870 05 00 71 ff 00 00 00 00 ja -0x8f + 878 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 880 05 00 6f ff 00 00 00 00 ja -0x91 + 888 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 890 05 00 6d ff 00 00 00 00 ja -0x93 + 898 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 8a0 05 00 6b ff 00 00 00 00 ja -0x95 + 8a8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 8b0 05 00 69 ff 00 00 00 00 ja -0x97 + 8b8 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + 8c0 05 00 67 ff 00 00 00 00 ja -0x99 + 8c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 8d0 05 00 65 ff 00 00 00 00 ja -0x9b + 8d8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 8e0 05 00 63 ff 00 00 00 00 ja -0x9d + 8e8 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 8f0 05 00 61 ff 00 00 00 00 ja -0x9f + 8f8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 900 05 00 5f ff 00 00 00 00 ja -0xa1 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index d2689712..d635c24b 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,54 +2,181 @@ entrypoint: add64 r10, -320 - ldxdw r3, [r2-8] - ldxb r2, [r2+0] - jne r2, 1, jmp_0038 + ldxdw r3, [r1+0] + ldxdw r4, [r2-8] + ldxb r5, [r2+0] + jne r5, 1, jmp_0408 + jne r4, 5, jmp_0860 + jlt r3, 2, jmp_0870 + ldxdw r4, [r1+88] + jne r4, 0, jmp_0880 + ldxb r4, [r1+10344] + jne r4, 255, jmp_0890 + mov64 r6, r1 + add64 r6, 10432 + ldxdw r4, [r1+10440] + jeq r4, 0, jmp_0090 + ldxdw r3, [r4+0] + stxdw [r1+10440], r3 + ja jmp_03d0 + +jmp_0090: + jne r3, 4, jmp_08c0 + ldxdw r3, [r1+10424] + mov64 r5, r3 + add64 r5, 7 + and64 r5, -8 + mov64 r4, r1 + add64 r4, r5 + ldxb r5, [r4+20680] + jne r5, 255, jmp_08a0 + ldxdw r5, [r4+20760] + jne r5, 14, jmp_08b0 + ldxb r5, [r4+31032] + jne r5, 255, jmp_08d0 + mov64 r0, 8 + mov32 r5, 399877894 + hor64 r5, 1364995097 + ldxdw r7, [r4+31040] + jne r7, r5, jmp_0400 + mov32 r5, 1288277025 + hor64 r5, 2146519613 + ldxdw r7, [r4+31048] + jne r7, r5, jmp_0400 + mov32 r5, 149871192 + hor64 r5, 1157472667 + ldxdw r7, [r4+31056] + jne r7, r5, jmp_0400 + mov64 r7, r2 + ldxdw r2, [r4+31064] + mov32 r5, -1965433885 + jne r2, r5, jmp_0400 + ldxdw r2, [r4+31120] + lmul64 r2, 29 + stxdw [r10+308], r2 + stw [r10+304], 2 + mov64 r4, r1 + add64 r4, 10352 + stxdw [r10+232], r4 + mov64 r2, r1 + add64 r2, 16 + stxdw [r10+216], r2 + sth [r10+240], 1 + sth [r10+224], 257 + mov64 r5, r1 + add64 r5, 10384 + stxdw [r10+192], r5 + stxdw [r10+184], r6 + stxdw [r10+176], r3 + mov64 r3, r1 + add64 r3, 10416 + stxdw [r10+168], r3 + stxdw [r10+160], r4 + mov64 r3, r1 + add64 r3, 48 + stxdw [r10+136], r3 + mov64 r3, r1 + add64 r3, 96 + stxdw [r10+128], r3 + mov64 r3, r1 + add64 r3, 80 + stxdw [r10+112], r3 + stxdw [r10+104], r2 + stb [r10+210], 0 + sth [r10+208], 256 + stdw [r10+200], 0 + stb [r10+154], 0 + sth [r10+152], 257 + stdw [r10+144], 0 + stdw [r10+120], 0 + stdw [r10+272], 0 + stdw [r10+264], 0 + stdw [r10+256], 0 + stdw [r10+248], 0 + mov64 r2, r10 + add64 r2, 304 + stxdw [r10+40], r2 + mov64 r2, r10 + add64 r2, 216 + stxdw [r10+24], r2 + mov64 r2, r10 + add64 r2, 248 + stxdw [r10+16], r2 + stdw [r10+48], 12 + stdw [r10+32], 2 + stdw [r10+80], 0 + stdw [r10+72], 0 + mov64 r3, r10 + add64 r3, 16 + mov64 r2, r10 + add64 r2, 104 + mov64 r4, r10 + add64 r4, 72 + mov64 r8, r1 + mov64 r1, r3 + mov64 r3, 2 + mov64 r5, 0 + call sol_invoke_signed_c + ldxdw r1, [r8+10424] + add64 r1, 29 + stxdw [r8+10424], r1 + ldxdw r4, [r8+10448] + mov64 r1, r4 + add64 r1, 29 + stxdw [r8+10448], r1 + mov64 r2, r7 + +jmp_03d0: + stxdw [r6+0], r4 + ldxh r1, [r2+1] + stxh [r4+24], r1 + ldxh r1, [r2+3] + stxh [r4+26], r1 + +jmp_03f8: mov64 r0, 0 - jne r3, 5, jmp_04a0 -jmp_0030: +jmp_0400: exit -jmp_0038: - jne r2, 0, jmp_04b0 - jne r3, 1, jmp_04a0 - ldxdw r2, [r1+0] - jne r2, 4, jmp_04c0 +jmp_0408: + jne r5, 0, jmp_08e0 + jne r4, 1, jmp_0860 + jne r3, 4, jmp_0870 ldxdw r2, [r1+88] - jne r2, 0, jmp_04d0 + jne r2, 0, jmp_0880 ldxb r2, [r1+10344] - jne r2, 255, jmp_04e0 + jne r2, 255, jmp_0890 ldxdw r2, [r1+10424] - jne r2, 0, jmp_04f0 + jne r2, 0, jmp_08f0 ldxb r2, [r1+20680] - jne r2, 255, jmp_0500 + jne r2, 255, jmp_08a0 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0510 + jne r2, 14, jmp_08b0 ldxb r2, [r1+31032] - jne r2, 255, jmp_0520 + jne r2, 255, jmp_08d0 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_0030 + jne r3, r2, jmp_0400 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_0030 + jne r3, r2, jmp_0400 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_0030 + jne r3, r2, jmp_0400 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_0030 + jne r2, r3, jmp_0400 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 add64 r4, 104 mov64 r5, r10 - add64 r5, 19 + add64 r5, 15 mov64 r7, r1 mov64 r2, 0 mov64 r3, r6 @@ -57,31 +184,31 @@ jmp_0038: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_0030 + jne r1, r2, jmp_0400 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_0030 + jne r1, r2, jmp_0400 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_0030 + jne r1, r2, jmp_0400 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_0030 + jne r1, r2, jmp_0400 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] ldxdw r3, [r6+24] - stxdw [r10+64], r3 + stxdw [r10+60], r3 ldxdw r3, [r6+16] - stxdw [r10+56], r3 + stxdw [r10+52], r3 ldxdw r3, [r6+8] - stxdw [r10+48], r3 + stxdw [r10+44], r3 ldxdw r3, [r6+0] - stxdw [r10+40], r3 + stxdw [r10+36], r3 lmul64 r2, 152 - stxdw [r10+24], r2 - stdw [r10+32], 24 - stw [r10+20], 0 + stxdw [r10+20], r2 + stdw [r10+28], 24 + stw [r10+16], 0 stxdw [r10+88], r1 mov64 r2, r7 add64 r2, 16 @@ -121,7 +248,7 @@ jmp_0038: stdw [r10+224], 0 stdw [r10+216], 0 mov64 r1, r10 - add64 r1, 20 + add64 r1, 16 stxdw [r10+272], r1 mov64 r1, r10 add64 r1, 72 @@ -132,7 +259,7 @@ jmp_0038: stdw [r10+280], 52 stdw [r10+264], 2 mov64 r1, r10 - add64 r1, 19 + add64 r1, 15 stxdw [r10+288], r1 stdw [r10+296], 1 mov64 r1, r10 @@ -151,41 +278,44 @@ jmp_0038: mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - mov64 r0, 0 - ja jmp_0030 + ja jmp_03f8 -jmp_04a0: +jmp_0860: mov64 r0, 12 - ja jmp_0030 + ja jmp_0400 -jmp_04b0: - mov64 r0, 11 - ja jmp_0030 - -jmp_04c0: +jmp_0870: mov64 r0, 1 - ja jmp_0030 + ja jmp_0400 -jmp_04d0: +jmp_0880: mov64 r0, 2 - ja jmp_0030 + ja jmp_0400 -jmp_04e0: +jmp_0890: mov64 r0, 5 - ja jmp_0030 + ja jmp_0400 -jmp_04f0: - mov64 r0, 3 - ja jmp_0030 - -jmp_0500: +jmp_08a0: mov64 r0, 6 - ja jmp_0030 + ja jmp_0400 -jmp_0510: +jmp_08b0: mov64 r0, 4 - ja jmp_0030 + ja jmp_0400 + +jmp_08c0: + mov64 r0, 13 + ja jmp_0400 -jmp_0520: +jmp_08d0: mov64 r0, 7 - ja jmp_0030 + ja jmp_0400 + +jmp_08e0: + mov64 r0, 11 + ja jmp_0400 + +jmp_08f0: + mov64 r0, 3 + ja jmp_0400 diff --git a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt index bc4fbf46..854c18ec 100644 --- a/examples/tree/artifacts/snippets/asm/initialize-create-account.txt +++ b/examples/tree/artifacts/snippets/asm/initialize-create-account.txt @@ -6,7 +6,7 @@ # - [x] Instruction data pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS - stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_CREATE_ACCOUNT_INSN_DATA_LEN # Pack CreateAccount instruction data. # --------------------------------------------------------------------- diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index d2aa128b..02744479 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,10 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction discriminator | 7 | 8 | +1 | +14.3% | +| Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 547baf75..a7dcd6ae 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,6 +1,6 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 8 | 9 | +1 | +12.5% | +| Invalid instruction data length | 8 | 10 | +2 | +25.0% | | Too few accounts | 9 | 11 | +2 | +22.2% | | Too many accounts | 9 | 11 | +2 | +22.2% | | User has nonzero data length | 11 | 13 | +2 | +18.2% | @@ -22,7 +22,7 @@ test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index ffc545f7..2ae7988c 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -1,8 +1,10 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| Instruction data too short | 7 | 9 | +2 | +28.6% | -| Instruction data too long | 7 | 9 | +2 | +28.6% | -| Insert happy path | 6 | 7 | +1 | +16.7% | +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | +| Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | +| Insert skip alloc | 0 | 6 | 25 | +19 | +316.7% | +| Insert alloc happy path | 1096 | 0 | 126 | +126 | N/A | + (ASM) Insert alloc happy path: data len: expected 53, got 24; lamports: expected 629880, got 528960; next: expected 0x4000028f5, got 0x4000028d8; root: expected 0x4000028d8, got 0x0; key: expected 42, got 50; value: expected 1, got 0 test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units @@ -20,5 +22,13 @@ test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1222 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/test.txt b/examples/tree/artifacts/tests/insert/test.txt index ee37483c..86fa6c32 100644 --- a/examples/tree/artifacts/tests/insert/test.txt +++ b/examples/tree/artifacts/tests/insert/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, false, false); + print_comparison_table(insert::InsertCase::CASES, true, false); } \ No newline at end of file diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 4c8833c2..9136e982 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -330,7 +330,7 @@ initialize: # - [x] Instruction data pointer. # --------------------------------------------------------------------- stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS - stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_INSN_DATA_LEN + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_CREATE_ACCOUNT_INSN_DATA_LEN # Pack CreateAccount instruction data. # --------------------------------------------------------------------- From 3cb65b068e23070fd50934fcfc220fc02ae7415b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:54:49 -0800 Subject: [PATCH 178/263] Add asm parity draft for allocate/pop --- examples/tree/artifacts/dumps/asm.txt | 215 +++++++++++++----- .../tree/artifacts/snippets/asm/constants.txt | 12 +- .../snippets/asm/insert-allocate.txt | 162 +++++++++++++ .../snippets/asm/insert-input-checks.txt | 18 ++ .../tree/artifacts/snippets/asm/insert.txt | 3 - .../tree/artifacts/tests/insert/result.txt | 12 +- examples/tree/interface/src/asm.rs | 24 +- examples/tree/src/tree/tree.s | 198 +++++++++++++++- 8 files changed, 575 insertions(+), 69 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/insert-allocate.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-input-checks.txt delete mode 100644 examples/tree/artifacts/snippets/asm/insert.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 4866c10f..1ab45357 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 1752 (bytes into file) + Start of section headers 2592 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x6d8 +There are 7 section headers, starting at offset 0xa20 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000460 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000548 000548 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000005e8 0005e8 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000648 000648 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000688 000688 000020 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0006a8 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000798 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000880 000880 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000920 000920 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000980 000980 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000009c0 0009c0 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0009f0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000460 0x000460 R E 0x1000 - LOAD 0x0005e8 0x00000000000005e8 0x00000000000005e8 0x0000c0 0x0000c0 R 0x1000 - DYNAMIC 0x000548 0x0000000000000548 0x0000000000000548 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000798 0x000798 R E 0x1000 + LOAD 0x000920 0x0000000000000920 0x0000000000000920 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000880 0x0000000000000880 0x0000000000000880 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,23 +52,24 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x548 contains 10 entries +Dynamic section at offset 0x880 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x688 - 0x0000000000000012 (RELSZ) 32 (bytes) + 0x0000000000000011 (REL) 0x9c0 + 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x5e8 + 0x0000000000000006 (SYMTAB) 0x920 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x648 + 0x0000000000000005 (STRTAB) 0x980 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x688 contains 2 entries +Relocation section '.rel.dyn' at offset 0x9c0 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000730 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -90,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 70 00 01 00 00 00 if r9 != 0x1 goto +0x70 - 37 55 08 71 00 04 00 00 00 if r8 != 0x4 goto +0x71 + 36 55 09 d5 00 01 00 00 00 if r9 != 0x1 goto +0xd5 + 37 55 08 d6 00 04 00 00 00 if r8 != 0x4 goto +0xd6 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 7f 00 00 00 00 00 if r9 != 0x0 goto +0x7f + 39 55 09 e6 00 00 00 00 00 if r9 != 0x0 goto +0xe6 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 7b 00 ff 00 00 00 if r9 != 0xff goto +0x7b + 41 55 09 e2 00 ff 00 00 00 if r9 != 0xff goto +0xe2 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 77 00 00 00 00 00 if r9 != 0x0 goto +0x77 + 43 55 09 de 00 00 00 00 00 if r9 != 0x0 goto +0xde 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 73 00 ff 00 00 00 if r9 != 0xff goto +0x73 + 45 55 09 da 00 ff 00 00 00 if r9 != 0xff goto +0xda 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 6f 00 0e 00 00 00 if r9 != 0xe goto +0x6f + 47 55 09 d6 00 0e 00 00 00 if r9 != 0xe goto +0xd6 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b + 49 55 09 d2 00 ff 00 00 00 if r9 != 0xff goto +0xd2 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 65 00 00 00 00 00 if r9 != r8 goto +0x65 + 53 5d 89 cc 00 00 00 00 00 if r9 != r8 goto +0xcc 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 61 00 00 00 00 00 if r9 != r8 goto +0x61 + 57 5d 89 c8 00 00 00 00 00 if r9 != r8 goto +0xc8 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 5d 00 00 00 00 00 if r9 != r8 goto +0x5d + 61 5d 89 c4 00 00 00 00 00 if r9 != r8 goto +0xc4 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 5a 00 00 00 00 00 if r9 != r8 goto +0x5a + 64 5d 89 c1 00 00 00 00 00 if r9 != r8 goto +0xc1 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -126,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 4d 00 00 00 00 00 if r9 != r8 goto +0x4d + 75 5d 89 b4 00 00 00 00 00 if r9 != r8 goto +0xb4 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 4a 00 00 00 00 00 if r9 != r8 goto +0x4a + 78 5d 89 b1 00 00 00 00 00 if r9 != r8 goto +0xb1 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 47 00 00 00 00 00 if r9 != r8 goto +0x47 + 81 5d 89 ae 00 00 00 00 00 if r9 != r8 goto +0xae 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 44 00 00 00 00 00 if r9 != r8 goto +0x44 + 84 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -196,27 +197,127 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 03 00 05 00 00 00 if r9 != 0x5 goto +0x3 - 146 95 00 00 00 00 00 00 00 exit - 147 b7 00 00 00 09 00 00 00 r0 = 0x9 - 148 95 00 00 00 00 00 00 00 exit - 149 b7 00 00 00 0c 00 00 00 r0 = 0xc - 150 95 00 00 00 00 00 00 00 exit - 151 b7 00 00 00 01 00 00 00 r0 = 0x1 - 152 95 00 00 00 00 00 00 00 exit - 153 b7 00 00 00 0a 00 00 00 r0 = 0xa - 154 95 00 00 00 00 00 00 00 exit - 155 b7 00 00 00 08 00 00 00 r0 = 0x8 - 156 95 00 00 00 00 00 00 00 exit - 157 b7 00 00 00 07 00 00 00 r0 = 0x7 - 158 95 00 00 00 00 00 00 00 exit - 159 b7 00 00 00 04 00 00 00 r0 = 0x4 - 160 95 00 00 00 00 00 00 00 exit - 161 b7 00 00 00 06 00 00 00 r0 = 0x6 - 162 95 00 00 00 00 00 00 00 exit - 163 b7 00 00 00 03 00 00 00 r0 = 0x3 - 164 95 00 00 00 00 00 00 00 exit - 165 b7 00 00 00 05 00 00 00 r0 = 0x5 - 166 95 00 00 00 00 00 00 00 exit - 167 b7 00 00 00 02 00 00 00 r0 = 0x2 - 168 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 145 55 09 68 00 05 00 00 00 if r9 != 0x5 goto +0x68 + 146 a5 08 69 00 02 00 00 00 if r8 < 0x2 goto +0x69 + 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 148 55 09 79 00 00 00 00 00 if r9 != 0x0 goto +0x79 + 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 150 55 09 75 00 ff 00 00 00 if r9 != 0xff goto +0x75 + 151 bf 27 00 00 00 00 00 00 r7 = r2 + 152 bf 16 00 00 00 00 00 00 r6 = r1 + 153 07 06 00 00 c0 28 00 00 r6 += 0x28c0 + 154 79 69 08 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x8) + 155 55 09 53 00 00 00 00 00 if r9 != 0x0 goto +0x53 + 156 55 08 61 00 04 00 00 00 if r8 != 0x4 goto +0x61 + 157 bf 18 00 00 00 00 00 00 r8 = r1 + 158 07 08 00 00 b8 28 00 00 r8 += 0x28b8 + 159 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) + 160 07 09 00 00 07 00 00 00 r9 += 0x7 + 161 57 09 00 00 f8 ff ff ff r9 &= -0x8 + 162 bf 13 00 00 00 00 00 00 r3 = r1 + 163 0f 93 00 00 00 00 00 00 r3 += r9 + 164 71 39 c8 50 00 00 00 00 r9 = *(u8 *)(r3 + 0x50c8) + 165 55 09 62 00 ff 00 00 00 if r9 != 0xff goto +0x62 + 166 79 39 18 51 00 00 00 00 r9 = *(u64 *)(r3 + 0x5118) + 167 55 09 5e 00 0e 00 00 00 if r9 != 0xe goto +0x5e + 168 71 39 38 79 00 00 00 00 r9 = *(u8 *)(r3 + 0x7938) + 169 55 09 5a 00 ff 00 00 00 if r9 != 0xff goto +0x5a + 170 79 39 40 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7940) + 171 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll + 173 5d 49 54 00 00 00 00 00 if r9 != r4 goto +0x54 + 174 79 39 48 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7948) + 175 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll + 177 5d 49 50 00 00 00 00 00 if r9 != r4 goto +0x50 + 178 79 39 50 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7950) + 179 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll + 181 5d 49 4c 00 00 00 00 00 if r9 != r4 goto +0x4c + 182 79 39 58 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7958) + 183 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d + 184 5d 49 49 00 00 00 00 00 if r9 != r4 goto +0x49 + 185 79 39 90 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7990) + 186 27 09 00 00 1d 00 00 00 r9 *= 0x1d + 187 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 + 188 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 + 189 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 190 7a 0a f8 fe 0c 00 00 00 *(u64 *)(r10 - 0x108) = 0xc + 191 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 192 72 0a 18 ff 01 00 00 00 *(u8 *)(r10 - 0xe8) = 0x1 + 193 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 194 72 0a 89 ff 01 00 00 00 *(u8 *)(r10 - 0x77) = 0x1 + 195 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) + 196 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 + 197 07 01 00 00 10 00 00 00 r1 += 0x10 + 198 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 199 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 200 07 01 00 00 20 00 00 00 r1 += 0x20 + 201 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 202 07 01 00 00 20 00 00 00 r1 += 0x20 + 203 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 204 07 01 00 00 10 00 00 00 r1 += 0x10 + 205 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 206 07 01 00 00 10 28 00 00 r1 += 0x2810 + 207 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 208 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 + 209 07 01 00 00 20 00 00 00 r1 += 0x20 + 210 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 211 07 01 00 00 20 00 00 00 r1 += 0x20 + 212 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 213 07 01 00 00 10 00 00 00 r1 += 0x10 + 214 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 215 bf a4 00 00 00 00 00 00 r4 = r10 + 216 07 04 00 00 e0 ff ff ff r4 += -0x20 + 217 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 218 07 04 00 00 20 ff ff ff r4 += -0xe0 + 219 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 220 07 04 00 00 a1 ff ff ff r4 += -0x5f + 221 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 222 bf a1 00 00 00 00 00 00 r1 = r10 + 223 07 01 00 00 d8 fe ff ff r1 += -0x128 + 224 bf a2 00 00 00 00 00 00 r2 = r10 + 225 07 02 00 00 20 ff ff ff r2 += -0xe0 + 226 b7 03 00 00 02 00 00 00 r3 = 0x2 + 227 07 04 00 00 ff 00 00 00 r4 += 0xff + 228 07 04 00 00 f0 ff ff ff r4 += -0x10 + 229 b7 05 00 00 00 00 00 00 r5 = 0x0 + 230 85 10 00 00 ff ff ff ff call -0x1 + 231 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) + 232 07 09 00 00 1d 00 00 00 r9 += 0x1d + 233 7b 98 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r9 + 234 79 69 10 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x10) + 235 bf 94 00 00 00 00 00 00 r4 = r9 + 236 07 04 00 00 1d 00 00 00 r4 += 0x1d + 237 7b 46 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r4 + 238 05 00 02 00 00 00 00 00 goto +0x2 + 239 79 94 00 00 00 00 00 00 r4 = *(u64 *)(r9 + 0x0) + 240 7b 46 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r4 + 241 7b 96 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r9 + 242 69 74 01 00 00 00 00 00 r4 = *(u16 *)(r7 + 0x1) + 243 6a 49 18 00 00 00 00 00 *(u16 *)(r9 + 0x18) = 0x0 + 244 69 74 03 00 00 00 00 00 r4 = *(u16 *)(r7 + 0x3) + 245 6a 49 1a 00 00 00 00 00 *(u16 *)(r9 + 0x1a) = 0x0 + 246 b7 00 00 00 00 00 00 00 r0 = 0x0 + 247 95 00 00 00 00 00 00 00 exit + 248 b7 00 00 00 09 00 00 00 r0 = 0x9 + 249 95 00 00 00 00 00 00 00 exit + 250 b7 00 00 00 0c 00 00 00 r0 = 0xc + 251 95 00 00 00 00 00 00 00 exit + 252 b7 00 00 00 01 00 00 00 r0 = 0x1 + 253 95 00 00 00 00 00 00 00 exit + 254 b7 00 00 00 0d 00 00 00 r0 = 0xd + 255 95 00 00 00 00 00 00 00 exit + 256 b7 00 00 00 0a 00 00 00 r0 = 0xa + 257 95 00 00 00 00 00 00 00 exit + 258 b7 00 00 00 08 00 00 00 r0 = 0x8 + 259 95 00 00 00 00 00 00 00 exit + 260 b7 00 00 00 07 00 00 00 r0 = 0x7 + 261 95 00 00 00 00 00 00 00 exit + 262 b7 00 00 00 04 00 00 00 r0 = 0x4 + 263 95 00 00 00 00 00 00 00 exit + 264 b7 00 00 00 06 00 00 00 r0 = 0x6 + 265 95 00 00 00 00 00 00 00 exit + 266 b7 00 00 00 03 00 00 00 r0 = 0x3 + 267 95 00 00 00 00 00 00 00 exit + 268 b7 00 00 00 05 00 00 00 r0 = 0x5 + 269 95 00 00 00 00 00 00 00 exit + 270 b7 00 00 00 02 00 00 00 r0 = 0x2 + 271 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index b6c3dd39..53880b0f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -28,12 +28,14 @@ .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. .equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. +.equ SIZE_OF_TREE_NODE, 29 # Size of TreeNode. # Data layout constants. # ---------------------- .equ DATA_LEN_ZERO, 0 # Data length of zero. .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ OFFSET_ZERO, 0 # No offset. +.equ NULL, 0 # Null pointer. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. @@ -118,6 +120,8 @@ .equ SF_INIT_SIGNER_SEED_ADDR_OFF, -96 # Bump signer seed address field. .equ SF_INIT_SIGNER_SEED_LEN_OFF, -88 # Bump signer seed length field. .equ SF_INIT_PDA_OFF, -80 # PDA address field. +# Discriminator field in CPI instruction data. +.equ SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF, -351 # Lamports field in CreateAccount instruction data. .equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -347 # Space address field in CreateAccount instruction data. @@ -154,8 +158,12 @@ .equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 # SolAccountInfo data_len field for user account. .equ SF_INIT_USER_INFO_DATA_OFF, -200 +# SolAccountInfo data_len for tree account. +.equ SF_INIT_TREE_INFO_DATA_LEN_OFF, -152 # SolAccountInfo is_signer field for tree account. .equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountInfo is_writable field for tree account. +.equ SF_INIT_TREE_INFO_IS_WRITABLE_UOFF, -119 # SolAccountMeta pubkey field for tree account. .equ SF_INIT_TREE_META_PUBKEY_OFF, -240 # SolAccountInfo pubkey field for tree account. @@ -213,4 +221,6 @@ .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. -.equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. \ No newline at end of file +.equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. +.equ TREE_NODE_KEY_OFF, 24 # Node key field. +.equ TREE_NODE_VALUE_OFF, 26 # Node value field. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-allocate.txt b/examples/tree/artifacts/snippets/asm/insert-allocate.txt new file mode 100644 index 00000000..5ae9a3c0 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-allocate.txt @@ -0,0 +1,162 @@ + # Check if top is null (need allocation) or non-null (pop from stack). + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_TREE_DATA_OFF + TREE_TOP_OFF] + jeq r9, NULL, insert_allocate + + # Pop node from free stack. r9 = top (non-null). + # --------------------------------------------------------------------- + mov64 r7, r2 # Save instruction data pointer. + mov64 r6, r1 + add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. + ldxdw r4, [r9 + OFFSET_ZERO] # Load StackNode.next. + stxdw [r6 + TREE_TOP_OFF], r4 # Update top. + # r9 = node pointer (top cast to TreeNode). + ja insert_set_root + +insert_allocate: + # Error if wrong number of accounts for allocation. + # --------------------------------------------------------------------- + jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts_insert_allocation + + mov64 r7, r2 # Save instruction data pointer. + mov64 r6, r1 + add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. + + # Compute shifted input buffer pointer based on tree data length. + # --------------------------------------------------------------------- + mov64 r8, r1 + add64 r8, IB_TREE_DATA_LEN_OFF # r8 = &tree.data_len. + ldxdw r9, [r8 + OFFSET_ZERO] # r9 = tree data_len. + add64 r9, MAX_DATA_PAD + and64 r9, DATA_LEN_AND_MASK # r9 = aligned data_len. + mov64 r3, r1 + add64 r3, r9 # r3 = shifted input. + + # Check system program is not duplicate and has correct data length. + # --------------------------------------------------------------------- + ldxb r9, [r3 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r9, [r3 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + + # Check rent sysvar is not duplicate and has correct address. + # --------------------------------------------------------------------- + ldxb r9, [r3 + IB_RENT_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_0] + lddw r4, IB_RENT_ID_CHUNK_0 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_1] + lddw r4, IB_RENT_ID_CHUNK_1 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_2] + lddw r4, IB_RENT_ID_CHUNK_2 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_3] + mov32 r4, IB_RENT_ID_CHUNK_3_LO + jne r9, r4, e_rent_address + + # Calculate transfer lamports = lamports_per_byte * sizeof(TreeNode). + # --------------------------------------------------------------------- + ldxdw r9, [r3 + IB_RENT_DATA_OFF] # Load lamports per byte. + mul64 r9, SIZE_OF_TREE_NODE # Multiply to get transfer cost. + + # Pack Transfer instruction data in CreateAccount slot on stack. + # --------------------------------------------------------------------- + stw [r10 + SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF], CPI_TRANSFER_DISCRIMINATOR + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + + # Pack SolInstruction. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_TRANSFER_INSN_DATA_LEN + + # Pack SolAccountMeta flags for user and tree. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], 1 # Writable, not signer. + + # Pack SolAccountInfo flags for user and tree. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], 1 # Writable only. + + # Store tree data_len in account info. + # --------------------------------------------------------------------- + ldxdw r9, [r8 + OFFSET_ZERO] # Reload tree data_len. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + + # Bulk assign/load pointers for account metas and infos. + # --------------------------------------------------------------------- + add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. + stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user owner. + stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. + stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to user data. + stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. + # Advance to tree address field. + add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM + stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. + stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. + stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to tree data. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + + # Bulk assign/load pointers for CPI bindings. + # --------------------------------------------------------------------- + # Point to System Program ID on zero-initialized stack. + mov64 r4, r10 + add64 r4, SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Store in SolInstruction. + # Advance to SolAccountMeta array pointer. + add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Advance to instruction data pointer. + add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. + + # Invoke Transfer CPI. + # --------------------------------------------------------------------- + mov64 r1, r10 + add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r2, r10 + add64 r2, SF_INIT_ACCT_INFOS_OFF + mov64 r3, CPI_N_ACCOUNTS + # Advance r4 to signers seeds area on zero-initialized stack. + add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM + add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + mov64 r5, CPI_N_PDA_SIGNERS_TRANSFER + call sol_invoke_signed_c + + # Update tree data length. + # --------------------------------------------------------------------- + ldxdw r9, [r8 + OFFSET_ZERO] # Load current data_len. + add64 r9, SIZE_OF_TREE_NODE + stxdw [r8 + OFFSET_ZERO], r9 # Store updated data_len. + + # Get node = next, then advance next by one TreeNode. + # --------------------------------------------------------------------- + ldxdw r9, [r6 + TREE_HEADER_NEXT_OFF] # r9 = node pointer. + mov64 r4, r9 + add64 r4, SIZE_OF_TREE_NODE + stxdw [r6 + TREE_HEADER_NEXT_OFF], r4 # Advance next. + +insert_set_root: + # Set node as root of tree. + # --------------------------------------------------------------------- + stxdw [r6 + TREE_ROOT_OFF], r9 + + # Set key and value from instruction data. + # --------------------------------------------------------------------- + ldxh r4, [r7 + INSN_INSERT_KEY_OFF] + sth [r9 + TREE_NODE_KEY_OFF], r4 + ldxh r4, [r7 + INSN_INSERT_VALUE_OFF] + sth [r9 + TREE_NODE_VALUE_OFF], r4 + + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-input-checks.txt b/examples/tree/artifacts/snippets/asm/insert-input-checks.txt new file mode 100644 index 00000000..c2c9e5a2 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-input-checks.txt @@ -0,0 +1,18 @@ +insert: + # Error if invalid instruction data length. + # --------------------------------------------------------------------- + jne r9, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len + + # Error if too few accounts. + # --------------------------------------------------------------------- + jlt r8, IB_N_ACCOUNTS_GENERAL, e_n_accounts + + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert.txt b/examples/tree/artifacts/snippets/asm/insert.txt deleted file mode 100644 index 7ab74eb6..00000000 --- a/examples/tree/artifacts/snippets/asm/insert.txt +++ /dev/null @@ -1,3 +0,0 @@ -insert: - jne r9, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len - exit \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index 2ae7988c..01127c46 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -2,9 +2,9 @@ |-----------|----------------|---------------|----------------|----------|------------| | Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | | Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | -| Insert skip alloc | 0 | 6 | 25 | +19 | +316.7% | -| Insert alloc happy path | 1096 | 0 | 126 | +126 | N/A | - (ASM) Insert alloc happy path: data len: expected 53, got 24; lamports: expected 629880, got 528960; next: expected 0x4000028f5, got 0x4000028d8; root: expected 0x4000028d8, got 0x0; key: expected 42, got 50; value: expected 1, got 0 +| Insert skip alloc | 0 | 24 | 25 | +1 | +4.2% | +| Insert alloc happy path | 1096 | 102 | 126 | +24 | +23.5% | + (ASM) Insert alloc happy path: key: expected 42, got 0; value: expected 1, got 0 test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units @@ -19,13 +19,15 @@ test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1198 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index ec900ac4..17898348 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -5,7 +5,7 @@ use crate::bindings::{ }; use crate::common::{ cpi, CreateAccountInstructionData, InitInputBuffer, InitializeInstruction, InputBufferHeader, - InsertInstruction, Instruction, TreeHeader, + InsertInstruction, Instruction, TreeHeader, TreeNode, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -24,11 +24,14 @@ sizes! { TreeHeader, InitializeInstruction, InsertInstruction, + TreeNode, } extend_constant_group!(data { /// No offset. OFFSET_ZERO = 0, + /// Null pointer. + NULL = 0, /// And mask for data length alignment. DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. @@ -100,6 +103,11 @@ asm_constant_group! { stack_frame_offset!(SIGNER_SEED_LEN, InitStackFrame.signer_seeds[0].len), /// PDA address field. stack_frame_offset!(PDA, InitStackFrame.pda), + /// Discriminator field in CPI instruction data. + stack_frame_offset_unaligned!( + CREATE_ACCOUNT_DISCRIMINATOR, + InitStackFrame.instruction_data.discriminator + ), /// Lamports field in CreateAccount instruction data. stack_frame_offset_unaligned!( CREATE_ACCOUNT_LAMPORTS, @@ -168,11 +176,21 @@ asm_constant_group! { USER_INFO_DATA, InitStackFrame.account_infos[cpi::USER_ACCOUNT_INDEX].data ), + /// SolAccountInfo data_len for tree account. + stack_frame_offset!( + TREE_INFO_DATA_LEN, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].data_len + ), /// SolAccountInfo is_signer field for tree account. stack_frame_offset!( TREE_INFO_IS_SIGNER, InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_signer ), + /// SolAccountInfo is_writable field for tree account. + stack_frame_offset_unaligned!( + TREE_INFO_IS_WRITABLE, + InitStackFrame.account_infos[cpi::TREE_ACCOUNT_INDEX].is_writable + ), /// SolAccountMeta pubkey field for tree account. stack_frame_offset!( TREE_META_PUBKEY, @@ -246,4 +264,8 @@ extend_constant_group!(tree { offset!(TOP, TreeHeader.top), /// Discriminator for insert instruction. DISCRIMINATOR_INSERT = Instruction::Insert as u8, + /// Node key field. + offset!(NODE_KEY, TreeNode.key), + /// Node value field. + offset!(NODE_VALUE, TreeNode.value), }); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 9136e982..3a838eef 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -29,12 +29,14 @@ .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. .equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. +.equ SIZE_OF_TREE_NODE, 29 # Size of TreeNode. # Data layout constants. # ---------------------- .equ DATA_LEN_ZERO, 0 # Data length of zero. .equ BPF_ALIGN_OF_U128, 8 # Data alignment during runtime. .equ OFFSET_ZERO, 0 # No offset. +.equ NULL, 0 # Null pointer. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. @@ -119,6 +121,8 @@ .equ SF_INIT_SIGNER_SEED_ADDR_OFF, -96 # Bump signer seed address field. .equ SF_INIT_SIGNER_SEED_LEN_OFF, -88 # Bump signer seed length field. .equ SF_INIT_PDA_OFF, -80 # PDA address field. +# Discriminator field in CPI instruction data. +.equ SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF, -351 # Lamports field in CreateAccount instruction data. .equ SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF, -347 # Space address field in CreateAccount instruction data. @@ -155,8 +159,12 @@ .equ SF_INIT_USER_INFO_LAMPORTS_OFF, -216 # SolAccountInfo data_len field for user account. .equ SF_INIT_USER_INFO_DATA_OFF, -200 +# SolAccountInfo data_len for tree account. +.equ SF_INIT_TREE_INFO_DATA_LEN_OFF, -152 # SolAccountInfo is_signer field for tree account. .equ SF_INIT_TREE_INFO_IS_SIGNER_OFF, -120 +# SolAccountInfo is_writable field for tree account. +.equ SF_INIT_TREE_INFO_IS_WRITABLE_UOFF, -119 # SolAccountMeta pubkey field for tree account. .equ SF_INIT_TREE_META_PUBKEY_OFF, -240 # SolAccountInfo pubkey field for tree account. @@ -215,6 +223,8 @@ .equ TREE_ROOT_OFF, 0 # Tree root. .equ TREE_TOP_OFF, 8 # Stack top. .equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. +.equ TREE_NODE_KEY_OFF, 24 # Node key field. +.equ TREE_NODE_VALUE_OFF, 26 # Node value field. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -471,11 +481,191 @@ initialize: exit // ANCHOR_END: initialize-create-account -# ANCHOR: insert +# ANCHOR: insert-input-checks insert: + # Error if invalid instruction data length. + # --------------------------------------------------------------------- jne r9, SIZE_OF_INSERT_INSTRUCTION, e_instruction_data_len + + # Error if too few accounts. + # --------------------------------------------------------------------- + jlt r8, IB_N_ACCOUNTS_GENERAL, e_n_accounts + + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + # ANCHOR_END: insert-input-checks + + # ANCHOR: insert-allocate + # Check if top is null (need allocation) or non-null (pop from stack). + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_TREE_DATA_OFF + TREE_TOP_OFF] + jeq r9, NULL, insert_allocate + + # Pop node from free stack. r9 = top (non-null). + # --------------------------------------------------------------------- + mov64 r7, r2 # Save instruction data pointer. + mov64 r6, r1 + add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. + ldxdw r4, [r9 + OFFSET_ZERO] # Load StackNode.next. + stxdw [r6 + TREE_TOP_OFF], r4 # Update top. + # r9 = node pointer (top cast to TreeNode). + ja insert_set_root + +insert_allocate: + # Error if wrong number of accounts for allocation. + # --------------------------------------------------------------------- + jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts_insert_allocation + + mov64 r7, r2 # Save instruction data pointer. + mov64 r6, r1 + add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. + + # Compute shifted input buffer pointer based on tree data length. + # --------------------------------------------------------------------- + mov64 r8, r1 + add64 r8, IB_TREE_DATA_LEN_OFF # r8 = &tree.data_len. + ldxdw r9, [r8 + OFFSET_ZERO] # r9 = tree data_len. + add64 r9, MAX_DATA_PAD + and64 r9, DATA_LEN_AND_MASK # r9 = aligned data_len. + mov64 r3, r1 + add64 r3, r9 # r3 = shifted input. + + # Check system program is not duplicate and has correct data length. + # --------------------------------------------------------------------- + ldxb r9, [r3 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r9, [r3 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + + # Check rent sysvar is not duplicate and has correct address. + # --------------------------------------------------------------------- + ldxb r9, [r3 + IB_RENT_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_0] + lddw r4, IB_RENT_ID_CHUNK_0 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_1] + lddw r4, IB_RENT_ID_CHUNK_1 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_2] + lddw r4, IB_RENT_ID_CHUNK_2 + jne r9, r4, e_rent_address + ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_3] + mov32 r4, IB_RENT_ID_CHUNK_3_LO + jne r9, r4, e_rent_address + + # Calculate transfer lamports = lamports_per_byte * sizeof(TreeNode). + # --------------------------------------------------------------------- + ldxdw r9, [r3 + IB_RENT_DATA_OFF] # Load lamports per byte. + mul64 r9, SIZE_OF_TREE_NODE # Multiply to get transfer cost. + + # Pack Transfer instruction data in CreateAccount slot on stack. + # --------------------------------------------------------------------- + stw [r10 + SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF], CPI_TRANSFER_DISCRIMINATOR + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + + # Pack SolInstruction. + # --------------------------------------------------------------------- + stdw [r10 + SF_INIT_INSN_ACCOUNT_LEN_OFF], CPI_N_ACCOUNTS + stdw [r10 + SF_INIT_INSN_DATA_LEN_OFF], CPI_TRANSFER_INSN_DATA_LEN + + # Pack SolAccountMeta flags for user and tree. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER + stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], 1 # Writable, not signer. + + # Pack SolAccountInfo flags for user and tree. + # --------------------------------------------------------------------- + sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER + stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], 1 # Writable only. + + # Store tree data_len in account info. + # --------------------------------------------------------------------- + ldxdw r9, [r8 + OFFSET_ZERO] # Reload tree data_len. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + + # Bulk assign/load pointers for account metas and infos. + # --------------------------------------------------------------------- + add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. + stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user owner. + stxdw [r10 + SF_INIT_USER_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to user lamports. + stxdw [r10 + SF_INIT_USER_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to user data. + stxdw [r10 + SF_INIT_USER_INFO_DATA_OFF], r1 # Store in account info. + # Advance to tree address field. + add64 r1, IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM + stxdw [r10 + SF_INIT_TREE_META_PUBKEY_OFF], r1 # Store in account meta. + stxdw [r10 + SF_INIT_TREE_INFO_PUBKEY_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree owner. + stxdw [r10 + SF_INIT_TREE_INFO_OWNER_OFF], r1 # Store in account info. + add64 r1, SIZE_OF_ADDRESS # Advance to tree lamports. + stxdw [r10 + SF_INIT_TREE_INFO_LAMPORTS_OFF], r1 # Store in acct info. + add64 r1, SIZE_OF_U128 # Advance to tree data. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_OFF], r1 # Store in account info. + + # Bulk assign/load pointers for CPI bindings. + # --------------------------------------------------------------------- + # Point to System Program ID on zero-initialized stack. + mov64 r4, r10 + add64 r4, SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Store in SolInstruction. + # Advance to SolAccountMeta array pointer. + add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Advance to instruction data pointer. + add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM + stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. + + # Invoke Transfer CPI. + # --------------------------------------------------------------------- + mov64 r1, r10 + add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r2, r10 + add64 r2, SF_INIT_ACCT_INFOS_OFF + mov64 r3, CPI_N_ACCOUNTS + # Advance r4 to signers seeds area on zero-initialized stack. + add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM + add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + mov64 r5, CPI_N_PDA_SIGNERS_TRANSFER + call sol_invoke_signed_c + + # Update tree data length. + # --------------------------------------------------------------------- + ldxdw r9, [r8 + OFFSET_ZERO] # Load current data_len. + add64 r9, SIZE_OF_TREE_NODE + stxdw [r8 + OFFSET_ZERO], r9 # Store updated data_len. + + # Get node = next, then advance next by one TreeNode. + # --------------------------------------------------------------------- + ldxdw r9, [r6 + TREE_HEADER_NEXT_OFF] # r9 = node pointer. + mov64 r4, r9 + add64 r4, SIZE_OF_TREE_NODE + stxdw [r6 + TREE_HEADER_NEXT_OFF], r4 # Advance next. + +insert_set_root: + # Set node as root of tree. + # --------------------------------------------------------------------- + stxdw [r6 + TREE_ROOT_OFF], r9 + + # Set key and value from instruction data. + # --------------------------------------------------------------------- + ldxh r4, [r7 + INSN_INSERT_KEY_OFF] + sth [r9 + TREE_NODE_KEY_OFF], r4 + ldxh r4, [r7 + INSN_INSERT_VALUE_OFF] + sth [r9 + TREE_NODE_VALUE_OFF], r4 + exit -# ANCHOR_END: insert + # ANCHOR_END: insert-allocate e_instruction_data: mov64 r0, E_INSTRUCTION_DATA @@ -489,6 +679,10 @@ e_n_accounts: mov64 r0, E_N_ACCOUNTS exit +e_n_accounts_insert_allocation: + mov64 r0, E_N_ACCOUNTS_INSERT_ALLOCATION + exit + e_pda_mismatch: mov64 r0, E_PDA_MISMATCH exit From 7c6f07238fdb1b7251a540da2ed94504da366226 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:53:09 -0700 Subject: [PATCH 179/263] Begin Claude.md --- CLAUDE.md | 42 ++++++++++++++++++++++++++++++++++++++++++ cfg/dictionary.txt | 2 ++ 2 files changed, 44 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..07649903 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,42 @@ +# Self-Improvement Loop + +After every task, ask: "What did I get wrong, get told twice, or discover? +Should it go in CLAUDE.md, a spec, a hook, a skill, or memory?" + +## Rules + +- **Before implementing anything non-trivial**: write or update a spec + and get approval first. + +- **After every change**: ask the user if CLAUDE.md, specs, or skills + should be updated to reflect what was learned. + +- **Repeated instruction** (user corrects the same thing twice): + add it to CLAUDE.md. + +- **Design decision**: write or update a spec. + +- **Repeatable workflow**: propose a skill. + +- **Must always happen**: propose a hook. + +- **Learned pattern**: save to memory. + +## Markdown + +- Use `-` for list markers. +- Wrap lines to maximize use of the 80-column limit. Break at word + boundaries, not early. + +Every markdown change must pass (run both): + +```sh +cfg=cfg/pre-commit/quick-lint.yml +pre-commit run -c $cfg markdownlint-fix --files +pre-commit run -c $cfg mdformat --files +``` + +## Specs + +- `specs/` for cross-cutting concerns (build, CI, conventions) +- `examples/tree/specs/` for tree-specific design decisions diff --git a/cfg/dictionary.txt b/cfg/dictionary.txt index 6f0fffe4..1505fc8e 100644 --- a/cfg/dictionary.txt +++ b/cfg/dictionary.txt @@ -17,7 +17,9 @@ lddw ldxb ldxdw ldxw +markdownlint mathjax +mdformat memcmp memcpy metas From 45615517c4507c5fdf9bde960d261df921d1a440 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:56:32 -0700 Subject: [PATCH 180/263] Update CLAUDE.md --- CLAUDE.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 07649903..12b6eb8e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,18 +1,20 @@ -# Self-Improvement Loop +# Conventions + +## Self-Improvement Loop After every task, ask: "What did I get wrong, get told twice, or discover? Should it go in CLAUDE.md, a spec, a hook, a skill, or memory?" ## Rules -- **Before implementing anything non-trivial**: write or update a spec - and get approval first. +- **Before implementing anything non-trivial**: write or update a spec and get + approval first. -- **After every change**: ask the user if CLAUDE.md, specs, or skills - should be updated to reflect what was learned. +- **After every change**: ask the user if CLAUDE.md, specs, or skills should be + updated to reflect what was learned. -- **Repeated instruction** (user corrects the same thing twice): - add it to CLAUDE.md. +- **Repeated instruction** (user corrects the same thing twice): add it to + CLAUDE.md. - **Design decision**: write or update a spec. @@ -25,8 +27,9 @@ Should it go in CLAUDE.md, a spec, a hook, a skill, or memory?" ## Markdown - Use `-` for list markers. -- Wrap lines to maximize use of the 80-column limit. Break at word - boundaries, not early. +- End list items with periods. +- Wrap lines to maximize use of the 80-column limit. Break at word boundaries, + not early. Every markdown change must pass (run both): @@ -38,5 +41,5 @@ pre-commit run -c $cfg mdformat --files ## Specs -- `specs/` for cross-cutting concerns (build, CI, conventions) -- `examples/tree/specs/` for tree-specific design decisions +- `specs/` for cross-cutting concerns (build, CI, conventions). +- `examples/tree/specs/` for tree-specific design decisions. From 37fe75cbe0a3516115baeacd46bb655010c76b8a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:58:12 -0700 Subject: [PATCH 181/263] Tweak CLAUDE.md --- CLAUDE.md | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 12b6eb8e..974cb47d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,28 +1,17 @@ # Conventions -## Self-Improvement Loop +## Self-Improvement -After every task, ask: "What did I get wrong, get told twice, or discover? -Should it go in CLAUDE.md, a spec, a hook, a skill, or memory?" +After every task, check what was learned and route it: -## Rules +- Repeated instruction (corrected twice): add it to CLAUDE.md. +- Design decision: write or update a spec. +- Repeatable workflow: propose a skill. +- Must always happen: propose a hook. +- Learned pattern: save to memory. -- **Before implementing anything non-trivial**: write or update a spec and get - approval first. - -- **After every change**: ask the user if CLAUDE.md, specs, or skills should be - updated to reflect what was learned. - -- **Repeated instruction** (user corrects the same thing twice): add it to - CLAUDE.md. - -- **Design decision**: write or update a spec. - -- **Repeatable workflow**: propose a skill. - -- **Must always happen**: propose a hook. - -- **Learned pattern**: save to memory. +Before implementing anything non-trivial, write or update a spec and get +approval first. ## Markdown From e0dd1bcb3d0ff26ba8bf1984c6eaa5536dfcb7aa Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:57:32 -0700 Subject: [PATCH 182/263] Update scaffolding --- examples/tree/interface/src/asm.rs | 8 ++++++-- examples/tree/interface/src/common.rs | 9 +++++++++ examples/tree/src/tests.rs | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 17898348..89f4e39c 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,8 +4,8 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, CreateAccountInstructionData, InitInputBuffer, InitializeInstruction, InputBufferHeader, - InsertInstruction, Instruction, TreeHeader, TreeNode, + cpi, CreateAccountInstructionData, GeneralInputBufferHeader, InitInputBuffer, + InitializeInstruction, InputBufferHeader, InsertInstruction, Instruction, TreeHeader, TreeNode, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -36,6 +36,8 @@ extend_constant_group!(data { DATA_LEN_AND_MASK = -8, /// Maximum possible data length padding. MAX_DATA_PAD = 7, + /// Boolean true value. + BOOL_TRUE = 1, }); extend_constant_group!(input_buffer { @@ -67,6 +69,8 @@ extend_constant_group!(input_buffer { pubkey_value!(RENT_ID, RENT_ID), /// Program ID field for initialize instruction. offset_immediate!(INIT_PROGRAM_ID, InitInputBuffer.footer.program_id), + /// Tree top pointer field within tree data. + offset!(TREE_DATA_TOP, GeneralInputBufferHeader.tree_data.top), /// Relative offset from user data field to tree pubkey field. relative_offset_immediate!( USER_DATA, diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 3566dcb5..c43847bb 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -164,6 +164,15 @@ pub struct InitInputBufferHeader { pub rent: RentRuntimeAccount, } +#[repr(C, packed)] +/// Input buffer header for general tree instructions. +pub struct GeneralInputBufferHeader { + pub n_accounts: u64, + pub user: EmptyRuntimeAccount, + pub tree_header: RuntimeAccountHeader, + pub tree_data: TreeHeader, +} + // ANCHOR: tree-defs-common #[repr(u8)] pub enum Color { diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 6d1f0479..62e762dc 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -169,7 +169,7 @@ fn test_entrypoint_branching() { #[test] fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, true, false); + print_comparison_table(insert::InsertCase::CASES, false, false); } #[test] From 59d19d2478031b5ff7029df40ccfc6ef24e0ac43 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:58:16 -0700 Subject: [PATCH 183/263] Add spec --- specs/asm-offset-safety.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 specs/asm-offset-safety.md diff --git a/specs/asm-offset-safety.md b/specs/asm-offset-safety.md new file mode 100644 index 00000000..5aa4873e --- /dev/null +++ b/specs/asm-offset-safety.md @@ -0,0 +1,37 @@ +# Assembly offset safety + +## Rule: no arithmetic on offset constants in assembly + +SBF load/store instructions encode memory offsets as i16 immediates. When two or +more offset constants are added together in an assembly instruction, no +compile-time check validates that the sum fits in i16. The assembler would +eventually reject an overflow, but the error is late and unclear. + +### Prohibited + +Adding multiple offset constants in a single instruction: + +```asm +ldxdw r9, [r1 + TREE_DATA_OFF + TREE_TOP_OFF] +``` + +### Required + +Define a single constant for the combined offset so that the full +value is validated at definition time. Then use that constant +alone in the instruction: + +```asm +ldxdw r9, [r1 + IB_TREE_DATA_TOP_OFF] +``` + +### When separate offsets are fine + +Using an offset constant in an `add64` followed by a different +offset in a subsequent load/store is safe, since each immediate +is validated independently: + +```asm +add64 r6, TREE_DATA_OFF +stxdw [r6 + TREE_TOP_OFF], r4 +``` From d88fa6296ebf8a9adef50ed3cc25d02b3d2ba5b0 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 16:21:47 -0700 Subject: [PATCH 184/263] Tweak algos --- examples/tree/artifacts/dumps/asm.txt | 286 +++++++++--------- .../tree/artifacts/snippets/asm/constants.txt | 8 +- .../snippets/asm/insert-allocate.txt | 122 ++++---- .../initialize_create_account/result.txt | 36 --- .../tests/initialize_create_account/test.txt | 4 - .../tests/initialize_input_checks/result.txt | 122 -------- .../tests/initialize_pda_checks/result.txt | 31 -- .../tests/initialize_pda_checks/test.txt | 4 - .../tree/artifacts/tests/insert/result.txt | 9 +- examples/tree/artifacts/tests/insert/test.txt | 2 +- examples/tree/interface/src/asm.rs | 8 +- examples/tree/src/tree/tree.s | 138 +++++---- 12 files changed, 274 insertions(+), 496 deletions(-) delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 1ab45357..26b63ff3 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 2592 (bytes into file) + Start of section headers 2544 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xa20 +There are 7 section headers, starting at offset 0x9f0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000798 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000880 000880 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000920 000920 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000980 000980 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 00000000000009c0 0009c0 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0009f0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000768 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000850 000850 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000008f0 0008f0 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000950 000950 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000990 000990 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0009c0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000798 0x000798 R E 0x1000 - LOAD 0x000920 0x0000000000000920 0x0000000000000920 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000880 0x0000000000000880 0x0000000000000880 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000768 0x000768 R E 0x1000 + LOAD 0x0008f0 0x00000000000008f0 0x00000000000008f0 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000850 0x0000000000000850 0x0000000000000850 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,24 +52,24 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x880 contains 10 entries +Dynamic section at offset 0x850 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x9c0 + 0x0000000000000011 (REL) 0x990 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x920 + 0x0000000000000006 (SYMTAB) 0x8f0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x980 + 0x0000000000000005 (STRTAB) 0x950 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x9c0 contains 3 entries +Relocation section '.rel.dyn' at offset 0x990 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c -0000000000000730 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000700 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 d5 00 01 00 00 00 if r9 != 0x1 goto +0xd5 - 37 55 08 d6 00 04 00 00 00 if r8 != 0x4 goto +0xd6 + 36 55 09 cf 00 01 00 00 00 if r9 != 0x1 goto +0xcf + 37 55 08 d0 00 04 00 00 00 if r8 != 0x4 goto +0xd0 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 e6 00 00 00 00 00 if r9 != 0x0 goto +0xe6 + 39 55 09 e0 00 00 00 00 00 if r9 != 0x0 goto +0xe0 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 e2 00 ff 00 00 00 if r9 != 0xff goto +0xe2 + 41 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 de 00 00 00 00 00 if r9 != 0x0 goto +0xde + 43 55 09 d8 00 00 00 00 00 if r9 != 0x0 goto +0xd8 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 da 00 ff 00 00 00 if r9 != 0xff goto +0xda + 45 55 09 d4 00 ff 00 00 00 if r9 != 0xff goto +0xd4 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 d6 00 0e 00 00 00 if r9 != 0xe goto +0xd6 + 47 55 09 d0 00 0e 00 00 00 if r9 != 0xe goto +0xd0 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 d2 00 ff 00 00 00 if r9 != 0xff goto +0xd2 + 49 55 09 cc 00 ff 00 00 00 if r9 != 0xff goto +0xcc 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 cc 00 00 00 00 00 if r9 != r8 goto +0xcc + 53 5d 89 c6 00 00 00 00 00 if r9 != r8 goto +0xc6 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 c8 00 00 00 00 00 if r9 != r8 goto +0xc8 + 57 5d 89 c2 00 00 00 00 00 if r9 != r8 goto +0xc2 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 c4 00 00 00 00 00 if r9 != r8 goto +0xc4 + 61 5d 89 be 00 00 00 00 00 if r9 != r8 goto +0xbe 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 c1 00 00 00 00 00 if r9 != r8 goto +0xc1 + 64 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 b4 00 00 00 00 00 if r9 != r8 goto +0xb4 + 75 5d 89 ae 00 00 00 00 00 if r9 != r8 goto +0xae 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 b1 00 00 00 00 00 if r9 != r8 goto +0xb1 + 78 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 ae 00 00 00 00 00 if r9 != r8 goto +0xae + 81 5d 89 a8 00 00 00 00 00 if r9 != r8 goto +0xa8 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab + 84 5d 89 a5 00 00 00 00 00 if r9 != r8 goto +0xa5 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,127 +197,121 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 68 00 05 00 00 00 if r9 != 0x5 goto +0x68 - 146 a5 08 69 00 02 00 00 00 if r8 < 0x2 goto +0x69 + 145 55 09 62 00 05 00 00 00 if r9 != 0x5 goto +0x62 + 146 a5 08 63 00 02 00 00 00 if r8 < 0x2 goto +0x63 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 79 00 00 00 00 00 if r9 != 0x0 goto +0x79 + 148 55 09 73 00 00 00 00 00 if r9 != 0x0 goto +0x73 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 75 00 ff 00 00 00 if r9 != 0xff goto +0x75 - 151 bf 27 00 00 00 00 00 00 r7 = r2 - 152 bf 16 00 00 00 00 00 00 r6 = r1 - 153 07 06 00 00 c0 28 00 00 r6 += 0x28c0 - 154 79 69 08 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x8) - 155 55 09 53 00 00 00 00 00 if r9 != 0x0 goto +0x53 - 156 55 08 61 00 04 00 00 00 if r8 != 0x4 goto +0x61 - 157 bf 18 00 00 00 00 00 00 r8 = r1 - 158 07 08 00 00 b8 28 00 00 r8 += 0x28b8 - 159 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) - 160 07 09 00 00 07 00 00 00 r9 += 0x7 - 161 57 09 00 00 f8 ff ff ff r9 &= -0x8 - 162 bf 13 00 00 00 00 00 00 r3 = r1 - 163 0f 93 00 00 00 00 00 00 r3 += r9 - 164 71 39 c8 50 00 00 00 00 r9 = *(u8 *)(r3 + 0x50c8) - 165 55 09 62 00 ff 00 00 00 if r9 != 0xff goto +0x62 - 166 79 39 18 51 00 00 00 00 r9 = *(u64 *)(r3 + 0x5118) - 167 55 09 5e 00 0e 00 00 00 if r9 != 0xe goto +0x5e - 168 71 39 38 79 00 00 00 00 r9 = *(u8 *)(r3 + 0x7938) - 169 55 09 5a 00 ff 00 00 00 if r9 != 0xff goto +0x5a - 170 79 39 40 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7940) - 171 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 173 5d 49 54 00 00 00 00 00 if r9 != r4 goto +0x54 - 174 79 39 48 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7948) - 175 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 177 5d 49 50 00 00 00 00 00 if r9 != r4 goto +0x50 - 178 79 39 50 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7950) - 179 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 181 5d 49 4c 00 00 00 00 00 if r9 != r4 goto +0x4c - 182 79 39 58 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7958) - 183 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 184 5d 49 49 00 00 00 00 00 if r9 != r4 goto +0x49 - 185 79 39 90 79 00 00 00 00 r9 = *(u64 *)(r3 + 0x7990) - 186 27 09 00 00 1d 00 00 00 r9 *= 0x1d - 187 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 - 188 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 - 189 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 - 190 7a 0a f8 fe 0c 00 00 00 *(u64 *)(r10 - 0x108) = 0xc - 191 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 - 192 72 0a 18 ff 01 00 00 00 *(u8 *)(r10 - 0xe8) = 0x1 - 193 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 - 194 72 0a 89 ff 01 00 00 00 *(u8 *)(r10 - 0x77) = 0x1 - 195 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) - 196 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 - 197 07 01 00 00 10 00 00 00 r1 += 0x10 - 198 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 - 199 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 - 200 07 01 00 00 20 00 00 00 r1 += 0x20 - 201 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 - 202 07 01 00 00 20 00 00 00 r1 += 0x20 - 203 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 - 204 07 01 00 00 10 00 00 00 r1 += 0x10 - 205 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 206 07 01 00 00 10 28 00 00 r1 += 0x2810 - 207 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 - 208 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 - 209 07 01 00 00 20 00 00 00 r1 += 0x20 - 210 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 - 211 07 01 00 00 20 00 00 00 r1 += 0x20 - 212 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 - 213 07 01 00 00 10 00 00 00 r1 += 0x10 - 214 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 215 bf a4 00 00 00 00 00 00 r4 = r10 - 216 07 04 00 00 e0 ff ff ff r4 += -0x20 - 217 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 218 07 04 00 00 20 ff ff ff r4 += -0xe0 - 219 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 220 07 04 00 00 a1 ff ff ff r4 += -0x5f - 221 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 222 bf a1 00 00 00 00 00 00 r1 = r10 - 223 07 01 00 00 d8 fe ff ff r1 += -0x128 - 224 bf a2 00 00 00 00 00 00 r2 = r10 - 225 07 02 00 00 20 ff ff ff r2 += -0xe0 - 226 b7 03 00 00 02 00 00 00 r3 = 0x2 - 227 07 04 00 00 ff 00 00 00 r4 += 0xff - 228 07 04 00 00 f0 ff ff ff r4 += -0x10 - 229 b7 05 00 00 00 00 00 00 r5 = 0x0 - 230 85 10 00 00 ff ff ff ff call -0x1 - 231 79 89 00 00 00 00 00 00 r9 = *(u64 *)(r8 + 0x0) - 232 07 09 00 00 1d 00 00 00 r9 += 0x1d - 233 7b 98 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r9 - 234 79 69 10 00 00 00 00 00 r9 = *(u64 *)(r6 + 0x10) - 235 bf 94 00 00 00 00 00 00 r4 = r9 - 236 07 04 00 00 1d 00 00 00 r4 += 0x1d - 237 7b 46 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r4 - 238 05 00 02 00 00 00 00 00 goto +0x2 - 239 79 94 00 00 00 00 00 00 r4 = *(u64 *)(r9 + 0x0) - 240 7b 46 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r4 - 241 7b 96 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r9 - 242 69 74 01 00 00 00 00 00 r4 = *(u16 *)(r7 + 0x1) - 243 6a 49 18 00 00 00 00 00 *(u16 *)(r9 + 0x18) = 0x0 - 244 69 74 03 00 00 00 00 00 r4 = *(u16 *)(r7 + 0x3) - 245 6a 49 1a 00 00 00 00 00 *(u16 *)(r9 + 0x1a) = 0x0 - 246 b7 00 00 00 00 00 00 00 r0 = 0x0 + 150 55 09 6f 00 ff 00 00 00 if r9 != 0xff goto +0x6f + 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) + 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 + 153 55 08 5e 00 04 00 00 00 if r8 != 0x4 goto +0x5e + 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 + 156 bf 97 00 00 00 00 00 00 r7 = r9 + 157 07 09 00 00 07 00 00 00 r9 += 0x7 + 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 + 159 0f 19 00 00 00 00 00 00 r9 += r1 + 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) + 161 55 08 60 00 ff 00 00 00 if r8 != 0xff goto +0x60 + 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) + 163 55 08 5c 00 0e 00 00 00 if r8 != 0xe goto +0x5c + 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) + 165 55 08 58 00 ff 00 00 00 if r8 != 0xff goto +0x58 + 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) + 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll + 169 5d 48 52 00 00 00 00 00 if r8 != r4 goto +0x52 + 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) + 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll + 173 5d 48 4e 00 00 00 00 00 if r8 != r4 goto +0x4e + 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) + 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll + 177 5d 48 4a 00 00 00 00 00 if r8 != r4 goto +0x4a + 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) + 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d + 180 5d 48 47 00 00 00 00 00 if r8 != r4 goto +0x47 + 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) + 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d + 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 + 184 7b 8a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r8 + 185 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 186 7a 0a f8 fe 0c 00 00 00 *(u64 *)(r10 - 0x108) = 0xc + 187 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 188 72 0a 18 ff 01 00 00 00 *(u8 *)(r10 - 0xe8) = 0x1 + 189 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 190 72 0a 89 ff 01 00 00 00 *(u8 *)(r10 - 0x77) = 0x1 + 191 bf 16 00 00 00 00 00 00 r6 = r1 + 192 07 01 00 00 10 00 00 00 r1 += 0x10 + 193 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 194 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 195 07 01 00 00 20 00 00 00 r1 += 0x20 + 196 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 197 07 01 00 00 20 00 00 00 r1 += 0x20 + 198 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 199 07 01 00 00 10 00 00 00 r1 += 0x10 + 200 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 201 07 01 00 00 10 28 00 00 r1 += 0x2810 + 202 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 203 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 + 204 07 01 00 00 20 00 00 00 r1 += 0x20 + 205 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 206 07 01 00 00 20 00 00 00 r1 += 0x20 + 207 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 208 07 01 00 00 10 00 00 00 r1 += 0x10 + 209 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 210 bf a4 00 00 00 00 00 00 r4 = r10 + 211 07 04 00 00 e0 ff ff ff r4 += -0x20 + 212 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 213 07 04 00 00 20 ff ff ff r4 += -0xe0 + 214 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 215 07 04 00 00 a1 ff ff ff r4 += -0x5f + 216 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 217 bf a1 00 00 00 00 00 00 r1 = r10 + 218 07 01 00 00 d8 fe ff ff r1 += -0x128 + 219 bf 28 00 00 00 00 00 00 r8 = r2 + 220 bf a2 00 00 00 00 00 00 r2 = r10 + 221 07 02 00 00 20 ff ff ff r2 += -0xe0 + 222 b7 03 00 00 02 00 00 00 r3 = 0x2 + 223 b7 05 00 00 00 00 00 00 r5 = 0x0 + 224 85 10 00 00 ff ff ff ff call -0x1 + 225 bf 82 00 00 00 00 00 00 r2 = r8 + 226 bf 61 00 00 00 00 00 00 r1 = r6 + 227 07 07 00 00 1d 00 00 00 r7 += 0x1d + 228 7b 71 b8 28 00 00 00 00 *(u64 *)(r1 + 0x28b8) = r7 + 229 79 17 d0 28 00 00 00 00 r7 = *(u64 *)(r1 + 0x28d0) + 230 bf 79 00 00 00 00 00 00 r9 = r7 + 231 07 07 00 00 1d 00 00 00 r7 += 0x1d + 232 7b 71 d0 28 00 00 00 00 *(u64 *)(r1 + 0x28d0) = r7 + 233 05 00 02 00 00 00 00 00 goto +0x2 + 234 79 98 00 00 00 00 00 00 r8 = *(u64 *)(r9 + 0x0) + 235 7b 81 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r8 + 236 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 + 237 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) + 238 6b 49 18 00 00 00 00 00 *(u16 *)(r9 + 0x18) = r4 + 239 69 24 03 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x3) + 240 6b 49 1a 00 00 00 00 00 *(u16 *)(r9 + 0x1a) = r4 + 241 95 00 00 00 00 00 00 00 exit + 242 b7 00 00 00 09 00 00 00 r0 = 0x9 + 243 95 00 00 00 00 00 00 00 exit + 244 b7 00 00 00 0c 00 00 00 r0 = 0xc + 245 95 00 00 00 00 00 00 00 exit + 246 b7 00 00 00 01 00 00 00 r0 = 0x1 247 95 00 00 00 00 00 00 00 exit - 248 b7 00 00 00 09 00 00 00 r0 = 0x9 + 248 b7 00 00 00 0d 00 00 00 r0 = 0xd 249 95 00 00 00 00 00 00 00 exit - 250 b7 00 00 00 0c 00 00 00 r0 = 0xc + 250 b7 00 00 00 0a 00 00 00 r0 = 0xa 251 95 00 00 00 00 00 00 00 exit - 252 b7 00 00 00 01 00 00 00 r0 = 0x1 + 252 b7 00 00 00 08 00 00 00 r0 = 0x8 253 95 00 00 00 00 00 00 00 exit - 254 b7 00 00 00 0d 00 00 00 r0 = 0xd + 254 b7 00 00 00 07 00 00 00 r0 = 0x7 255 95 00 00 00 00 00 00 00 exit - 256 b7 00 00 00 0a 00 00 00 r0 = 0xa + 256 b7 00 00 00 04 00 00 00 r0 = 0x4 257 95 00 00 00 00 00 00 00 exit - 258 b7 00 00 00 08 00 00 00 r0 = 0x8 + 258 b7 00 00 00 06 00 00 00 r0 = 0x6 259 95 00 00 00 00 00 00 00 exit - 260 b7 00 00 00 07 00 00 00 r0 = 0x7 + 260 b7 00 00 00 03 00 00 00 r0 = 0x3 261 95 00 00 00 00 00 00 00 exit - 262 b7 00 00 00 04 00 00 00 r0 = 0x4 + 262 b7 00 00 00 05 00 00 00 r0 = 0x5 263 95 00 00 00 00 00 00 00 exit - 264 b7 00 00 00 06 00 00 00 r0 = 0x6 - 265 95 00 00 00 00 00 00 00 exit - 266 b7 00 00 00 03 00 00 00 r0 = 0x3 - 267 95 00 00 00 00 00 00 00 exit - 268 b7 00 00 00 05 00 00 00 r0 = 0x5 - 269 95 00 00 00 00 00 00 00 exit - 270 b7 00 00 00 02 00 00 00 r0 = 0x2 - 271 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 264 b7 00 00 00 02 00 00 00 r0 = 0x2 + 265 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 53880b0f..097bd9de 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -38,6 +38,7 @@ .equ NULL, 0 # Null pointer. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ BOOL_TRUE, 1 # Boolean true value. # Pubkey chunking offsets. # ------------------------ @@ -102,6 +103,11 @@ .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41401 +.equ IB_TREE_DATA_TOP_OFF, 10440 # Tree top pointer field within tree data. +# Tree next pointer field within tree data. +.equ IB_TREE_DATA_NEXT_OFF, 10448 +# Tree root pointer field within tree data. +.equ IB_TREE_DATA_ROOT_OFF, 10432 # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 @@ -219,8 +225,6 @@ .equ TREE_COLOR_R, 1 # Red color. .equ TREE_HEADER_TOP_OFF, 8 # Stack top field in header. .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. -.equ TREE_ROOT_OFF, 0 # Tree root. -.equ TREE_TOP_OFF, 8 # Stack top. .equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. .equ TREE_NODE_KEY_OFF, 24 # Node key field. .equ TREE_NODE_VALUE_OFF, 26 # Node value field. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-allocate.txt b/examples/tree/artifacts/snippets/asm/insert-allocate.txt index 5ae9a3c0..d29cd625 100644 --- a/examples/tree/artifacts/snippets/asm/insert-allocate.txt +++ b/examples/tree/artifacts/snippets/asm/insert-allocate.txt @@ -1,70 +1,57 @@ - # Check if top is null (need allocation) or non-null (pop from stack). + # Branch based on state of stack top. # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_TREE_DATA_OFF + TREE_TOP_OFF] - jeq r9, NULL, insert_allocate - - # Pop node from free stack. r9 = top (non-null). - # --------------------------------------------------------------------- - mov64 r7, r2 # Save instruction data pointer. - mov64 r6, r1 - add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. - ldxdw r4, [r9 + OFFSET_ZERO] # Load StackNode.next. - stxdw [r6 + TREE_TOP_OFF], r4 # Update top. - # r9 = node pointer (top cast to TreeNode). - ja insert_set_root + # Get stack top pointer. + ldxdw r9, [r1 + IB_TREE_DATA_TOP_OFF] + jne r9, NULL, insert_pop # Pop node from stack if non-null. insert_allocate: # Error if wrong number of accounts for allocation. # --------------------------------------------------------------------- jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts_insert_allocation - mov64 r7, r2 # Save instruction data pointer. - mov64 r6, r1 - add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. - # Compute shifted input buffer pointer based on tree data length. # --------------------------------------------------------------------- - mov64 r8, r1 - add64 r8, IB_TREE_DATA_LEN_OFF # r8 = &tree.data_len. - ldxdw r9, [r8 + OFFSET_ZERO] # r9 = tree data_len. - add64 r9, MAX_DATA_PAD - and64 r9, DATA_LEN_AND_MASK # r9 = aligned data_len. - mov64 r3, r1 - add64 r3, r9 # r3 = shifted input. + ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + # Store in account info for CPI. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + mov64 r7, r9 # Store copy for later. + add64 r9, MAX_DATA_PAD # Add max possible padding. + and64 r9, DATA_LEN_AND_MASK # Truncate to 8-byte alignment. + add64 r9, r1 # Increment by input buffer. # Check system program is not duplicate and has correct data length. # --------------------------------------------------------------------- - ldxb r9, [r3 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r9, [r3 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] - jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + ldxb r8, [r9 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r8, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r8, [r9 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r8, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Check rent sysvar is not duplicate and has correct address. # --------------------------------------------------------------------- - ldxb r9, [r3 + IB_RENT_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_0] + ldxb r8, [r9 + IB_RENT_NON_DUP_MARKER_OFF] + jne r8, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_0] lddw r4, IB_RENT_ID_CHUNK_0 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_1] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_1] lddw r4, IB_RENT_ID_CHUNK_1 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_2] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_2] lddw r4, IB_RENT_ID_CHUNK_2 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_3] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_3] mov32 r4, IB_RENT_ID_CHUNK_3_LO - jne r9, r4, e_rent_address + jne r8, r4, e_rent_address - # Calculate transfer lamports = lamports_per_byte * sizeof(TreeNode). + # Calculate transfer lamports. # --------------------------------------------------------------------- - ldxdw r9, [r3 + IB_RENT_DATA_OFF] # Load lamports per byte. - mul64 r9, SIZE_OF_TREE_NODE # Multiply to get transfer cost. + ldxdw r8, [r9 + IB_RENT_DATA_OFF] # Load lamports per byte. + mul64 r8, SIZE_OF_TREE_NODE # Multiply to get transfer cost. # Pack Transfer instruction data in CreateAccount slot on stack. # --------------------------------------------------------------------- stw [r10 + SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF], CPI_TRANSFER_DISCRIMINATOR - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r8 # Pack SolInstruction. # --------------------------------------------------------------------- @@ -74,20 +61,16 @@ insert_allocate: # Pack SolAccountMeta flags for user and tree. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER - stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], 1 # Writable, not signer. + stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], BOOL_TRUE # Pack SolAccountInfo flags for user and tree. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER - stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], 1 # Writable only. - - # Store tree data_len in account info. - # --------------------------------------------------------------------- - ldxdw r9, [r8 + OFFSET_ZERO] # Reload tree data_len. - stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], BOOL_TRUE # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- + mov64 r6, r1 # Store input buffer pointer for later. add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. @@ -113,10 +96,12 @@ insert_allocate: # Point to System Program ID on zero-initialized stack. mov64 r4, r10 add64 r4, SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF - stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Store in SolInstruction. + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Advance to SolAccountMeta array pointer. add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM - stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Advance to instruction data pointer. add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. @@ -125,38 +110,33 @@ insert_allocate: # --------------------------------------------------------------------- mov64 r1, r10 add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r8, r2 # Save instruction data pointer for later. mov64 r2, r10 add64 r2, SF_INIT_ACCT_INFOS_OFF mov64 r3, CPI_N_ACCOUNTS - # Advance r4 to signers seeds area on zero-initialized stack. - add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM - add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + # Ignore PDA signer seeds pointer, since none required. mov64 r5, CPI_N_PDA_SIGNERS_TRANSFER call sol_invoke_signed_c + mov64 r2, r8 # Restore instruction data pointer. + mov64 r1, r6 # Restore input buffer pointer. # Update tree data length. # --------------------------------------------------------------------- - ldxdw r9, [r8 + OFFSET_ZERO] # Load current data_len. - add64 r9, SIZE_OF_TREE_NODE - stxdw [r8 + OFFSET_ZERO], r9 # Store updated data_len. + add64 r7, SIZE_OF_TREE_NODE # Increment data length. + stxdw [r1 + IB_TREE_DATA_LEN_OFF], r7 # Store in input buffer. # Get node = next, then advance next by one TreeNode. # --------------------------------------------------------------------- - ldxdw r9, [r6 + TREE_HEADER_NEXT_OFF] # r9 = node pointer. - mov64 r4, r9 - add64 r4, SIZE_OF_TREE_NODE - stxdw [r6 + TREE_HEADER_NEXT_OFF], r4 # Advance next. + ldxdw r7, [r1 + IB_TREE_DATA_NEXT_OFF] # Get pointer to next node. + mov64 r9, r7 # Store node pointer for later, the new node. + add64 r7, SIZE_OF_TREE_NODE # Increment to point to new next. + stxdw [r1 + IB_TREE_DATA_NEXT_OFF], r7 # Advance next. -insert_set_root: - # Set node as root of tree. + # Continue insert. # --------------------------------------------------------------------- - stxdw [r6 + TREE_ROOT_OFF], r9 + ja insert_mutate_new_node - # Set key and value from instruction data. +insert_pop: # --------------------------------------------------------------------- - ldxh r4, [r7 + INSN_INSERT_KEY_OFF] - sth [r9 + TREE_NODE_KEY_OFF], r4 - ldxh r4, [r7 + INSN_INSERT_VALUE_OFF] - sth [r9 + TREE_NODE_VALUE_OFF], r4 - - exit \ No newline at end of file + ldxdw r8, [r9 + OFFSET_ZERO] # Load StackNode.next. + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r8 # Update top in header. \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt deleted file mode 100644 index ac84fbbb..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ /dev/null @@ -1,36 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | -| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | -| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | -test tests::test_initialize_create_account ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt deleted file mode 100644 index aa2dd6c3..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index a7dcd6ae..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,122 +0,0 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 8 | 10 | +2 | +25.0% | -| Too few accounts | 9 | 11 | +2 | +22.2% | -| Too many accounts | 9 | 11 | +2 | +22.2% | -| User has nonzero data length | 11 | 13 | +2 | +18.2% | -| Tree account is duplicate | 13 | 15 | +2 | +15.4% | -| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | -| System program is duplicate | 17 | 19 | +2 | +11.8% | -| System program wrong data length | 19 | 21 | +2 | +10.5% | -| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | -| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | -| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 49588334..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | -| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | -| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | -| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 0f682d5d..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index 01127c46..3bde3ef3 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -2,9 +2,8 @@ |-----------|----------------|---------------|----------------|----------|------------| | Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | | Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | -| Insert skip alloc | 0 | 24 | 25 | +1 | +4.2% | -| Insert alloc happy path | 1096 | 102 | 126 | +24 | +23.5% | - (ASM) Insert alloc happy path: key: expected 42, got 0; value: expected 1, got 0 +| Insert skip alloc | 0 | 20 | 25 | +5 | +25.0% | +| Insert alloc happy path | 1096 | 96 | 126 | +30 | +31.2% | test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units @@ -19,7 +18,7 @@ test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -27,7 +26,7 @@ test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1198 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1192 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] diff --git a/examples/tree/artifacts/tests/insert/test.txt b/examples/tree/artifacts/tests/insert/test.txt index 86fa6c32..ee37483c 100644 --- a/examples/tree/artifacts/tests/insert/test.txt +++ b/examples/tree/artifacts/tests/insert/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, true, false); + print_comparison_table(insert::InsertCase::CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 89f4e39c..74b536cc 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -71,6 +71,10 @@ extend_constant_group!(input_buffer { offset_immediate!(INIT_PROGRAM_ID, InitInputBuffer.footer.program_id), /// Tree top pointer field within tree data. offset!(TREE_DATA_TOP, GeneralInputBufferHeader.tree_data.top), + /// Tree next pointer field within tree data. + offset!(TREE_DATA_NEXT, GeneralInputBufferHeader.tree_data.next), + /// Tree root pointer field within tree data. + offset!(TREE_DATA_ROOT, GeneralInputBufferHeader.tree_data.root), /// Relative offset from user data field to tree pubkey field. relative_offset_immediate!( USER_DATA, @@ -262,10 +266,6 @@ asm_constant_group! { extend_constant_group!(tree { prefix = "TREE", - /// Tree root. - offset!(ROOT, TreeHeader.root), - /// Stack top. - offset!(TOP, TreeHeader.top), /// Discriminator for insert instruction. DISCRIMINATOR_INSERT = Instruction::Insert as u8, /// Node key field. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 3a838eef..caedfcb0 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -39,6 +39,7 @@ .equ NULL, 0 # Null pointer. .equ DATA_LEN_AND_MASK, -8 # And mask for data length alignment. .equ MAX_DATA_PAD, 7 # Maximum possible data length padding. +.equ BOOL_TRUE, 1 # Boolean true value. # Pubkey chunking offsets. # ------------------------ @@ -103,6 +104,11 @@ .equ IB_RENT_ID_CHUNK_3_HI, 0 # Rent sysvar ID (chunk 3 hi). # Program ID field for initialize instruction. .equ IB_INIT_PROGRAM_ID_OFF_IMM, 41401 +.equ IB_TREE_DATA_TOP_OFF, 10440 # Tree top pointer field within tree data. +# Tree next pointer field within tree data. +.equ IB_TREE_DATA_NEXT_OFF, 10448 +# Tree root pointer field within tree data. +.equ IB_TREE_DATA_ROOT_OFF, 10432 # Relative offset from user data field to tree pubkey field. .equ IB_USER_DATA_TO_TREE_ADDRESS_REL_OFF_IMM, 10256 @@ -220,8 +226,6 @@ .equ TREE_COLOR_R, 1 # Red color. .equ TREE_HEADER_TOP_OFF, 8 # Stack top field in header. .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. -.equ TREE_ROOT_OFF, 0 # Tree root. -.equ TREE_TOP_OFF, 8 # Stack top. .equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. .equ TREE_NODE_KEY_OFF, 24 # Node key field. .equ TREE_NODE_VALUE_OFF, 26 # Node value field. @@ -503,73 +507,60 @@ insert: # ANCHOR_END: insert-input-checks # ANCHOR: insert-allocate - # Check if top is null (need allocation) or non-null (pop from stack). + # Branch based on state of stack top. # --------------------------------------------------------------------- - ldxdw r9, [r1 + IB_TREE_DATA_OFF + TREE_TOP_OFF] - jeq r9, NULL, insert_allocate - - # Pop node from free stack. r9 = top (non-null). - # --------------------------------------------------------------------- - mov64 r7, r2 # Save instruction data pointer. - mov64 r6, r1 - add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. - ldxdw r4, [r9 + OFFSET_ZERO] # Load StackNode.next. - stxdw [r6 + TREE_TOP_OFF], r4 # Update top. - # r9 = node pointer (top cast to TreeNode). - ja insert_set_root + # Get stack top pointer. + ldxdw r9, [r1 + IB_TREE_DATA_TOP_OFF] + jne r9, NULL, insert_pop # Pop node from stack if non-null. insert_allocate: # Error if wrong number of accounts for allocation. # --------------------------------------------------------------------- jne r8, IB_N_ACCOUNTS_INIT, e_n_accounts_insert_allocation - mov64 r7, r2 # Save instruction data pointer. - mov64 r6, r1 - add64 r6, IB_TREE_DATA_OFF # r6 = tree header pointer. - # Compute shifted input buffer pointer based on tree data length. # --------------------------------------------------------------------- - mov64 r8, r1 - add64 r8, IB_TREE_DATA_LEN_OFF # r8 = &tree.data_len. - ldxdw r9, [r8 + OFFSET_ZERO] # r9 = tree data_len. - add64 r9, MAX_DATA_PAD - and64 r9, DATA_LEN_AND_MASK # r9 = aligned data_len. - mov64 r3, r1 - add64 r3, r9 # r3 = shifted input. + ldxdw r9, [r1 + IB_TREE_DATA_LEN_OFF] # Get tree data length. + # Store in account info for CPI. + stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + mov64 r7, r9 # Store copy for later. + add64 r9, MAX_DATA_PAD # Add max possible padding. + and64 r9, DATA_LEN_AND_MASK # Truncate to 8-byte alignment. + add64 r9, r1 # Increment by input buffer. # Check system program is not duplicate and has correct data length. # --------------------------------------------------------------------- - ldxb r9, [r3 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_system_program_duplicate - ldxdw r9, [r3 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] - jne r9, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len + ldxb r8, [r9 + IB_SYSTEM_PROGRAM_NON_DUP_MARKER_OFF] + jne r8, IB_NON_DUP_MARKER, e_system_program_duplicate + ldxdw r8, [r9 + IB_SYSTEM_PROGRAM_DATA_LEN_OFF] + jne r8, IB_SYSTEM_PROGRAM_DATA_LEN, e_system_program_data_len # Check rent sysvar is not duplicate and has correct address. # --------------------------------------------------------------------- - ldxb r9, [r3 + IB_RENT_NON_DUP_MARKER_OFF] - jne r9, IB_NON_DUP_MARKER, e_rent_duplicate - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_0] + ldxb r8, [r9 + IB_RENT_NON_DUP_MARKER_OFF] + jne r8, IB_NON_DUP_MARKER, e_rent_duplicate + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_0] lddw r4, IB_RENT_ID_CHUNK_0 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_1] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_1] lddw r4, IB_RENT_ID_CHUNK_1 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_2] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_2] lddw r4, IB_RENT_ID_CHUNK_2 - jne r9, r4, e_rent_address - ldxdw r9, [r3 + IB_RENT_ADDRESS_OFF_3] + jne r8, r4, e_rent_address + ldxdw r8, [r9 + IB_RENT_ADDRESS_OFF_3] mov32 r4, IB_RENT_ID_CHUNK_3_LO - jne r9, r4, e_rent_address + jne r8, r4, e_rent_address - # Calculate transfer lamports = lamports_per_byte * sizeof(TreeNode). + # Calculate transfer lamports. # --------------------------------------------------------------------- - ldxdw r9, [r3 + IB_RENT_DATA_OFF] # Load lamports per byte. - mul64 r9, SIZE_OF_TREE_NODE # Multiply to get transfer cost. + ldxdw r8, [r9 + IB_RENT_DATA_OFF] # Load lamports per byte. + mul64 r8, SIZE_OF_TREE_NODE # Multiply to get transfer cost. # Pack Transfer instruction data in CreateAccount slot on stack. # --------------------------------------------------------------------- stw [r10 + SF_INIT_CREATE_ACCOUNT_DISCRIMINATOR_UOFF], CPI_TRANSFER_DISCRIMINATOR - stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r9 + stxdw [r10 + SF_INIT_CREATE_ACCOUNT_LAMPORTS_UOFF], r8 # Pack SolInstruction. # --------------------------------------------------------------------- @@ -579,20 +570,16 @@ insert_allocate: # Pack SolAccountMeta flags for user and tree. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_META_IS_WRITABLE_OFF], CPI_WRITABLE_SIGNER - stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], 1 # Writable, not signer. + stb [r10 + SF_INIT_TREE_META_IS_WRITABLE_OFF], BOOL_TRUE # Pack SolAccountInfo flags for user and tree. # --------------------------------------------------------------------- sth [r10 + SF_INIT_USER_INFO_IS_SIGNER_OFF], CPI_WRITABLE_SIGNER - stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], 1 # Writable only. - - # Store tree data_len in account info. - # --------------------------------------------------------------------- - ldxdw r9, [r8 + OFFSET_ZERO] # Reload tree data_len. - stxdw [r10 + SF_INIT_TREE_INFO_DATA_LEN_OFF], r9 + stb [r10 + SF_INIT_TREE_INFO_IS_WRITABLE_UOFF], BOOL_TRUE # Bulk assign/load pointers for account metas and infos. # --------------------------------------------------------------------- + mov64 r6, r1 # Store input buffer pointer for later. add64 r1, IB_USER_ADDRESS_OFF # Point to user address in input buffer. stxdw [r10 + SF_INIT_USER_META_PUBKEY_OFF], r1 # Store in account meta. stxdw [r10 + SF_INIT_USER_INFO_PUBKEY_OFF], r1 # Store in account info. @@ -618,10 +605,12 @@ insert_allocate: # Point to System Program ID on zero-initialized stack. mov64 r4, r10 add64 r4, SF_INIT_SYSTEM_PROGRAM_ADDRESS_OFF - stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Store in SolInstruction. + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_PROGRAM_ID_OFF], r4 # Advance to SolAccountMeta array pointer. add64 r4, SF_INIT_SYSTEM_PROGRAM_ID_TO_ACCT_METAS_REL_OFF_IMM - stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Store in SolInstruction. + # Store in SolInstruction. + stxdw [r10 + SF_INIT_INSN_ACCOUNTS_OFF], r4 # Advance to instruction data pointer. add64 r4, SF_INIT_ACCT_METAS_TO_INSN_DATA_REL_OFF_IMM stxdw [r10 + SF_INIT_INSN_DATA_OFF], r4 # Store in SolInstruction. @@ -630,42 +619,51 @@ insert_allocate: # --------------------------------------------------------------------- mov64 r1, r10 add64 r1, SF_INIT_INSN_PROGRAM_ID_OFF + mov64 r8, r2 # Save instruction data pointer for later. mov64 r2, r10 add64 r2, SF_INIT_ACCT_INFOS_OFF mov64 r3, CPI_N_ACCOUNTS - # Advance r4 to signers seeds area on zero-initialized stack. - add64 r4, SF_INIT_INSN_DATA_TO_SIGNER_SEEDS_REL_OFF_IMM - add64 r4, SF_INIT_SIGNER_SEEDS_TO_SIGNERS_SEEDS_REL_OFF_IMM + # Ignore PDA signer seeds pointer, since none required. mov64 r5, CPI_N_PDA_SIGNERS_TRANSFER call sol_invoke_signed_c + mov64 r2, r8 # Restore instruction data pointer. + mov64 r1, r6 # Restore input buffer pointer. # Update tree data length. # --------------------------------------------------------------------- - ldxdw r9, [r8 + OFFSET_ZERO] # Load current data_len. - add64 r9, SIZE_OF_TREE_NODE - stxdw [r8 + OFFSET_ZERO], r9 # Store updated data_len. + add64 r7, SIZE_OF_TREE_NODE # Increment data length. + stxdw [r1 + IB_TREE_DATA_LEN_OFF], r7 # Store in input buffer. # Get node = next, then advance next by one TreeNode. # --------------------------------------------------------------------- - ldxdw r9, [r6 + TREE_HEADER_NEXT_OFF] # r9 = node pointer. - mov64 r4, r9 - add64 r4, SIZE_OF_TREE_NODE - stxdw [r6 + TREE_HEADER_NEXT_OFF], r4 # Advance next. + ldxdw r7, [r1 + IB_TREE_DATA_NEXT_OFF] # Get pointer to next node. + mov64 r9, r7 # Store node pointer for later, the new node. + add64 r7, SIZE_OF_TREE_NODE # Increment to point to new next. + stxdw [r1 + IB_TREE_DATA_NEXT_OFF], r7 # Advance next. -insert_set_root: + # Continue insert. + # --------------------------------------------------------------------- + ja insert_mutate_new_node + +insert_pop: + # --------------------------------------------------------------------- + ldxdw r8, [r9 + OFFSET_ZERO] # Load StackNode.next. + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r8 # Update top in header. + # ANCHOR_END: insert-allocate + +insert_mutate_new_node: # Set node as root of tree. # --------------------------------------------------------------------- - stxdw [r6 + TREE_ROOT_OFF], r9 + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # Set key and value from instruction data. # --------------------------------------------------------------------- - ldxh r4, [r7 + INSN_INSERT_KEY_OFF] - sth [r9 + TREE_NODE_KEY_OFF], r4 - ldxh r4, [r7 + INSN_INSERT_VALUE_OFF] - sth [r9 + TREE_NODE_VALUE_OFF], r4 + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] + stxh [r9 + TREE_NODE_KEY_OFF], r4 + ldxh r4, [r2 + INSN_INSERT_VALUE_OFF] + stxh [r9 + TREE_NODE_VALUE_OFF], r4 exit - # ANCHOR_END: insert-allocate e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From f991c7a7fef55d44edcebaced245149f6ec9ffae Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 16:36:10 -0700 Subject: [PATCH 185/263] Add failure tests, more parity --- .../initialize_create_account/result.txt | 36 ++++++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 122 ++++++++++++++++++ .../tests/initialize_pda_checks/result.txt | 31 +++++ .../tests/initialize_pda_checks/test.txt | 4 + examples/tree/src/program.rs | 12 +- examples/tree/src/tests.rs | 5 + examples/tree/src/tests/insert.rs | 115 ++++++++++++++++- examples/tree/src/tree/tree.s | 6 +- 9 files changed, 323 insertions(+), 12 deletions(-) create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..ac84fbbb --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,36 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | +| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | +| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..aa2dd6c3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..a7dcd6ae --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,122 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Invalid instruction data length | 8 | 10 | +2 | +25.0% | +| Too few accounts | 9 | 11 | +2 | +22.2% | +| Too many accounts | 9 | 11 | +2 | +22.2% | +| User has nonzero data length | 11 | 13 | +2 | +18.2% | +| Tree account is duplicate | 13 | 15 | +2 | +15.4% | +| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | +| System program is duplicate | 17 | 19 | +2 | +11.8% | +| System program wrong data length | 19 | 21 | +2 | +10.5% | +| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | +| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | +| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..49588334 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | +| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | +| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | +| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 6b98d88b..b02eeb59 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -287,17 +287,15 @@ unsafe fn insert( // Initialize node as root of tree. (*tree_header).root = node; - // Set key and value from instruction data. Parent, children, and color are already null/zero. - (*node).key = read_unaligned( + // Set key and value together as a single word. + let key_value: u32 = read_unaligned( instruction_data .add(instruction::INSERT_KEY_OFF as usize) .cast(), ); - (*node).value = read_unaligned( - instruction_data - .add(instruction::INSERT_VALUE_OFF as usize) - .cast(), - ); + addr_of_mut!((*node).key) + .cast::() + .write_unaligned(key_value); SUCCESS } diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 62e762dc..9f83ba17 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -172,6 +172,11 @@ fn test_insert() { print_comparison_table(insert::InsertCase::CASES, false, false); } +#[test] +fn test_insert_alloc_checks() { + print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES, false, false); +} + #[test] fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES, false, false); diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 2efd9caa..72a5c83e 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -4,7 +4,7 @@ use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; use tree_interface::{ - cpi, input_buffer, tree, InstructionHeader, Instruction as TreeInstruction, InsertInstruction, + cpi, input_buffer, tree, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, StackNode, TreeHeader, TreeNode, }; @@ -113,12 +113,34 @@ fn insert_skip_alloc_setup( (setup, instruction, accounts) } +fn insert_alloc_address_mismatch( + lang: ProgramLanguage, + account_index: usize, + chunk_index: usize, + expected_error: error_codes::error, +) -> CaseResult { + let (setup, mut instruction, mut accounts) = insert_setup(lang); + // Flip the last byte of the 8-byte chunk to trigger a mismatch. + let flip_index = (chunk_index * size_of::()) + size_of::() - 1; + accounts[account_index].0.as_mut()[flip_index] ^= 1; + instruction.accounts[account_index].pubkey = accounts[account_index].0; + check_error(&setup, &instruction, &accounts, expected_error) +} + #[derive(Clone, Copy)] pub(super) enum InsertCase { InstructionDataLenShort, InstructionDataLenLong, InsertSkipAlloc, InsertAllocHappyPath, + NAccountsInsertAllocation, + SystemProgramDuplicate, + SystemProgramDataLen, + RentDuplicate, + RentAddressChunk0, + RentAddressChunk1, + RentAddressChunk2, + RentAddressChunk3, } impl InsertCase { @@ -128,6 +150,17 @@ impl InsertCase { Self::InsertSkipAlloc, Self::InsertAllocHappyPath, ]; + + pub(super) const ALLOC_CHECK_CASES: &'static [Self] = &[ + Self::NAccountsInsertAllocation, + Self::SystemProgramDuplicate, + Self::SystemProgramDataLen, + Self::RentDuplicate, + Self::RentAddressChunk0, + Self::RentAddressChunk1, + Self::RentAddressChunk2, + Self::RentAddressChunk3, + ]; } impl TestCase for InsertCase { @@ -137,6 +170,14 @@ impl TestCase for InsertCase { Self::InstructionDataLenLong => "Instruction data too long", Self::InsertSkipAlloc => "Insert skip alloc", Self::InsertAllocHappyPath => "Insert alloc happy path", + Self::NAccountsInsertAllocation => "Wrong N accounts for allocation", + Self::SystemProgramDuplicate => "System program is duplicate", + Self::SystemProgramDataLen => "System program wrong data length", + Self::RentDuplicate => "Rent sysvar is duplicate", + Self::RentAddressChunk0 => "Rent address mismatch chunk 0", + Self::RentAddressChunk1 => "Rent address mismatch chunk 1", + Self::RentAddressChunk2 => "Rent address mismatch chunk 2", + Self::RentAddressChunk3 => "Rent address mismatch chunk 3", } } @@ -185,6 +226,78 @@ impl TestCase for InsertCase { }, } } + Self::NAccountsInsertAllocation => { + // Use insert_setup (top=null triggers allocation) but strip CPI accounts. + let (setup, mut instruction, mut accounts) = insert_setup(lang); + instruction.accounts.truncate(2); + accounts.truncate(2); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS_INSERT_ALLOCATION, + ) + } + Self::SystemProgramDuplicate => { + let (setup, mut instruction, mut accounts) = insert_setup(lang); + instruction.accounts[AccountIndex::SystemProgram as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::SystemProgram as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DUPLICATE, + ) + } + Self::SystemProgramDataLen => { + let (setup, instruction, mut accounts) = insert_setup(lang); + accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::SYSTEM_PROGRAM_DATA_LEN, + ) + } + Self::RentDuplicate => { + let (setup, mut instruction, mut accounts) = insert_setup(lang); + instruction.accounts[AccountIndex::RentSysvar as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::RentSysvar as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::RENT_DUPLICATE, + ) + } + Self::RentAddressChunk0 => insert_alloc_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 0, + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressChunk1 => insert_alloc_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 1, + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressChunk2 => insert_alloc_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 2, + error_codes::error::RENT_ADDRESS, + ), + Self::RentAddressChunk3 => insert_alloc_address_mismatch( + lang, + AccountIndex::RentSysvar as usize, + 3, + error_codes::error::RENT_ADDRESS, + ), Self::InsertAllocHappyPath => { let (setup, instruction, accounts) = insert_setup(lang); let result = setup.mollusk.process_instruction(&instruction, &accounts); diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index caedfcb0..22f03d8d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -658,10 +658,8 @@ insert_mutate_new_node: # Set key and value from instruction data. # --------------------------------------------------------------------- - ldxh r4, [r2 + INSN_INSERT_KEY_OFF] - stxh [r9 + TREE_NODE_KEY_OFF], r4 - ldxh r4, [r2 + INSN_INSERT_VALUE_OFF] - stxh [r9 + TREE_NODE_VALUE_OFF], r4 + ldxw r4, [r2 + INSN_INSERT_KEY_OFF] # Load two fields together. + stxw [r9 + TREE_NODE_KEY_OFF], r4 # Store both fields together. exit From bacd2116456958c96e0d9f04d2b2fb52c1377f9e Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 16:37:25 -0700 Subject: [PATCH 186/263] Consolidate cast --- examples/tree/src/program.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index b02eeb59..197c1219 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -288,14 +288,11 @@ unsafe fn insert( (*tree_header).root = node; // Set key and value together as a single word. - let key_value: u32 = read_unaligned( + *addr_of_mut!((*node).key).cast::() = read_unaligned( instruction_data .add(instruction::INSERT_KEY_OFF as usize) .cast(), ); - addr_of_mut!((*node).key) - .cast::() - .write_unaligned(key_value); SUCCESS } From dcfb52c45275a89071016113b60ae3e5ccc6f268 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 17:14:28 -0700 Subject: [PATCH 187/263] Begin insert to tree flow --- .../tree/artifacts/snippets/asm/constants.txt | 1 + .../artifacts/snippets/rs/insert-allocate.txt | 4 +- .../artifacts/snippets/rs/insert-search.txt | 15 ++++ .../artifacts/snippets/rs/insert-to-tree.txt | 16 ++++ examples/tree/interface/src/common.rs | 2 + examples/tree/interface/src/lib.rs | 5 +- examples/tree/src/program.rs | 79 ++++++++++++++++--- examples/tree/src/tree/tree.s | 1 + 8 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/insert-search.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-to-tree.txt diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 097bd9de..9cec67b9 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -18,6 +18,7 @@ .equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. # Not enough accounts passed for insertion allocation. .equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 +.equ E_KEY_EXISTS, 14 # Key already exists in tree during insertion. # Type sizes. # ----------- diff --git a/examples/tree/artifacts/snippets/rs/insert-allocate.txt b/examples/tree/artifacts/snippets/rs/insert-allocate.txt index 8fec731f..8eb71cfa 100644 --- a/examples/tree/artifacts/snippets/rs/insert-allocate.txt +++ b/examples/tree/artifacts/snippets/rs/insert-allocate.txt @@ -109,4 +109,6 @@ let top = (*tree_header).top; (*tree_header).top = (*top).next; top.cast() - }; \ No newline at end of file + }; + // Set key and value together as a single word. + *addr_of_mut!((*node).key).cast() = ldxw(instruction_data, instruction::INSERT_KEY_OFF); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt new file mode 100644 index 00000000..27e1c8fc --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -0,0 +1,15 @@ + let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); + let mut parent = (*tree_header).root; + loop { + if parent.is_null() { + break; + } + let parent_key = (*parent).key; + if key > parent_key { + parent = (*parent).child[tree::DIR_R]; + } else if key < parent_key { + parent = (*parent).child[tree::DIR_L]; + } else { + return error::KEY_EXISTS.into(); + } + } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt new file mode 100644 index 00000000..86f90cbd --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt @@ -0,0 +1,16 @@ + (*node).color = Color::Red; + (*node).parent = parent; + + // New node at root. + if (parent.is_null()) { + (*tree_header).root = node; + return SUCCESS; + } + + // Get child direction, set at parent. + let dir = if (key > (*parent).key) { + tree::DIR_R + } else { + tree::DIR_L + }; + (*parent).child[dir] = node; \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index c43847bb..6dd09491 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -33,6 +33,8 @@ error_codes! { INSTRUCTION_DATA_LEN, /// Not enough accounts passed for insertion allocation. N_ACCOUNTS_INSERT_ALLOCATION, + /// Key already exists in tree during insertion. + KEY_EXISTS, } constant_group! { diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 1b73368f..abd3c41d 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -11,7 +11,6 @@ pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, - InitializeInstruction, InstructionHeader, InsertInstruction, Instruction, StackNode, - TransferInstructionData, - TreeHeader, TreeNode, + InitializeInstruction, InsertInstruction, Instruction, InstructionHeader, StackNode, + TransferInstructionData, TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 197c1219..a3483d43 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -1,4 +1,4 @@ -use core::ptr::{addr_of, addr_of_mut, read_unaligned}; +use core::ptr::{addr_of, addr_of_mut, null_mut, read_unaligned}; use pinocchio::{ account::RuntimeAccount, entrypoint::NON_DUP_MARKER, @@ -8,9 +8,10 @@ use pinocchio::{ Address, SUCCESS, }; use tree_interface::{ - cpi, data, error_codes::error, input_buffer, instruction, tree, CreateAccountInstructionData, - Direction, InitializeInstruction, InsertInstruction, SolAccountInfo, SolAccountMeta, - SolInstruction, SolSignerSeed, SolSignerSeeds, TransferInstructionData, TreeHeader, TreeNode, + cpi, data, error_codes::error, input_buffer, instruction, tree, Color, + CreateAccountInstructionData, Direction, InitializeInstruction, InsertInstruction, + SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, + TransferInstructionData, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -30,6 +31,16 @@ unsafe fn ldxb(ptr: *const u8, offset: i16) -> u8 { read_unaligned(ptr.add(offset as usize)) } +#[inline(always)] +unsafe fn ldxh(ptr: *const u8, offset: i16) -> u16 { + read_unaligned(ptr.add(offset as usize).cast()) +} + +#[inline(always)] +unsafe fn ldxw(ptr: *const u8, offset: i16) -> u32 { + read_unaligned(ptr.add(offset as usize).cast()) +} + #[inline(always)] unsafe fn ldxdw(ptr: *const u8, offset: i16) -> u64 { read_unaligned(ptr.add(offset as usize).cast()) @@ -282,17 +293,46 @@ unsafe fn insert( (*tree_header).top = (*top).next; top.cast() }; + // Set key and value together as a single word. + *addr_of_mut!((*node).key).cast() = ldxw(instruction_data, instruction::INSERT_KEY_OFF); // ANCHOR_END: insert-allocate - // Initialize node as root of tree. - (*tree_header).root = node; + // ANCHOR: insert-search + let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); + let mut parent = (*tree_header).root; + loop { + if parent.is_null() { + break; + } + let parent_key = (*parent).key; + if key > parent_key { + parent = (*parent).child[tree::DIR_R]; + } else if key < parent_key { + parent = (*parent).child[tree::DIR_L]; + } else { + return error::KEY_EXISTS.into(); + } + } + // ANCHOR_END: insert-search - // Set key and value together as a single word. - *addr_of_mut!((*node).key).cast::() = read_unaligned( - instruction_data - .add(instruction::INSERT_KEY_OFF as usize) - .cast(), - ); + // ANCHOR: insert-to-tree + (*node).color = Color::Red; + (*node).parent = parent; + + // New node at root. + if (parent.is_null()) { + (*tree_header).root = node; + return SUCCESS; + } + + // Get child direction, set at parent. + let dir = if (key > (*parent).key) { + tree::DIR_R + } else { + tree::DIR_L + }; + (*parent).child[dir] = node; + // ANCHOR_END: insert-to-tree SUCCESS } @@ -467,6 +507,21 @@ const fn opposite(direction: usize) -> usize { 1 - direction } +#[inline(always)] +unsafe fn search(tree_header: *const TreeHeader, key: u16) -> *mut TreeNode { + let mut node = (*tree_header).root; + loop { + if node.is_null() { + break; + } + if (*node).key == key { + break; + } + node = (*node).child[(key > (*node).key) as usize]; + } + node +} + /// Rotate the subtree rooted at `subtree` in the given direction, returning new root of subtree. #[inline(always)] unsafe fn rotate_subtree( diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 22f03d8d..f26dc332 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -19,6 +19,7 @@ .equ E_INSTRUCTION_DATA_LEN, 12 # Invalid instruction data length. # Not enough accounts passed for insertion allocation. .equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 +.equ E_KEY_EXISTS, 14 # Key already exists in tree during insertion. # Type sizes. # ----------- From bb46e16ef8ba25f7d9e2e06c00c22a1d21eab2ff Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 17:27:59 -0700 Subject: [PATCH 188/263] Add insertion algorithm --- .../snippets/interface/tree-defs-common.txt | 1 + .../artifacts/snippets/rs/insert-allocate.txt | 2 +- .../artifacts/snippets/rs/insert-to-tree.txt | 51 +++++++++++++++++-- examples/tree/interface/src/common.rs | 1 + examples/tree/src/program.rs | 51 +++++++++++++++++-- 5 files changed, 98 insertions(+), 8 deletions(-) diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index 9cc5fe41..aaaf4380 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -1,4 +1,5 @@ #[repr(u8)] +#[derive(PartialEq)] pub enum Color { Black, Red, diff --git a/examples/tree/artifacts/snippets/rs/insert-allocate.txt b/examples/tree/artifacts/snippets/rs/insert-allocate.txt index 8eb71cfa..93dde9c4 100644 --- a/examples/tree/artifacts/snippets/rs/insert-allocate.txt +++ b/examples/tree/artifacts/snippets/rs/insert-allocate.txt @@ -1,6 +1,6 @@ // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let node: *mut TreeNode = if (*tree_header).top.is_null() { + let mut node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, diff --git a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt index 86f90cbd..157c596b 100644 --- a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt +++ b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt @@ -2,15 +2,60 @@ (*node).parent = parent; // New node at root. - if (parent.is_null()) { + if parent.is_null() { (*tree_header).root = node; return SUCCESS; } // Get child direction, set at parent. - let dir = if (key > (*parent).key) { + let mut dir = if (key > (*parent).key) { tree::DIR_R } else { tree::DIR_L }; - (*parent).child[dir] = node; \ No newline at end of file + (*parent).child[dir] = node; + + // Rebalance the tree. + loop { + // Case 1. + if (*parent).color == Color::Black { + return SUCCESS; + } + + let grandparent = (*parent).parent; + if grandparent.is_null() { + // Case 4. + (*parent).color = Color::Black; + return SUCCESS; + } + + dir = direction(parent) as usize; + let uncle = (*grandparent).child[opposite(dir)]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5. + if node == (*parent).child[opposite(dir)] { + rotate_subtree(tree_header, parent, dir); + node = parent; + parent = (*grandparent).child[dir]; + } + + // Case 6. + rotate_subtree(tree_header, grandparent, opposite(dir)); + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + + // Case 2. + (*parent).color = Color::Black; + (*uncle).color = Color::Black; + (*grandparent).color = Color::Red; + node = grandparent; + + parent = (*node).parent; + if parent.is_null() { + break; + } + } + // Case 3. + SUCCESS \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 6dd09491..0b8b7be2 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -177,6 +177,7 @@ pub struct GeneralInputBufferHeader { // ANCHOR: tree-defs-common #[repr(u8)] +#[derive(PartialEq)] pub enum Color { Black, Red, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a3483d43..50a23ad6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -183,7 +183,7 @@ unsafe fn insert( // ANCHOR: insert-allocate // Allocate or recycle a node. let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let node: *mut TreeNode = if (*tree_header).top.is_null() { + let mut node: *mut TreeNode = if (*tree_header).top.is_null() { // Error if wrong number of accounts passed, since need extra accounts to allocate space. if_err!( n_accounts != input_buffer::N_ACCOUNTS_INIT, @@ -320,21 +320,64 @@ unsafe fn insert( (*node).parent = parent; // New node at root. - if (parent.is_null()) { + if parent.is_null() { (*tree_header).root = node; return SUCCESS; } // Get child direction, set at parent. - let dir = if (key > (*parent).key) { + let mut dir = if (key > (*parent).key) { tree::DIR_R } else { tree::DIR_L }; (*parent).child[dir] = node; - // ANCHOR_END: insert-to-tree + // Rebalance the tree. + loop { + // Case 1. + if (*parent).color == Color::Black { + return SUCCESS; + } + + let grandparent = (*parent).parent; + if grandparent.is_null() { + // Case 4. + (*parent).color = Color::Black; + return SUCCESS; + } + + dir = direction(parent) as usize; + let uncle = (*grandparent).child[opposite(dir)]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5. + if node == (*parent).child[opposite(dir)] { + rotate_subtree(tree_header, parent, dir); + node = parent; + parent = (*grandparent).child[dir]; + } + + // Case 6. + rotate_subtree(tree_header, grandparent, opposite(dir)); + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + + // Case 2. + (*parent).color = Color::Black; + (*uncle).color = Color::Black; + (*grandparent).color = Color::Red; + node = grandparent; + + parent = (*node).parent; + if parent.is_null() { + break; + } + } + // Case 3. SUCCESS + // ANCHOR_END: insert-to-tree } // ANCHOR: initialize-input-checks From 4809fb1018211e3732d8ab866901d71dcd3b3c5a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 17:56:54 -0700 Subject: [PATCH 189/263] Add insert test spec --- examples/tree/specs/insert-tests.md | 308 ++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 examples/tree/specs/insert-tests.md diff --git a/examples/tree/specs/insert-tests.md b/examples/tree/specs/insert-tests.md new file mode 100644 index 00000000..d10ba298 --- /dev/null +++ b/examples/tree/specs/insert-tests.md @@ -0,0 +1,308 @@ +# Insert-to-tree test specification + +## Scope + +Tests for the search, insertion, and rebalancing logic in the insert +instruction — everything after node allocation. The existing insert +tests cover input validation and the allocation/recycle paths; this +spec covers what happens once we have a node and need to place it in +the tree. + +## Approach + +### Pre-built tree states + +Each rebalancing case requires a specific tree shape. Rather than +chaining multiple insert instructions, construct the tree layout +directly in account memory before processing the insert instruction. +This gives precise control over which case is triggered. + +A helper builds the account data buffer by: + +- Allocating space for `TreeHeader` + N existing `TreeNode`s + 1 free + node on the stack. +- Setting all pointers as virtual addresses + (`MM_INPUT_START + input_buffer::TREE_DATA_OFF + offset`). +- Setting `header.top` to the free stack node so the insert pops it + instead of allocating (same pattern as `insert_skip_alloc_setup`). + +### Fixed costs + +Targeted case tests pop from the free stack, so they have zero fixed +costs. Multi-insert integration tests use the allocation path (CPI +transfer) for each insert. Their `fixed_costs()` must return +`CPI_BASE + SYSTEM_PROGRAM` per insert so the comparison table +subtracts the transfer CPI overhead and isolates the tree logic. + +### Full-state assertion + +Every targeted case test asserts the **entire** tree data account +after the insert instruction. Nothing is left unchecked. + +**TreeHeader** (every field): + +- `root` — pointer to the expected root node. +- `top` — pointer to the new free-stack top (null when the only + free node was consumed). +- `next` — allocation pointer (unchanged by pop-from-stack inserts). + +**Every TreeNode** (every field of every node in the buffer): + +- `parent` — pointer to the expected parent (null for root). +- `child[L]`, `child[R]` — pointers to expected children (null for + leaves). +- `key` — expected key. +- `value` — expected value (pre-set for existing nodes, from + instruction data for the inserted node). +- `color` — expected color after rebalancing. + +Each case below specifies the full expected state using compact +notation: + +```text +Header: root=N0 top=null next= +N0: B key=10 parent=-- L=N1 R=N2 +N1: R key=5 parent=N0 L=-- R=-- <- inserted +N2: B key=15 parent=N0 L=-- R=-- +``` + +`--` means null. `` is the address past the last node slot. +Node indices (N0, N1, ...) reflect memory layout order, not tree +position — N0 is always at offset `sizeof(TreeHeader)` in the +account data. Values are omitted from the notation for brevity; +pre-existing nodes keep their original values, and the inserted +node gets the instruction data value. + +## Cases + +### Search + +Error cases — the tree account must be unchanged after the +instruction returns `KEY_EXISTS`. + +| Case | Setup | Key | Expected | +| ------------ | ------------------- | --- | ------------------ | +| Dup at root | Root with key 10 | 10 | `KEY_EXISTS` error | +| Dup in left | Root 10, L child 5 | 5 | `KEY_EXISTS` error | +| Dup in right | Root 10, R child 15 | 15 | `KEY_EXISTS` error | + +### Insert to empty tree + +```text +Before: + Header: root=-- top=N0 next= + N0: (free stack node) + +After insert key=42: + Header: root=N0 top=-- next= + N0: R key=42 parent=-- L=-- R=-- +``` + +### Case 1: parent is black + +No rebalancing needed. Inserted node stays red under a black parent. + +Left child variant (insert key=5): + +```text +Before: + Header: root=N0 top=N1 next= + N0: B key=10 parent=-- L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- <- inserted +``` + +Right child variant (insert key=15): mirror of above, N1 at R of +N0. + +### Case 4: parent is root and red + +Parent is root (no grandparent). Recolor parent to black. + +Left child variant (insert key=5): + +```text +Before: + Header: root=N0 top=N1 next= + N0: R key=10 parent=-- L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=10 parent=-- L=N1 R=-- <- recolored B + N1: R key=5 parent=N0 L=-- R=-- <- inserted +``` + +Right child variant (insert key=15): mirror of above. + +### Case 2 + 3: red uncle, propagate to root + +Parent and uncle are both red. Recolor parent, uncle, grandparent. +Grandparent is root, so the loop exits (case 3). + +Left-left variant (insert key=1): + +```text +Before: + Header: root=N0 top=N3 next= + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=-- R=-- + N2: R key=15 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: R key=10 parent=-- L=N1 R=N2 <- recolored R + N1: B key=5 parent=N0 L=N3 R=-- <- recolored B + N2: B key=15 parent=N0 L=-- R=-- <- recolored B + N3: R key=1 parent=N1 L=-- R=-- <- inserted +``` + +All four child positions trigger the same recolor path — only the +inserted node's position differs. + +| Variant | Insert key | Inserted at | +| ----------- | ---------- | ----------- | +| Left-left | 1 | N1.L | +| Left-right | 7 | N1.R | +| Right-left | 12 | N2.L | +| Right-right | 20 | N2.R | + +### Case 2 + 1: red uncle, propagate to black ancestor + +Same recolor as case 2+3, but grandparent is not root — its parent +is black, so case 1 terminates. + +Left-left variant (insert key=1): + +```text +Before: + Header: root=N0 top=N4 next= + N0: B key=20 parent=-- L=N1 R=-- + N1: B key=10 parent=N0 L=N2 R=N3 + N2: R key=5 parent=N1 L=-- R=-- + N3: R key=15 parent=N1 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=20 parent=-- L=N1 R=-- + N1: R key=10 parent=N0 L=N2 R=N3 <- recolored R + N2: B key=5 parent=N1 L=N4 R=-- <- recolored B + N3: B key=15 parent=N1 L=-- R=-- <- recolored B + N4: R key=1 parent=N2 L=-- R=-- <- inserted +``` + +Mirror variant: B(2) as root with B(10) as right child, insert +key=20. Same recolor pattern, mirrored. + +### Case 6: black uncle, outer child — single rotation + +Uncle is black or null. Node is an outer child (same direction as +parent relative to grandparent). Rotate grandparent, recolor. + +Left-left, null uncle variant (insert key=1): + +```text +Before: + Header: root=N0 top=N2 next= + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- + +After: + Header: root=N1 top=-- next= + N0: R key=10 parent=N1 L=-- R=-- <- recolored R + N1: B key=5 parent=-- L=N2 R=N0 <- recolored B, new root + N2: R key=1 parent=N1 L=-- R=-- <- inserted +``` + +Left-left, black uncle variant (insert key=1): + +```text +Before: + Header: root=N0 top=N3 next= + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=-- + +After: + Header: root=N1 top=-- next= + N0: R key=10 parent=N1 L=-- R=N2 <- recolored R + N1: B key=5 parent=-- L=N3 R=N0 <- recolored B, new root + N2: B key=15 parent=N0 L=-- R=-- + N3: R key=1 parent=N1 L=-- R=-- <- inserted +``` + +Right-right variants: mirror of above (insert key=20, parent is +R(15), rotation goes left). + +### Case 5 + 6: black uncle, inner child — double rotation + +Uncle is black or null. Node is an inner child (opposite direction +from parent relative to grandparent). Rotate parent first (case 5), +then fall through to case 6. + +Left-right, null uncle variant (insert key=7): + +```text +Before: + Header: root=N0 top=N2 next= + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- + +After: + Header: root=N2 top=-- next= + N0: R key=10 parent=N2 L=-- R=-- <- recolored R + N1: R key=5 parent=N2 L=-- R=-- + N2: B key=7 parent=-- L=N1 R=N0 <- inserted, new root +``` + +Left-right, black uncle variant (insert key=7): + +```text +Before: + Header: root=N0 top=N3 next= + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=-- + +After: + Header: root=N3 top=-- next= + N0: R key=10 parent=N3 L=-- R=N2 <- recolored R + N1: R key=5 parent=N3 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=-- + N3: B key=7 parent=-- L=N1 R=N0 <- inserted, new root +``` + +Right-left variants: mirror of above (insert key=12, parent is +R(15), double rotation goes right then left). + +## Multi-insert integration tests + +A handful of sequential-insert tests to validate that chained +insertions produce correct trees. Process multiple insert instructions +in sequence, feeding each resulting account state into the next. + +| Test | Sequence | Purpose | +| ----------- | ----------------------- | ---------------- | +| 3-node | 10, 5, 15 | Minimal balanced | +| Left-skew | 10, 5, 1 | Right rotation | +| Right-skew | 10, 15, 20 | Left rotation | +| Zigzag | 10, 5, 7 | Double rotation | +| 7-node full | 10, 5, 15, 3, 7, 12, 20 | Multiple rounds | + +## Multi-insert verification + +Multi-insert integration tests also assert full state. After each +insert in the sequence, the expected complete tree layout is +specified. The test feeds the resulting account data from one +instruction into the next and asserts the full state at each step. + +## Test helpers needed + +- `build_tree(nodes: &[NodeSpec]) -> Vec` — Serialize a tree + layout into account data with correct virtual address pointers + and a free stack node for the new insertion. +- `assert_tree(account_data: &[u8], expected: &TreeSpec)` — Assert + every field of the header and every field of every node against + the expected specification. Panics with a diff on mismatch. From 5448f1b3d0647b15c09dc6cc82dfa4a64658462f Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 18:35:38 -0700 Subject: [PATCH 190/263] Pass rust insert --- .../artifacts/snippets/rs/insert-search.txt | 16 +- examples/tree/src/program.rs | 16 +- examples/tree/src/tests.rs | 11 + examples/tree/src/tests/insert_tree.rs | 880 ++++++++++++++++++ 4 files changed, 909 insertions(+), 14 deletions(-) create mode 100644 examples/tree/src/tests/insert_tree.rs diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index 27e1c8fc..d30bc010 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -1,14 +1,16 @@ let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); - let mut parent = (*tree_header).root; + let mut parent: *mut TreeNode = null_mut(); + let mut cursor = (*tree_header).root; loop { - if parent.is_null() { + if cursor.is_null() { break; } - let parent_key = (*parent).key; - if key > parent_key { - parent = (*parent).child[tree::DIR_R]; - } else if key < parent_key { - parent = (*parent).child[tree::DIR_L]; + parent = cursor; + let cursor_key = (*cursor).key; + if key > cursor_key { + cursor = (*cursor).child[tree::DIR_R]; + } else if key < cursor_key { + cursor = (*cursor).child[tree::DIR_L]; } else { return error::KEY_EXISTS.into(); } diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 50a23ad6..32584e17 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -299,16 +299,18 @@ unsafe fn insert( // ANCHOR: insert-search let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); - let mut parent = (*tree_header).root; + let mut parent: *mut TreeNode = null_mut(); + let mut cursor = (*tree_header).root; loop { - if parent.is_null() { + if cursor.is_null() { break; } - let parent_key = (*parent).key; - if key > parent_key { - parent = (*parent).child[tree::DIR_R]; - } else if key < parent_key { - parent = (*parent).child[tree::DIR_L]; + parent = cursor; + let cursor_key = (*cursor).key; + if key > cursor_key { + cursor = (*cursor).child[tree::DIR_R]; + } else if key < cursor_key { + cursor = (*cursor).child[tree::DIR_L]; } else { return error::KEY_EXISTS.into(); } diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 9f83ba17..1bd74bdf 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,6 +1,7 @@ mod entrypoint; mod init; mod insert; +mod insert_tree; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_sdk::account::Account; @@ -191,3 +192,13 @@ fn test_initialize_pda_checks() { fn test_initialize_create_account() { print_comparison_table(init::InitCase::CPI_CASES, false, false); } + +#[test] +fn test_insert_search() { + print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, true, false); +} + +#[test] +fn test_insert_to_tree() { + print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, true, false); +} diff --git a/examples/tree/src/tests/insert_tree.rs b/examples/tree/src/tests/insert_tree.rs new file mode 100644 index 00000000..120364ad --- /dev/null +++ b/examples/tree/src/tests/insert_tree.rs @@ -0,0 +1,880 @@ +use super::*; +use solana_sdk::instruction::AccountMeta; +use tree_interface::{ + input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, + StackNode, TreeHeader, TreeNode, +}; + +const TEST_VALUE: u16 = 1; + +// --------------------------------------------------------------------------- +// Helpers: tree description types +// --------------------------------------------------------------------------- + +struct NodeDesc { + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +} + +struct TreeDesc<'a> { + root: Option, + nodes: &'a [NodeDesc], +} + +/// Compute the virtual address of node slot `i` in the tree account. +fn node_vaddr(i: usize) -> u64 { + MM_INPUT_START + + input_buffer::TREE_DATA_OFF as u64 + + size_of::() as u64 + + (i as u64) * (size_of::() as u64) +} + +/// Convert an optional node index to a virtual address (0 for None). +fn opt_vaddr(idx: Option) -> u64 { + match idx { + Some(i) => node_vaddr(i), + None => 0, + } +} + +// --------------------------------------------------------------------------- +// Helper: build tree account data +// --------------------------------------------------------------------------- + +/// Build tree account data with pre-existing nodes and one free StackNode. +/// +/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] | free_slot +/// +/// - `header.root` → virtual address of `nodes[root]`, or null. +/// - `header.top` → virtual address of the free slot (index = nodes.len()). +/// - `header.next` → 0 (unused in skip-alloc path). +fn build_tree_account(desc: &TreeDesc, program_id: &Pubkey) -> (Pubkey, Account) { + let n = desc.nodes.len(); + // N existing nodes + 1 free slot. + let data_len = size_of::() + (n + 1) * size_of::(); + let mut data = vec![0u8; data_len]; + + // Write header. + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = opt_vaddr(desc.root) as *mut TreeNode; + (*header).top = node_vaddr(n) as *mut StackNode; + (*header).next = core::ptr::null_mut(); + } + + // Write existing nodes. + for (i, node) in desc.nodes.iter().enumerate() { + let offset = size_of::() + i * size_of::(); + let ptr = unsafe { data.as_mut_ptr().add(offset) as *mut TreeNode }; + unsafe { + (*ptr).parent = opt_vaddr(node.parent) as *mut TreeNode; + (*ptr).child[tree::DIR_L] = opt_vaddr(node.left) as *mut TreeNode; + (*ptr).child[tree::DIR_R] = opt_vaddr(node.right) as *mut TreeNode; + (*ptr).key = node.key; + (*ptr).value = node.value; + (*ptr).color = core::mem::transmute(node.color); + } + } + + // Free slot is already zeroed (StackNode.next = null). + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} + +// --------------------------------------------------------------------------- +// Helper: assert tree account (full state) +// --------------------------------------------------------------------------- + +struct ExpectedNode { + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +} + +struct ExpectedTree { + root: Option, + top: Option, + nodes: Vec, +} + +/// Assert every field of the tree account data against expected state. +/// Returns Ok(()) on match, Err(description) on mismatch. +fn assert_tree_account(data: &[u8], expected: &ExpectedTree) -> Result<(), String> { + let mut errors = Vec::new(); + let n = expected.nodes.len(); + + // Check data length. + let expected_len = size_of::() + n * size_of::(); + if data.len() != expected_len { + errors.push(format!( + "data len: expected {}, got {}", + expected_len, + data.len() + )); + } + + // Check header. + let header = data.as_ptr() as *const TreeHeader; + unsafe { + let root_addr = (*header).root as u64; + let expected_root = opt_vaddr(expected.root); + if root_addr != expected_root { + errors.push(format!( + "header.root: expected {:#x}, got {:#x}", + expected_root, root_addr + )); + } + + let top_addr = (*header).top as u64; + let expected_top = opt_vaddr(expected.top); + if top_addr != expected_top { + errors.push(format!( + "header.top: expected {:#x}, got {:#x}", + expected_top, top_addr + )); + } + + let next_addr = (*header).next as u64; + if next_addr != 0 { + errors.push(format!("header.next: expected 0x0, got {:#x}", next_addr)); + } + } + + // Check each node. + for i in 0..n { + let offset = size_of::() + i * size_of::(); + if offset + size_of::() > data.len() { + errors.push(format!("N{}: out of bounds", i)); + continue; + } + let ptr = unsafe { data.as_ptr().add(offset) as *const TreeNode }; + let exp = &expected.nodes[i]; + let label = format!("N{}", i); + + unsafe { + let parent_addr = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).parent)) as u64; + let expected_parent = opt_vaddr(exp.parent); + if parent_addr != expected_parent { + errors.push(format!( + "{}.parent: expected {:#x}, got {:#x}", + label, expected_parent, parent_addr + )); + } + + let left_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_L])) as u64; + let expected_left = opt_vaddr(exp.left); + if left_addr != expected_left { + errors.push(format!( + "{}.L: expected {:#x}, got {:#x}", + label, expected_left, left_addr + )); + } + + let right_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_R])) as u64; + let expected_right = opt_vaddr(exp.right); + if right_addr != expected_right { + errors.push(format!( + "{}.R: expected {:#x}, got {:#x}", + label, expected_right, right_addr + )); + } + + let key = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).key)); + if key != exp.key { + errors.push(format!("{}.key: expected {}, got {}", label, exp.key, key)); + } + + let value = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).value)); + if value != exp.value { + errors.push(format!( + "{}.value: expected {}, got {}", + label, exp.value, value + )); + } + + let color = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).color)) as u8; + if color != exp.color { + let color_name = |c: u8| if c == 0 { "B" } else { "R" }; + errors.push(format!( + "{}.color: expected {}, got {}", + label, + color_name(exp.color), + color_name(color) + )); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors.join("; ")) + } +} + +// --------------------------------------------------------------------------- +// Helper: setup +// --------------------------------------------------------------------------- + +fn insert_tree_setup( + lang: ProgramLanguage, + desc: &TreeDesc, + insert_key: u16, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(lang); + let (system_program_pubkey, _) = mollusk_svm::program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, tree_account) = build_tree_account(desc, &setup.program_id); + + let insn_data = InsertInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Insert as u8, + }, + key: insert_key, + value: TEST_VALUE, + }; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + unsafe { as_bytes(&insn_data) }, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account), + ]; + + (setup, instruction, accounts) +} + +/// Run an insert and assert success with full tree state check. +fn run_success( + lang: ProgramLanguage, + desc: &TreeDesc, + insert_key: u16, + expected: &ExpectedTree, +) -> CaseResult { + let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => { + let tree_data = &result.resulting_accounts[AccountIndex::Tree as usize].1.data; + match assert_tree_account(tree_data, expected) { + Ok(()) => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + Err(e) => CaseResult { + cu: result.compute_units_consumed, + error: Some(e), + }, + } + } + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } +} + +/// Run an insert and check for KEY_EXISTS error. +fn run_dup_error(lang: ProgramLanguage, desc: &TreeDesc, insert_key: u16) -> CaseResult { + let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::KEY_EXISTS, + ) +} + +// --------------------------------------------------------------------------- +// Shorthand constructors +// --------------------------------------------------------------------------- + +const B: u8 = Color::Black as u8; +const R: u8 = Color::Red as u8; + +fn node(key: u16, color: u8, parent: Option, left: Option, right: Option) -> NodeDesc { + NodeDesc { + key, + value: key, // Use key as value for pre-existing nodes. + color, + parent, + left, + right, + } +} + +fn expected(key: u16, value: u16, color: u8, parent: Option, left: Option, right: Option) -> ExpectedNode { + ExpectedNode { + key, + value, + color, + parent, + left, + right, + } +} + +// --------------------------------------------------------------------------- +// Test case enum +// --------------------------------------------------------------------------- + +#[derive(Clone, Copy)] +pub(super) enum InsertTreeCase { + // Search — expect KEY_EXISTS error. + DupAtRoot, + DupInLeft, + DupInRight, + // Insert to empty tree. + EmptyTree, + // Case 1: parent is black. + Case1Left, + Case1Right, + // Case 4: parent is root and red. + Case4Left, + Case4Right, + // Case 2+3: red uncle, propagate to root. + Case23LeftLeft, + Case23LeftRight, + Case23RightLeft, + Case23RightRight, + // Case 2+1: red uncle, propagate to black ancestor. + Case21Left, + Case21Right, + // Case 6: single rotation (outer child). + Case6LeftNull, + Case6RightNull, + Case6LeftBlack, + Case6RightBlack, + // Case 5+6: double rotation (inner child). + Case56LeftNull, + Case56RightNull, + Case56LeftBlack, + Case56RightBlack, +} + +impl InsertTreeCase { + pub(super) const SEARCH_CASES: &'static [Self] = &[ + Self::DupAtRoot, + Self::DupInLeft, + Self::DupInRight, + ]; + + pub(super) const TREE_CASES: &'static [Self] = &[ + Self::EmptyTree, + Self::Case1Left, + Self::Case1Right, + Self::Case4Left, + Self::Case4Right, + Self::Case23LeftLeft, + Self::Case23LeftRight, + Self::Case23RightLeft, + Self::Case23RightRight, + Self::Case21Left, + Self::Case21Right, + Self::Case6LeftNull, + Self::Case6RightNull, + Self::Case6LeftBlack, + Self::Case6RightBlack, + Self::Case56LeftNull, + Self::Case56RightNull, + Self::Case56LeftBlack, + Self::Case56RightBlack, + ]; +} + +impl TestCase for InsertTreeCase { + fn name(&self) -> &'static str { + match self { + Self::DupAtRoot => "Dup at root", + Self::DupInLeft => "Dup in left", + Self::DupInRight => "Dup in right", + Self::EmptyTree => "Empty tree", + Self::Case1Left => "Case 1: left child", + Self::Case1Right => "Case 1: right child", + Self::Case4Left => "Case 4: left child", + Self::Case4Right => "Case 4: right child", + Self::Case23LeftLeft => "Case 2+3: left-left", + Self::Case23LeftRight => "Case 2+3: left-right", + Self::Case23RightLeft => "Case 2+3: right-left", + Self::Case23RightRight => "Case 2+3: right-right", + Self::Case21Left => "Case 2+1: left", + Self::Case21Right => "Case 2+1: right", + Self::Case6LeftNull => "Case 6: left-left null uncle", + Self::Case6RightNull => "Case 6: right-right null uncle", + Self::Case6LeftBlack => "Case 6: left-left black uncle", + Self::Case6RightBlack => "Case 6: right-right black uncle", + Self::Case56LeftNull => "Case 5+6: left-right null uncle", + Self::Case56RightNull => "Case 5+6: right-left null uncle", + Self::Case56LeftBlack => "Case 5+6: left-right black uncle", + Self::Case56RightBlack => "Case 5+6: right-left black uncle", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + // ----- Search: duplicate key errors ----- + + // Root with key 10, insert 10. + Self::DupAtRoot => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + run_dup_error(lang, &desc, 10) + } + // Root 10, left child 5, insert 5. + Self::DupInLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + run_dup_error(lang, &desc, 5) + } + // Root 10, right child 15, insert 15. + Self::DupInRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + run_dup_error(lang, &desc, 15) + } + + // ----- Insert to empty tree ----- + + Self::EmptyTree => { + let desc = TreeDesc { + root: None, + nodes: &[], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![expected(42, TEST_VALUE, R, None, None, None)], + }; + run_success(lang, &desc, 42, &exp) + } + + // ----- Case 1: parent is black ----- + + // B(10) root, insert 5 → left child. + Self::Case1Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, Some(1), None), + expected(5, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 5, &exp) + } + // B(10) root, insert 15 → right child. + Self::Case1Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, None, Some(1)), + expected(15, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 15, &exp) + } + + // ----- Case 4: parent is root and red ----- + + // R(10) root, insert 5 → left child, parent recolored B. + Self::Case4Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, R, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, Some(1), None), + expected(5, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 5, &exp) + } + // R(10) root, insert 15 → right child, parent recolored B. + Self::Case4Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, R, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, None, Some(1)), + expected(15, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 15, &exp) + } + + // ----- Case 2+3: red uncle, propagate to root ----- + // Before: B(10) root, R(5) left, R(15) right. + // After recolor: R(10), B(5), B(15), inserted node red. + + Self::Case23LeftLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), Some(3), None), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + Self::Case23LeftRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, Some(3)), + expected(15, 15, B, Some(0), None, None), + expected(7, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 7, &exp) + } + Self::Case23RightLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, Some(0), Some(3), None), + expected(12, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 12, &exp) + } + Self::Case23RightRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, Some(0), None, Some(3)), + expected(20, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 2+1: red uncle, propagate to black ancestor ----- + + // Before: B(20) root, B(10) left of root, R(5) left of 10, R(15) right of 10. + // After: B(20), R(10), B(5), B(15), R(1) inserted. + Self::Case21Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), None), + node(10, B, Some(0), Some(2), Some(3)), + node(5, R, Some(1), None, None), + node(15, R, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(1), None), + expected(10, 10, R, Some(0), Some(2), Some(3)), + expected(5, 5, B, Some(1), Some(4), None), + expected(15, 15, B, Some(1), None, None), + expected(1, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Mirror: B(2) root, B(10) right of root, R(5) left of 10, R(15) right of 10. + Self::Case21Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(2, B, None, None, Some(1)), + node(10, B, Some(0), Some(2), Some(3)), + node(5, R, Some(1), None, None), + node(15, R, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(2, 2, B, None, None, Some(1)), + expected(10, 10, R, Some(0), Some(2), Some(3)), + expected(5, 5, B, Some(1), None, None), + expected(15, 15, B, Some(1), None, Some(4)), + expected(20, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 6: single rotation (outer child) ----- + + // Left-left, null uncle: B(10) root, R(5) left, insert 1. + // After: B(5) new root, R(1) left, R(10) right. + Self::Case6LeftNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, None), + expected(5, 5, B, None, Some(2), Some(0)), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Right-right, null uncle: B(10) root, R(15) right, insert 20. + // After: B(15) new root, R(10) left, R(20) right. + Self::Case6RightNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, None), + expected(15, 15, B, None, Some(0), Some(2)), + expected(20, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + // Left-left, black uncle: B(10) root, R(5) left, B(15) right, insert 1. + // After: B(5) new root, R(1) left, R(10) right with B(15) as 10's right. + Self::Case6LeftBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, Some(2)), + expected(5, 5, B, None, Some(3), Some(0)), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Right-right, black uncle: B(10) root, B(5) left, R(15) right, insert 20. + // After: B(15) new root, R(10) left with B(5) as 10's left, R(20) right. + Self::Case6RightBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), Some(1), None), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, None, Some(0), Some(3)), + expected(20, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 5+6: double rotation (inner child) ----- + + // Left-right, null uncle: B(10) root, R(5) left, insert 7. + // After: B(7) new root, R(5) left, R(10) right. + Self::Case56LeftNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), None, None), + expected(5, 5, R, Some(2), None, None), + expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + ], + }; + run_success(lang, &desc, 7, &exp) + } + // Right-left, null uncle: B(10) root, R(15) right, insert 12. + // After: B(12) new root, R(10) left, R(15) right. + Self::Case56RightNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), None, None), + expected(15, 15, R, Some(2), None, None), + expected(12, TEST_VALUE, B, None, Some(0), Some(1)), + ], + }; + run_success(lang, &desc, 12, &exp) + } + // Left-right, black uncle: B(10) root, R(5) left, B(15) right, insert 7. + // After: B(7) new root, R(5) left, R(10) right with B(15) as 10's right. + Self::Case56LeftBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), None, Some(2)), + expected(5, 5, R, Some(3), None, None), + expected(15, 15, B, Some(0), None, None), + expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + ], + }; + run_success(lang, &desc, 7, &exp) + } + // Right-left, black uncle: B(10) root, B(5) left, R(15) right, insert 12. + // After: B(12) new root, R(10) left with B(5) as 10's left, R(15) right. + Self::Case56RightBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), Some(1), None), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, R, Some(3), None, None), + expected(12, TEST_VALUE, B, None, Some(0), Some(2)), + ], + }; + run_success(lang, &desc, 12, &exp) + } + } + } +} From 6f0d77c0efb02a63fddc1734a2442b900bf8b23c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 19:32:03 -0700 Subject: [PATCH 191/263] Begin implementing asm insert --- examples/tree/artifacts/dumps/asm.txt | 145 ++-- examples/tree/artifacts/dumps/rs.txt | 745 +++++++++++------- examples/tree/artifacts/rs-disassembly.s | 307 ++++++-- .../tree/artifacts/snippets/asm/constants.txt | 6 +- .../snippets/asm/insert-allocate.txt | 9 +- .../artifacts/snippets/asm/insert-search.txt | 19 + .../artifacts/snippets/asm/insert-to-tree.txt | 11 + .../snippets/interface/tree-defs-common.txt | 1 + .../artifacts/snippets/rs/insert-search.txt | 1 + .../tests/entrypoint_branching/result.txt | 4 +- .../initialize_create_account/result.txt | 36 - .../tests/initialize_create_account/test.txt | 4 - .../tests/initialize_input_checks/result.txt | 122 --- .../tests/initialize_input_checks/test.txt | 4 - .../tests/initialize_pda_checks/result.txt | 31 - .../tests/initialize_pda_checks/test.txt | 4 - .../tree/artifacts/tests/insert/result.txt | 35 - examples/tree/interface/src/asm.rs | 10 +- examples/tree/interface/src/common.rs | 3 +- examples/tree/macros/src/lib.rs | 281 ++++--- examples/tree/src/program.rs | 1 + examples/tree/src/tree/tree.s | 50 +- 22 files changed, 1033 insertions(+), 796 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/insert-search.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-to-tree.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt delete mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt delete mode 100644 examples/tree/artifacts/tests/insert/result.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 26b63ff3..e9d6e912 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 2544 (bytes into file) + Start of section headers 2520 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x9f0 +There are 7 section headers, starting at offset 0x9d8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000768 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000850 000850 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000008f0 0008f0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000950 000950 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000990 000990 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0009c0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000750 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000838 000838 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000008d8 0008d8 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000938 000938 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000978 000978 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 0009a8 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000768 0x000768 R E 0x1000 - LOAD 0x0008f0 0x00000000000008f0 0x00000000000008f0 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000850 0x0000000000000850 0x0000000000000850 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000750 0x000750 R E 0x1000 + LOAD 0x0008d8 0x00000000000008d8 0x00000000000008d8 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000838 0x0000000000000838 0x0000000000000838 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x850 contains 10 entries +Dynamic section at offset 0x838 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x990 + 0x0000000000000011 (REL) 0x978 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x8f0 + 0x0000000000000006 (SYMTAB) 0x8d8 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x950 + 0x0000000000000005 (STRTAB) 0x938 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x990 contains 3 entries +Relocation section '.rel.dyn' at offset 0x978 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 cf 00 01 00 00 00 if r9 != 0x1 goto +0xcf - 37 55 08 d0 00 04 00 00 00 if r8 != 0x4 goto +0xd0 + 36 55 09 cc 00 01 00 00 00 if r9 != 0x1 goto +0xcc + 37 55 08 cd 00 04 00 00 00 if r8 != 0x4 goto +0xcd 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 e0 00 00 00 00 00 if r9 != 0x0 goto +0xe0 + 39 55 09 dd 00 00 00 00 00 if r9 != 0x0 goto +0xdd 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc + 41 55 09 d9 00 ff 00 00 00 if r9 != 0xff goto +0xd9 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 d8 00 00 00 00 00 if r9 != 0x0 goto +0xd8 + 43 55 09 d5 00 00 00 00 00 if r9 != 0x0 goto +0xd5 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 d4 00 ff 00 00 00 if r9 != 0xff goto +0xd4 + 45 55 09 d1 00 ff 00 00 00 if r9 != 0xff goto +0xd1 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 d0 00 0e 00 00 00 if r9 != 0xe goto +0xd0 + 47 55 09 cd 00 0e 00 00 00 if r9 != 0xe goto +0xcd 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 cc 00 ff 00 00 00 if r9 != 0xff goto +0xcc + 49 55 09 c9 00 ff 00 00 00 if r9 != 0xff goto +0xc9 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 c6 00 00 00 00 00 if r9 != r8 goto +0xc6 + 53 5d 89 c3 00 00 00 00 00 if r9 != r8 goto +0xc3 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 c2 00 00 00 00 00 if r9 != r8 goto +0xc2 + 57 5d 89 bf 00 00 00 00 00 if r9 != r8 goto +0xbf 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 be 00 00 00 00 00 if r9 != r8 goto +0xbe + 61 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb + 64 5d 89 b8 00 00 00 00 00 if r9 != r8 goto +0xb8 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 ae 00 00 00 00 00 if r9 != r8 goto +0xae + 75 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab + 78 5d 89 a8 00 00 00 00 00 if r9 != r8 goto +0xa8 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 a8 00 00 00 00 00 if r9 != r8 goto +0xa8 + 81 5d 89 a5 00 00 00 00 00 if r9 != r8 goto +0xa5 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 a5 00 00 00 00 00 if r9 != r8 goto +0xa5 + 84 5d 89 a2 00 00 00 00 00 if r9 != r8 goto +0xa2 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 62 00 05 00 00 00 if r9 != 0x5 goto +0x62 - 146 a5 08 63 00 02 00 00 00 if r8 < 0x2 goto +0x63 + 145 55 09 5f 00 05 00 00 00 if r9 != 0x5 goto +0x5f + 146 a5 08 60 00 02 00 00 00 if r8 < 0x2 goto +0x60 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 73 00 00 00 00 00 if r9 != 0x0 goto +0x73 + 148 55 09 70 00 00 00 00 00 if r9 != 0x0 goto +0x70 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 6f 00 ff 00 00 00 if r9 != 0xff goto +0x6f + 150 55 09 6c 00 ff 00 00 00 if r9 != 0xff goto +0x6c 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 5e 00 04 00 00 00 if r8 != 0x4 goto +0x5e + 153 55 08 5b 00 04 00 00 00 if r8 != 0x4 goto +0x5b 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 60 00 ff 00 00 00 if r8 != 0xff goto +0x60 + 161 55 08 5d 00 ff 00 00 00 if r8 != 0xff goto +0x5d 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 5c 00 0e 00 00 00 if r8 != 0xe goto +0x5c + 163 55 08 59 00 0e 00 00 00 if r8 != 0xe goto +0x59 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 58 00 ff 00 00 00 if r8 != 0xff goto +0x58 + 165 55 08 55 00 ff 00 00 00 if r8 != 0xff goto +0x55 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 52 00 00 00 00 00 if r8 != r4 goto +0x52 + 169 5d 48 4f 00 00 00 00 00 if r8 != r4 goto +0x4f 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 4e 00 00 00 00 00 if r8 != r4 goto +0x4e + 173 5d 48 4b 00 00 00 00 00 if r8 != r4 goto +0x4b 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 4a 00 00 00 00 00 if r8 != r4 goto +0x4a + 177 5d 48 47 00 00 00 00 00 if r8 != r4 goto +0x47 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 47 00 00 00 00 00 if r8 != r4 goto +0x47 + 180 5d 48 44 00 00 00 00 00 if r8 != r4 goto +0x44 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -285,33 +285,30 @@ Disassembly of section .text 233 05 00 02 00 00 00 00 00 goto +0x2 234 79 98 00 00 00 00 00 00 r8 = *(u64 *)(r9 + 0x0) 235 7b 81 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r8 - 236 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 - 237 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) - 238 6b 49 18 00 00 00 00 00 *(u16 *)(r9 + 0x18) = r4 - 239 69 24 03 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x3) - 240 6b 49 1a 00 00 00 00 00 *(u16 *)(r9 + 0x1a) = r4 - 241 95 00 00 00 00 00 00 00 exit - 242 b7 00 00 00 09 00 00 00 r0 = 0x9 - 243 95 00 00 00 00 00 00 00 exit - 244 b7 00 00 00 0c 00 00 00 r0 = 0xc - 245 95 00 00 00 00 00 00 00 exit - 246 b7 00 00 00 01 00 00 00 r0 = 0x1 - 247 95 00 00 00 00 00 00 00 exit - 248 b7 00 00 00 0d 00 00 00 r0 = 0xd - 249 95 00 00 00 00 00 00 00 exit - 250 b7 00 00 00 0a 00 00 00 r0 = 0xa - 251 95 00 00 00 00 00 00 00 exit - 252 b7 00 00 00 08 00 00 00 r0 = 0x8 - 253 95 00 00 00 00 00 00 00 exit - 254 b7 00 00 00 07 00 00 00 r0 = 0x7 - 255 95 00 00 00 00 00 00 00 exit - 256 b7 00 00 00 04 00 00 00 r0 = 0x4 - 257 95 00 00 00 00 00 00 00 exit - 258 b7 00 00 00 06 00 00 00 r0 = 0x6 - 259 95 00 00 00 00 00 00 00 exit - 260 b7 00 00 00 03 00 00 00 r0 = 0x3 - 261 95 00 00 00 00 00 00 00 exit - 262 b7 00 00 00 05 00 00 00 r0 = 0x5 - 263 95 00 00 00 00 00 00 00 exit - 264 b7 00 00 00 02 00 00 00 r0 = 0x2 - 265 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 236 61 24 01 00 00 00 00 00 r4 = *(u32 *)(r2 + 0x1) + 237 63 49 18 00 00 00 00 00 *(u32 *)(r9 + 0x18) = r4 + 238 95 00 00 00 00 00 00 00 exit + 239 b7 00 00 00 09 00 00 00 r0 = 0x9 + 240 95 00 00 00 00 00 00 00 exit + 241 b7 00 00 00 0c 00 00 00 r0 = 0xc + 242 95 00 00 00 00 00 00 00 exit + 243 b7 00 00 00 01 00 00 00 r0 = 0x1 + 244 95 00 00 00 00 00 00 00 exit + 245 b7 00 00 00 0d 00 00 00 r0 = 0xd + 246 95 00 00 00 00 00 00 00 exit + 247 b7 00 00 00 0a 00 00 00 r0 = 0xa + 248 95 00 00 00 00 00 00 00 exit + 249 b7 00 00 00 08 00 00 00 r0 = 0x8 + 250 95 00 00 00 00 00 00 00 exit + 251 b7 00 00 00 07 00 00 00 r0 = 0x7 + 252 95 00 00 00 00 00 00 00 exit + 253 b7 00 00 00 04 00 00 00 r0 = 0x4 + 254 95 00 00 00 00 00 00 00 exit + 255 b7 00 00 00 06 00 00 00 r0 = 0x6 + 256 95 00 00 00 00 00 00 00 exit + 257 b7 00 00 00 03 00 00 00 r0 = 0x3 + 258 95 00 00 00 00 00 00 00 exit + 259 b7 00 00 00 05 00 00 00 r0 = 0x5 + 260 95 00 00 00 00 00 00 00 exit + 261 b7 00 00 00 02 00 00 00 r0 = 0x2 + 262 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 89f70694..a85ade07 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 4888 (bytes into file) + Start of section headers 6016 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x1318 +There are 8 section headers, starting at offset 0x1780 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000908 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000a28 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000a30 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000a30 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000a30 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 000da8 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 000de6 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000d70 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000e90 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000e98 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000e98 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000e98 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001210 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00124e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000908 0x000908 E 0x8 - LOAD 0x000a28 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000a30 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000a30 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000d70 0x000d70 E 0x8 + LOAD 0x000e90 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000e98 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000e98 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 2312 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3440 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,292 +104,433 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 - 8 9c 13 00 00 00 00 00 00 ldxdw r3, [r1 + 0x0] - 10 9c 24 f8 ff 00 00 00 00 ldxdw r4, [r2 - 0x8] + 0 07 0a 00 00 80 fe ff ff add64 r10, -0x180 + 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] + 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 7c 00 01 00 00 00 jne r5, 0x1, +0x7c - 28 55 04 05 01 05 00 00 00 jne r4, 0x5, +0x105 - 30 a5 03 06 01 02 00 00 00 jlt r3, 0x2, +0x106 - 38 9c 14 58 00 00 00 00 00 ldxdw r4, [r1 + 0x58] - 40 55 04 06 01 00 00 00 00 jne r4, 0x0, +0x106 - 48 2c 14 68 28 00 00 00 00 ldxb w4, [r1 + 0x2868] - 50 55 04 06 01 ff 00 00 00 jne r4, 0xff, +0x106 - 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 - 68 9c 14 c8 28 00 00 00 00 ldxdw r4, [r1 + 0x28c8] - 70 15 04 03 00 00 00 00 00 jeq r4, 0x0, +0x3 - 78 9c 43 00 00 00 00 00 00 ldxdw r3, [r4 + 0x0] - 80 9f 31 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r3 - 88 05 00 68 00 00 00 00 00 ja +0x68 - 90 55 03 04 01 04 00 00 00 jne r3, 0x4, +0x104 - 98 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - a0 bf 35 00 00 00 00 00 00 mov64 r5, r3 - a8 07 05 00 00 07 00 00 00 add64 r5, 0x7 - b0 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - b8 bf 14 00 00 00 00 00 00 mov64 r4, r1 - c0 0f 54 00 00 00 00 00 00 add64 r4, r5 - c8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - d0 55 05 f8 00 ff 00 00 00 jne r5, 0xff, +0xf8 - d8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - e0 55 05 f8 00 0e 00 00 00 jne r5, 0xe, +0xf8 - e8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - f0 55 05 fa 00 ff 00 00 00 jne r5, 0xff, +0xfa - f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 100 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 108 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 110 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] - 118 5d 57 5c 00 00 00 00 00 jne r7, r5, +0x5c - 120 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 128 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 130 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] - 138 5d 57 58 00 00 00 00 00 jne r7, r5, +0x58 - 140 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 148 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 150 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] - 158 5d 57 54 00 00 00 00 00 jne r7, r5, +0x54 - 160 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 168 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 170 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 178 5d 52 50 00 00 00 00 00 jne r2, r5, +0x50 - 180 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 188 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 190 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 - 198 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 - 1a0 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 1a8 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 1b0 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 - 1b8 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 1c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 1c8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 - 1d0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 - 1d8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 - 1e0 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 1e8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 1f0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 - 1f8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 - 200 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 - 208 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 210 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 218 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 220 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 - 228 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 230 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 238 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 - 240 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 248 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 250 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 - 258 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 260 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 268 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 270 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 278 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 280 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 - 288 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 290 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 298 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 2a0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 2a8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 2b0 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 - 2b8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 2c0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 - 2c8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 - 2d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 2d8 07 02 00 00 30 01 00 00 add64 r2, 0x130 - 2e0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 - 2e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 2f0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 - 2f8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 300 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 308 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 - 310 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 - 318 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc - 320 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 - 328 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 - 330 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 - 338 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 340 07 03 00 00 10 00 00 00 add64 r3, 0x10 - 348 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 350 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 358 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 360 07 04 00 00 48 00 00 00 add64 r4, 0x48 - 368 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 370 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 378 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 380 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 388 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 390 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 398 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 3a0 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 - 3a8 9c 84 d0 28 00 00 00 00 ldxdw r4, [r8 + 0x28d0] - 3b0 bf 41 00 00 00 00 00 00 mov64 r1, r4 - 3b8 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 3c0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - 3c8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 3d0 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 - 3d8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] - 3e0 3f 14 18 00 00 00 00 00 stxh [r4 + 0x18], w1 - 3e8 3c 21 03 00 00 00 00 00 ldxh w1, [r2 + 0x3] - 3f0 3f 14 1a 00 00 00 00 00 stxh [r4 + 0x1a], w1 - 3f8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 400 9d 00 00 00 00 00 00 00 return - 408 55 05 9b 00 00 00 00 00 jne r5, 0x0, +0x9b - 410 55 04 88 00 01 00 00 00 jne r4, 0x1, +0x88 - 418 55 03 89 00 04 00 00 00 jne r3, 0x4, +0x89 - 420 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 428 55 02 89 00 00 00 00 00 jne r2, 0x0, +0x89 - 430 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 438 55 02 89 00 ff 00 00 00 jne r2, 0xff, +0x89 - 440 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 448 55 02 95 00 00 00 00 00 jne r2, 0x0, +0x95 - 450 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 458 55 02 87 00 ff 00 00 00 jne r2, 0xff, +0x87 - 460 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 468 55 02 87 00 0e 00 00 00 jne r2, 0xe, +0x87 - 470 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 478 55 02 89 00 ff 00 00 00 jne r2, 0xff, +0x89 - 480 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 488 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 490 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 498 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 4a0 5d 23 eb ff 00 00 00 00 jne r3, r2, -0x15 - 4a8 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 4b0 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 4b8 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 4c0 5d 23 e7 ff 00 00 00 00 jne r3, r2, -0x19 - 4c8 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 4d0 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 4d8 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 4e0 5d 23 e3 ff 00 00 00 00 jne r3, r2, -0x1d - 4e8 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 4f0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 4f8 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 - 500 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 508 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 510 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 518 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 520 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 528 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 530 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 538 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 540 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 548 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 550 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 558 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 560 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 568 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 570 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 578 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b - 580 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 588 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 590 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 - 598 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 5a0 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 5a8 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 - 5b0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 5b8 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 5c0 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 5c8 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 5d0 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - 5d8 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 5e0 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - 5e8 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 5f0 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - 5f8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 600 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - 608 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 610 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - 618 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - 620 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - 628 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 630 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 638 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 640 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 648 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 650 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 658 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 660 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 668 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 670 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 678 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 680 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - 688 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 690 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 698 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 6a0 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - 6a8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 6b0 07 01 00 00 30 00 00 00 add64 r1, 0x30 - 6b8 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - 6c0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 6c8 07 01 00 00 60 00 00 00 add64 r1, 0x60 - 6d0 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - 6d8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 6e0 07 01 00 00 50 00 00 00 add64 r1, 0x50 - 6e8 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - 6f0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 6f8 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 700 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - 708 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 710 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - 718 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 720 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 728 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 730 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 738 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - 740 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - 748 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - 750 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - 758 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 760 07 01 00 00 10 00 00 00 add64 r1, 0x10 - 768 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - 770 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 778 07 01 00 00 48 00 00 00 add64 r1, 0x48 - 780 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - 788 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 790 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - 798 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - 7a0 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - 7a8 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - 7b0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 7b8 07 01 00 00 0f 00 00 00 add64 r1, 0xf - 7c0 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - 7c8 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - 7d0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 7d8 07 01 00 00 20 01 00 00 add64 r1, 0x120 - 7e0 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - 7e8 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - 7f0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - 7f8 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - 800 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 808 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 810 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 818 07 04 00 00 30 01 00 00 add64 r4, 0x130 - 820 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 828 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - 830 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 838 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 840 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - 848 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - 850 05 00 74 ff 00 00 00 00 ja -0x8c - 858 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - 860 05 00 73 ff 00 00 00 00 ja -0x8d - 868 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - 870 05 00 71 ff 00 00 00 00 ja -0x8f - 878 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - 880 05 00 6f ff 00 00 00 00 ja -0x91 - 888 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - 890 05 00 6d ff 00 00 00 00 ja -0x93 - 898 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - 8a0 05 00 6b ff 00 00 00 00 ja -0x95 - 8a8 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - 8b0 05 00 69 ff 00 00 00 00 ja -0x97 - 8b8 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - 8c0 05 00 67 ff 00 00 00 00 ja -0x99 - 8c8 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - 8d0 05 00 65 ff 00 00 00 00 ja -0x9b - 8d8 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - 8e0 05 00 63 ff 00 00 00 00 ja -0x9d - 8e8 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - 8f0 05 00 61 ff 00 00 00 00 ja -0x9f - 8f8 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - 900 05 00 5f ff 00 00 00 00 ja -0xa1 \ No newline at end of file + 20 55 05 08 01 01 00 00 00 jne r5, 0x1, +0x108 + 28 55 03 92 01 05 00 00 00 jne r3, 0x5, +0x192 + 30 a5 04 93 01 02 00 00 00 jlt r4, 0x2, +0x193 + 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 40 55 03 93 01 00 00 00 00 jne r3, 0x0, +0x193 + 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 50 55 03 93 01 ff 00 00 00 jne r3, 0xff, +0x193 + 58 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 60 07 07 00 00 c0 28 00 00 add64 r7, 0x28c0 + 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] + 70 15 03 3e 00 00 00 00 00 jeq r3, 0x0, +0x3e + 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] + 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 + 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 98 9c 74 00 00 00 00 00 00 ldxdw r4, [r7 + 0x0] + a0 15 04 a7 00 00 00 00 00 jeq r4, 0x0, +0xa7 + a8 3c 22 01 00 00 00 00 00 ldxh w2, [r2 + 0x1] + b0 05 00 04 00 00 00 00 00 ja +0x4 + b8 bf 15 00 00 00 00 00 00 mov64 r5, r1 + c0 0f 45 00 00 00 00 00 00 add64 r5, r4 + c8 9c 54 00 00 00 00 00 00 ldxdw r4, [r5 + 0x0] + d0 15 04 09 00 00 00 00 00 jeq r4, 0x0, +0x9 + d8 bf 41 00 00 00 00 00 00 mov64 r1, r4 + e0 b7 04 00 00 10 00 00 00 mov64 r4, 0x10 + e8 3c 15 18 00 00 00 00 00 ldxh w5, [r1 + 0x18] + f0 bf 20 00 00 00 00 00 00 mov64 r0, r2 + f8 2d 50 f7 ff 00 00 00 00 jgt r0, r5, -0x9 + 100 b7 04 00 00 08 00 00 00 mov64 r4, 0x8 + 108 ad 50 f5 ff 00 00 00 00 jlt r0, r5, -0xb + 110 b7 01 00 00 0e 00 00 00 mov64 r1, 0xe + 118 05 00 9c 00 00 00 00 00 ja +0x9c + 120 9f 7a 38 00 00 00 00 00 stxdw [r10 + 0x38], r7 + 128 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 130 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 138 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 140 3c 15 18 00 00 00 00 00 ldxh w5, [r1 + 0x18] + 148 b4 02 00 00 01 00 00 00 mov32 w2, 0x1 + 150 2d 54 01 00 00 00 00 00 jgt r4, r5, +0x1 + 158 b4 02 00 00 00 00 00 00 mov32 w2, 0x0 + 160 67 02 00 00 03 00 00 00 lsh64 r2, 0x3 + 168 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 170 0f 24 00 00 00 00 00 00 add64 r4, r2 + 178 9f 34 08 00 00 00 00 00 stxdw [r4 + 0x8], r3 + 180 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 188 9f 2a 40 00 00 00 00 00 stxdw [r10 + 0x40], r2 + 190 2c 12 1c 00 00 00 00 00 ldxb w2, [r1 + 0x1c] + 198 15 02 d7 00 00 00 00 00 jeq r2, 0x0, +0xd7 + 1a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 1a8 15 02 98 00 00 00 00 00 jeq r2, 0x0, +0x98 + 1b0 9c 28 10 00 00 00 00 00 ldxdw r8, [r2 + 0x10] + 1b8 b4 00 00 00 01 00 00 00 mov32 w0, 0x1 + 1c0 1d 81 01 00 00 00 00 00 jeq r1, r8, +0x1 + 1c8 b4 00 00 00 00 00 00 00 mov32 w0, 0x0 + 1d0 bf 25 00 00 00 00 00 00 mov64 r5, r2 + 1d8 07 05 00 00 08 00 00 00 add64 r5, 0x8 + 1e0 bf 04 00 00 00 00 00 00 mov64 r4, r0 + 1e8 a7 04 00 00 01 00 00 00 xor64 r4, 0x1 + 1f0 bf 47 00 00 00 00 00 00 mov64 r7, r4 + 1f8 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 + 200 bf 59 00 00 00 00 00 00 mov64 r9, r5 + 208 0f 79 00 00 00 00 00 00 add64 r9, r7 + 210 9c 99 00 00 00 00 00 00 ldxdw r9, [r9 + 0x0] + 218 15 09 7e 00 00 00 00 00 jeq r9, 0x0, +0x7e + 220 2c 96 1c 00 00 00 00 00 ldxb w6, [r9 + 0x1c] + 228 15 06 7c 00 00 00 00 00 jeq r6, 0x0, +0x7c + 230 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 + 238 27 09 1c 00 00 00 00 00 stb [r9 + 0x1c], 0x0 + 240 27 02 1c 00 01 00 00 00 stb [r2 + 0x1c], 0x1 + 248 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] + 250 bf 23 00 00 00 00 00 00 mov64 r3, r2 + 258 55 01 e4 ff 00 00 00 00 jne r1, 0x0, -0x1c + 260 05 00 be 00 00 00 00 00 ja +0xbe + 268 55 04 56 01 04 00 00 00 jne r4, 0x4, +0x156 + 270 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 278 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 280 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 288 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 290 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 298 0f 54 00 00 00 00 00 00 add64 r4, r5 + 2a0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 2a8 55 05 4a 01 ff 00 00 00 jne r5, 0xff, +0x14a + 2b0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2b8 55 05 4a 01 0e 00 00 00 jne r5, 0xe, +0x14a + 2c0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2c8 55 05 4c 01 ff 00 00 00 jne r5, 0xff, +0x14c + 2d0 b7 05 00 00 08 00 00 00 mov64 r5, 0x8 + 2d8 9f 5a 40 00 00 00 00 00 stxdw [r10 + 0x40], r5 + 2e0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 2e8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 2f0 9c 46 40 79 00 00 00 00 ldxdw r6, [r4 + 0x7940] + 2f8 5d 56 ab 00 00 00 00 00 jne r6, r5, +0xab + 300 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 308 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 310 9c 46 48 79 00 00 00 00 ldxdw r6, [r4 + 0x7948] + 318 5d 56 a7 00 00 00 00 00 jne r6, r5, +0xa7 + 320 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 328 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 330 9c 46 50 79 00 00 00 00 ldxdw r6, [r4 + 0x7950] + 338 5d 56 a3 00 00 00 00 00 jne r6, r5, +0xa3 + 340 bf 78 00 00 00 00 00 00 mov64 r8, r7 + 348 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 350 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 358 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 360 5d 52 9e 00 00 00 00 00 jne r2, r5, +0x9e + 368 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 370 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 378 9f 2a 74 01 00 00 00 00 stxdw [r10 + 0x174], r2 + 380 87 0a 70 01 02 00 00 00 stw [r10 + 0x170], 0x2 + 388 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 390 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 398 9f 4a 28 01 00 00 00 00 stxdw [r10 + 0x128], r4 + 3a0 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 3a8 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 3b0 9f 2a 18 01 00 00 00 00 stxdw [r10 + 0x118], r2 + 3b8 37 0a 30 01 01 00 00 00 sth [r10 + 0x130], 0x1 + 3c0 37 0a 20 01 01 01 00 00 sth [r10 + 0x120], 0x101 + 3c8 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3d0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3d8 9f 5a 00 01 00 00 00 00 stxdw [r10 + 0x100], r5 + 3e0 9f 8a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r8 + 3e8 9f 3a f0 00 00 00 00 00 stxdw [r10 + 0xf0], r3 + 3f0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 3f8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 400 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + 408 9f 4a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r4 + 410 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 418 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 420 9f 3a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r3 + 428 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 430 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 438 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 440 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 448 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 450 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 458 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + 460 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + 468 37 0a 10 01 00 01 00 00 sth [r10 + 0x110], 0x100 + 470 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 478 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + 480 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + 488 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + 490 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + 498 97 0a 50 01 00 00 00 00 stdw [r10 + 0x150], 0x0 + 4a0 97 0a 48 01 00 00 00 00 stdw [r10 + 0x148], 0x0 + 4a8 97 0a 40 01 00 00 00 00 stdw [r10 + 0x140], 0x0 + 4b0 97 0a 38 01 00 00 00 00 stdw [r10 + 0x138], 0x0 + 4b8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4c0 07 02 00 00 70 01 00 00 add64 r2, 0x170 + 4c8 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 4d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4d8 07 02 00 00 18 01 00 00 add64 r2, 0x118 + 4e0 9f 2a 58 00 00 00 00 00 stxdw [r10 + 0x58], r2 + 4e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4f0 07 02 00 00 38 01 00 00 add64 r2, 0x138 + 4f8 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 + 500 97 0a 70 00 0c 00 00 00 stdw [r10 + 0x70], 0xc + 508 97 0a 60 00 02 00 00 00 stdw [r10 + 0x60], 0x2 + 510 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 518 97 0a 88 00 00 00 00 00 stdw [r10 + 0x88], 0x0 + 520 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 528 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 530 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 538 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 + 540 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 548 07 04 00 00 88 00 00 00 add64 r4, 0x88 + 550 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 558 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 560 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 568 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 570 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 578 9c 61 b8 28 00 00 00 00 ldxdw r1, [r6 + 0x28b8] + 580 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 588 9f 16 b8 28 00 00 00 00 stxdw [r6 + 0x28b8], r1 + 590 9c 63 d0 28 00 00 00 00 ldxdw r3, [r6 + 0x28d0] + 598 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 5a0 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 5a8 9f 16 d0 28 00 00 00 00 stxdw [r6 + 0x28d0], r1 + 5b0 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 5b8 bf 87 00 00 00 00 00 00 mov64 r7, r8 + 5c0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5c8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5d0 9c 74 00 00 00 00 00 00 ldxdw r4, [r7 + 0x0] + 5d8 55 04 59 ff 00 00 00 00 jne r4, 0x0, -0xa7 + 5e0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5e8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 5f0 9f 37 00 00 00 00 00 00 stxdw [r7 + 0x0], r3 + 5f8 b7 01 00 00 00 00 00 00 mov64 r1, 0x0 + 600 9f 1a 40 00 00 00 00 00 stxdw [r10 + 0x40], r1 + 608 05 00 49 00 00 00 00 00 ja +0x49 + 610 bf 19 00 00 00 00 00 00 mov64 r9, r1 + 618 07 09 00 00 08 00 00 00 add64 r9, 0x8 + 620 bf 96 00 00 00 00 00 00 mov64 r6, r9 + 628 0f 76 00 00 00 00 00 00 add64 r6, r7 + 630 9c 66 00 00 00 00 00 00 ldxdw r6, [r6 + 0x0] + 638 1d 63 08 00 00 00 00 00 jeq r3, r6, +0x8 + 640 bf 03 00 00 00 00 00 00 mov64 r3, r0 + 648 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 + 650 bf 56 00 00 00 00 00 00 mov64 r6, r5 + 658 0f 36 00 00 00 00 00 00 add64 r6, r3 + 660 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 668 05 00 22 00 00 00 00 00 ja +0x22 + 670 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 + 678 05 00 3b 00 00 00 00 00 ja +0x3b + 680 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 + 688 5d 81 01 00 00 00 00 00 jne r1, r8, +0x1 + 690 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 + 698 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 + 6a0 0f 39 00 00 00 00 00 00 add64 r9, r3 + 6a8 bf 06 00 00 00 00 00 00 mov64 r6, r0 + 6b0 67 06 00 00 03 00 00 00 lsh64 r6, 0x3 + 6b8 9c 93 00 00 00 00 00 00 ldxdw r3, [r9 + 0x0] + 6c0 bf 37 00 00 00 00 00 00 mov64 r7, r3 + 6c8 0f 67 00 00 00 00 00 00 add64 r7, r6 + 6d0 9c 78 08 00 00 00 00 00 ldxdw r8, [r7 + 0x8] + 6d8 9f 89 00 00 00 00 00 00 stxdw [r9 + 0x0], r8 + 6e0 07 07 00 00 08 00 00 00 add64 r7, 0x8 + 6e8 15 08 01 00 00 00 00 00 jeq r8, 0x0, +0x1 + 6f0 9f 18 00 00 00 00 00 00 stxdw [r8 + 0x0], r1 + 6f8 9f 17 00 00 00 00 00 00 stxdw [r7 + 0x0], r1 + 700 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 708 9f 31 00 00 00 00 00 00 stxdw [r1 + 0x0], r3 + 710 9c 26 10 00 00 00 00 00 ldxdw r6, [r2 + 0x10] + 718 b4 07 00 00 01 00 00 00 mov32 w7, 0x1 + 720 1d 16 01 00 00 00 00 00 jeq r6, r1, +0x1 + 728 b4 07 00 00 00 00 00 00 mov32 w7, 0x0 + 730 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 + 738 bf 51 00 00 00 00 00 00 mov64 r1, r5 + 740 0f 71 00 00 00 00 00 00 add64 r1, r7 + 748 9f 31 00 00 00 00 00 00 stxdw [r1 + 0x0], r3 + 750 bf 01 00 00 00 00 00 00 mov64 r1, r0 + 758 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + 760 bf 53 00 00 00 00 00 00 mov64 r3, r5 + 768 0f 13 00 00 00 00 00 00 add64 r3, r1 + 770 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] + 778 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 780 67 00 00 00 03 00 00 00 lsh64 r0, 0x3 + 788 0f 05 00 00 00 00 00 00 add64 r5, r0 + 790 67 04 00 00 03 00 00 00 lsh64 r4, 0x3 + 798 bf 36 00 00 00 00 00 00 mov64 r6, r3 + 7a0 0f 46 00 00 00 00 00 00 add64 r6, r4 + 7a8 9c 24 00 00 00 00 00 00 ldxdw r4, [r2 + 0x0] + 7b0 9c 67 08 00 00 00 00 00 ldxdw r7, [r6 + 0x8] + 7b8 9f 75 00 00 00 00 00 00 stxdw [r5 + 0x0], r7 + 7c0 07 06 00 00 08 00 00 00 add64 r6, 0x8 + 7c8 15 07 01 00 00 00 00 00 jeq r7, 0x0, +0x1 + 7d0 9f 27 00 00 00 00 00 00 stxdw [r7 + 0x0], r2 + 7d8 9f 26 00 00 00 00 00 00 stxdw [r6 + 0x0], r2 + 7e0 9f 43 00 00 00 00 00 00 stxdw [r3 + 0x0], r4 + 7e8 9f 32 00 00 00 00 00 00 stxdw [r2 + 0x0], r3 + 7f0 9c a5 38 00 00 00 00 00 ldxdw r5, [r10 + 0x38] + 7f8 15 04 08 00 00 00 00 00 jeq r4, 0x0, +0x8 + 800 9c 40 10 00 00 00 00 00 ldxdw r0, [r4 + 0x10] + 808 b4 05 00 00 01 00 00 00 mov32 w5, 0x1 + 810 1d 20 01 00 00 00 00 00 jeq r0, r2, +0x1 + 818 b4 05 00 00 00 00 00 00 mov32 w5, 0x0 + 820 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + 828 0f 54 00 00 00 00 00 00 add64 r4, r5 + 830 07 04 00 00 08 00 00 00 add64 r4, 0x8 + 838 bf 45 00 00 00 00 00 00 mov64 r5, r4 + 840 9f 35 00 00 00 00 00 00 stxdw [r5 + 0x0], r3 + 848 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 + 850 27 02 1c 00 01 00 00 00 stb [r2 + 0x1c], 0x1 + 858 9c a0 40 00 00 00 00 00 ldxdw r0, [r10 + 0x40] + 860 9d 00 00 00 00 00 00 00 return + 868 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c + 870 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 878 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 880 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 888 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 890 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 898 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 8a0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 8a8 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 + 8b0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 8b8 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 8c0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 8c8 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 8d0 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 8d8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 8e0 b7 02 00 00 08 00 00 00 mov64 r2, 0x8 + 8e8 9f 2a 40 00 00 00 00 00 stxdw [r10 + 0x40], r2 + 8f0 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 8f8 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 900 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 908 5d 23 e9 ff 00 00 00 00 jne r3, r2, -0x17 + 910 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 918 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 920 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 928 5d 23 e5 ff 00 00 00 00 jne r3, r2, -0x1b + 930 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 938 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 940 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 948 5d 23 e1 ff 00 00 00 00 jne r3, r2, -0x1f + 950 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 958 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 960 5d 32 de ff 00 00 00 00 jne r2, r3, -0x22 + 968 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 970 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 978 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 980 07 04 00 00 a8 00 00 00 add64 r4, 0xa8 + 988 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 990 07 05 00 00 4f 00 00 00 add64 r5, 0x4f + 998 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 9a0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 9a8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 9b0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 9b8 9c a1 a8 00 00 00 00 00 ldxdw r1, [r10 + 0xa8] + 9c0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 9c8 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 9d0 9c a1 b0 00 00 00 00 00 ldxdw r1, [r10 + 0xb0] + 9d8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 9e0 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b + 9e8 9c a1 b8 00 00 00 00 00 ldxdw r1, [r10 + 0xb8] + 9f0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 9f8 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 + a00 9c a1 c0 00 00 00 00 00 ldxdw r1, [r10 + 0xc0] + a08 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + a10 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 + a18 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a20 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + a28 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + a30 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + a38 9f 3a 7c 00 00 00 00 00 stxdw [r10 + 0x7c], r3 + a40 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + a48 9f 3a 74 00 00 00 00 00 stxdw [r10 + 0x74], r3 + a50 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + a58 9f 3a 6c 00 00 00 00 00 stxdw [r10 + 0x6c], r3 + a60 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + a68 9f 3a 64 00 00 00 00 00 stxdw [r10 + 0x64], r3 + a70 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + a78 9f 2a 54 00 00 00 00 00 stxdw [r10 + 0x54], r2 + a80 97 0a 5c 00 18 00 00 00 stdw [r10 + 0x5c], 0x18 + a88 87 0a 50 00 00 00 00 00 stw [r10 + 0x50], 0x0 + a90 9f 1a 98 00 00 00 00 00 stxdw [r10 + 0x98], r1 + a98 bf 72 00 00 00 00 00 00 mov64 r2, r7 + aa0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + aa8 9f 2a 88 00 00 00 00 00 stxdw [r10 + 0x88], r2 + ab0 37 0a a0 00 01 01 00 00 sth [r10 + 0xa0], 0x101 + ab8 37 0a 90 00 01 01 00 00 sth [r10 + 0x90], 0x101 + ac0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + ac8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + ad0 9f 3a 00 01 00 00 00 00 stxdw [r10 + 0x100], r3 + ad8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + ae0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + ae8 9f 3a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r3 + af0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + af8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + b00 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + b08 9f 1a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r1 + b10 bf 71 00 00 00 00 00 00 mov64 r1, r7 + b18 07 01 00 00 30 00 00 00 add64 r1, 0x30 + b20 9f 1a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r1 + b28 bf 71 00 00 00 00 00 00 mov64 r1, r7 + b30 07 01 00 00 60 00 00 00 add64 r1, 0x60 + b38 9f 1a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r1 + b40 bf 71 00 00 00 00 00 00 mov64 r1, r7 + b48 07 01 00 00 50 00 00 00 add64 r1, 0x50 + b50 9f 1a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r1 + b58 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + b60 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + b68 37 0a 10 01 01 01 00 00 sth [r10 + 0x110], 0x101 + b70 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + b78 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + b80 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + b88 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + b90 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + b98 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + ba0 97 0a 30 01 00 00 00 00 stdw [r10 + 0x130], 0x0 + ba8 97 0a 28 01 00 00 00 00 stdw [r10 + 0x128], 0x0 + bb0 97 0a 20 01 00 00 00 00 stdw [r10 + 0x120], 0x0 + bb8 97 0a 18 01 00 00 00 00 stdw [r10 + 0x118], 0x0 + bc0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + bc8 07 01 00 00 50 00 00 00 add64 r1, 0x50 + bd0 9f 1a 50 01 00 00 00 00 stxdw [r10 + 0x150], r1 + bd8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + be0 07 01 00 00 88 00 00 00 add64 r1, 0x88 + be8 9f 1a 40 01 00 00 00 00 stxdw [r10 + 0x140], r1 + bf0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + bf8 07 01 00 00 18 01 00 00 add64 r1, 0x118 + c00 9f 1a 38 01 00 00 00 00 stxdw [r10 + 0x138], r1 + c08 97 0a 58 01 34 00 00 00 stdw [r10 + 0x158], 0x34 + c10 97 0a 48 01 02 00 00 00 stdw [r10 + 0x148], 0x2 + c18 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c20 07 01 00 00 4f 00 00 00 add64 r1, 0x4f + c28 9f 1a 60 01 00 00 00 00 stxdw [r10 + 0x160], r1 + c30 97 0a 68 01 01 00 00 00 stdw [r10 + 0x168], 0x1 + c38 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c40 07 01 00 00 60 01 00 00 add64 r1, 0x160 + c48 9f 1a 70 01 00 00 00 00 stxdw [r10 + 0x170], r1 + c50 97 0a 78 01 01 00 00 00 stdw [r10 + 0x178], 0x1 + c58 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c60 07 01 00 00 38 01 00 00 add64 r1, 0x138 + c68 bf a2 00 00 00 00 00 00 mov64 r2, r10 + c70 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 + c78 bf a4 00 00 00 00 00 00 mov64 r4, r10 + c80 07 04 00 00 70 01 00 00 add64 r4, 0x170 + c88 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + c90 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + c98 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + ca0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + ca8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + cb0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + cb8 05 00 27 ff 00 00 00 00 ja -0xd9 + cc0 b7 01 00 00 0c 00 00 00 mov64 r1, 0xc + cc8 05 00 26 ff 00 00 00 00 ja -0xda + cd0 b7 01 00 00 01 00 00 00 mov64 r1, 0x1 + cd8 05 00 24 ff 00 00 00 00 ja -0xdc + ce0 b7 01 00 00 02 00 00 00 mov64 r1, 0x2 + ce8 05 00 22 ff 00 00 00 00 ja -0xde + cf0 b7 01 00 00 05 00 00 00 mov64 r1, 0x5 + cf8 05 00 20 ff 00 00 00 00 ja -0xe0 + d00 b7 01 00 00 06 00 00 00 mov64 r1, 0x6 + d08 05 00 1e ff 00 00 00 00 ja -0xe2 + d10 b7 01 00 00 04 00 00 00 mov64 r1, 0x4 + d18 05 00 1c ff 00 00 00 00 ja -0xe4 + d20 b7 01 00 00 0d 00 00 00 mov64 r1, 0xd + d28 05 00 1a ff 00 00 00 00 ja -0xe6 + d30 b7 01 00 00 07 00 00 00 mov64 r1, 0x7 + d38 05 00 18 ff 00 00 00 00 ja -0xe8 + d40 b7 01 00 00 0a 00 00 00 mov64 r1, 0xa + d48 05 00 16 ff 00 00 00 00 ja -0xea + d50 b7 01 00 00 0b 00 00 00 mov64 r1, 0xb + d58 05 00 14 ff 00 00 00 00 ja -0xec + d60 b7 01 00 00 03 00 00 00 mov64 r1, 0x3 + d68 05 00 12 ff 00 00 00 00 ja -0xee \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index d635c24b..b523233e 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -2,26 +2,98 @@ entrypoint: add64 r10, -320 - ldxdw r3, [r1+0] - ldxdw r4, [r2-8] + ldxdw r4, [r1+0] + ldxdw r3, [r2-8] ldxb r5, [r2+0] - jne r5, 1, jmp_0408 - jne r4, 5, jmp_0860 - jlt r3, 2, jmp_0870 - ldxdw r4, [r1+88] - jne r4, 0, jmp_0880 - ldxb r4, [r1+10344] - jne r4, 255, jmp_0890 + jne r5, 1, jmp_0800 + jne r3, 5, jmp_0c58 + jlt r4, 2, jmp_0c68 + ldxdw r3, [r1+88] + jne r3, 0, jmp_0c78 + ldxb r3, [r1+10344] + jne r3, 255, jmp_0c88 mov64 r6, r1 add64 r6, 10432 - ldxdw r4, [r1+10440] - jeq r4, 0, jmp_0090 - ldxdw r3, [r4+0] - stxdw [r1+10440], r3 - ja jmp_03d0 - -jmp_0090: - jne r3, 4, jmp_08c0 + ldxdw r3, [r1+10440] + jeq r3, 0, jmp_0260 + ldxdw r4, [r3+0] + stxdw [r1+10440], r4 + ldxw r1, [r2+1] + stxw [r3+24], r1 + ldxdw r4, [r6+0] + jeq r4, 0, jmp_05c0 + +jmp_00a8: + ldxh r2, [r2+1] + ja jmp_00d8 + +jmp_00b8: + mov64 r5, r1 + add64 r5, r4 + ldxdw r4, [r5+0] + jeq r4, 0, jmp_0120 + +jmp_00d8: + mov64 r1, r4 + mov64 r4, 16 + ldxh r5, [r1+24] + mov64 r0, r2 + jgt r0, r5, jmp_00b8 + mov64 r4, 8 + jlt r0, r5, jmp_00b8 + mov64 r0, 14 + ja jmp_07f8 + +jmp_0120: + stxdw [r10+0], r6 + stxdw [r3+0], r1 + stb [r3+28], 1 + mov64 r4, r2 + ldxh r5, [r1+24] + mov32 r2, 1 + jgt r4, r5, jmp_0160 + mov32 r2, 0 + +jmp_0160: + lsh64 r2, 3 + mov64 r4, r1 + add64 r4, r2 + stxdw [r4+8], r3 + mov64 r0, 0 + +jmp_0188: + ldxb r2, [r1+28] + jeq r2, 0, jmp_07f8 + ldxdw r2, [r1+0] + jeq r2, 0, jmp_0638 + ldxdw r5, [r2+16] + mov32 r4, 1 + jeq r1, r5, jmp_01c8 + mov32 r4, 0 + +jmp_01c8: + mov64 r5, r2 + add64 r5, 8 + mov64 r7, r4 + xor64 r7, 1 + mov64 r8, r7 + lsh64 r8, 3 + mov64 r9, r5 + add64 r9, r8 + ldxdw r9, [r9+0] + jeq r9, 0, jmp_05e8 + ldxb r6, [r9+28] + jeq r6, 0, jmp_05e8 + stb [r1+28], 0 + stb [r9+28], 0 + stb [r2+28], 1 + ldxdw r1, [r2+0] + mov64 r3, r2 + jne r1, 0, jmp_0188 + ja jmp_07f8 + +jmp_0260: + jne r4, 4, jmp_0cb8 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -29,28 +101,28 @@ jmp_0090: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_08a0 + jne r5, 255, jmp_0c98 ldxdw r5, [r4+20760] - jne r5, 14, jmp_08b0 + jne r5, 14, jmp_0ca8 ldxb r5, [r4+31032] - jne r5, 255, jmp_08d0 + jne r5, 255, jmp_0cc8 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 ldxdw r7, [r4+31040] - jne r7, r5, jmp_0400 + jne r7, r5, jmp_07f8 mov32 r5, 1288277025 hor64 r5, 2146519613 ldxdw r7, [r4+31048] - jne r7, r5, jmp_0400 + jne r7, r5, jmp_07f8 mov32 r5, 149871192 hor64 r5, 1157472667 ldxdw r7, [r4+31056] - jne r7, r5, jmp_0400 + jne r7, r5, jmp_07f8 mov64 r7, r2 ldxdw r2, [r4+31064] mov32 r5, -1965433885 - jne r2, r5, jmp_0400 + jne r2, r5, jmp_07f8 ldxdw r2, [r4+31120] lmul64 r2, 29 stxdw [r10+308], r2 @@ -120,57 +192,146 @@ jmp_0090: ldxdw r1, [r8+10424] add64 r1, 29 stxdw [r8+10424], r1 - ldxdw r4, [r8+10448] - mov64 r1, r4 + ldxdw r3, [r8+10448] + mov64 r1, r3 add64 r1, 29 stxdw [r8+10448], r1 mov64 r2, r7 + ldxw r1, [r2+1] + stxw [r3+24], r1 + ldxdw r4, [r6+0] + jne r4, 0, jmp_00a8 -jmp_03d0: - stxdw [r6+0], r4 - ldxh r1, [r2+1] - stxh [r4+24], r1 - ldxh r1, [r2+3] - stxh [r4+26], r1 +jmp_05c0: + stdw [r3+0], 0 + stb [r3+28], 1 + stxdw [r6+0], r3 -jmp_03f8: +jmp_05d8: mov64 r0, 0 + ja jmp_07f8 + +jmp_05e8: + mov64 r9, r1 + add64 r9, r8 + ldxdw r8, [r9+8] + jeq r3, r8, jmp_0648 + mov64 r3, r4 + lsh64 r3, 3 + mov64 r6, r5 + add64 r6, r3 + ldxdw r3, [r6+0] + ja jmp_0720 + +jmp_0638: + stb [r1+28], 0 + ja jmp_07f8 + +jmp_0648: + add64 r9, 8 + mov64 r6, r4 + lsh64 r6, 3 + mov64 r3, r8 + add64 r3, r6 + ldxdw r6, [r3+8] + stxdw [r9+0], r6 + add64 r3, 8 + jeq r6, 0, jmp_0698 + stxdw [r6+0], r1 + +jmp_0698: + stxdw [r3+0], r1 + stxdw [r8+0], r2 + stxdw [r1+0], r8 + ldxdw r6, [r2+16] + mov32 r3, 1 + jeq r1, r6, jmp_06d0 + mov32 r3, 0 + +jmp_06d0: + lsh64 r3, 3 + mov64 r1, r5 + add64 r1, r3 + stxdw [r1+0], r8 + mov64 r1, r4 + lsh64 r1, 3 + mov64 r3, r5 + add64 r3, r1 + ldxdw r3, [r3+0] + mov64 r1, r3 + +jmp_0720: + lsh64 r4, 3 + add64 r5, r4 + lsh64 r7, 3 + mov64 r8, r3 + add64 r8, r7 + ldxdw r4, [r2+0] + ldxdw r7, [r8+8] + stxdw [r5+0], r7 + add64 r8, 8 + jeq r7, 0, jmp_0778 + stxdw [r7+0], r2 + +jmp_0778: + stxdw [r8+0], r2 + stxdw [r3+0], r4 + stxdw [r2+0], r3 + jeq r4, 0, jmp_07d8 + ldxdw r6, [r4+16] + mov32 r5, 1 + jeq r2, r6, jmp_07b8 + mov32 r5, 0 + +jmp_07b8: + lsh64 r5, 3 + add64 r4, r5 + stxdw [r4+8], r3 + ja jmp_07e8 + +jmp_07d8: + ldxdw r4, [r10+0] + stxdw [r4+0], r3 + +jmp_07e8: + stb [r1+28], 0 + stb [r2+28], 1 -jmp_0400: +jmp_07f8: exit -jmp_0408: - jne r5, 0, jmp_08e0 - jne r4, 1, jmp_0860 - jne r3, 4, jmp_0870 +jmp_0800: + jne r5, 0, jmp_0cd8 + jne r3, 1, jmp_0c58 + jne r4, 4, jmp_0c68 ldxdw r2, [r1+88] - jne r2, 0, jmp_0880 + jne r2, 0, jmp_0c78 ldxb r2, [r1+10344] - jne r2, 255, jmp_0890 + jne r2, 255, jmp_0c88 ldxdw r2, [r1+10424] - jne r2, 0, jmp_08f0 + jne r2, 0, jmp_0ce8 ldxb r2, [r1+20680] - jne r2, 255, jmp_08a0 + jne r2, 255, jmp_0c98 ldxdw r2, [r1+20760] - jne r2, 14, jmp_08b0 + jne r2, 14, jmp_0ca8 ldxb r2, [r1+31032] - jne r2, 255, jmp_08d0 + jne r2, 255, jmp_0cc8 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_0400 + jne r3, r2, jmp_07f8 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_0400 + jne r3, r2, jmp_07f8 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_0400 + jne r3, r2, jmp_07f8 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_0400 + jne r2, r3, jmp_07f8 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 @@ -184,16 +345,16 @@ jmp_0408: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_0400 + jne r1, r2, jmp_07f8 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_0400 + jne r1, r2, jmp_07f8 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_0400 + jne r1, r2, jmp_07f8 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_0400 + jne r1, r2, jmp_07f8 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -278,44 +439,44 @@ jmp_0408: mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - ja jmp_03f8 + ja jmp_05d8 -jmp_0860: +jmp_0c58: mov64 r0, 12 - ja jmp_0400 + ja jmp_07f8 -jmp_0870: +jmp_0c68: mov64 r0, 1 - ja jmp_0400 + ja jmp_07f8 -jmp_0880: +jmp_0c78: mov64 r0, 2 - ja jmp_0400 + ja jmp_07f8 -jmp_0890: +jmp_0c88: mov64 r0, 5 - ja jmp_0400 + ja jmp_07f8 -jmp_08a0: +jmp_0c98: mov64 r0, 6 - ja jmp_0400 + ja jmp_07f8 -jmp_08b0: +jmp_0ca8: mov64 r0, 4 - ja jmp_0400 + ja jmp_07f8 -jmp_08c0: +jmp_0cb8: mov64 r0, 13 - ja jmp_0400 + ja jmp_07f8 -jmp_08d0: +jmp_0cc8: mov64 r0, 7 - ja jmp_0400 + ja jmp_07f8 -jmp_08e0: +jmp_0cd8: mov64 r0, 11 - ja jmp_0400 + ja jmp_07f8 -jmp_08f0: +jmp_0ce8: mov64 r0, 3 - ja jmp_0400 + ja jmp_07f8 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 9cec67b9..922b7635 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -228,4 +228,8 @@ .equ TREE_HEADER_NEXT_OFF, 16 # Next node field in header. .equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. .equ TREE_NODE_KEY_OFF, 24 # Node key field. -.equ TREE_NODE_VALUE_OFF, 26 # Node value field. \ No newline at end of file +.equ TREE_NODE_VALUE_OFF, 26 # Node value field. +.equ TREE_NODE_CHILD_L_OFF, 8 # Node left child field. +.equ TREE_NODE_CHILD_R_OFF, 16 # Node right child field. +.equ TREE_NODE_PARENT_OFF, 0 # Node parent field. +.equ TREE_NODE_COLOR_OFF, 28 # Color field. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-allocate.txt b/examples/tree/artifacts/snippets/asm/insert-allocate.txt index d29cd625..3ec3098c 100644 --- a/examples/tree/artifacts/snippets/asm/insert-allocate.txt +++ b/examples/tree/artifacts/snippets/asm/insert-allocate.txt @@ -134,9 +134,14 @@ insert_allocate: # Continue insert. # --------------------------------------------------------------------- - ja insert_mutate_new_node + ja insert_store_key_value_pair insert_pop: + # Pop node from free stack. # --------------------------------------------------------------------- ldxdw r8, [r9 + OFFSET_ZERO] # Load StackNode.next. - stxdw [r1 + IB_TREE_DATA_TOP_OFF], r8 # Update top in header. \ No newline at end of file + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r8 # Update top in header. + +insert_store_key_value_pair: + ldxw r4, [r2 + INSN_INSERT_KEY_OFF] # Load two fields together. + stxw [r9 + TREE_NODE_KEY_OFF], r4 # Store both fields together. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt new file mode 100644 index 00000000..2d56e1e6 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -0,0 +1,19 @@ +insert_search: + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # Get key to insert. + mov64 r2, NULL # Set parent node as null. + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # Get root pointer for cursor. + +insert_search_loop: + jeq r3, NULL, insert_to_tree + mov64 r2, r3 # Update parent to current cursor. + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # Get cursor key. + jlt r4, r5, insert_search_branch_l + jgt r4, r5, insert_search_branch_r + mov64 r0, E_KEY_EXISTS # Error if key already exists. + exit +insert_search_branch_l: + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] + ja insert_search_loop +insert_search_branch_r: + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] + ja insert_search_loop \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt new file mode 100644 index 00000000..5002086f --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt @@ -0,0 +1,11 @@ +insert_to_tree: + # Flag new node as red and store parent pointer. + # --------------------------------------------------------------------- + stxb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # Flag new node as red. + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer + + jne r2, NULL, insert_get_child_dir + exit # Parent is null, new node at root. + +insert_get_child_dir: + exit diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index aaaf4380..af8c71db 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -42,6 +42,7 @@ pub struct TreeHeader { pub next: *mut TreeNode, } +#[array_fields] #[repr(C, packed)] pub struct TreeNode { pub parent: *mut TreeNode, diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index d30bc010..4cea1678 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -1,3 +1,4 @@ + // Shift to get key only, since value is not used in tree logic. let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 02744479..17b2b41b 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,10 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | +| Invalid instruction discriminator | 7 | 12 | +5 | +71.4% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt deleted file mode 100644 index ac84fbbb..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ /dev/null @@ -1,36 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | -| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | -| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | -test tests::test_initialize_create_account ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 -[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt deleted file mode 100644 index aa2dd6c3..00000000 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt deleted file mode 100644 index a7dcd6ae..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ /dev/null @@ -1,122 +0,0 @@ -| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | -|-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 8 | 10 | +2 | +25.0% | -| Too few accounts | 9 | 11 | +2 | +22.2% | -| Too many accounts | 9 | 11 | +2 | +22.2% | -| User has nonzero data length | 11 | 13 | +2 | +18.2% | -| Tree account is duplicate | 13 | 15 | +2 | +15.4% | -| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | -| System program is duplicate | 17 | 19 | +2 | +11.8% | -| System program wrong data length | 19 | 21 | +2 | +10.5% | -| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | -| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | -| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | -test tests::test_initialize_input_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt deleted file mode 100644 index 24226cfc..00000000 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt deleted file mode 100644 index 49588334..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ /dev/null @@ -1,31 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | -| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | -| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | -| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | -test tests::test_initialize_pda_checks ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt deleted file mode 100644 index 0f682d5d..00000000 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt deleted file mode 100644 index 3bde3ef3..00000000 --- a/examples/tree/artifacts/tests/insert/result.txt +++ /dev/null @@ -1,35 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | -| Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | -| Insert skip alloc | 0 | 20 | 25 | +5 | +25.0% | -| Insert alloc happy path | 1096 | 96 | 126 | +30 | +31.2% | -test tests::test_insert ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1192 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1222 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 74b536cc..9a43b1da 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -4,7 +4,7 @@ use crate::bindings::{ SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, }; use crate::common::{ - cpi, CreateAccountInstructionData, GeneralInputBufferHeader, InitInputBuffer, + cpi, CreateAccountInstructionData, Direction, GeneralInputBufferHeader, InitInputBuffer, InitializeInstruction, InputBufferHeader, InsertInstruction, Instruction, TreeHeader, TreeNode, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; @@ -272,4 +272,12 @@ extend_constant_group!(tree { offset!(NODE_KEY, TreeNode.key), /// Node value field. offset!(NODE_VALUE, TreeNode.value), + /// Node left child field. + offset!(NODE_CHILD_L, TreeNode.child[Direction::Left as usize]), + /// Node right child field. + offset!(NODE_CHILD_R, TreeNode.child[Direction::Right as usize]), + /// Node parent field. + offset!(NODE_PARENT, TreeNode.parent), + /// Color field. + offset!(NODE_COLOR, TreeNode.color), }); diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 0b8b7be2..96dd9d48 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,5 +1,5 @@ use core::mem::size_of; -use macros::{constant_group, error_codes}; +use macros::{array_fields, constant_group, error_codes}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, sysvars::rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, @@ -220,6 +220,7 @@ pub struct TreeHeader { pub next: *mut TreeNode, } +#[array_fields] #[repr(C, packed)] pub struct TreeNode { pub parent: *mut TreeNode, diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index aa5ed393..59f14964 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -193,15 +193,19 @@ enum ConstantKind { }, /// Offset derived from struct field path (i16 validated). /// Name gets `_OFF` suffix appended. + /// Supports optional array indexing via `___fields` companion module. Offset { struct_name: Ident, - field_path: Vec, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, }, /// Offset derived from struct field path (i32 validated). /// Name gets `_OFF_IMM` suffix appended. For use as BPF immediate operand. + /// Supports optional array indexing via `___fields` companion module. OffsetImmediate { struct_name: Ident, - field_path: Vec, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. @@ -350,7 +354,7 @@ impl Parse for ConstantGroup { let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let parsed = parse_stack_frame_field_path(&inner)?; + let parsed = parse_indexed_field_path(&inner)?; let _ = content.parse::(); let base_doc = const_doc.trim_end_matches('.'); @@ -424,51 +428,39 @@ impl Parse for ConstantGroup { }, ) } else if ident == "offset" { - // offset!(NAME, Struct.field.nested.path) + // offset!(NAME, Struct.field[expr].nested) content.parse::()?; let inner; syn::parenthesized!(inner in content); let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); ( full_name, ConstantKind::Offset { struct_name, - field_path, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, }, ) } else if ident == "offset_immediate" { - // offset_immediate!(NAME, Struct.field.nested.path) + // offset_immediate!(NAME, Struct.field[expr].nested) content.parse::()?; let inner; syn::parenthesized!(inner in content); let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); ( full_name, ConstantKind::OffsetImmediate { struct_name, - field_path, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, }, ) } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { @@ -480,7 +472,7 @@ impl Parse for ConstantGroup { let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let parsed = parse_stack_frame_field_path(&inner)?; + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); ( full_name, @@ -649,36 +641,40 @@ pub fn constant_group(input: TokenStream) -> TokenStream { } ConstantKind::Offset { struct_name, - field_path, + field_path_tokens, + array_index, } => { let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; + pub const #name: i16 = { use super::*; (#offset_expr) as i16 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), + { use super::*; #offset_expr } >= (i16::MIN as i64) + && { use super::*; #offset_expr } <= (i16::MAX as i64), "Offset must fit in i16 range" ); }); } ConstantKind::OffsetImmediate { struct_name, - field_path, + field_path_tokens, + array_index, } => { let assert_name = Ident::new(&format!("_ASSERT_{}_FITS", name), name.span()); const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + pub const #name: i32 = { use super::*; (#offset_expr) as i32 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + { use super::*; #offset_expr } >= (i32::MIN as i64) + && { use super::*; #offset_expr } <= (i32::MAX as i64), "Offset immediate must fit in i32 range" ); }); @@ -863,16 +859,19 @@ enum AsmConstantKind { Expr(syn::Expr), /// Offset derived from struct field path (i16 validated). /// Name gets `_OFF` suffix appended. - /// Supports nested fields like `Struct.field1.field2.field3`. + /// Supports optional array indexing via `___fields` companion module. Offset { struct_name: Ident, - field_path: Vec, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, }, /// Offset derived from struct field path (i32 validated). /// Name gets `_OFF_IMM` suffix appended. For use as BPF immediate operand. + /// Supports optional array indexing via `___fields` companion module. OffsetImmediate { struct_name: Ident, - field_path: Vec, + field_path_tokens: proc_macro2::TokenStream, + array_index: Option, }, /// Negative offset from end of a stack frame struct (i16 validated). /// Computed as `offset_of!(Struct, field) - size_of::()`. @@ -955,15 +954,15 @@ fn parse_field_path(inner: ParseStream) -> syn::Result Ok(tokens) } -/// Result of parsing a stack frame field path. -struct StackFrameFieldPath { +/// Result of parsing a field path with optional array indexing. +struct IndexedFieldPath { /// Token stream for `offset_of!(Struct, )` (fields before any bracket). field_path_tokens: proc_macro2::TokenStream, /// Optional array index info (bracket expression, inner field access). array_index: Option, } -/// Parse a stack frame field path with optional array indexing and inner field access. +/// Parse a field path with optional array indexing and inner field access. /// /// Supports: /// - `Struct.field` → simple field access @@ -972,8 +971,8 @@ struct StackFrameFieldPath { /// - `Struct.a.b.c` → nested field access (no array) /// /// Array element types are resolved via `___fields::` type aliases -/// generated by `#[stack_frame]`, so the element type is not required in the syntax. -fn parse_stack_frame_field_path(inner: ParseStream) -> syn::Result { +/// generated by `#[stack_frame]` or `#[array_fields]`. +fn parse_indexed_field_path(inner: ParseStream) -> syn::Result { let mut fields: Vec = Vec::new(); let mut tokens = proc_macro2::TokenStream::new(); @@ -1003,7 +1002,7 @@ fn parse_stack_frame_field_path(inner: ParseStream) -> syn::Result syn::Result syn::Result> let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let parsed = parse_stack_frame_field_path(&inner)?; + let parsed = parse_indexed_field_path(&inner)?; let _ = content.parse::(); let base_doc = const_doc.trim_end_matches('.'); @@ -1281,54 +1280,39 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> }, ) } else if ident == "offset" { - // Parse offset!(NAME, Struct.field.nested.path) + // Parse offset!(NAME, Struct.field[expr].nested) content.parse::()?; let inner; syn::parenthesized!(inner in content); let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - // Parse field path (one or more fields separated by dots). - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } - // Append _OFF suffix to the name. + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}_OFF", base_name), base_name.span()); ( full_name, AsmConstantKind::Offset { struct_name, - field_path, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, }, ) } else if ident == "offset_immediate" { - // Parse offset_immediate!(NAME, Struct.field.nested.path) + // Parse offset_immediate!(NAME, Struct.field[expr].nested) content.parse::()?; let inner; syn::parenthesized!(inner in content); let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let mut field_path = Vec::new(); - while inner.peek(Token![.]) { - inner.parse::()?; - field_path.push(inner.parse::()?); - } - if field_path.is_empty() { - return Err(inner.error("Expected at least one field after struct name")); - } - // Append _OFF_IMM suffix to the name. + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}_OFF_IMM", base_name), base_name.span()); ( full_name, AsmConstantKind::OffsetImmediate { struct_name, - field_path, + field_path_tokens: parsed.field_path_tokens, + array_index: parsed.array_index, }, ) } else if ident == "stack_frame_offset" || ident == "stack_frame_offset_unaligned" { @@ -1340,7 +1324,7 @@ fn parse_asm_constants(content: ParseStream) -> syn::Result> let base_name: Ident = inner.parse()?; inner.parse::()?; let struct_name: Ident = inner.parse()?; - let parsed = parse_stack_frame_field_path(&inner)?; + let parsed = parse_indexed_field_path(&inner)?; let full_name = Ident::new(&format!("{}{}", base_name, suffix), base_name.span()); ( full_name, @@ -1416,6 +1400,35 @@ impl Parse for AsmConstantGroupInput { } } +/// Generate an offset expression for a struct field with optional array indexing. +/// +/// Without array index: `offset_of!(super::Struct, field) as i64`. +/// With array index: adds `+ index * Struct::__FIELD_STRIDE` using the hidden +/// associated constant generated by `#[array_fields]`. +fn gen_offset_expr( + struct_name: &Ident, + field_path_tokens: &proc_macro2::TokenStream, + array_index: &Option, +) -> proc_macro2::TokenStream { + match array_index { + Some(info) => { + let array_field_name = &info.array_field_name; + let index_expr = &info.index_expr; + let stride_const = Ident::new( + &format!("__{}_STRIDE", array_field_name.to_string().to_uppercase()), + array_field_name.span(), + ); + quote! { + core::mem::offset_of!(super::#struct_name, #field_path_tokens) as i64 + + (#index_expr) as i64 * (super::#struct_name::#stride_const) as i64 + } + } + None => quote! { + core::mem::offset_of!(super::#struct_name, #field_path_tokens) as i64 + }, + } +} + /// Generate code for a `stack_frame_offset!` constant. /// /// Returns `(const_def_tokens, literal_repr)` where literal_repr is always `None` @@ -1722,33 +1735,36 @@ pub fn asm_constant_group(input: TokenStream) -> TokenStream { } AsmConstantKind::Offset { struct_name, - field_path, + field_path_tokens, + array_index, } => { - // Offsets are computed at runtime, no literal to preserve. const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; + pub const #name: i16 = { use super::*; (#offset_expr) as i16 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), + { use super::*; #offset_expr } >= (i16::MIN as i64) + && { use super::*; #offset_expr } <= (i16::MAX as i64), "Offset must fit in i16 range" ); }); } AsmConstantKind::OffsetImmediate { struct_name, - field_path, + field_path_tokens, + array_index, } => { const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + pub const #name: i32 = { use super::*; (#offset_expr) as i32 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + { use super::*; #offset_expr } >= (i32::MIN as i64) + && { use super::*; #offset_expr } <= (i32::MAX as i64), "Offset immediate must fit in i32 range" ); }); @@ -1998,33 +2014,36 @@ pub fn extend_constant_group(input: TokenStream) -> TokenStream { } AsmConstantKind::Offset { struct_name, - field_path, + field_path_tokens, + array_index, } => { - // Offsets are computed at runtime, no literal to preserve. const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i16 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i16; + pub const #name: i16 = { use super::*; (#offset_expr) as i16 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i16::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i16::MAX as i64), + { use super::*; #offset_expr } >= (i16::MIN as i64) + && { use super::*; #offset_expr } <= (i16::MAX as i64), "Offset must fit in i16 range" ); }); } AsmConstantKind::OffsetImmediate { struct_name, - field_path, + field_path_tokens, + array_index, } => { const_value_strs.push(None); + let offset_expr = gen_offset_expr(struct_name, field_path_tokens, array_index); const_defs.push(quote! { #[doc = #doc] - pub const #name: i32 = core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i32; + pub const #name: i32 = { use super::*; (#offset_expr) as i32 }; const #assert_name: () = assert!( - (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) >= (i32::MIN as i64) - && (core::mem::offset_of!(super::#struct_name, #(#field_path).*) as i64) <= (i32::MAX as i64), + { use super::*; #offset_expr } >= (i32::MIN as i64) + && { use super::*; #offset_expr } <= (i32::MAX as i64), "Offset immediate must fit in i32 range" ); }); @@ -2411,6 +2430,37 @@ pub fn pubkey_chunk_group(_input: TokenStream) -> TokenStream { /// pub type data = u8; /// } /// ``` +/// Generate the `___fields` companion module containing type +/// aliases for each array field's element type. +fn gen_fields_module(input: &syn::ItemStruct) -> proc_macro2::TokenStream { + let struct_name = &input.ident; + let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); + + let mut type_aliases = Vec::new(); + if let syn::Fields::Named(ref fields) = input.fields { + for field in &fields.named { + if let Some(ref field_name) = field.ident { + if let syn::Type::Array(array_type) = &field.ty { + let elem_type = &*array_type.elem; + type_aliases.push(quote! { + #[allow(non_camel_case_types)] + pub type #field_name = #elem_type; + }); + } + } + } + } + + quote! { + #[doc(hidden)] + #[allow(non_snake_case)] + pub mod #fields_mod { + use super::*; + #(#type_aliases)* + } + } +} + #[proc_macro_attribute] pub fn stack_frame(_attr: TokenStream, item: TokenStream) -> TokenStream { let mut input = parse_macro_input!(item as syn::ItemStruct); @@ -2418,19 +2468,60 @@ pub fn stack_frame(_attr: TokenStream, item: TokenStream) -> TokenStream { // Remove existing repr attributes to avoid conflicts. input.attrs.retain(|attr| !attr.path().is_ident("repr")); + let fields_mod = gen_fields_module(&input); + + let expanded = quote! { + #[repr(C, align(8))] + #input + + #fields_mod + }; + + TokenStream::from(expanded) +} + +/// Attribute macro that generates hidden associated constants for array field +/// element sizes. +/// +/// Enables `offset!` and `offset_immediate!` to resolve element sizes when +/// using array index syntax (e.g., `Struct.field[expr]`). +/// +/// Unlike `#[stack_frame]`, this does not modify the struct's `#[repr]`. +/// +/// # Example +/// ```ignore +/// #[array_fields] +/// #[repr(C, packed)] +/// struct TreeNode { +/// child: [*mut TreeNode; 2], +/// key: u16, +/// } +/// ``` +/// +/// Generates: +/// ```ignore +/// impl TreeNode { +/// const __CHILD_STRIDE: usize = core::mem::size_of::<*mut TreeNode>(); +/// } +/// ``` +#[proc_macro_attribute] +pub fn array_fields(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as syn::ItemStruct); let struct_name = &input.ident; - let fields_mod = Ident::new(&format!("__{}_fields", struct_name), struct_name.span()); - // Extract array element types for each array field. - let mut type_aliases = Vec::new(); + let mut stride_consts = Vec::new(); if let syn::Fields::Named(ref fields) = input.fields { for field in &fields.named { if let Some(ref field_name) = field.ident { if let syn::Type::Array(array_type) = &field.ty { let elem_type = &*array_type.elem; - type_aliases.push(quote! { - #[allow(non_camel_case_types)] - pub type #field_name = #elem_type; + let const_name = Ident::new( + &format!("__{}_STRIDE", field_name.to_string().to_uppercase()), + field_name.span(), + ); + stride_consts.push(quote! { + #[doc(hidden)] + pub const #const_name: usize = core::mem::size_of::<#elem_type>(); }); } } @@ -2438,14 +2529,12 @@ pub fn stack_frame(_attr: TokenStream, item: TokenStream) -> TokenStream { } let expanded = quote! { - #[repr(C, align(8))] #input #[doc(hidden)] - #[allow(non_snake_case)] - mod #fields_mod { - use super::*; - #(#type_aliases)* + #[allow(dead_code)] + impl #struct_name { + #(#stride_consts)* } }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 32584e17..6ee8440b 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -298,6 +298,7 @@ unsafe fn insert( // ANCHOR_END: insert-allocate // ANCHOR: insert-search + // Shift to get key only, since value is not used in tree logic. let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index f26dc332..feb792ab 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -230,6 +230,10 @@ .equ TREE_DISCRIMINATOR_INSERT, 1 # Discriminator for insert instruction. .equ TREE_NODE_KEY_OFF, 24 # Node key field. .equ TREE_NODE_VALUE_OFF, 26 # Node value field. +.equ TREE_NODE_CHILD_L_OFF, 8 # Node left child field. +.equ TREE_NODE_CHILD_R_OFF, 16 # Node right child field. +.equ TREE_NODE_PARENT_OFF, 0 # Node parent field. +.equ TREE_NODE_COLOR_OFF, 28 # Color field. # ANCHOR_END: constants # ANCHOR: entrypoint-branching @@ -644,26 +648,56 @@ insert_allocate: # Continue insert. # --------------------------------------------------------------------- - ja insert_mutate_new_node + ja insert_store_key_value_pair insert_pop: + # Pop node from free stack. # --------------------------------------------------------------------- ldxdw r8, [r9 + OFFSET_ZERO] # Load StackNode.next. stxdw [r1 + IB_TREE_DATA_TOP_OFF], r8 # Update top in header. + +insert_store_key_value_pair: + ldxw r4, [r2 + INSN_INSERT_KEY_OFF] # Load two fields together. + stxw [r9 + TREE_NODE_KEY_OFF], r4 # Store both fields together. # ANCHOR_END: insert-allocate -insert_mutate_new_node: - # Set node as root of tree. - # --------------------------------------------------------------------- - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 +# ANCHOR: insert-search +insert_search: + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # Get key to insert. + mov64 r2, NULL # Set parent node as null. + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # Get root pointer for cursor. + +insert_search_loop: + jeq r3, NULL, insert_to_tree + mov64 r2, r3 # Update parent to current cursor. + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # Get cursor key. + jlt r4, r5, insert_search_branch_l + jgt r4, r5, insert_search_branch_r + mov64 r0, E_KEY_EXISTS # Error if key already exists. + exit +insert_search_branch_l: + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] + ja insert_search_loop +insert_search_branch_r: + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] + ja insert_search_loop +# ANCHOR_END: insert-search - # Set key and value from instruction data. +# ANCHOR: insert-to-tree +insert_to_tree: + # Flag new node as red and store parent pointer. # --------------------------------------------------------------------- - ldxw r4, [r2 + INSN_INSERT_KEY_OFF] # Load two fields together. - stxw [r9 + TREE_NODE_KEY_OFF], r4 # Store both fields together. + stxb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # Flag new node as red. + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer + jne r2, NULL, insert_get_child_dir + exit # Parent is null, new node at root. + +insert_get_child_dir: exit +# ANCHOR_END: insert-to-tree + e_instruction_data: mov64 r0, E_INSTRUCTION_DATA exit From 75b0ae8d43b452805c25b53d532dbdf3d26be83c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 19:35:49 -0700 Subject: [PATCH 192/263] Fix insert search algo --- examples/tree/artifacts/dumps/asm.txt | 155 ++++++++++-------- .../artifacts/snippets/asm/insert-to-tree.txt | 1 + .../artifacts/snippets/rs/insert-search.txt | 1 - examples/tree/src/program.rs | 1 - examples/tree/src/tree/tree.s | 1 + 5 files changed, 89 insertions(+), 70 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index e9d6e912..ebb2c68f 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 2520 (bytes into file) + Start of section headers 2672 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x9d8 +There are 7 section headers, starting at offset 0xa70 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000750 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000838 000838 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000008d8 0008d8 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000938 000938 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000978 000978 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 0009a8 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 0007e8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000008d0 0008d0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000970 000970 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000009d0 0009d0 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000a10 000a10 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000a40 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000750 0x000750 R E 0x1000 - LOAD 0x0008d8 0x00000000000008d8 0x00000000000008d8 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000838 0x0000000000000838 0x0000000000000838 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0007e8 0x0007e8 R E 0x1000 + LOAD 0x000970 0x0000000000000970 0x0000000000000970 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x0008d0 0x00000000000008d0 0x00000000000008d0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x838 contains 10 entries +Dynamic section at offset 0x8d0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x978 + 0x0000000000000011 (REL) 0xa10 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x8d8 + 0x0000000000000006 (SYMTAB) 0x970 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x938 + 0x0000000000000005 (STRTAB) 0x9d0 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x978 contains 3 entries +Relocation section '.rel.dyn' at offset 0xa10 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 cc 00 01 00 00 00 if r9 != 0x1 goto +0xcc - 37 55 08 cd 00 04 00 00 00 if r8 != 0x4 goto +0xcd + 36 55 09 df 00 01 00 00 00 if r9 != 0x1 goto +0xdf + 37 55 08 e0 00 04 00 00 00 if r8 != 0x4 goto +0xe0 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 dd 00 00 00 00 00 if r9 != 0x0 goto +0xdd + 39 55 09 f0 00 00 00 00 00 if r9 != 0x0 goto +0xf0 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 d9 00 ff 00 00 00 if r9 != 0xff goto +0xd9 + 41 55 09 ec 00 ff 00 00 00 if r9 != 0xff goto +0xec 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 d5 00 00 00 00 00 if r9 != 0x0 goto +0xd5 + 43 55 09 e8 00 00 00 00 00 if r9 != 0x0 goto +0xe8 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 d1 00 ff 00 00 00 if r9 != 0xff goto +0xd1 + 45 55 09 e4 00 ff 00 00 00 if r9 != 0xff goto +0xe4 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 cd 00 0e 00 00 00 if r9 != 0xe goto +0xcd + 47 55 09 e0 00 0e 00 00 00 if r9 != 0xe goto +0xe0 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 c9 00 ff 00 00 00 if r9 != 0xff goto +0xc9 + 49 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 c3 00 00 00 00 00 if r9 != r8 goto +0xc3 + 53 5d 89 d6 00 00 00 00 00 if r9 != r8 goto +0xd6 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 bf 00 00 00 00 00 if r9 != r8 goto +0xbf + 57 5d 89 d2 00 00 00 00 00 if r9 != r8 goto +0xd2 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb + 61 5d 89 ce 00 00 00 00 00 if r9 != r8 goto +0xce 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 b8 00 00 00 00 00 if r9 != r8 goto +0xb8 + 64 5d 89 cb 00 00 00 00 00 if r9 != r8 goto +0xcb 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 ab 00 00 00 00 00 if r9 != r8 goto +0xab + 75 5d 89 be 00 00 00 00 00 if r9 != r8 goto +0xbe 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 a8 00 00 00 00 00 if r9 != r8 goto +0xa8 + 78 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 a5 00 00 00 00 00 if r9 != r8 goto +0xa5 + 81 5d 89 b8 00 00 00 00 00 if r9 != r8 goto +0xb8 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 a2 00 00 00 00 00 if r9 != r8 goto +0xa2 + 84 5d 89 b5 00 00 00 00 00 if r9 != r8 goto +0xb5 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 5f 00 05 00 00 00 if r9 != 0x5 goto +0x5f - 146 a5 08 60 00 02 00 00 00 if r8 < 0x2 goto +0x60 + 145 55 09 72 00 05 00 00 00 if r9 != 0x5 goto +0x72 + 146 a5 08 73 00 02 00 00 00 if r8 < 0x2 goto +0x73 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 70 00 00 00 00 00 if r9 != 0x0 goto +0x70 + 148 55 09 83 00 00 00 00 00 if r9 != 0x0 goto +0x83 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 6c 00 ff 00 00 00 if r9 != 0xff goto +0x6c + 150 55 09 7f 00 ff 00 00 00 if r9 != 0xff goto +0x7f 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 5b 00 04 00 00 00 if r8 != 0x4 goto +0x5b + 153 55 08 6e 00 04 00 00 00 if r8 != 0x4 goto +0x6e 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 5d 00 ff 00 00 00 if r8 != 0xff goto +0x5d + 161 55 08 70 00 ff 00 00 00 if r8 != 0xff goto +0x70 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 59 00 0e 00 00 00 if r8 != 0xe goto +0x59 + 163 55 08 6c 00 0e 00 00 00 if r8 != 0xe goto +0x6c 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 55 00 ff 00 00 00 if r8 != 0xff goto +0x55 + 165 55 08 68 00 ff 00 00 00 if r8 != 0xff goto +0x68 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 4f 00 00 00 00 00 if r8 != r4 goto +0x4f + 169 5d 48 62 00 00 00 00 00 if r8 != r4 goto +0x62 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 4b 00 00 00 00 00 if r8 != r4 goto +0x4b + 173 5d 48 5e 00 00 00 00 00 if r8 != r4 goto +0x5e 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 47 00 00 00 00 00 if r8 != r4 goto +0x47 + 177 5d 48 5a 00 00 00 00 00 if r8 != r4 goto +0x5a 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 44 00 00 00 00 00 if r8 != r4 goto +0x44 + 180 5d 48 57 00 00 00 00 00 if r8 != r4 goto +0x57 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -287,28 +287,47 @@ Disassembly of section .text 235 7b 81 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r8 236 61 24 01 00 00 00 00 00 r4 = *(u32 *)(r2 + 0x1) 237 63 49 18 00 00 00 00 00 *(u32 *)(r9 + 0x18) = r4 - 238 95 00 00 00 00 00 00 00 exit - 239 b7 00 00 00 09 00 00 00 r0 = 0x9 - 240 95 00 00 00 00 00 00 00 exit - 241 b7 00 00 00 0c 00 00 00 r0 = 0xc - 242 95 00 00 00 00 00 00 00 exit - 243 b7 00 00 00 01 00 00 00 r0 = 0x1 - 244 95 00 00 00 00 00 00 00 exit - 245 b7 00 00 00 0d 00 00 00 r0 = 0xd - 246 95 00 00 00 00 00 00 00 exit - 247 b7 00 00 00 0a 00 00 00 r0 = 0xa - 248 95 00 00 00 00 00 00 00 exit - 249 b7 00 00 00 08 00 00 00 r0 = 0x8 - 250 95 00 00 00 00 00 00 00 exit - 251 b7 00 00 00 07 00 00 00 r0 = 0x7 - 252 95 00 00 00 00 00 00 00 exit - 253 b7 00 00 00 04 00 00 00 r0 = 0x4 - 254 95 00 00 00 00 00 00 00 exit - 255 b7 00 00 00 06 00 00 00 r0 = 0x6 + 238 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) + 239 b7 02 00 00 00 00 00 00 r2 = 0x0 + 240 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) + 241 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa + 242 bf 32 00 00 00 00 00 00 r2 = r3 + 243 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) + 244 ad 54 03 00 00 00 00 00 if r4 < r5 goto +0x3 + 245 2d 54 04 00 00 00 00 00 if r4 > r5 goto +0x4 + 246 b7 00 00 00 0e 00 00 00 r0 = 0xe + 247 95 00 00 00 00 00 00 00 exit + 248 79 33 08 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x8) + 249 05 00 f7 ff 00 00 00 00 goto -0x9 + 250 79 33 10 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x10) + 251 05 00 f5 ff 00 00 00 00 goto -0xb + 252 73 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = r0 + 253 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 254 55 02 02 00 00 00 00 00 if r2 != 0x0 goto +0x2 + 255 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 256 95 00 00 00 00 00 00 00 exit - 257 b7 00 00 00 03 00 00 00 r0 = 0x3 - 258 95 00 00 00 00 00 00 00 exit - 259 b7 00 00 00 05 00 00 00 r0 = 0x5 - 260 95 00 00 00 00 00 00 00 exit - 261 b7 00 00 00 02 00 00 00 r0 = 0x2 - 262 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 257 95 00 00 00 00 00 00 00 exit + 258 b7 00 00 00 09 00 00 00 r0 = 0x9 + 259 95 00 00 00 00 00 00 00 exit + 260 b7 00 00 00 0c 00 00 00 r0 = 0xc + 261 95 00 00 00 00 00 00 00 exit + 262 b7 00 00 00 01 00 00 00 r0 = 0x1 + 263 95 00 00 00 00 00 00 00 exit + 264 b7 00 00 00 0d 00 00 00 r0 = 0xd + 265 95 00 00 00 00 00 00 00 exit + 266 b7 00 00 00 0a 00 00 00 r0 = 0xa + 267 95 00 00 00 00 00 00 00 exit + 268 b7 00 00 00 08 00 00 00 r0 = 0x8 + 269 95 00 00 00 00 00 00 00 exit + 270 b7 00 00 00 07 00 00 00 r0 = 0x7 + 271 95 00 00 00 00 00 00 00 exit + 272 b7 00 00 00 04 00 00 00 r0 = 0x4 + 273 95 00 00 00 00 00 00 00 exit + 274 b7 00 00 00 06 00 00 00 r0 = 0x6 + 275 95 00 00 00 00 00 00 00 exit + 276 b7 00 00 00 03 00 00 00 r0 = 0x3 + 277 95 00 00 00 00 00 00 00 exit + 278 b7 00 00 00 05 00 00 00 r0 = 0x5 + 279 95 00 00 00 00 00 00 00 exit + 280 b7 00 00 00 02 00 00 00 r0 = 0x2 + 281 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt index 5002086f..b15608a5 100644 --- a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt +++ b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt @@ -5,6 +5,7 @@ insert_to_tree: stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer jne r2, NULL, insert_get_child_dir + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # Store new node as root. exit # Parent is null, new node at root. insert_get_child_dir: diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index 4cea1678..d30bc010 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -1,4 +1,3 @@ - // Shift to get key only, since value is not used in tree logic. let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 6ee8440b..32584e17 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -298,7 +298,6 @@ unsafe fn insert( // ANCHOR_END: insert-allocate // ANCHOR: insert-search - // Shift to get key only, since value is not used in tree logic. let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index feb792ab..aa1b99dd 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -691,6 +691,7 @@ insert_to_tree: stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer jne r2, NULL, insert_get_child_dir + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # Store new node as root. exit # Parent is null, new node at root. insert_get_child_dir: From 3b00e53225d371b917247e071c453780a23cab79 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 19:36:02 -0700 Subject: [PATCH 193/263] REbuild exampels --- .../initialize_create_account/result.txt | 36 ++++++ .../tests/initialize_create_account/test.txt | 4 + .../tests/initialize_input_checks/result.txt | 122 ++++++++++++++++++ .../tests/initialize_input_checks/test.txt | 4 + .../tests/initialize_pda_checks/result.txt | 31 +++++ .../tests/initialize_pda_checks/test.txt | 4 + .../tree/artifacts/tests/insert/result.txt | 35 +++++ .../tests/insert_alloc_checks/result.txt | 59 +++++++++ .../tests/insert_alloc_checks/test.txt | 4 + .../artifacts/tests/insert_search/result.txt | 24 ++++ .../artifacts/tests/insert_search/test.txt | 4 + .../artifacts/tests/insert_to_tree/test.txt | 4 + 12 files changed, 331 insertions(+) create mode 100644 examples/tree/artifacts/tests/initialize_create_account/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_create_account/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/result.txt create mode 100644 examples/tree/artifacts/tests/initialize_pda_checks/test.txt create mode 100644 examples/tree/artifacts/tests/insert/result.txt create mode 100644 examples/tree/artifacts/tests/insert_alloc_checks/result.txt create mode 100644 examples/tree/artifacts/tests/insert_alloc_checks/test.txt create mode 100644 examples/tree/artifacts/tests/insert_search/result.txt create mode 100644 examples/tree/artifacts/tests/insert_search/test.txt create mode 100644 examples/tree/artifacts/tests/insert_to_tree/test.txt diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt new file mode 100644 index 00000000..e06b9339 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -0,0 +1,36 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| System Program is wrong address | 2446 | 107 | 140 | +33 | +30.8% | +| User has insufficient Lamports | 2596 | 107 | 140 | +33 | +30.8% | +| CreateAccount happy path | 2596 | 111 | 149 | +38 | +34.2% | +test tests::test_initialize_create_account ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 +[ ... DEBUG ... ] Program DASMAC... consumed 2586 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 +[ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... consumed 2736 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 2745 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt new file mode 100644 index 00000000..aa2dd6c3 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_create_account() { + print_comparison_table(init::InitCase::CPI_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt new file mode 100644 index 00000000..278c543a --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -0,0 +1,122 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Invalid instruction data length | 8 | 13 | +5 | +62.5% | +| Too few accounts | 9 | 14 | +5 | +55.6% | +| Too many accounts | 9 | 14 | +5 | +55.6% | +| User has nonzero data length | 11 | 16 | +5 | +45.5% | +| Tree account is duplicate | 13 | 18 | +5 | +38.5% | +| Tree has nonzero data length | 15 | 20 | +5 | +33.3% | +| System program is duplicate | 17 | 22 | +5 | +29.4% | +| System program wrong data length | 19 | 24 | +5 | +26.3% | +| Rent sysvar is duplicate | 21 | 26 | +5 | +23.8% | +| Rent address mismatch word 0 | 24 | 28 | +4 | +16.7% | +| Rent address mismatch word 1 | 24 | 28 | +4 | +16.7% | +| Rent address mismatch word 2 | 27 | 32 | +5 | +18.5% | +| Rent address mismatch word 3 | 27 | 32 | +5 | +18.5% | +| Rent address mismatch word 4 | 30 | 36 | +6 | +20.0% | +| Rent address mismatch word 5 | 30 | 36 | +6 | +20.0% | +| Rent address mismatch word 6 | 33 | 39 | +6 | +18.2% | +| Rent address mismatch word 7 | 33 | 39 | +6 | +18.2% | +test tests::test_initialize_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt new file mode 100644 index 00000000..24226cfc --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_input_checks() { + print_comparison_table(init::InitCase::CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt new file mode 100644 index 00000000..8a45a489 --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -0,0 +1,31 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| PDA mismatch chunk 1 | 1500 | 44 | 56 | +12 | +27.3% | +| PDA mismatch chunk 2 | 1500 | 47 | 59 | +12 | +25.5% | +| PDA mismatch chunk 3 | 1500 | 50 | 62 | +12 | +24.0% | +| PDA mismatch chunk 4 | 1500 | 53 | 65 | +12 | +22.6% | +test tests::test_initialize_pda_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1562 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 1565 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt new file mode 100644 index 00000000..0f682d5d --- /dev/null +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_initialize_pda_checks() { + print_comparison_table(init::InitCase::PDA_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt new file mode 100644 index 00000000..77112f51 --- /dev/null +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -0,0 +1,35 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| Instruction data too short | 0 | 7 | 12 | +5 | +71.4% | +| Instruction data too long | 0 | 7 | 12 | +5 | +71.4% | +| Insert skip alloc | 0 | 25 | 29 | +4 | +16.0% | +| Insert alloc happy path | 1096 | 101 | 134 | +33 | +32.7% | +test tests::test_insert ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1197 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1230 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc_checks/result.txt b/examples/tree/artifacts/tests/insert_alloc_checks/result.txt new file mode 100644 index 00000000..e20d8d5c --- /dev/null +++ b/examples/tree/artifacts/tests/insert_alloc_checks/result.txt @@ -0,0 +1,59 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Wrong N accounts for allocation | 15 | 22 | +7 | +46.7% | +| System program is duplicate | 23 | 30 | +7 | +30.4% | +| System program wrong data length | 25 | 32 | +7 | +28.0% | +| Rent sysvar is duplicate | 27 | 34 | +7 | +25.9% | +| Rent address mismatch chunk 0 | 30 | 36 | +6 | +20.0% | +| Rent address mismatch chunk 1 | 33 | 40 | +7 | +21.2% | +| Rent address mismatch chunk 2 | 36 | 44 | +8 | +22.2% | +| Rent address mismatch chunk 3 | 39 | 49 | +10 | +25.6% | +test tests::test_insert_alloc_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc_checks/test.txt b/examples/tree/artifacts/tests/insert_alloc_checks/test.txt new file mode 100644 index 00000000..cd77af95 --- /dev/null +++ b/examples/tree/artifacts/tests/insert_alloc_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert_alloc_checks() { + print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/result.txt b/examples/tree/artifacts/tests/insert_search/result.txt new file mode 100644 index 00000000..afc8e18a --- /dev/null +++ b/examples/tree/artifacts/tests/insert_search/result.txt @@ -0,0 +1,24 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Dup at root | 26 | 36 | +10 | +38.5% | +| Dup in left | 32 | 47 | +15 | +46.9% | +| Dup in right | 33 | 45 | +12 | +36.4% | +test tests::test_insert_search ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/test.txt b/examples/tree/artifacts/tests/insert_search/test.txt new file mode 100644 index 00000000..25cfad66 --- /dev/null +++ b/examples/tree/artifacts/tests/insert_search/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert_search() { + print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, true, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/test.txt b/examples/tree/artifacts/tests/insert_to_tree/test.txt new file mode 100644 index 00000000..666754d2 --- /dev/null +++ b/examples/tree/artifacts/tests/insert_to_tree/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert_to_tree() { + print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, true, false); +} \ No newline at end of file From 49829d2a7b695d4769aa070bd9fd65ea86761234 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 19:36:10 -0700 Subject: [PATCH 194/263] Check in result --- .../artifacts/tests/insert_to_tree/result.txt | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 examples/tree/artifacts/tests/insert_to_tree/result.txt diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt new file mode 100644 index 00000000..742373ab --- /dev/null +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -0,0 +1,155 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Empty tree | 25 | 29 | +4 | +16.0% | + (ASM) Empty tree: N0.color: expected R, got B +| Case 1: left child | 30 | 52 | +22 | +73.3% | + (ASM) Case 1: left child: N0.L: expected 0x4000028f5, got 0x0; N1.color: expected R, got B +| Case 1: right child | 31 | 49 | +18 | +58.1% | + (ASM) Case 1: right child: N0.R: expected 0x4000028f5, got 0x0; N1.color: expected R, got B +| Case 4: left child | 30 | 56 | +26 | +86.7% | + (ASM) Case 4: left child: N0.L: expected 0x4000028f5, got 0x0; N0.color: expected B, got R; N1.color: expected R, got B +| Case 4: right child | 31 | 53 | +22 | +71.0% | + (ASM) Case 4: right child: N0.R: expected 0x4000028f5, got 0x0; N0.color: expected B, got R; N1.color: expected R, got B +| Case 2+3: left-left | 36 | 88 | +52 | +144.4% | + (ASM) Case 2+3: left-left: N0.color: expected R, got B; N1.L: expected 0x40000292f, got 0x0; N1.color: expected B, got R; N2.color: expected B, got R; N3.color: expected R, got B +| Case 2+3: left-right | 37 | 85 | +48 | +129.7% | + (ASM) Case 2+3: left-right: N0.color: expected R, got B; N1.R: expected 0x40000292f, got 0x0; N1.color: expected B, got R; N2.color: expected B, got R; N3.color: expected R, got B +| Case 2+3: right-left | 37 | 85 | +48 | +129.7% | + (ASM) Case 2+3: right-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.L: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B +| Case 2+3: right-right | 38 | 82 | +44 | +115.8% | + (ASM) Case 2+3: right-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.R: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B +| Case 2+1: left | 42 | 102 | +60 | +142.9% | + (ASM) Case 2+1: left: N1.color: expected R, got B; N2.L: expected 0x40000294c, got 0x0; N2.color: expected B, got R; N3.color: expected B, got R; N4.color: expected R, got B +| Case 2+1: right | 45 | 94 | +49 | +108.9% | + (ASM) Case 2+1: right: N1.color: expected R, got B; N2.color: expected B, got R; N3.R: expected 0x40000294c, got 0x0; N3.color: expected B, got R; N4.color: expected R, got B +| Case 6: left-left null uncle | 36 | 109 | +73 | +202.8% | + (ASM) Case 6: left-left null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x400002912, got 0x0; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R; N2.color: expected R, got B +| Case 6: right-right null uncle | 38 | 103 | +65 | +171.1% | + (ASM) Case 6: right-right null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x4000028d8, got 0x0; N1.R: expected 0x400002912, got 0x0; N1.color: expected B, got R; N2.color: expected R, got B +| Case 6: left-left black uncle | 36 | 111 | +75 | +208.3% | + (ASM) Case 6: left-left black uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x40000292f, got 0x0; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R; N3.color: expected R, got B +| Case 6: right-right black uncle | 38 | 105 | +67 | +176.3% | + (ASM) Case 6: right-right black uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x0, got 0x4000028d8; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B +| Case 5+6: left-right null uncle | 37 | 130 | +93 | +251.4% | + (ASM) Case 5+6: left-right null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028f5, got 0x0; N2.R: expected 0x4000028d8, got 0x0 +| Case 5+6: right-left null uncle | 37 | 130 | +93 | +251.4% | + (ASM) Case 5+6: right-left null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x4000028f5, got 0x0 +| Case 5+6: left-right black uncle | 37 | 132 | +95 | +256.8% | + (ASM) Case 5+6: left-right black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x40000292f, got 0x4000028d8; N3.parent: expected 0x0, got 0x4000028f5; N3.L: expected 0x4000028f5, got 0x0; N3.R: expected 0x4000028d8, got 0x0 +| Case 5+6: right-left black uncle | 37 | 132 | +95 | +256.8% | + (ASM) Case 5+6: right-left black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x40000292f, got 0x4000028d8; N3.parent: expected 0x0, got 0x400002912; N3.L: expected 0x4000028d8, got 0x0; N3.R: expected 0x400002912, got 0x0 +test tests::test_insert_to_tree ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 94 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 111 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file From 2aa3e533c9ceebd2c7026ab659e3bc085ba3955d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:29:30 -0700 Subject: [PATCH 195/263] Continue with asm impl --- examples/tree/src/program.rs | 9 +++--- examples/tree/src/tests.rs | 2 +- examples/tree/src/tree/tree.s | 54 ++++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 32584e17..e6a592f5 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -326,16 +326,17 @@ unsafe fn insert( (*tree_header).root = node; return SUCCESS; } + // ANCHOR_END: insert-to-tree + // ANCHOR: insert-fixup // Get child direction, set at parent. - let mut dir = if (key > (*parent).key) { + let dir = if (key > (*parent).key) { tree::DIR_R } else { tree::DIR_L }; (*parent).child[dir] = node; - // Rebalance the tree. loop { // Case 1. if (*parent).color == Color::Black { @@ -349,7 +350,7 @@ unsafe fn insert( return SUCCESS; } - dir = direction(parent) as usize; + let dir = direction(parent) as usize; let uncle = (*grandparent).child[opposite(dir)]; if uncle.is_null() || (*uncle).color == Color::Black { // Case 5. @@ -379,8 +380,8 @@ unsafe fn insert( } // Case 3. SUCCESS - // ANCHOR_END: insert-to-tree } +// ANCHOR_END: insert-fixup // ANCHOR: initialize-input-checks #[inline(always)] diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 1bd74bdf..1ca2297e 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -195,7 +195,7 @@ fn test_initialize_create_account() { #[test] fn test_insert_search() { - print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, true, false); + print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, false, false); } #[test] diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index aa1b99dd..a7b440a0 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -663,23 +663,23 @@ insert_store_key_value_pair: # ANCHOR: insert-search insert_search: - ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # Get key to insert. - mov64 r2, NULL # Set parent node as null. - ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # Get root pointer for cursor. + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; + mov64 r2, NULL # r2 = parent = null; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; insert_search_loop: jeq r3, NULL, insert_to_tree - mov64 r2, r3 # Update parent to current cursor. - ldxh r5, [r3 + TREE_NODE_KEY_OFF] # Get cursor key. + mov64 r2, r3 # r2 = parent = cursor; + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; ja insert_search_loop # ANCHOR_END: insert-search @@ -687,17 +687,49 @@ insert_search_branch_r: insert_to_tree: # Flag new node as red and store parent pointer. # --------------------------------------------------------------------- - stxb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # Flag new node as red. - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + # Handle case of new node at root. + # --------------------------------------------------------------------- jne r2, NULL, insert_get_child_dir - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # Store new node as root. + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; exit # Parent is null, new node at root. +# ANCHOR_END: insert-to-tree +# ANCHOR: insert-fixup insert_get_child_dir: + # Get child direction, set at parent. + # --------------------------------------------------------------------- + ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; + jgt r4, r5, insert_get_child_dir_branch_r +insert_get_child_dir_branch_l: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + ja insert_fixup_main +insert_get_child_dir_branch_r: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + +insert_fixup_main: + # Case 1. + # --------------------------------------------------------------------- + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + jne r6, TREE_COLOR_B, insert_fixup_check_case_4 + exit # If parent is black, tree is still valid, so exit. + +insert_fixup_check_case_4: + # Check case 4. + # --------------------------------------------------------------------- + ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; + jne r3, NULL, insert_fixup_check_case_5_6 + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; exit -# ANCHOR_END: insert-to-tree +insert_fixup_check_case_5_6: + # Get parent's direction as a child. + # --------------------------------------------------------------------- + exit +# ANCHOR_END: insert-fixup + e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From d2ceba760a4d673c4c347f3f8b369dd6d9cbf697 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:30:57 -0700 Subject: [PATCH 196/263] Rebuild --- examples/tree/artifacts/dumps/asm.txt | 140 ++++++++++-------- .../artifacts/snippets/asm/insert-fixup.txt | 30 ++++ .../artifacts/snippets/asm/insert-search.txt | 14 +- .../artifacts/snippets/asm/insert-to-tree.txt | 13 +- .../artifacts/snippets/rs/insert-fixup.txt | 54 +++++++ .../artifacts/snippets/rs/insert-to-tree.txt | 55 +------ .../artifacts/tests/insert_search/test.txt | 2 +- .../artifacts/tests/insert_to_tree/result.txt | 105 +++++++------ examples/tree/src/program.rs | 2 + 9 files changed, 227 insertions(+), 188 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index ebb2c68f..7acae006 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 2672 (bytes into file) + Start of section headers 2768 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xa70 +There are 7 section headers, starting at offset 0xad0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 0007e8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 00000000000008d0 0008d0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000970 000970 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 00000000000009d0 0009d0 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000a10 000a10 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000a40 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000848 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000930 000930 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 00000000000009d0 0009d0 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000a30 000a30 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000a70 000a70 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000aa0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x0007e8 0x0007e8 R E 0x1000 - LOAD 0x000970 0x0000000000000970 0x0000000000000970 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x0008d0 0x00000000000008d0 0x00000000000008d0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000848 0x000848 R E 0x1000 + LOAD 0x0009d0 0x00000000000009d0 0x00000000000009d0 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000930 0x0000000000000930 0x0000000000000930 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x8d0 contains 10 entries +Dynamic section at offset 0x930 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xa10 + 0x0000000000000011 (REL) 0xa70 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x970 + 0x0000000000000006 (SYMTAB) 0x9d0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0x9d0 + 0x0000000000000005 (STRTAB) 0xa30 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xa10 contains 3 entries +Relocation section '.rel.dyn' at offset 0xa70 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 df 00 01 00 00 00 if r9 != 0x1 goto +0xdf - 37 55 08 e0 00 04 00 00 00 if r8 != 0x4 goto +0xe0 + 36 55 09 eb 00 01 00 00 00 if r9 != 0x1 goto +0xeb + 37 55 08 ec 00 04 00 00 00 if r8 != 0x4 goto +0xec 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 f0 00 00 00 00 00 if r9 != 0x0 goto +0xf0 + 39 55 09 fc 00 00 00 00 00 if r9 != 0x0 goto +0xfc 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 ec 00 ff 00 00 00 if r9 != 0xff goto +0xec + 41 55 09 f8 00 ff 00 00 00 if r9 != 0xff goto +0xf8 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 e8 00 00 00 00 00 if r9 != 0x0 goto +0xe8 + 43 55 09 f4 00 00 00 00 00 if r9 != 0x0 goto +0xf4 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 e4 00 ff 00 00 00 if r9 != 0xff goto +0xe4 + 45 55 09 f0 00 ff 00 00 00 if r9 != 0xff goto +0xf0 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 e0 00 0e 00 00 00 if r9 != 0xe goto +0xe0 + 47 55 09 ec 00 0e 00 00 00 if r9 != 0xe goto +0xec 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc + 49 55 09 e8 00 ff 00 00 00 if r9 != 0xff goto +0xe8 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 d6 00 00 00 00 00 if r9 != r8 goto +0xd6 + 53 5d 89 e2 00 00 00 00 00 if r9 != r8 goto +0xe2 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 d2 00 00 00 00 00 if r9 != r8 goto +0xd2 + 57 5d 89 de 00 00 00 00 00 if r9 != r8 goto +0xde 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 ce 00 00 00 00 00 if r9 != r8 goto +0xce + 61 5d 89 da 00 00 00 00 00 if r9 != r8 goto +0xda 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 cb 00 00 00 00 00 if r9 != r8 goto +0xcb + 64 5d 89 d7 00 00 00 00 00 if r9 != r8 goto +0xd7 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 be 00 00 00 00 00 if r9 != r8 goto +0xbe + 75 5d 89 ca 00 00 00 00 00 if r9 != r8 goto +0xca 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 bb 00 00 00 00 00 if r9 != r8 goto +0xbb + 78 5d 89 c7 00 00 00 00 00 if r9 != r8 goto +0xc7 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 b8 00 00 00 00 00 if r9 != r8 goto +0xb8 + 81 5d 89 c4 00 00 00 00 00 if r9 != r8 goto +0xc4 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 b5 00 00 00 00 00 if r9 != r8 goto +0xb5 + 84 5d 89 c1 00 00 00 00 00 if r9 != r8 goto +0xc1 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 72 00 05 00 00 00 if r9 != 0x5 goto +0x72 - 146 a5 08 73 00 02 00 00 00 if r8 < 0x2 goto +0x73 + 145 55 09 7e 00 05 00 00 00 if r9 != 0x5 goto +0x7e + 146 a5 08 7f 00 02 00 00 00 if r8 < 0x2 goto +0x7f 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 83 00 00 00 00 00 if r9 != 0x0 goto +0x83 + 148 55 09 8f 00 00 00 00 00 if r9 != 0x0 goto +0x8f 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 7f 00 ff 00 00 00 if r9 != 0xff goto +0x7f + 150 55 09 8b 00 ff 00 00 00 if r9 != 0xff goto +0x8b 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 6e 00 04 00 00 00 if r8 != 0x4 goto +0x6e + 153 55 08 7a 00 04 00 00 00 if r8 != 0x4 goto +0x7a 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 70 00 ff 00 00 00 if r8 != 0xff goto +0x70 + 161 55 08 7c 00 ff 00 00 00 if r8 != 0xff goto +0x7c 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 6c 00 0e 00 00 00 if r8 != 0xe goto +0x6c + 163 55 08 78 00 0e 00 00 00 if r8 != 0xe goto +0x78 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 68 00 ff 00 00 00 if r8 != 0xff goto +0x68 + 165 55 08 74 00 ff 00 00 00 if r8 != 0xff goto +0x74 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 62 00 00 00 00 00 if r8 != r4 goto +0x62 + 169 5d 48 6e 00 00 00 00 00 if r8 != r4 goto +0x6e 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 5e 00 00 00 00 00 if r8 != r4 goto +0x5e + 173 5d 48 6a 00 00 00 00 00 if r8 != r4 goto +0x6a 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 5a 00 00 00 00 00 if r8 != r4 goto +0x5a + 177 5d 48 66 00 00 00 00 00 if r8 != r4 goto +0x66 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 57 00 00 00 00 00 if r8 != r4 goto +0x57 + 180 5d 48 63 00 00 00 00 00 if r8 != r4 goto +0x63 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -301,33 +301,45 @@ Disassembly of section .text 249 05 00 f7 ff 00 00 00 00 goto -0x9 250 79 33 10 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x10) 251 05 00 f5 ff 00 00 00 00 goto -0xb - 252 73 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = r0 + 252 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 253 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 254 55 02 02 00 00 00 00 00 if r2 != 0x0 goto +0x2 255 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 256 95 00 00 00 00 00 00 00 exit - 257 95 00 00 00 00 00 00 00 exit - 258 b7 00 00 00 09 00 00 00 r0 = 0x9 - 259 95 00 00 00 00 00 00 00 exit - 260 b7 00 00 00 0c 00 00 00 r0 = 0xc - 261 95 00 00 00 00 00 00 00 exit - 262 b7 00 00 00 01 00 00 00 r0 = 0x1 - 263 95 00 00 00 00 00 00 00 exit - 264 b7 00 00 00 0d 00 00 00 r0 = 0xd - 265 95 00 00 00 00 00 00 00 exit - 266 b7 00 00 00 0a 00 00 00 r0 = 0xa - 267 95 00 00 00 00 00 00 00 exit - 268 b7 00 00 00 08 00 00 00 r0 = 0x8 + 257 69 25 18 00 00 00 00 00 r5 = *(u16 *)(r2 + 0x18) + 258 2d 54 02 00 00 00 00 00 if r4 > r5 goto +0x2 + 259 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 + 260 05 00 01 00 00 00 00 00 goto +0x1 + 261 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 + 262 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 263 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 + 264 95 00 00 00 00 00 00 00 exit + 265 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) + 266 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 + 267 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 268 95 00 00 00 00 00 00 00 exit 269 95 00 00 00 00 00 00 00 exit - 270 b7 00 00 00 07 00 00 00 r0 = 0x7 + 270 b7 00 00 00 09 00 00 00 r0 = 0x9 271 95 00 00 00 00 00 00 00 exit - 272 b7 00 00 00 04 00 00 00 r0 = 0x4 + 272 b7 00 00 00 0c 00 00 00 r0 = 0xc 273 95 00 00 00 00 00 00 00 exit - 274 b7 00 00 00 06 00 00 00 r0 = 0x6 + 274 b7 00 00 00 01 00 00 00 r0 = 0x1 275 95 00 00 00 00 00 00 00 exit - 276 b7 00 00 00 03 00 00 00 r0 = 0x3 + 276 b7 00 00 00 0d 00 00 00 r0 = 0xd 277 95 00 00 00 00 00 00 00 exit - 278 b7 00 00 00 05 00 00 00 r0 = 0x5 + 278 b7 00 00 00 0a 00 00 00 r0 = 0xa 279 95 00 00 00 00 00 00 00 exit - 280 b7 00 00 00 02 00 00 00 r0 = 0x2 - 281 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 280 b7 00 00 00 08 00 00 00 r0 = 0x8 + 281 95 00 00 00 00 00 00 00 exit + 282 b7 00 00 00 07 00 00 00 r0 = 0x7 + 283 95 00 00 00 00 00 00 00 exit + 284 b7 00 00 00 04 00 00 00 r0 = 0x4 + 285 95 00 00 00 00 00 00 00 exit + 286 b7 00 00 00 06 00 00 00 r0 = 0x6 + 287 95 00 00 00 00 00 00 00 exit + 288 b7 00 00 00 03 00 00 00 r0 = 0x3 + 289 95 00 00 00 00 00 00 00 exit + 290 b7 00 00 00 05 00 00 00 r0 = 0x5 + 291 95 00 00 00 00 00 00 00 exit + 292 b7 00 00 00 02 00 00 00 r0 = 0x2 + 293 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt new file mode 100644 index 00000000..65ba28b2 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup.txt @@ -0,0 +1,30 @@ +insert_get_child_dir: + # Get child direction, set at parent. + # --------------------------------------------------------------------- + ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; + jgt r4, r5, insert_get_child_dir_branch_r +insert_get_child_dir_branch_l: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + ja insert_fixup_main +insert_get_child_dir_branch_r: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + +insert_fixup_main: + # Case 1. + # --------------------------------------------------------------------- + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + jne r6, TREE_COLOR_B, insert_fixup_check_case_4 + exit # If parent is black, tree is still valid, so exit. + +insert_fixup_check_case_4: + # Check case 4. + # --------------------------------------------------------------------- + ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; + jne r3, NULL, insert_fixup_check_case_5_6 + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + exit + +insert_fixup_check_case_5_6: + # Get parent's direction as a child. + # --------------------------------------------------------------------- + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index 2d56e1e6..b0ae1ffa 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -1,19 +1,19 @@ insert_search: - ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # Get key to insert. - mov64 r2, NULL # Set parent node as null. - ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # Get root pointer for cursor. + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; + mov64 r2, NULL # r2 = parent = null; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; insert_search_loop: jeq r3, NULL, insert_to_tree - mov64 r2, r3 # Update parent to current cursor. - ldxh r5, [r3 + TREE_NODE_KEY_OFF] # Get cursor key. + mov64 r2, r3 # r2 = parent = cursor; + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; ja insert_search_loop \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt index b15608a5..010d124a 100644 --- a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt +++ b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt @@ -1,12 +1,11 @@ insert_to_tree: # Flag new node as red and store parent pointer. # --------------------------------------------------------------------- - stxb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # Flag new node as red. - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # Store parent pointer + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + # Handle case of new node at root. + # --------------------------------------------------------------------- jne r2, NULL, insert_get_child_dir - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # Store new node as root. - exit # Parent is null, new node at root. - -insert_get_child_dir: - exit + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; + exit # Parent is null, new node at root. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup.txt b/examples/tree/artifacts/snippets/rs/insert-fixup.txt new file mode 100644 index 00000000..e951c2d1 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup.txt @@ -0,0 +1,54 @@ + // Get child direction, set at parent. + let dir = if (key > (*parent).key) { + tree::DIR_R + } else { + tree::DIR_L + }; + (*parent).child[dir] = node; + + // Main insert fixup. + loop { + // Case 1. + if (*parent).color == Color::Black { + return SUCCESS; + } + + let grandparent = (*parent).parent; + if grandparent.is_null() { + // Case 4. + (*parent).color = Color::Black; + return SUCCESS; + } + + // Case 5/6. + let dir = direction(parent) as usize; + let uncle = (*grandparent).child[opposite(dir)]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5. + if node == (*parent).child[opposite(dir)] { + rotate_subtree(tree_header, parent, dir); + node = parent; + parent = (*grandparent).child[dir]; + } + + // Case 6. + rotate_subtree(tree_header, grandparent, opposite(dir)); + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + + // Case 2. + (*parent).color = Color::Black; + (*uncle).color = Color::Black; + (*grandparent).color = Color::Red; + node = grandparent; + + parent = (*node).parent; + if parent.is_null() { + break; + } + } + // Case 3. + SUCCESS +} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt index 157c596b..1b058bf8 100644 --- a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt +++ b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt @@ -5,57 +5,4 @@ if parent.is_null() { (*tree_header).root = node; return SUCCESS; - } - - // Get child direction, set at parent. - let mut dir = if (key > (*parent).key) { - tree::DIR_R - } else { - tree::DIR_L - }; - (*parent).child[dir] = node; - - // Rebalance the tree. - loop { - // Case 1. - if (*parent).color == Color::Black { - return SUCCESS; - } - - let grandparent = (*parent).parent; - if grandparent.is_null() { - // Case 4. - (*parent).color = Color::Black; - return SUCCESS; - } - - dir = direction(parent) as usize; - let uncle = (*grandparent).child[opposite(dir)]; - if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5. - if node == (*parent).child[opposite(dir)] { - rotate_subtree(tree_header, parent, dir); - node = parent; - parent = (*grandparent).child[dir]; - } - - // Case 6. - rotate_subtree(tree_header, grandparent, opposite(dir)); - (*parent).color = Color::Black; - (*grandparent).color = Color::Red; - return SUCCESS; - } - - // Case 2. - (*parent).color = Color::Black; - (*uncle).color = Color::Black; - (*grandparent).color = Color::Red; - node = grandparent; - - parent = (*node).parent; - if parent.is_null() { - break; - } - } - // Case 3. - SUCCESS \ No newline at end of file + } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/test.txt b/examples/tree/artifacts/tests/insert_search/test.txt index 25cfad66..06d36d40 100644 --- a/examples/tree/artifacts/tests/insert_search/test.txt +++ b/examples/tree/artifacts/tests/insert_search/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_search() { - print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, true, false); + print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 742373ab..1af0af9a 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,43 +1,38 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | Empty tree | 25 | 29 | +4 | +16.0% | - (ASM) Empty tree: N0.color: expected R, got B -| Case 1: left child | 30 | 52 | +22 | +73.3% | - (ASM) Case 1: left child: N0.L: expected 0x4000028f5, got 0x0; N1.color: expected R, got B -| Case 1: right child | 31 | 49 | +18 | +58.1% | - (ASM) Case 1: right child: N0.R: expected 0x4000028f5, got 0x0; N1.color: expected R, got B -| Case 4: left child | 30 | 56 | +26 | +86.7% | - (ASM) Case 4: left child: N0.L: expected 0x4000028f5, got 0x0; N0.color: expected B, got R; N1.color: expected R, got B -| Case 4: right child | 31 | 53 | +22 | +71.0% | - (ASM) Case 4: right child: N0.R: expected 0x4000028f5, got 0x0; N0.color: expected B, got R; N1.color: expected R, got B -| Case 2+3: left-left | 36 | 88 | +52 | +144.4% | - (ASM) Case 2+3: left-left: N0.color: expected R, got B; N1.L: expected 0x40000292f, got 0x0; N1.color: expected B, got R; N2.color: expected B, got R; N3.color: expected R, got B -| Case 2+3: left-right | 37 | 85 | +48 | +129.7% | - (ASM) Case 2+3: left-right: N0.color: expected R, got B; N1.R: expected 0x40000292f, got 0x0; N1.color: expected B, got R; N2.color: expected B, got R; N3.color: expected R, got B -| Case 2+3: right-left | 37 | 85 | +48 | +129.7% | - (ASM) Case 2+3: right-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.L: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B -| Case 2+3: right-right | 38 | 82 | +44 | +115.8% | - (ASM) Case 2+3: right-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.R: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B -| Case 2+1: left | 42 | 102 | +60 | +142.9% | - (ASM) Case 2+1: left: N1.color: expected R, got B; N2.L: expected 0x40000294c, got 0x0; N2.color: expected B, got R; N3.color: expected B, got R; N4.color: expected R, got B -| Case 2+1: right | 45 | 94 | +49 | +108.9% | - (ASM) Case 2+1: right: N1.color: expected R, got B; N2.color: expected B, got R; N3.R: expected 0x40000294c, got 0x0; N3.color: expected B, got R; N4.color: expected R, got B -| Case 6: left-left null uncle | 36 | 109 | +73 | +202.8% | - (ASM) Case 6: left-left null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x400002912, got 0x0; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R; N2.color: expected R, got B -| Case 6: right-right null uncle | 38 | 103 | +65 | +171.1% | - (ASM) Case 6: right-right null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x4000028d8, got 0x0; N1.R: expected 0x400002912, got 0x0; N1.color: expected B, got R; N2.color: expected R, got B -| Case 6: left-left black uncle | 36 | 111 | +75 | +208.3% | - (ASM) Case 6: left-left black uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x40000292f, got 0x0; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R; N3.color: expected R, got B -| Case 6: right-right black uncle | 38 | 105 | +67 | +176.3% | - (ASM) Case 6: right-right black uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x0, got 0x4000028d8; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x40000292f, got 0x0; N2.color: expected B, got R; N3.color: expected R, got B -| Case 5+6: left-right null uncle | 37 | 130 | +93 | +251.4% | - (ASM) Case 5+6: left-right null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028f5, got 0x0; N2.R: expected 0x4000028d8, got 0x0 -| Case 5+6: right-left null uncle | 37 | 130 | +93 | +251.4% | - (ASM) Case 5+6: right-left null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x4000028f5, got 0x0 -| Case 5+6: left-right black uncle | 37 | 132 | +95 | +256.8% | - (ASM) Case 5+6: left-right black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x40000292f, got 0x4000028d8; N3.parent: expected 0x0, got 0x4000028f5; N3.L: expected 0x4000028f5, got 0x0; N3.R: expected 0x4000028d8, got 0x0 -| Case 5+6: right-left black uncle | 37 | 132 | +95 | +256.8% | - (ASM) Case 5+6: right-left black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x40000292f, got 0x4000028d8; N3.parent: expected 0x0, got 0x400002912; N3.L: expected 0x4000028d8, got 0x0; N3.R: expected 0x400002912, got 0x0 +| Case 1: left child | 36 | 52 | +16 | +44.4% | +| Case 1: right child | 36 | 49 | +13 | +36.1% | +| Case 4: left child | 39 | 56 | +17 | +43.6% | +| Case 4: right child | 39 | 53 | +14 | +35.9% | +| Case 2+3: left-left | 44 | 88 | +44 | +100.0% | + (ASM) Case 2+3: left-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R +| Case 2+3: left-right | 44 | 85 | +41 | +93.2% | + (ASM) Case 2+3: left-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R +| Case 2+3: right-left | 45 | 85 | +40 | +88.9% | + (ASM) Case 2+3: right-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R +| Case 2+3: right-right | 45 | 82 | +37 | +82.2% | + (ASM) Case 2+3: right-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R +| Case 2+1: left | 50 | 102 | +52 | +104.0% | + (ASM) Case 2+1: left: N1.color: expected R, got B; N2.color: expected B, got R; N3.color: expected B, got R +| Case 2+1: right | 52 | 94 | +42 | +80.8% | + (ASM) Case 2+1: right: N1.color: expected R, got B; N2.color: expected B, got R; N3.color: expected B, got R +| Case 6: left-left null uncle | 44 | 109 | +65 | +147.7% | + (ASM) Case 6: left-left null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R +| Case 6: right-right null uncle | 45 | 103 | +58 | +128.9% | + (ASM) Case 6: right-right null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x4000028d8, got 0x0; N1.color: expected B, got R +| Case 6: left-left black uncle | 44 | 111 | +67 | +152.3% | + (ASM) Case 6: left-left black uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R +| Case 6: right-right black uncle | 45 | 105 | +60 | +133.3% | + (ASM) Case 6: right-right black uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x0, got 0x4000028d8; N2.L: expected 0x4000028d8, got 0x0; N2.color: expected B, got R +| Case 5+6: left-right null uncle | 44 | 130 | +86 | +195.5% | + (ASM) Case 5+6: left-right null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N1.R: expected 0x0, got 0x400002912; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028f5, got 0x0; N2.R: expected 0x4000028d8, got 0x0; N2.color: expected B, got R +| Case 5+6: right-left null uncle | 45 | 130 | +85 | +188.9% | + (ASM) Case 5+6: right-left null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N1.L: expected 0x0, got 0x400002912; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x4000028f5, got 0x0; N2.color: expected B, got R +| Case 5+6: left-right black uncle | 44 | 132 | +88 | +200.0% | + (ASM) Case 5+6: left-right black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x40000292f, got 0x4000028d8; N1.R: expected 0x0, got 0x40000292f; N3.parent: expected 0x0, got 0x4000028f5; N3.L: expected 0x4000028f5, got 0x0; N3.R: expected 0x4000028d8, got 0x0; N3.color: expected B, got R +| Case 5+6: right-left black uncle | 45 | 132 | +87 | +193.3% | + (ASM) Case 5+6: right-left black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x40000292f, got 0x4000028d8; N2.L: expected 0x0, got 0x40000292f; N3.parent: expected 0x0, got 0x400002912; N3.L: expected 0x4000028d8, got 0x0; N3.R: expected 0x400002912, got 0x0; N3.color: expected B, got R test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -46,109 +41,109 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 94 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 111 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index e6a592f5..bd141bf2 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -337,6 +337,7 @@ unsafe fn insert( }; (*parent).child[dir] = node; + // Main insert fixup. loop { // Case 1. if (*parent).color == Color::Black { @@ -350,6 +351,7 @@ unsafe fn insert( return SUCCESS; } + // Case 5/6. let dir = direction(parent) as usize; let uncle = (*grandparent).child[opposite(dir)]; if uncle.is_null() || (*uncle).color == Color::Black { From 32fb2133e27a5b488fb44f98d28303d902c5d792 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 11:42:07 -0700 Subject: [PATCH 197/263] Add insert cases except 5/6 --- .../artifacts/snippets/asm/insert-fixup.txt | 60 ++++++++++++-- .../artifacts/snippets/asm/insert-search.txt | 16 ++-- .../artifacts/snippets/asm/insert-to-tree.txt | 6 +- examples/tree/src/tests.rs | 2 +- examples/tree/src/tree/tree.s | 80 ++++++++++++++----- 5 files changed, 126 insertions(+), 38 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt index 65ba28b2..33e147ca 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup.txt @@ -1,30 +1,74 @@ insert_get_child_dir: # Get child direction, set at parent. # --------------------------------------------------------------------- - ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; + ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; jgt r4, r5, insert_get_child_dir_branch_r insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; ja insert_fixup_main insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; insert_fixup_main: # Case 1. # --------------------------------------------------------------------- - ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; jne r6, TREE_COLOR_B, insert_fixup_check_case_4 exit # If parent is black, tree is still valid, so exit. insert_fixup_check_case_4: # Check case 4. # --------------------------------------------------------------------- - ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; + ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; jne r3, NULL, insert_fixup_check_case_5_6 - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; exit insert_fixup_check_case_5_6: - # Get parent's direction as a child. + # Get uncle and check for case 5 or 6. # --------------------------------------------------------------------- - exit \ No newline at end of file + ldxh r4, [r3 + TREE_NODE_KEY_OFF] # r4 = grandparent.key; + jgt r5, r4, insert_fixup_check_case_5_6_dir_r + +insert_fixup_check_case_5_6_dir_l: + ldxdw r7, [r3 + TREE_NODE_CHILD_R_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_l + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_l: + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[right]; + jne r9, r8, insert_fixup_case_6_dir_l + +insert_fixup_case_5_dir_l: + # rotate_subtree(tree_header, parent, left); + # --------------------------------------------------------------------- + +insert_fixup_case_6_dir_l: + exit + +insert_fixup_check_case_5_6_dir_r: + ldxdw r7, [r3 + TREE_NODE_CHILD_L_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_r + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_r: + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[left]; + jne r9, r8, insert_fixup_case_6_dir_r + +insert_fixup_case_5_dir_r: + # rotate_subtree(tree_header, parent, right); + # --------------------------------------------------------------------- + +insert_fixup_case_6_dir_r: + exit + +insert_fixup_case_2: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + mov64 r9, r3 # r9 = node = grandparent; + ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # r2 = parent = node.parent; + jne r2, NULL, insert_fixup_main + exit # Case 3. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index b0ae1ffa..0b3f37fa 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -1,19 +1,19 @@ -insert_search: - ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; - mov64 r2, NULL # r2 = parent = null; - ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; +insert_search: # r9 = node + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; + mov64 r2, NULL # r2 = parent = null; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; insert_search_loop: jeq r3, NULL, insert_to_tree - mov64 r2, r3 # r2 = parent = cursor; - ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; + mov64 r2, r3 # r2 = parent = cursor; + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; ja insert_search_loop \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt index 010d124a..f5005262 100644 --- a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt +++ b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt @@ -1,11 +1,11 @@ insert_to_tree: # Flag new node as red and store parent pointer. # --------------------------------------------------------------------- - stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; # Handle case of new node at root. # --------------------------------------------------------------------- jne r2, NULL, insert_get_child_dir - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; exit # Parent is null, new node at root. \ No newline at end of file diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 1ca2297e..f7b32b2a 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -200,5 +200,5 @@ fn test_insert_search() { #[test] fn test_insert_to_tree() { - print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, true, false); + print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, false, false); } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a7b440a0..51326a7a 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -662,24 +662,24 @@ insert_store_key_value_pair: # ANCHOR_END: insert-allocate # ANCHOR: insert-search -insert_search: - ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; - mov64 r2, NULL # r2 = parent = null; - ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; +insert_search: # r9 = node + ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; + mov64 r2, NULL # r2 = parent = null; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; insert_search_loop: jeq r3, NULL, insert_to_tree - mov64 r2, r3 # r2 = parent = cursor; - ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; + mov64 r2, r3 # r2 = parent = cursor; + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; ja insert_search_loop # ANCHOR_END: insert-search @@ -687,13 +687,13 @@ insert_search_branch_r: insert_to_tree: # Flag new node as red and store parent pointer. # --------------------------------------------------------------------- - stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; # Handle case of new node at root. # --------------------------------------------------------------------- jne r2, NULL, insert_get_child_dir - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; exit # Parent is null, new node at root. # ANCHOR_END: insert-to-tree @@ -701,33 +701,77 @@ insert_to_tree: insert_get_child_dir: # Get child direction, set at parent. # --------------------------------------------------------------------- - ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; + ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; jgt r4, r5, insert_get_child_dir_branch_r insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; ja insert_fixup_main insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; insert_fixup_main: # Case 1. # --------------------------------------------------------------------- - ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; jne r6, TREE_COLOR_B, insert_fixup_check_case_4 exit # If parent is black, tree is still valid, so exit. insert_fixup_check_case_4: # Check case 4. # --------------------------------------------------------------------- - ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; + ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; jne r3, NULL, insert_fixup_check_case_5_6 - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; exit insert_fixup_check_case_5_6: - # Get parent's direction as a child. + # Get uncle and check for case 5 or 6. # --------------------------------------------------------------------- + ldxh r4, [r3 + TREE_NODE_KEY_OFF] # r4 = grandparent.key; + jgt r5, r4, insert_fixup_check_case_5_6_dir_r + +insert_fixup_check_case_5_6_dir_l: + ldxdw r7, [r3 + TREE_NODE_CHILD_R_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_l + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_l: + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[right]; + jne r9, r8, insert_fixup_case_6_dir_l + +insert_fixup_case_5_dir_l: + # rotate_subtree(tree_header, parent, left); + # --------------------------------------------------------------------- + +insert_fixup_case_6_dir_l: + exit + +insert_fixup_check_case_5_6_dir_r: + ldxdw r7, [r3 + TREE_NODE_CHILD_L_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_r + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_r: + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[left]; + jne r9, r8, insert_fixup_case_6_dir_r + +insert_fixup_case_5_dir_r: + # rotate_subtree(tree_header, parent, right); + # --------------------------------------------------------------------- + +insert_fixup_case_6_dir_r: exit + +insert_fixup_case_2: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + mov64 r9, r3 # r9 = node = grandparent; + ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # r2 = parent = node.parent; + jne r2, NULL, insert_fixup_main + exit # Case 3. # ANCHOR_END: insert-fixup From 469d0e053ceb884271b921085e1704736bb18b8d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:56:06 -0700 Subject: [PATCH 198/263] Add SPP insertion --- examples/tree/artifacts/dumps/asm.txt | 218 ++++++++++++------ .../artifacts/snippets/asm/insert-fixup.txt | 93 +++++++- .../artifacts/tests/insert_to_tree/result.txt | 70 +++--- .../artifacts/tests/insert_to_tree/test.txt | 2 +- examples/tree/specs/insert-fixup-rotation.md | 202 ++++++++++++++++ examples/tree/src/tree/tree.s | 97 +++++++- 6 files changed, 558 insertions(+), 124 deletions(-) create mode 100644 examples/tree/specs/insert-fixup-rotation.md diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 7acae006..1ed3b84d 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 2768 (bytes into file) + Start of section headers 3408 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xad0 +There are 7 section headers, starting at offset 0xd50 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000848 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000930 000930 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 00000000000009d0 0009d0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000a30 000a30 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000a70 000a70 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000aa0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000ac8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000bb0 000bb0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000c50 000c50 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000cb0 000cb0 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000cf0 000cf0 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000d20 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000848 0x000848 R E 0x1000 - LOAD 0x0009d0 0x00000000000009d0 0x00000000000009d0 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000930 0x0000000000000930 0x0000000000000930 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ac8 0x000ac8 R E 0x1000 + LOAD 0x000c50 0x0000000000000c50 0x0000000000000c50 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000bb0 0x0000000000000bb0 0x0000000000000bb0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0x930 contains 10 entries +Dynamic section at offset 0xbb0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xa70 + 0x0000000000000011 (REL) 0xcf0 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0x9d0 + 0x0000000000000006 (SYMTAB) 0xc50 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xa30 + 0x0000000000000005 (STRTAB) 0xcb0 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xa70 contains 3 entries +Relocation section '.rel.dyn' at offset 0xcf0 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 eb 00 01 00 00 00 if r9 != 0x1 goto +0xeb - 37 55 08 ec 00 04 00 00 00 if r8 != 0x4 goto +0xec + 36 55 09 3b 01 01 00 00 00 if r9 != 0x1 goto +0x13b + 37 55 08 3c 01 04 00 00 00 if r8 != 0x4 goto +0x13c 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 fc 00 00 00 00 00 if r9 != 0x0 goto +0xfc + 39 55 09 4c 01 00 00 00 00 if r9 != 0x0 goto +0x14c 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 f8 00 ff 00 00 00 if r9 != 0xff goto +0xf8 + 41 55 09 48 01 ff 00 00 00 if r9 != 0xff goto +0x148 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 f4 00 00 00 00 00 if r9 != 0x0 goto +0xf4 + 43 55 09 44 01 00 00 00 00 if r9 != 0x0 goto +0x144 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 f0 00 ff 00 00 00 if r9 != 0xff goto +0xf0 + 45 55 09 40 01 ff 00 00 00 if r9 != 0xff goto +0x140 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 ec 00 0e 00 00 00 if r9 != 0xe goto +0xec + 47 55 09 3c 01 0e 00 00 00 if r9 != 0xe goto +0x13c 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 e8 00 ff 00 00 00 if r9 != 0xff goto +0xe8 + 49 55 09 38 01 ff 00 00 00 if r9 != 0xff goto +0x138 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 e2 00 00 00 00 00 if r9 != r8 goto +0xe2 + 53 5d 89 32 01 00 00 00 00 if r9 != r8 goto +0x132 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 de 00 00 00 00 00 if r9 != r8 goto +0xde + 57 5d 89 2e 01 00 00 00 00 if r9 != r8 goto +0x12e 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 da 00 00 00 00 00 if r9 != r8 goto +0xda + 61 5d 89 2a 01 00 00 00 00 if r9 != r8 goto +0x12a 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 d7 00 00 00 00 00 if r9 != r8 goto +0xd7 + 64 5d 89 27 01 00 00 00 00 if r9 != r8 goto +0x127 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 ca 00 00 00 00 00 if r9 != r8 goto +0xca + 75 5d 89 1a 01 00 00 00 00 if r9 != r8 goto +0x11a 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 c7 00 00 00 00 00 if r9 != r8 goto +0xc7 + 78 5d 89 17 01 00 00 00 00 if r9 != r8 goto +0x117 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 c4 00 00 00 00 00 if r9 != r8 goto +0xc4 + 81 5d 89 14 01 00 00 00 00 if r9 != r8 goto +0x114 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 c1 00 00 00 00 00 if r9 != r8 goto +0xc1 + 84 5d 89 11 01 00 00 00 00 if r9 != r8 goto +0x111 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 7e 00 05 00 00 00 if r9 != 0x5 goto +0x7e - 146 a5 08 7f 00 02 00 00 00 if r8 < 0x2 goto +0x7f + 145 55 09 ce 00 05 00 00 00 if r9 != 0x5 goto +0xce + 146 a5 08 cf 00 02 00 00 00 if r8 < 0x2 goto +0xcf 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 8f 00 00 00 00 00 if r9 != 0x0 goto +0x8f + 148 55 09 df 00 00 00 00 00 if r9 != 0x0 goto +0xdf 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 8b 00 ff 00 00 00 if r9 != 0xff goto +0x8b + 150 55 09 db 00 ff 00 00 00 if r9 != 0xff goto +0xdb 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 7a 00 04 00 00 00 if r8 != 0x4 goto +0x7a + 153 55 08 ca 00 04 00 00 00 if r8 != 0x4 goto +0xca 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 7c 00 ff 00 00 00 if r8 != 0xff goto +0x7c + 161 55 08 cc 00 ff 00 00 00 if r8 != 0xff goto +0xcc 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 78 00 0e 00 00 00 if r8 != 0xe goto +0x78 + 163 55 08 c8 00 0e 00 00 00 if r8 != 0xe goto +0xc8 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 74 00 ff 00 00 00 if r8 != 0xff goto +0x74 + 165 55 08 c4 00 ff 00 00 00 if r8 != 0xff goto +0xc4 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 6e 00 00 00 00 00 if r8 != r4 goto +0x6e + 169 5d 48 be 00 00 00 00 00 if r8 != r4 goto +0xbe 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 6a 00 00 00 00 00 if r8 != r4 goto +0x6a + 173 5d 48 ba 00 00 00 00 00 if r8 != r4 goto +0xba 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 66 00 00 00 00 00 if r8 != r4 goto +0x66 + 177 5d 48 b6 00 00 00 00 00 if r8 != r4 goto +0xb6 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 63 00 00 00 00 00 if r8 != r4 goto +0x63 + 180 5d 48 b3 00 00 00 00 00 if r8 != r4 goto +0xb3 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -318,28 +318,108 @@ Disassembly of section .text 266 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 267 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 268 95 00 00 00 00 00 00 00 exit - 269 95 00 00 00 00 00 00 00 exit - 270 b7 00 00 00 09 00 00 00 r0 = 0x9 - 271 95 00 00 00 00 00 00 00 exit - 272 b7 00 00 00 0c 00 00 00 r0 = 0xc - 273 95 00 00 00 00 00 00 00 exit - 274 b7 00 00 00 01 00 00 00 r0 = 0x1 - 275 95 00 00 00 00 00 00 00 exit - 276 b7 00 00 00 0d 00 00 00 r0 = 0xd - 277 95 00 00 00 00 00 00 00 exit - 278 b7 00 00 00 0a 00 00 00 r0 = 0xa - 279 95 00 00 00 00 00 00 00 exit - 280 b7 00 00 00 08 00 00 00 r0 = 0x8 - 281 95 00 00 00 00 00 00 00 exit - 282 b7 00 00 00 07 00 00 00 r0 = 0x7 - 283 95 00 00 00 00 00 00 00 exit - 284 b7 00 00 00 04 00 00 00 r0 = 0x4 - 285 95 00 00 00 00 00 00 00 exit - 286 b7 00 00 00 06 00 00 00 r0 = 0x6 - 287 95 00 00 00 00 00 00 00 exit - 288 b7 00 00 00 03 00 00 00 r0 = 0x3 - 289 95 00 00 00 00 00 00 00 exit - 290 b7 00 00 00 05 00 00 00 r0 = 0x5 - 291 95 00 00 00 00 00 00 00 exit - 292 b7 00 00 00 02 00 00 00 r0 = 0x2 - 293 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 269 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) + 270 2d 45 24 00 00 00 00 00 if r5 > r4 goto +0x24 + 271 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) + 272 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 273 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 274 55 08 44 00 00 00 00 00 if r8 != 0x0 goto +0x44 + 275 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 276 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb + 277 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) + 278 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) + 279 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 + 280 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 281 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 282 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 + 283 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 284 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 285 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 + 286 bf 29 00 00 00 00 00 00 r9 = r2 + 287 bf 62 00 00 00 00 00 00 r2 = r6 + 288 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 289 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 290 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 + 291 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 292 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 293 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 + 294 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 295 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 296 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 297 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 298 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 299 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 300 05 00 03 00 00 00 00 00 goto +0x3 + 301 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 302 05 00 01 00 00 00 00 00 goto +0x1 + 303 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 304 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 305 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 306 95 00 00 00 00 00 00 00 exit + 307 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 308 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 309 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 310 55 08 20 00 00 00 00 00 if r8 != 0x0 goto +0x20 + 311 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 312 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb + 313 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 314 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 315 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 316 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 317 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 318 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 319 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 320 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 321 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 322 bf 29 00 00 00 00 00 00 r9 = r2 + 323 bf 62 00 00 00 00 00 00 r2 = r6 + 324 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 325 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 326 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 327 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 328 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 329 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 330 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 331 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 332 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 333 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 334 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 335 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 336 05 00 03 00 00 00 00 00 goto +0x3 + 337 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 338 05 00 01 00 00 00 00 00 goto +0x1 + 339 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 340 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 341 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 342 95 00 00 00 00 00 00 00 exit + 343 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 344 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 345 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 346 bf 39 00 00 00 00 00 00 r9 = r3 + 347 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 348 55 02 a9 ff 00 00 00 00 if r2 != 0x0 goto -0x57 + 349 95 00 00 00 00 00 00 00 exit + 350 b7 00 00 00 09 00 00 00 r0 = 0x9 + 351 95 00 00 00 00 00 00 00 exit + 352 b7 00 00 00 0c 00 00 00 r0 = 0xc + 353 95 00 00 00 00 00 00 00 exit + 354 b7 00 00 00 01 00 00 00 r0 = 0x1 + 355 95 00 00 00 00 00 00 00 exit + 356 b7 00 00 00 0d 00 00 00 r0 = 0xd + 357 95 00 00 00 00 00 00 00 exit + 358 b7 00 00 00 0a 00 00 00 r0 = 0xa + 359 95 00 00 00 00 00 00 00 exit + 360 b7 00 00 00 08 00 00 00 r0 = 0x8 + 361 95 00 00 00 00 00 00 00 exit + 362 b7 00 00 00 07 00 00 00 r0 = 0x7 + 363 95 00 00 00 00 00 00 00 exit + 364 b7 00 00 00 04 00 00 00 r0 = 0x4 + 365 95 00 00 00 00 00 00 00 exit + 366 b7 00 00 00 06 00 00 00 r0 = 0x6 + 367 95 00 00 00 00 00 00 00 exit + 368 b7 00 00 00 03 00 00 00 r0 = 0x3 + 369 95 00 00 00 00 00 00 00 exit + 370 b7 00 00 00 05 00 00 00 r0 = 0x5 + 371 95 00 00 00 00 00 00 00 exit + 372 b7 00 00 00 02 00 00 00 r0 = 0x2 + 373 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt index 33e147ca..91fda2d0 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup.txt @@ -10,7 +10,9 @@ insert_get_child_dir_branch_r: stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; insert_fixup_main: - # Case 1. + # r2 := parent + # r5 := parent.key + # Case 1. # r9 := node # --------------------------------------------------------------------- ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; jne r6, TREE_COLOR_B, insert_fixup_check_case_4 @@ -41,10 +43,48 @@ insert_fixup_case_5_6_dir_l: jne r9, r8, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - # rotate_subtree(tree_header, parent, left); + # rotate_subtree(tree_header, parent, LEFT) + # subtree=r2(parent), grandparent=r3(non-null), dir=L, opp=R # --------------------------------------------------------------------- + ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; + ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_l_skip: + stxdw [r6 + TREE_NODE_CHILD_L_OFF], r2 # new_root.child[L] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r6 # grandparent.child[L] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_l: + # rotate_subtree(tree_header, grandparent, RIGHT) + # subtree=r3(grandparent), new_root=r2(parent), dir=R, opp=L + # --------------------------------------------------------------------- + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_l_skip: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r3 # parent.child[R] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_l_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_l_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_l_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit insert_fixup_check_case_5_6_dir_r: @@ -58,17 +98,60 @@ insert_fixup_case_5_6_dir_r: jne r9, r8, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - # rotate_subtree(tree_header, parent, right); + # rotate_subtree(tree_header, parent, RIGHT) + # subtree=r2(parent), grandparent=r3(non-null), dir=R, opp=L # --------------------------------------------------------------------- + ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_r_skip: + stxdw [r6 + TREE_NODE_CHILD_R_OFF], r2 # new_root.child[R] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r6 # grandparent.child[R] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_r: + # rotate_subtree(tree_header, grandparent, LEFT) + # subtree=r3(grandparent), new_root=r2(parent), dir=L, opp=R + # --------------------------------------------------------------------- + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_r_skip: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r3 # parent.child[L] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_r_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_r_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_r_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit insert_fixup_case_2: + # r2 := parent + # r3 := grandparent + # r7 := uncle + # r9 := node + # --------------------------------------------------------------------- stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; - mov64 r9, r3 # r9 = node = grandparent; - ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # r2 = parent = node.parent; + mov64 r9, r3 # node = grandparent; + ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # parent = node.parent; jne r2, NULL, insert_fixup_main exit # Case 3. \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 1af0af9a..387e9230 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -5,34 +5,20 @@ | Case 1: right child | 36 | 49 | +13 | +36.1% | | Case 4: left child | 39 | 56 | +17 | +43.6% | | Case 4: right child | 39 | 53 | +14 | +35.9% | -| Case 2+3: left-left | 44 | 88 | +44 | +100.0% | - (ASM) Case 2+3: left-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R -| Case 2+3: left-right | 44 | 85 | +41 | +93.2% | - (ASM) Case 2+3: left-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R -| Case 2+3: right-left | 45 | 85 | +40 | +88.9% | - (ASM) Case 2+3: right-left: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R -| Case 2+3: right-right | 45 | 82 | +37 | +82.2% | - (ASM) Case 2+3: right-right: N0.color: expected R, got B; N1.color: expected B, got R; N2.color: expected B, got R -| Case 2+1: left | 50 | 102 | +52 | +104.0% | - (ASM) Case 2+1: left: N1.color: expected R, got B; N2.color: expected B, got R; N3.color: expected B, got R -| Case 2+1: right | 52 | 94 | +42 | +80.8% | - (ASM) Case 2+1: right: N1.color: expected R, got B; N2.color: expected B, got R; N3.color: expected B, got R -| Case 6: left-left null uncle | 44 | 109 | +65 | +147.7% | - (ASM) Case 6: left-left null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R -| Case 6: right-right null uncle | 45 | 103 | +58 | +128.9% | - (ASM) Case 6: right-right null uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.L: expected 0x4000028d8, got 0x0; N1.color: expected B, got R -| Case 6: left-left black uncle | 44 | 111 | +67 | +152.3% | - (ASM) Case 6: left-left black uncle: header.root: expected 0x4000028f5, got 0x4000028d8; N0.parent: expected 0x4000028f5, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x0, got 0x4000028d8; N1.R: expected 0x4000028d8, got 0x0; N1.color: expected B, got R -| Case 6: right-right black uncle | 45 | 105 | +60 | +133.3% | - (ASM) Case 6: right-right black uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x0, got 0x4000028d8; N2.L: expected 0x4000028d8, got 0x0; N2.color: expected B, got R -| Case 5+6: left-right null uncle | 44 | 130 | +86 | +195.5% | - (ASM) Case 5+6: left-right null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N1.R: expected 0x0, got 0x400002912; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028f5, got 0x0; N2.R: expected 0x4000028d8, got 0x0; N2.color: expected B, got R -| Case 5+6: right-left null uncle | 45 | 130 | +85 | +188.9% | - (ASM) Case 5+6: right-left null uncle: header.root: expected 0x400002912, got 0x4000028d8; N0.parent: expected 0x400002912, got 0x0; N0.R: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x400002912, got 0x4000028d8; N1.L: expected 0x0, got 0x400002912; N2.parent: expected 0x0, got 0x4000028f5; N2.L: expected 0x4000028d8, got 0x0; N2.R: expected 0x4000028f5, got 0x0; N2.color: expected B, got R -| Case 5+6: left-right black uncle | 44 | 132 | +88 | +200.0% | - (ASM) Case 5+6: left-right black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.L: expected 0x0, got 0x4000028f5; N0.color: expected R, got B; N1.parent: expected 0x40000292f, got 0x4000028d8; N1.R: expected 0x0, got 0x40000292f; N3.parent: expected 0x0, got 0x4000028f5; N3.L: expected 0x4000028f5, got 0x0; N3.R: expected 0x4000028d8, got 0x0; N3.color: expected B, got R -| Case 5+6: right-left black uncle | 45 | 132 | +87 | +193.3% | - (ASM) Case 5+6: right-left black uncle: header.root: expected 0x40000292f, got 0x4000028d8; N0.parent: expected 0x40000292f, got 0x0; N0.R: expected 0x0, got 0x400002912; N0.color: expected R, got B; N2.parent: expected 0x40000292f, got 0x4000028d8; N2.L: expected 0x0, got 0x40000292f; N3.parent: expected 0x0, got 0x400002912; N3.L: expected 0x4000028d8, got 0x0; N3.R: expected 0x400002912, got 0x0; N3.color: expected B, got R +| Case 2+3: left-left | 56 | 88 | +32 | +57.1% | +| Case 2+3: left-right | 56 | 85 | +29 | +51.8% | +| Case 2+3: right-left | 57 | 85 | +28 | +49.1% | +| Case 2+3: right-right | 57 | 82 | +25 | +43.9% | +| Case 2+1: left | 64 | 102 | +38 | +59.4% | +| Case 2+1: right | 66 | 94 | +28 | +42.4% | +| Case 6: left-left null uncle | 61 | 109 | +48 | +78.7% | +| Case 6: right-right null uncle | 62 | 103 | +41 | +66.1% | +| Case 6: left-left black uncle | 63 | 111 | +48 | +76.2% | +| Case 6: right-right black uncle | 64 | 105 | +41 | +64.1% | +| Case 5+6: left-right null uncle | 71 | 130 | +59 | +83.1% | +| Case 5+6: right-left null uncle | 72 | 130 | +58 | +80.6% | +| Case 5+6: left-right black uncle | 73 | 132 | +59 | +80.8% | +| Case 5+6: right-left black uncle | 74 | 132 | +58 | +78.4% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -65,85 +51,85 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 94 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 111 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/insert_to_tree/test.txt b/examples/tree/artifacts/tests/insert_to_tree/test.txt index 666754d2..4077243e 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/test.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_to_tree() { - print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, true, false); + print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/specs/insert-fixup-rotation.md b/examples/tree/specs/insert-fixup-rotation.md new file mode 100644 index 00000000..675ba081 --- /dev/null +++ b/examples/tree/specs/insert-fixup-rotation.md @@ -0,0 +1,202 @@ +# Insert fixup rotation specification + +## Scope + +Assembly implementation of cases 5 and 6 in the insert fixup loop, +covering the four labels: `insert_fixup_case_5_dir_l`, +`insert_fixup_case_6_dir_l`, `insert_fixup_case_5_dir_r`, +`insert_fixup_case_6_dir_r`. Each label inlines the `rotate_subtree` +call from `program.rs` with the direction hardcoded. + +## Conventions + +- `dir_l`: parent is the LEFT child of grandparent (dir = LEFT). +- `dir_r`: parent is the RIGHT child of grandparent (dir = RIGHT). +- Case 5 rotates parent in dir, then reassigns node/parent. +- Case 6 rotates grandparent in opposite(dir), recolors, exits. + +## Register contract + +### Live registers at entry to case 5/6 + +| Reg | Value | Source | +| --- | ------------ | ------------------------------------ | +| r1 | input buffer | entrypoint, never modified | +| r2 | parent | insert_search / case 5 reassignment | +| r3 | grandparent | insert_fixup_check_case_4 (non-null) | +| r9 | node | insert_store_key_value_pair / case 5 | + +### Scratch registers + +Available for rotation temporaries. These do not need to be +preserved because cases 5/6 always exit with SUCCESS and never +reach `insert_fixup_case_2` or loop back to `insert_fixup_main`. + +| Reg | Prior value | Use in rotation | +| --- | --------------- | ------------------------------- | +| r4 | grandparent.key | great-grandparent (case 6 only) | +| r5 | parent.key | free | +| r6 | parent.color | new_root (case 5 only) | +| r7 | uncle | free | +| r8 | check scratch | new_child / cmp scratch | + +## Control flow + +```text +case_5_dir_l -> (fall through) -> case_6_dir_l -> exit +case_5_dir_r -> (fall through) -> case_6_dir_r -> exit + +(or, skipping case 5:) +case_6_dir_l -> exit +case_6_dir_r -> exit +``` + +## Rotation algorithm + +Reference (`program.rs:575`): + +```rust +let parent = (*subtree).parent; +let new_root = (*subtree).child[opposite(direction)]; +let new_child = (*new_root).child[direction]; + +(*subtree).child[opposite(direction)] = new_child; +if !new_child.is_null() { (*new_child).parent = subtree; } + +(*new_root).child[direction] = subtree; +(*new_root).parent = parent; +(*subtree).parent = new_root; + +if !parent.is_null() { + (*parent).child[(subtree == (*parent).child[DIR_R]) as usize] = new_root; +} else { + (*tree).root = new_root; +} +``` + +## Case 5, dir_l — rotate(parent, LEFT) + +Subtree = parent (r2). Parent-of-subtree = grandparent (r3, +non-null per case 4 check). Direction = LEFT, opposite = RIGHT. + +```text +r6 = parent.child[RIGHT] # new_root +r8 = r6.child[LEFT] # new_child + +parent.child[RIGHT] = r8 # detach new_child +if r8 != null: r8.parent = parent # reparent new_child + +r6.child[LEFT] = parent # new_root adopts subtree +r6.parent = grandparent # new_root links up +parent.parent = r6 # subtree links to new_root + +grandparent.child[LEFT] = r6 # parent is LEFT child, hardcoded + +# Rust post-rotation: +r9 = r2 # node = old parent +r2 = r6 # parent = new_root +# fall through to case_6_dir_l +``` + +## Case 6, dir_l — rotate(grandparent, RIGHT) + +Subtree = grandparent (r3). Direction = RIGHT, opposite = LEFT. +New_root = grandparent.child[LEFT] = parent = r2 (already in +register). + +```text +r4 = grandparent.parent # great-grandparent +r8 = r2.child[RIGHT] # new_child + +grandparent.child[LEFT] = r8 # detach new_child +if r8 != null: r8.parent = grandparent # reparent new_child + +r2.child[RIGHT] = grandparent # parent adopts grandparent +r2.parent = r4 # parent links up +grandparent.parent = r2 # grandparent links to parent + +if r4 != null: + r8 = r4.child[RIGHT] + if grandparent == r8: + r4.child[RIGHT] = r2 + else: + r4.child[LEFT] = r2 +else: + tree.root = r2 # [r1 + IB_TREE_DATA_ROOT_OFF] + +# Recolor and exit: +parent.color = BLACK +grandparent.color = RED +exit +``` + +## Case 5, dir_r — rotate(parent, RIGHT) + +Mirror of case 5 dir_l. Subtree = parent (r2). Direction = RIGHT, +opposite = LEFT. + +```text +r6 = parent.child[LEFT] # new_root +r8 = r6.child[RIGHT] # new_child + +parent.child[LEFT] = r8 # detach new_child +if r8 != null: r8.parent = parent # reparent new_child + +r6.child[RIGHT] = parent # new_root adopts subtree +r6.parent = grandparent # new_root links up +parent.parent = r6 # subtree links to new_root + +grandparent.child[RIGHT] = r6 # parent is RIGHT child, hardcoded + +# Rust post-rotation: +r9 = r2 # node = old parent +r2 = r6 # parent = new_root +# fall through to case_6_dir_r +``` + +## Case 6, dir_r — rotate(grandparent, LEFT) + +Mirror of case 6 dir_l. Subtree = grandparent (r3). Direction = +LEFT, opposite = RIGHT. New_root = grandparent.child[RIGHT] = +parent = r2. + +```text +r4 = grandparent.parent # great-grandparent +r8 = r2.child[LEFT] # new_child + +grandparent.child[RIGHT] = r8 # detach new_child +if r8 != null: r8.parent = grandparent # reparent new_child + +r2.child[LEFT] = grandparent # parent adopts grandparent +r2.parent = r4 # parent links up +grandparent.parent = r2 # grandparent links to parent + +if r4 != null: + r8 = r4.child[RIGHT] + if grandparent == r8: + r4.child[RIGHT] = r2 + else: + r4.child[LEFT] = r2 +else: + tree.root = r2 # [r1 + IB_TREE_DATA_ROOT_OFF] + +# Recolor and exit: +parent.color = BLACK +grandparent.color = RED +exit +``` + +## Key observations + +- Case 5 never needs a null/root check because grandparent is + guaranteed non-null by the case 4 check. The direction of + grandparent's child update is hardcoded (LEFT for dir_l, RIGHT + for dir_r). +- Case 6 needs the full null check because great-grandparent can + be null (grandparent may be root). The great-grandparent child + update cannot be hardcoded by direction — it requires a pointer + comparison. +- In case 6, new_root is always parent (r2), avoiding an extra + load. +- The dir_l/dir_r variants are exact mirrors: every CHILD_L swaps + with CHILD_R. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 51326a7a..a5b34a20 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -710,7 +710,9 @@ insert_get_child_dir_branch_r: stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; insert_fixup_main: - # Case 1. + # r2 := parent + # r5 := parent.key + # Case 1. # r9 := node # --------------------------------------------------------------------- ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; jne r6, TREE_COLOR_B, insert_fixup_check_case_4 @@ -741,10 +743,48 @@ insert_fixup_case_5_6_dir_l: jne r9, r8, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - # rotate_subtree(tree_header, parent, left); - # --------------------------------------------------------------------- + # rotate_subtree(tree_header, parent, LEFT) + # subtree=r2(parent), grandparent=r3(non-null), dir=L, opp=R + # --------------------------------------------------------------------- + ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; + ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_l_skip: + stxdw [r6 + TREE_NODE_CHILD_L_OFF], r2 # new_root.child[L] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r6 # grandparent.child[L] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_l: + # rotate_subtree(tree_header, grandparent, RIGHT) + # subtree=r3(grandparent), new_root=r2(parent), dir=R, opp=L + # --------------------------------------------------------------------- + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_l_skip: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r3 # parent.child[R] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_l_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_l_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_l_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit insert_fixup_check_case_5_6_dir_r: @@ -758,18 +798,61 @@ insert_fixup_case_5_6_dir_r: jne r9, r8, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - # rotate_subtree(tree_header, parent, right); - # --------------------------------------------------------------------- + # rotate_subtree(tree_header, parent, RIGHT) + # subtree=r2(parent), grandparent=r3(non-null), dir=R, opp=L + # --------------------------------------------------------------------- + ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_r_skip: + stxdw [r6 + TREE_NODE_CHILD_R_OFF], r2 # new_root.child[R] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r6 # grandparent.child[R] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_r: + # rotate_subtree(tree_header, grandparent, LEFT) + # subtree=r3(grandparent), new_root=r2(parent), dir=L, opp=R + # --------------------------------------------------------------------- + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_r_skip: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r3 # parent.child[L] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_r_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_r_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_r_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit insert_fixup_case_2: + # r2 := parent + # r3 := grandparent + # r7 := uncle + # r9 := node + # --------------------------------------------------------------------- stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; - mov64 r9, r3 # r9 = node = grandparent; - ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # r2 = parent = node.parent; + mov64 r9, r3 # node = grandparent; + ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # parent = node.parent; jne r2, NULL, insert_fixup_main exit # Case 3. # ANCHOR_END: insert-fixup From df70f6188a5aa1683b89d99c3f44b9a72260aa6c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:12:51 -0700 Subject: [PATCH 199/263] Optimize, build examples --- examples/tree/artifacts/dumps/rs.txt | 816 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 491 ++++++----- .../artifacts/snippets/asm/insert-fixup.txt | 20 +- .../artifacts/snippets/asm/insert-search.txt | 4 +- .../artifacts/snippets/rs/insert-fixup.txt | 58 +- .../tests/entrypoint_branching/result.txt | 4 +- .../initialize_create_account/result.txt | 12 +- .../tests/initialize_input_checks/result.txt | 68 +- .../tests/initialize_pda_checks/result.txt | 16 +- .../tree/artifacts/tests/insert/result.txt | 16 +- .../tests/insert_alloc_checks/result.txt | 32 +- .../artifacts/tests/insert_search/result.txt | 12 +- .../artifacts/tests/insert_to_tree/result.txt | 76 +- .../specs/rotate-subtree-specialization.md | 131 +++ examples/tree/src/program.rs | 58 +- examples/tree/src/tree/tree.s | 24 +- 16 files changed, 1008 insertions(+), 830 deletions(-) create mode 100644 examples/tree/specs/rotate-subtree-specialization.md diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index a85ade07..e8a27552 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 6016 (bytes into file) + Start of section headers 5872 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x1780 +There are 8 section headers, starting at offset 0x16f0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000d70 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000e90 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000e98 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000e98 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000e98 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001210 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00124e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000ce0 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000e00 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000e08 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000e08 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000e08 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001180 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 0011be 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000d70 0x000d70 E 0x8 - LOAD 0x000e90 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000e98 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000e98 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000ce0 0x000ce0 E 0x8 + LOAD 0x000e00 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000e08 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000e08 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3440 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3296 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -108,429 +108,411 @@ Disassembly of section .text 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 08 01 01 00 00 00 jne r5, 0x1, +0x108 - 28 55 03 92 01 05 00 00 00 jne r3, 0x5, +0x192 - 30 a5 04 93 01 02 00 00 00 jlt r4, 0x2, +0x193 + 20 55 05 f6 00 01 00 00 00 jne r5, 0x1, +0xf6 + 28 55 03 80 01 05 00 00 00 jne r3, 0x5, +0x180 + 30 a5 04 81 01 02 00 00 00 jlt r4, 0x2, +0x181 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 93 01 00 00 00 00 jne r3, 0x0, +0x193 + 40 55 03 81 01 00 00 00 00 jne r3, 0x0, +0x181 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 93 01 ff 00 00 00 jne r3, 0xff, +0x193 - 58 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 60 07 07 00 00 c0 28 00 00 add64 r7, 0x28c0 + 50 55 03 81 01 ff 00 00 00 jne r3, 0xff, +0x181 + 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 70 15 03 3e 00 00 00 00 00 jeq r3, 0x0, +0x3e + 70 15 03 3d 00 00 00 00 00 jeq r3, 0x0, +0x3d 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 98 9c 74 00 00 00 00 00 00 ldxdw r4, [r7 + 0x0] - a0 15 04 a7 00 00 00 00 00 jeq r4, 0x0, +0xa7 - a8 3c 22 01 00 00 00 00 00 ldxh w2, [r2 + 0x1] + 98 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + a0 15 04 a3 00 00 00 00 00 jeq r4, 0x0, +0xa3 + a8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] b0 05 00 04 00 00 00 00 00 ja +0x4 - b8 bf 15 00 00 00 00 00 00 mov64 r5, r1 + b8 bf 25 00 00 00 00 00 00 mov64 r5, r2 c0 0f 45 00 00 00 00 00 00 add64 r5, r4 c8 9c 54 00 00 00 00 00 00 ldxdw r4, [r5 + 0x0] d0 15 04 09 00 00 00 00 00 jeq r4, 0x0, +0x9 - d8 bf 41 00 00 00 00 00 00 mov64 r1, r4 + d8 bf 42 00 00 00 00 00 00 mov64 r2, r4 e0 b7 04 00 00 10 00 00 00 mov64 r4, 0x10 - e8 3c 15 18 00 00 00 00 00 ldxh w5, [r1 + 0x18] - f0 bf 20 00 00 00 00 00 00 mov64 r0, r2 + e8 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] + f0 bf 10 00 00 00 00 00 00 mov64 r0, r1 f8 2d 50 f7 ff 00 00 00 00 jgt r0, r5, -0x9 100 b7 04 00 00 08 00 00 00 mov64 r4, 0x8 108 ad 50 f5 ff 00 00 00 00 jlt r0, r5, -0xb - 110 b7 01 00 00 0e 00 00 00 mov64 r1, 0xe - 118 05 00 9c 00 00 00 00 00 ja +0x9c - 120 9f 7a 38 00 00 00 00 00 stxdw [r10 + 0x38], r7 - 128 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 110 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + 118 05 00 d6 00 00 00 00 00 ja +0xd6 + 120 9f 6a 40 00 00 00 00 00 stxdw [r10 + 0x40], r6 + 128 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 130 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 138 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 140 3c 15 18 00 00 00 00 00 ldxh w5, [r1 + 0x18] - 148 b4 02 00 00 01 00 00 00 mov32 w2, 0x1 + 138 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 140 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] + 148 b4 01 00 00 01 00 00 00 mov32 w1, 0x1 150 2d 54 01 00 00 00 00 00 jgt r4, r5, +0x1 - 158 b4 02 00 00 00 00 00 00 mov32 w2, 0x0 - 160 67 02 00 00 03 00 00 00 lsh64 r2, 0x3 - 168 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 170 0f 24 00 00 00 00 00 00 add64 r4, r2 + 158 b4 01 00 00 00 00 00 00 mov32 w1, 0x0 + 160 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + 168 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 170 0f 14 00 00 00 00 00 00 add64 r4, r1 178 9f 34 08 00 00 00 00 00 stxdw [r4 + 0x8], r3 - 180 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 188 9f 2a 40 00 00 00 00 00 stxdw [r10 + 0x40], r2 - 190 2c 12 1c 00 00 00 00 00 ldxb w2, [r1 + 0x1c] - 198 15 02 d7 00 00 00 00 00 jeq r2, 0x0, +0xd7 - 1a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 1a8 15 02 98 00 00 00 00 00 jeq r2, 0x0, +0x98 - 1b0 9c 28 10 00 00 00 00 00 ldxdw r8, [r2 + 0x10] - 1b8 b4 00 00 00 01 00 00 00 mov32 w0, 0x1 - 1c0 1d 81 01 00 00 00 00 00 jeq r1, r8, +0x1 - 1c8 b4 00 00 00 00 00 00 00 mov32 w0, 0x0 - 1d0 bf 25 00 00 00 00 00 00 mov64 r5, r2 - 1d8 07 05 00 00 08 00 00 00 add64 r5, 0x8 - 1e0 bf 04 00 00 00 00 00 00 mov64 r4, r0 - 1e8 a7 04 00 00 01 00 00 00 xor64 r4, 0x1 - 1f0 bf 47 00 00 00 00 00 00 mov64 r7, r4 - 1f8 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 - 200 bf 59 00 00 00 00 00 00 mov64 r9, r5 - 208 0f 79 00 00 00 00 00 00 add64 r9, r7 - 210 9c 99 00 00 00 00 00 00 ldxdw r9, [r9 + 0x0] - 218 15 09 7e 00 00 00 00 00 jeq r9, 0x0, +0x7e - 220 2c 96 1c 00 00 00 00 00 ldxb w6, [r9 + 0x1c] - 228 15 06 7c 00 00 00 00 00 jeq r6, 0x0, +0x7c - 230 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 - 238 27 09 1c 00 00 00 00 00 stb [r9 + 0x1c], 0x0 - 240 27 02 1c 00 01 00 00 00 stb [r2 + 0x1c], 0x1 - 248 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] - 250 bf 23 00 00 00 00 00 00 mov64 r3, r2 - 258 55 01 e4 ff 00 00 00 00 jne r1, 0x0, -0x1c - 260 05 00 be 00 00 00 00 00 ja +0xbe - 268 55 04 56 01 04 00 00 00 jne r4, 0x4, +0x156 - 270 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 278 bf 35 00 00 00 00 00 00 mov64 r5, r3 - 280 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 288 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - 290 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 298 0f 54 00 00 00 00 00 00 add64 r4, r5 - 2a0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2a8 55 05 4a 01 ff 00 00 00 jne r5, 0xff, +0x14a - 2b0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2b8 55 05 4a 01 0e 00 00 00 jne r5, 0xe, +0x14a - 2c0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2c8 55 05 4c 01 ff 00 00 00 jne r5, 0xff, +0x14c - 2d0 b7 05 00 00 08 00 00 00 mov64 r5, 0x8 - 2d8 9f 5a 40 00 00 00 00 00 stxdw [r10 + 0x40], r5 - 2e0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 2e8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 2f0 9c 46 40 79 00 00 00 00 ldxdw r6, [r4 + 0x7940] - 2f8 5d 56 ab 00 00 00 00 00 jne r6, r5, +0xab - 300 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 308 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 310 9c 46 48 79 00 00 00 00 ldxdw r6, [r4 + 0x7948] - 318 5d 56 a7 00 00 00 00 00 jne r6, r5, +0xa7 - 320 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 328 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 330 9c 46 50 79 00 00 00 00 ldxdw r6, [r4 + 0x7950] - 338 5d 56 a3 00 00 00 00 00 jne r6, r5, +0xa3 - 340 bf 78 00 00 00 00 00 00 mov64 r8, r7 - 348 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 350 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 358 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 360 5d 52 9e 00 00 00 00 00 jne r2, r5, +0x9e - 368 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 370 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 378 9f 2a 74 01 00 00 00 00 stxdw [r10 + 0x174], r2 - 380 87 0a 70 01 02 00 00 00 stw [r10 + 0x170], 0x2 - 388 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 390 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 398 9f 4a 28 01 00 00 00 00 stxdw [r10 + 0x128], r4 - 3a0 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 3a8 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 3b0 9f 2a 18 01 00 00 00 00 stxdw [r10 + 0x118], r2 - 3b8 37 0a 30 01 01 00 00 00 sth [r10 + 0x130], 0x1 - 3c0 37 0a 20 01 01 01 00 00 sth [r10 + 0x120], 0x101 - 3c8 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 3d0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3d8 9f 5a 00 01 00 00 00 00 stxdw [r10 + 0x100], r5 - 3e0 9f 8a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r8 - 3e8 9f 3a f0 00 00 00 00 00 stxdw [r10 + 0xf0], r3 - 3f0 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 3f8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 400 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 - 408 9f 4a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r4 + 180 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 188 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 190 15 01 c7 00 00 00 00 00 jeq r1, 0x0, +0xc7 + 198 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] + 1a0 15 01 8f 00 00 00 00 00 jeq r1, 0x0, +0x8f + 1a8 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] + 1b0 b4 05 00 00 01 00 00 00 mov32 w5, 0x1 + 1b8 1d 42 01 00 00 00 00 00 jeq r2, r4, +0x1 + 1c0 b4 05 00 00 00 00 00 00 mov32 w5, 0x0 + 1c8 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 1d0 07 08 00 00 08 00 00 00 add64 r8, 0x8 + 1d8 bf 57 00 00 00 00 00 00 mov64 r7, r5 + 1e0 a7 07 00 00 01 00 00 00 xor64 r7, 0x1 + 1e8 bf 74 00 00 00 00 00 00 mov64 r4, r7 + 1f0 67 04 00 00 03 00 00 00 lsh64 r4, 0x3 + 1f8 bf 89 00 00 00 00 00 00 mov64 r9, r8 + 200 0f 49 00 00 00 00 00 00 add64 r9, r4 + 208 9c 99 00 00 00 00 00 00 ldxdw r9, [r9 + 0x0] + 210 15 09 7a 00 00 00 00 00 jeq r9, 0x0, +0x7a + 218 2c 96 1c 00 00 00 00 00 ldxb w6, [r9 + 0x1c] + 220 15 06 78 00 00 00 00 00 jeq r6, 0x0, +0x78 + 228 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 230 27 09 1c 00 00 00 00 00 stb [r9 + 0x1c], 0x0 + 238 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 240 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 248 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 250 55 02 e6 ff 00 00 00 00 jne r2, 0x0, -0x1a + 258 05 00 ae 00 00 00 00 00 ja +0xae + 260 55 04 45 01 04 00 00 00 jne r4, 0x4, +0x145 + 268 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 270 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 278 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 280 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 288 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 290 0f 54 00 00 00 00 00 00 add64 r4, r5 + 298 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 2a0 55 05 39 01 ff 00 00 00 jne r5, 0xff, +0x139 + 2a8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2b0 55 05 39 01 0e 00 00 00 jne r5, 0xe, +0x139 + 2b8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2c0 55 05 3b 01 ff 00 00 00 jne r5, 0xff, +0x13b + 2c8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 2d0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 2d8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 2e0 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 2e8 5d 57 9c 00 00 00 00 00 jne r7, r5, +0x9c + 2f0 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 2f8 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 300 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 308 5d 57 98 00 00 00 00 00 jne r7, r5, +0x98 + 310 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 318 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 320 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 328 5d 57 94 00 00 00 00 00 jne r7, r5, +0x94 + 330 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 338 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 340 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 348 5d 52 90 00 00 00 00 00 jne r2, r5, +0x90 + 350 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 358 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 360 9f 2a 74 01 00 00 00 00 stxdw [r10 + 0x174], r2 + 368 87 0a 70 01 02 00 00 00 stw [r10 + 0x170], 0x2 + 370 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 378 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 380 9f 4a 28 01 00 00 00 00 stxdw [r10 + 0x128], r4 + 388 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 390 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 398 9f 2a 18 01 00 00 00 00 stxdw [r10 + 0x118], r2 + 3a0 37 0a 30 01 01 00 00 00 sth [r10 + 0x130], 0x1 + 3a8 37 0a 20 01 01 01 00 00 sth [r10 + 0x120], 0x101 + 3b0 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3b8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3c0 9f 5a 00 01 00 00 00 00 stxdw [r10 + 0x100], r5 + 3c8 9f 6a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r6 + 3d0 9f 3a f0 00 00 00 00 00 stxdw [r10 + 0xf0], r3 + 3d8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 3e0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 3e8 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + 3f0 9f 4a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r4 + 3f8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 400 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 408 9f 3a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r3 410 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 418 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 420 9f 3a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r3 + 418 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 420 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 428 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 430 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 438 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 440 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 448 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 450 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 - 458 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 - 460 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 - 468 37 0a 10 01 00 01 00 00 sth [r10 + 0x110], 0x100 - 470 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 478 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 - 480 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 - 488 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 - 490 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 - 498 97 0a 50 01 00 00 00 00 stdw [r10 + 0x150], 0x0 - 4a0 97 0a 48 01 00 00 00 00 stdw [r10 + 0x148], 0x0 - 4a8 97 0a 40 01 00 00 00 00 stdw [r10 + 0x140], 0x0 - 4b0 97 0a 38 01 00 00 00 00 stdw [r10 + 0x138], 0x0 + 430 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 438 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 440 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + 448 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + 450 37 0a 10 01 00 01 00 00 sth [r10 + 0x110], 0x100 + 458 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 460 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + 468 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + 470 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + 478 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + 480 97 0a 50 01 00 00 00 00 stdw [r10 + 0x150], 0x0 + 488 97 0a 48 01 00 00 00 00 stdw [r10 + 0x148], 0x0 + 490 97 0a 40 01 00 00 00 00 stdw [r10 + 0x140], 0x0 + 498 97 0a 38 01 00 00 00 00 stdw [r10 + 0x138], 0x0 + 4a0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4a8 07 02 00 00 70 01 00 00 add64 r2, 0x170 + 4b0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 4b8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4c0 07 02 00 00 70 01 00 00 add64 r2, 0x170 - 4c8 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 4c0 07 02 00 00 18 01 00 00 add64 r2, 0x118 + 4c8 9f 2a 58 00 00 00 00 00 stxdw [r10 + 0x58], r2 4d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d8 07 02 00 00 18 01 00 00 add64 r2, 0x118 - 4e0 9f 2a 58 00 00 00 00 00 stxdw [r10 + 0x58], r2 - 4e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4f0 07 02 00 00 38 01 00 00 add64 r2, 0x138 - 4f8 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 - 500 97 0a 70 00 0c 00 00 00 stdw [r10 + 0x70], 0xc - 508 97 0a 60 00 02 00 00 00 stdw [r10 + 0x60], 0x2 - 510 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 518 97 0a 88 00 00 00 00 00 stdw [r10 + 0x88], 0x0 - 520 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 528 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 530 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 538 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 - 540 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 548 07 04 00 00 88 00 00 00 add64 r4, 0x88 - 550 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 558 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 560 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 568 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 570 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 578 9c 61 b8 28 00 00 00 00 ldxdw r1, [r6 + 0x28b8] - 580 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 588 9f 16 b8 28 00 00 00 00 stxdw [r6 + 0x28b8], r1 - 590 9c 63 d0 28 00 00 00 00 ldxdw r3, [r6 + 0x28d0] - 598 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 5a0 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 5a8 9f 16 d0 28 00 00 00 00 stxdw [r6 + 0x28d0], r1 - 5b0 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 5b8 bf 87 00 00 00 00 00 00 mov64 r7, r8 - 5c0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] - 5c8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 5d0 9c 74 00 00 00 00 00 00 ldxdw r4, [r7 + 0x0] - 5d8 55 04 59 ff 00 00 00 00 jne r4, 0x0, -0xa7 - 5e0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 - 5e8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 5f0 9f 37 00 00 00 00 00 00 stxdw [r7 + 0x0], r3 - 5f8 b7 01 00 00 00 00 00 00 mov64 r1, 0x0 - 600 9f 1a 40 00 00 00 00 00 stxdw [r10 + 0x40], r1 - 608 05 00 49 00 00 00 00 00 ja +0x49 - 610 bf 19 00 00 00 00 00 00 mov64 r9, r1 - 618 07 09 00 00 08 00 00 00 add64 r9, 0x8 - 620 bf 96 00 00 00 00 00 00 mov64 r6, r9 - 628 0f 76 00 00 00 00 00 00 add64 r6, r7 - 630 9c 66 00 00 00 00 00 00 ldxdw r6, [r6 + 0x0] - 638 1d 63 08 00 00 00 00 00 jeq r3, r6, +0x8 - 640 bf 03 00 00 00 00 00 00 mov64 r3, r0 - 648 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 - 650 bf 56 00 00 00 00 00 00 mov64 r6, r5 - 658 0f 36 00 00 00 00 00 00 add64 r6, r3 - 660 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 668 05 00 22 00 00 00 00 00 ja +0x22 - 670 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 - 678 05 00 3b 00 00 00 00 00 ja +0x3b - 680 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 - 688 5d 81 01 00 00 00 00 00 jne r1, r8, +0x1 - 690 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 - 698 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 - 6a0 0f 39 00 00 00 00 00 00 add64 r9, r3 - 6a8 bf 06 00 00 00 00 00 00 mov64 r6, r0 - 6b0 67 06 00 00 03 00 00 00 lsh64 r6, 0x3 - 6b8 9c 93 00 00 00 00 00 00 ldxdw r3, [r9 + 0x0] - 6c0 bf 37 00 00 00 00 00 00 mov64 r7, r3 - 6c8 0f 67 00 00 00 00 00 00 add64 r7, r6 - 6d0 9c 78 08 00 00 00 00 00 ldxdw r8, [r7 + 0x8] - 6d8 9f 89 00 00 00 00 00 00 stxdw [r9 + 0x0], r8 - 6e0 07 07 00 00 08 00 00 00 add64 r7, 0x8 - 6e8 15 08 01 00 00 00 00 00 jeq r8, 0x0, +0x1 - 6f0 9f 18 00 00 00 00 00 00 stxdw [r8 + 0x0], r1 - 6f8 9f 17 00 00 00 00 00 00 stxdw [r7 + 0x0], r1 - 700 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 708 9f 31 00 00 00 00 00 00 stxdw [r1 + 0x0], r3 - 710 9c 26 10 00 00 00 00 00 ldxdw r6, [r2 + 0x10] - 718 b4 07 00 00 01 00 00 00 mov32 w7, 0x1 - 720 1d 16 01 00 00 00 00 00 jeq r6, r1, +0x1 - 728 b4 07 00 00 00 00 00 00 mov32 w7, 0x0 - 730 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 - 738 bf 51 00 00 00 00 00 00 mov64 r1, r5 - 740 0f 71 00 00 00 00 00 00 add64 r1, r7 - 748 9f 31 00 00 00 00 00 00 stxdw [r1 + 0x0], r3 - 750 bf 01 00 00 00 00 00 00 mov64 r1, r0 - 758 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 - 760 bf 53 00 00 00 00 00 00 mov64 r3, r5 - 768 0f 13 00 00 00 00 00 00 add64 r3, r1 - 770 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] - 778 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 780 67 00 00 00 03 00 00 00 lsh64 r0, 0x3 - 788 0f 05 00 00 00 00 00 00 add64 r5, r0 - 790 67 04 00 00 03 00 00 00 lsh64 r4, 0x3 - 798 bf 36 00 00 00 00 00 00 mov64 r6, r3 - 7a0 0f 46 00 00 00 00 00 00 add64 r6, r4 - 7a8 9c 24 00 00 00 00 00 00 ldxdw r4, [r2 + 0x0] - 7b0 9c 67 08 00 00 00 00 00 ldxdw r7, [r6 + 0x8] - 7b8 9f 75 00 00 00 00 00 00 stxdw [r5 + 0x0], r7 - 7c0 07 06 00 00 08 00 00 00 add64 r6, 0x8 - 7c8 15 07 01 00 00 00 00 00 jeq r7, 0x0, +0x1 - 7d0 9f 27 00 00 00 00 00 00 stxdw [r7 + 0x0], r2 - 7d8 9f 26 00 00 00 00 00 00 stxdw [r6 + 0x0], r2 - 7e0 9f 43 00 00 00 00 00 00 stxdw [r3 + 0x0], r4 - 7e8 9f 32 00 00 00 00 00 00 stxdw [r2 + 0x0], r3 - 7f0 9c a5 38 00 00 00 00 00 ldxdw r5, [r10 + 0x38] - 7f8 15 04 08 00 00 00 00 00 jeq r4, 0x0, +0x8 - 800 9c 40 10 00 00 00 00 00 ldxdw r0, [r4 + 0x10] - 808 b4 05 00 00 01 00 00 00 mov32 w5, 0x1 - 810 1d 20 01 00 00 00 00 00 jeq r0, r2, +0x1 - 818 b4 05 00 00 00 00 00 00 mov32 w5, 0x0 - 820 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 - 828 0f 54 00 00 00 00 00 00 add64 r4, r5 - 830 07 04 00 00 08 00 00 00 add64 r4, 0x8 - 838 bf 45 00 00 00 00 00 00 mov64 r5, r4 - 840 9f 35 00 00 00 00 00 00 stxdw [r5 + 0x0], r3 - 848 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 - 850 27 02 1c 00 01 00 00 00 stb [r2 + 0x1c], 0x1 - 858 9c a0 40 00 00 00 00 00 ldxdw r0, [r10 + 0x40] - 860 9d 00 00 00 00 00 00 00 return - 868 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c - 870 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 878 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 880 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 888 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 890 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 898 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 8a0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 8a8 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 - 8b0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 8b8 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 8c0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 8c8 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 8d0 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 8d8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 8e0 b7 02 00 00 08 00 00 00 mov64 r2, 0x8 - 8e8 9f 2a 40 00 00 00 00 00 stxdw [r10 + 0x40], r2 - 8f0 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 8f8 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 900 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 908 5d 23 e9 ff 00 00 00 00 jne r3, r2, -0x17 - 910 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 918 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 920 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 928 5d 23 e5 ff 00 00 00 00 jne r3, r2, -0x1b - 930 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 938 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 940 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 948 5d 23 e1 ff 00 00 00 00 jne r3, r2, -0x1f - 950 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 958 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 960 5d 32 de ff 00 00 00 00 jne r2, r3, -0x22 - 968 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 970 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 978 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 980 07 04 00 00 a8 00 00 00 add64 r4, 0xa8 - 988 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 990 07 05 00 00 4f 00 00 00 add64 r5, 0x4f - 998 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 9a0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 9a8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 9b0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 9b8 9c a1 a8 00 00 00 00 00 ldxdw r1, [r10 + 0xa8] - 9c0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 9c8 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 9d0 9c a1 b0 00 00 00 00 00 ldxdw r1, [r10 + 0xb0] - 9d8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 9e0 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b - 9e8 9c a1 b8 00 00 00 00 00 ldxdw r1, [r10 + 0xb8] - 9f0 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 9f8 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 - a00 9c a1 c0 00 00 00 00 00 ldxdw r1, [r10 + 0xc0] - a08 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - a10 5d 21 65 00 00 00 00 00 jne r1, r2, +0x65 - a18 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a20 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - a28 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - a30 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - a38 9f 3a 7c 00 00 00 00 00 stxdw [r10 + 0x7c], r3 - a40 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - a48 9f 3a 74 00 00 00 00 00 stxdw [r10 + 0x74], r3 - a50 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - a58 9f 3a 6c 00 00 00 00 00 stxdw [r10 + 0x6c], r3 - a60 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - a68 9f 3a 64 00 00 00 00 00 stxdw [r10 + 0x64], r3 - a70 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - a78 9f 2a 54 00 00 00 00 00 stxdw [r10 + 0x54], r2 - a80 97 0a 5c 00 18 00 00 00 stdw [r10 + 0x5c], 0x18 - a88 87 0a 50 00 00 00 00 00 stw [r10 + 0x50], 0x0 - a90 9f 1a 98 00 00 00 00 00 stxdw [r10 + 0x98], r1 - a98 bf 72 00 00 00 00 00 00 mov64 r2, r7 - aa0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - aa8 9f 2a 88 00 00 00 00 00 stxdw [r10 + 0x88], r2 - ab0 37 0a a0 00 01 01 00 00 sth [r10 + 0xa0], 0x101 - ab8 37 0a 90 00 01 01 00 00 sth [r10 + 0x90], 0x101 - ac0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - ac8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - ad0 9f 3a 00 01 00 00 00 00 stxdw [r10 + 0x100], r3 - ad8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - ae0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - ae8 9f 3a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r3 - af0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - af8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - b00 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 - b08 9f 1a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r1 - b10 bf 71 00 00 00 00 00 00 mov64 r1, r7 - b18 07 01 00 00 30 00 00 00 add64 r1, 0x30 - b20 9f 1a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r1 - b28 bf 71 00 00 00 00 00 00 mov64 r1, r7 - b30 07 01 00 00 60 00 00 00 add64 r1, 0x60 - b38 9f 1a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r1 - b40 bf 71 00 00 00 00 00 00 mov64 r1, r7 - b48 07 01 00 00 50 00 00 00 add64 r1, 0x50 - b50 9f 1a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r1 - b58 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 - b60 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 - b68 37 0a 10 01 01 01 00 00 sth [r10 + 0x110], 0x101 - b70 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - b78 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - b80 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 - b88 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 - b90 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 - b98 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 - ba0 97 0a 30 01 00 00 00 00 stdw [r10 + 0x130], 0x0 - ba8 97 0a 28 01 00 00 00 00 stdw [r10 + 0x128], 0x0 - bb0 97 0a 20 01 00 00 00 00 stdw [r10 + 0x120], 0x0 - bb8 97 0a 18 01 00 00 00 00 stdw [r10 + 0x118], 0x0 + 4d8 07 02 00 00 38 01 00 00 add64 r2, 0x138 + 4e0 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 + 4e8 97 0a 70 00 0c 00 00 00 stdw [r10 + 0x70], 0xc + 4f0 97 0a 60 00 02 00 00 00 stdw [r10 + 0x60], 0x2 + 4f8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 500 97 0a 88 00 00 00 00 00 stdw [r10 + 0x88], 0x0 + 508 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 510 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 518 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 520 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 + 528 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 530 07 04 00 00 88 00 00 00 add64 r4, 0x88 + 538 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 540 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 548 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 550 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 558 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 560 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 568 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 570 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 578 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] + 580 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 588 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 590 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 598 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 5a0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5a8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5b0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + 5b8 55 04 5d ff 00 00 00 00 jne r4, 0x0, -0xa3 + 5c0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5c8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 5d0 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 + 5d8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 5e0 05 00 3d 00 00 00 00 00 ja +0x3d + 5e8 bf 29 00 00 00 00 00 00 mov64 r9, r2 + 5f0 0f 49 00 00 00 00 00 00 add64 r9, r4 + 5f8 9c 94 08 00 00 00 00 00 ldxdw r4, [r9 + 0x8] + 600 1d 43 05 00 00 00 00 00 jeq r3, r4, +0x5 + 608 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 610 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 618 05 00 1c 00 00 00 00 00 ja +0x1c + 620 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 628 05 00 34 00 00 00 00 00 ja +0x34 + 630 07 09 00 00 08 00 00 00 add64 r9, 0x8 + 638 bf 56 00 00 00 00 00 00 mov64 r6, r5 + 640 67 06 00 00 03 00 00 00 lsh64 r6, 0x3 + 648 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 650 07 03 00 00 08 00 00 00 add64 r3, 0x8 + 658 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 + 660 9f 6a 30 00 00 00 00 00 stxdw [r10 + 0x30], r6 + 668 0f 63 00 00 00 00 00 00 add64 r3, r6 + 670 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 + 678 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] + 680 9f 39 00 00 00 00 00 00 stxdw [r9 + 0x0], r3 + 688 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 690 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 698 9c a3 38 00 00 00 00 00 ldxdw r3, [r10 + 0x38] + 6a0 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 6a8 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 6b0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 6b8 bf 82 00 00 00 00 00 00 mov64 r2, r8 + 6c0 9c a3 30 00 00 00 00 00 ldxdw r3, [r10 + 0x30] + 6c8 0f 32 00 00 00 00 00 00 add64 r2, r3 + 6d0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 6d8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 6e0 67 02 00 00 03 00 00 00 lsh64 r2, 0x3 + 6e8 9c a3 28 00 00 00 00 00 ldxdw r3, [r10 + 0x28] + 6f0 0f 23 00 00 00 00 00 00 add64 r3, r2 + 6f8 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] + 700 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + 708 0f 58 00 00 00 00 00 00 add64 r8, r5 + 710 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 718 9f 38 00 00 00 00 00 00 stxdw [r8 + 0x0], r3 + 720 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 + 728 bf 45 00 00 00 00 00 00 mov64 r5, r4 + 730 0f 75 00 00 00 00 00 00 add64 r5, r7 + 738 07 05 00 00 08 00 00 00 add64 r5, 0x8 + 740 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 748 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 750 9f 15 00 00 00 00 00 00 stxdw [r5 + 0x0], r1 + 758 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 760 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 768 9c a3 40 00 00 00 00 00 ldxdw r3, [r10 + 0x40] + 770 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 + 778 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] + 780 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 + 788 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 + 790 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 + 798 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 + 7a0 0f 32 00 00 00 00 00 00 add64 r2, r3 + 7a8 07 02 00 00 08 00 00 00 add64 r2, 0x8 + 7b0 bf 23 00 00 00 00 00 00 mov64 r3, r2 + 7b8 9f 43 00 00 00 00 00 00 stxdw [r3 + 0x0], r4 + 7c0 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 7c8 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 7d0 9d 00 00 00 00 00 00 00 return + 7d8 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c + 7e0 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 7e8 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 7f0 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 7f8 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 800 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 808 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 810 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 818 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 + 820 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 828 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 830 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 838 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 840 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 848 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 850 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 858 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 860 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 868 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 870 5d 23 eb ff 00 00 00 00 jne r3, r2, -0x15 + 878 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 880 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 888 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 890 5d 23 e7 ff 00 00 00 00 jne r3, r2, -0x19 + 898 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 8a0 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 8a8 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 8b0 5d 23 e3 ff 00 00 00 00 jne r3, r2, -0x1d + 8b8 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 8c0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 8c8 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 + 8d0 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 8d8 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 8e0 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 8e8 07 04 00 00 a8 00 00 00 add64 r4, 0xa8 + 8f0 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 8f8 07 05 00 00 4f 00 00 00 add64 r5, 0x4f + 900 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 908 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 910 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 918 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 920 9c a1 a8 00 00 00 00 00 ldxdw r1, [r10 + 0xa8] + 928 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 930 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f + 938 9c a1 b0 00 00 00 00 00 ldxdw r1, [r10 + 0xb0] + 940 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 948 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c + 950 9c a1 b8 00 00 00 00 00 ldxdw r1, [r10 + 0xb8] + 958 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 960 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 + 968 9c a1 c0 00 00 00 00 00 ldxdw r1, [r10 + 0xc0] + 970 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 978 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 + 980 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 988 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 990 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 998 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 9a0 9f 3a 7c 00 00 00 00 00 stxdw [r10 + 0x7c], r3 + 9a8 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 9b0 9f 3a 74 00 00 00 00 00 stxdw [r10 + 0x74], r3 + 9b8 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 9c0 9f 3a 6c 00 00 00 00 00 stxdw [r10 + 0x6c], r3 + 9c8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 9d0 9f 3a 64 00 00 00 00 00 stxdw [r10 + 0x64], r3 + 9d8 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 9e0 9f 2a 54 00 00 00 00 00 stxdw [r10 + 0x54], r2 + 9e8 97 0a 5c 00 18 00 00 00 stdw [r10 + 0x5c], 0x18 + 9f0 87 0a 50 00 00 00 00 00 stw [r10 + 0x50], 0x0 + 9f8 9f 1a 98 00 00 00 00 00 stxdw [r10 + 0x98], r1 + a00 bf 72 00 00 00 00 00 00 mov64 r2, r7 + a08 07 02 00 00 10 00 00 00 add64 r2, 0x10 + a10 9f 2a 88 00 00 00 00 00 stxdw [r10 + 0x88], r2 + a18 37 0a a0 00 01 01 00 00 sth [r10 + 0xa0], 0x101 + a20 37 0a 90 00 01 01 00 00 sth [r10 + 0x90], 0x101 + a28 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a30 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + a38 9f 3a 00 01 00 00 00 00 stxdw [r10 + 0x100], r3 + a40 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a48 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + a50 9f 3a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r3 + a58 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a60 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + a68 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + a70 9f 1a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r1 + a78 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a80 07 01 00 00 30 00 00 00 add64 r1, 0x30 + a88 9f 1a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r1 + a90 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a98 07 01 00 00 60 00 00 00 add64 r1, 0x60 + aa0 9f 1a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r1 + aa8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + ab0 07 01 00 00 50 00 00 00 add64 r1, 0x50 + ab8 9f 1a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r1 + ac0 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + ac8 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + ad0 37 0a 10 01 01 01 00 00 sth [r10 + 0x110], 0x101 + ad8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + ae0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + ae8 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + af0 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + af8 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + b00 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + b08 97 0a 30 01 00 00 00 00 stdw [r10 + 0x130], 0x0 + b10 97 0a 28 01 00 00 00 00 stdw [r10 + 0x128], 0x0 + b18 97 0a 20 01 00 00 00 00 stdw [r10 + 0x120], 0x0 + b20 97 0a 18 01 00 00 00 00 stdw [r10 + 0x118], 0x0 + b28 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b30 07 01 00 00 50 00 00 00 add64 r1, 0x50 + b38 9f 1a 50 01 00 00 00 00 stxdw [r10 + 0x150], r1 + b40 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b48 07 01 00 00 88 00 00 00 add64 r1, 0x88 + b50 9f 1a 40 01 00 00 00 00 stxdw [r10 + 0x140], r1 + b58 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b60 07 01 00 00 18 01 00 00 add64 r1, 0x118 + b68 9f 1a 38 01 00 00 00 00 stxdw [r10 + 0x138], r1 + b70 97 0a 58 01 34 00 00 00 stdw [r10 + 0x158], 0x34 + b78 97 0a 48 01 02 00 00 00 stdw [r10 + 0x148], 0x2 + b80 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b88 07 01 00 00 4f 00 00 00 add64 r1, 0x4f + b90 9f 1a 60 01 00 00 00 00 stxdw [r10 + 0x160], r1 + b98 97 0a 68 01 01 00 00 00 stdw [r10 + 0x168], 0x1 + ba0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + ba8 07 01 00 00 60 01 00 00 add64 r1, 0x160 + bb0 9f 1a 70 01 00 00 00 00 stxdw [r10 + 0x170], r1 + bb8 97 0a 78 01 01 00 00 00 stdw [r10 + 0x178], 0x1 bc0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bc8 07 01 00 00 50 00 00 00 add64 r1, 0x50 - bd0 9f 1a 50 01 00 00 00 00 stxdw [r10 + 0x150], r1 - bd8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - be0 07 01 00 00 88 00 00 00 add64 r1, 0x88 - be8 9f 1a 40 01 00 00 00 00 stxdw [r10 + 0x140], r1 - bf0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bf8 07 01 00 00 18 01 00 00 add64 r1, 0x118 - c00 9f 1a 38 01 00 00 00 00 stxdw [r10 + 0x138], r1 - c08 97 0a 58 01 34 00 00 00 stdw [r10 + 0x158], 0x34 - c10 97 0a 48 01 02 00 00 00 stdw [r10 + 0x148], 0x2 - c18 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c20 07 01 00 00 4f 00 00 00 add64 r1, 0x4f - c28 9f 1a 60 01 00 00 00 00 stxdw [r10 + 0x160], r1 - c30 97 0a 68 01 01 00 00 00 stdw [r10 + 0x168], 0x1 - c38 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c40 07 01 00 00 60 01 00 00 add64 r1, 0x160 - c48 9f 1a 70 01 00 00 00 00 stxdw [r10 + 0x170], r1 - c50 97 0a 78 01 01 00 00 00 stdw [r10 + 0x178], 0x1 - c58 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c60 07 01 00 00 38 01 00 00 add64 r1, 0x138 - c68 bf a2 00 00 00 00 00 00 mov64 r2, r10 - c70 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 - c78 bf a4 00 00 00 00 00 00 mov64 r4, r10 - c80 07 04 00 00 70 01 00 00 add64 r4, 0x170 - c88 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - c90 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - c98 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - ca0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - ca8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - cb0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - cb8 05 00 27 ff 00 00 00 00 ja -0xd9 - cc0 b7 01 00 00 0c 00 00 00 mov64 r1, 0xc - cc8 05 00 26 ff 00 00 00 00 ja -0xda - cd0 b7 01 00 00 01 00 00 00 mov64 r1, 0x1 - cd8 05 00 24 ff 00 00 00 00 ja -0xdc - ce0 b7 01 00 00 02 00 00 00 mov64 r1, 0x2 - ce8 05 00 22 ff 00 00 00 00 ja -0xde - cf0 b7 01 00 00 05 00 00 00 mov64 r1, 0x5 - cf8 05 00 20 ff 00 00 00 00 ja -0xe0 - d00 b7 01 00 00 06 00 00 00 mov64 r1, 0x6 - d08 05 00 1e ff 00 00 00 00 ja -0xe2 - d10 b7 01 00 00 04 00 00 00 mov64 r1, 0x4 - d18 05 00 1c ff 00 00 00 00 ja -0xe4 - d20 b7 01 00 00 0d 00 00 00 mov64 r1, 0xd - d28 05 00 1a ff 00 00 00 00 ja -0xe6 - d30 b7 01 00 00 07 00 00 00 mov64 r1, 0x7 - d38 05 00 18 ff 00 00 00 00 ja -0xe8 - d40 b7 01 00 00 0a 00 00 00 mov64 r1, 0xa - d48 05 00 16 ff 00 00 00 00 ja -0xea - d50 b7 01 00 00 0b 00 00 00 mov64 r1, 0xb - d58 05 00 14 ff 00 00 00 00 ja -0xec - d60 b7 01 00 00 03 00 00 00 mov64 r1, 0x3 - d68 05 00 12 ff 00 00 00 00 ja -0xee \ No newline at end of file + bc8 07 01 00 00 38 01 00 00 add64 r1, 0x138 + bd0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + bd8 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 + be0 bf a4 00 00 00 00 00 00 mov64 r4, r10 + be8 07 04 00 00 70 01 00 00 add64 r4, 0x170 + bf0 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + bf8 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + c00 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + c08 bf 71 00 00 00 00 00 00 mov64 r1, r7 + c10 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + c18 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + c20 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + c28 05 00 74 ff 00 00 00 00 ja -0x8c + c30 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + c38 05 00 72 ff 00 00 00 00 ja -0x8e + c40 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + c48 05 00 70 ff 00 00 00 00 ja -0x90 + c50 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + c58 05 00 6e ff 00 00 00 00 ja -0x92 + c60 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + c68 05 00 6c ff 00 00 00 00 ja -0x94 + c70 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + c78 05 00 6a ff 00 00 00 00 ja -0x96 + c80 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + c88 05 00 68 ff 00 00 00 00 ja -0x98 + c90 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + c98 05 00 66 ff 00 00 00 00 ja -0x9a + ca0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + ca8 05 00 64 ff 00 00 00 00 ja -0x9c + cb0 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + cb8 05 00 62 ff 00 00 00 00 ja -0x9e + cc0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + cc8 05 00 60 ff 00 00 00 00 ja -0xa0 + cd0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + cd8 05 00 5e ff 00 00 00 00 ja -0xa2 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index b523233e..7f3b4d2e 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,17 +1,17 @@ .globl entrypoint entrypoint: - add64 r10, -320 + add64 r10, -384 ldxdw r4, [r1+0] ldxdw r3, [r2-8] ldxb r5, [r2+0] - jne r5, 1, jmp_0800 - jne r3, 5, jmp_0c58 - jlt r4, 2, jmp_0c68 + jne r5, 1, jmp_07d8 + jne r3, 5, jmp_0c30 + jlt r4, 2, jmp_0c40 ldxdw r3, [r1+88] - jne r3, 0, jmp_0c78 + jne r3, 0, jmp_0c50 ldxb r3, [r1+10344] - jne r3, 255, jmp_0c88 + jne r3, 255, jmp_0c60 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] @@ -24,76 +24,76 @@ entrypoint: jeq r4, 0, jmp_05c0 jmp_00a8: - ldxh r2, [r2+1] + ldxh r1, [r2+1] ja jmp_00d8 jmp_00b8: - mov64 r5, r1 + mov64 r5, r2 add64 r5, r4 ldxdw r4, [r5+0] jeq r4, 0, jmp_0120 jmp_00d8: - mov64 r1, r4 + mov64 r2, r4 mov64 r4, 16 - ldxh r5, [r1+24] - mov64 r0, r2 + ldxh r5, [r2+24] + mov64 r0, r1 jgt r0, r5, jmp_00b8 mov64 r4, 8 jlt r0, r5, jmp_00b8 mov64 r0, 14 - ja jmp_07f8 + ja jmp_07d0 jmp_0120: - stxdw [r10+0], r6 - stxdw [r3+0], r1 + stxdw [r10+64], r6 + stxdw [r3+0], r2 stb [r3+28], 1 - mov64 r4, r2 - ldxh r5, [r1+24] - mov32 r2, 1 + mov64 r4, r1 + ldxh r5, [r2+24] + mov32 r1, 1 jgt r4, r5, jmp_0160 - mov32 r2, 0 + mov32 r1, 0 jmp_0160: - lsh64 r2, 3 - mov64 r4, r1 - add64 r4, r2 + lsh64 r1, 3 + mov64 r4, r2 + add64 r4, r1 stxdw [r4+8], r3 mov64 r0, 0 jmp_0188: - ldxb r2, [r1+28] - jeq r2, 0, jmp_07f8 - ldxdw r2, [r1+0] - jeq r2, 0, jmp_0638 - ldxdw r5, [r2+16] - mov32 r4, 1 - jeq r1, r5, jmp_01c8 - mov32 r4, 0 + ldxb r1, [r2+28] + jeq r1, 0, jmp_07d0 + ldxdw r1, [r2+0] + jeq r1, 0, jmp_0620 + ldxdw r4, [r1+16] + mov32 r5, 1 + jeq r2, r4, jmp_01c8 + mov32 r5, 0 jmp_01c8: - mov64 r5, r2 - add64 r5, 8 - mov64 r7, r4 + mov64 r8, r1 + add64 r8, 8 + mov64 r7, r5 xor64 r7, 1 - mov64 r8, r7 - lsh64 r8, 3 - mov64 r9, r5 - add64 r9, r8 + mov64 r4, r7 + lsh64 r4, 3 + mov64 r9, r8 + add64 r9, r4 ldxdw r9, [r9+0] jeq r9, 0, jmp_05e8 ldxb r6, [r9+28] jeq r6, 0, jmp_05e8 - stb [r1+28], 0 + stb [r2+28], 0 stb [r9+28], 0 - stb [r2+28], 1 - ldxdw r1, [r2+0] - mov64 r3, r2 - jne r1, 0, jmp_0188 - ja jmp_07f8 + stb [r1+28], 1 + ldxdw r2, [r1+0] + mov64 r3, r1 + jne r2, 0, jmp_0188 + ja jmp_07d0 jmp_0260: - jne r4, 4, jmp_0cb8 + jne r4, 4, jmp_0c90 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -101,89 +101,89 @@ jmp_0260: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0c98 + jne r5, 255, jmp_0c70 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0ca8 + jne r5, 14, jmp_0c80 ldxb r5, [r4+31032] - jne r5, 255, jmp_0cc8 + jne r5, 255, jmp_0ca0 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 ldxdw r7, [r4+31040] - jne r7, r5, jmp_07f8 + jne r7, r5, jmp_07d0 mov32 r5, 1288277025 hor64 r5, 2146519613 ldxdw r7, [r4+31048] - jne r7, r5, jmp_07f8 + jne r7, r5, jmp_07d0 mov32 r5, 149871192 hor64 r5, 1157472667 ldxdw r7, [r4+31056] - jne r7, r5, jmp_07f8 + jne r7, r5, jmp_07d0 mov64 r7, r2 ldxdw r2, [r4+31064] mov32 r5, -1965433885 - jne r2, r5, jmp_07f8 + jne r2, r5, jmp_07d0 ldxdw r2, [r4+31120] lmul64 r2, 29 - stxdw [r10+308], r2 - stw [r10+304], 2 + stxdw [r10+372], r2 + stw [r10+368], 2 mov64 r4, r1 add64 r4, 10352 - stxdw [r10+232], r4 + stxdw [r10+296], r4 mov64 r2, r1 add64 r2, 16 - stxdw [r10+216], r2 - sth [r10+240], 1 - sth [r10+224], 257 + stxdw [r10+280], r2 + sth [r10+304], 1 + sth [r10+288], 257 mov64 r5, r1 add64 r5, 10384 - stxdw [r10+192], r5 - stxdw [r10+184], r6 - stxdw [r10+176], r3 + stxdw [r10+256], r5 + stxdw [r10+248], r6 + stxdw [r10+240], r3 mov64 r3, r1 add64 r3, 10416 - stxdw [r10+168], r3 - stxdw [r10+160], r4 + stxdw [r10+232], r3 + stxdw [r10+224], r4 mov64 r3, r1 add64 r3, 48 - stxdw [r10+136], r3 + stxdw [r10+200], r3 mov64 r3, r1 add64 r3, 96 - stxdw [r10+128], r3 + stxdw [r10+192], r3 mov64 r3, r1 add64 r3, 80 - stxdw [r10+112], r3 - stxdw [r10+104], r2 - stb [r10+210], 0 - sth [r10+208], 256 - stdw [r10+200], 0 - stb [r10+154], 0 - sth [r10+152], 257 - stdw [r10+144], 0 - stdw [r10+120], 0 - stdw [r10+272], 0 + stxdw [r10+176], r3 + stxdw [r10+168], r2 + stb [r10+274], 0 + sth [r10+272], 256 stdw [r10+264], 0 - stdw [r10+256], 0 - stdw [r10+248], 0 + stb [r10+218], 0 + sth [r10+216], 257 + stdw [r10+208], 0 + stdw [r10+184], 0 + stdw [r10+336], 0 + stdw [r10+328], 0 + stdw [r10+320], 0 + stdw [r10+312], 0 mov64 r2, r10 - add64 r2, 304 - stxdw [r10+40], r2 + add64 r2, 368 + stxdw [r10+104], r2 mov64 r2, r10 - add64 r2, 216 - stxdw [r10+24], r2 + add64 r2, 280 + stxdw [r10+88], r2 mov64 r2, r10 - add64 r2, 248 - stxdw [r10+16], r2 - stdw [r10+48], 12 - stdw [r10+32], 2 - stdw [r10+80], 0 - stdw [r10+72], 0 + add64 r2, 312 + stxdw [r10+80], r2 + stdw [r10+112], 12 + stdw [r10+96], 2 + stdw [r10+144], 0 + stdw [r10+136], 0 mov64 r3, r10 - add64 r3, 16 + add64 r3, 80 mov64 r2, r10 - add64 r2, 104 + add64 r2, 168 mov64 r4, r10 - add64 r4, 72 + add64 r4, 136 mov64 r8, r1 mov64 r1, r3 mov64 r3, 2 @@ -209,230 +209,223 @@ jmp_05c0: jmp_05d8: mov64 r0, 0 - ja jmp_07f8 + ja jmp_07d0 jmp_05e8: - mov64 r9, r1 - add64 r9, r8 - ldxdw r8, [r9+8] - jeq r3, r8, jmp_0648 + mov64 r9, r2 + add64 r9, r4 + ldxdw r4, [r9+8] + jeq r3, r4, jmp_0630 mov64 r3, r4 - lsh64 r3, 3 - mov64 r6, r5 - add64 r6, r3 - ldxdw r3, [r6+0] - ja jmp_0720 + mov64 r4, r2 + ja jmp_0700 -jmp_0638: - stb [r1+28], 0 - ja jmp_07f8 +jmp_0620: + stb [r2+28], 0 + ja jmp_07d0 -jmp_0648: +jmp_0630: add64 r9, 8 - mov64 r6, r4 + mov64 r6, r5 lsh64 r6, 3 - mov64 r3, r8 - add64 r3, r6 - ldxdw r6, [r3+8] - stxdw [r9+0], r6 + mov64 r3, r4 add64 r3, 8 - jeq r6, 0, jmp_0698 - stxdw [r6+0], r1 + stxdw [r10+40], r3 + stxdw [r10+48], r6 + add64 r3, r6 + stxdw [r10+56], r3 + ldxdw r3, [r3+0] + stxdw [r9+0], r3 + jeq r3, 0, jmp_0698 + stxdw [r3+0], r2 jmp_0698: + ldxdw r3, [r10+56] + stxdw [r3+0], r2 + stxdw [r4+0], r1 + stxdw [r2+0], r4 + mov64 r2, r8 + ldxdw r3, [r10+48] + add64 r2, r3 + stxdw [r2+0], r4 + mov64 r2, r7 + lsh64 r2, 3 + ldxdw r3, [r10+40] + add64 r3, r2 + ldxdw r3, [r3+0] + +jmp_0700: + lsh64 r5, 3 + add64 r8, r5 + ldxdw r2, [r1+0] + stxdw [r8+0], r3 + lsh64 r7, 3 + mov64 r5, r4 + add64 r5, r7 + add64 r5, 8 + jeq r3, 0, jmp_0750 stxdw [r3+0], r1 - stxdw [r8+0], r2 - stxdw [r1+0], r8 - ldxdw r6, [r2+16] + +jmp_0750: + stxdw [r5+0], r1 + stxdw [r4+0], r2 + stxdw [r1+0], r4 + ldxdw r3, [r10+64] + jeq r2, 0, jmp_07b8 + ldxdw r5, [r2+16] mov32 r3, 1 - jeq r1, r6, jmp_06d0 + jeq r1, r5, jmp_0798 mov32 r3, 0 -jmp_06d0: +jmp_0798: lsh64 r3, 3 - mov64 r1, r5 - add64 r1, r3 - stxdw [r1+0], r8 - mov64 r1, r4 - lsh64 r1, 3 - mov64 r3, r5 - add64 r3, r1 - ldxdw r3, [r3+0] - mov64 r1, r3 - -jmp_0720: - lsh64 r4, 3 - add64 r5, r4 - lsh64 r7, 3 - mov64 r8, r3 - add64 r8, r7 - ldxdw r4, [r2+0] - ldxdw r7, [r8+8] - stxdw [r5+0], r7 - add64 r8, 8 - jeq r7, 0, jmp_0778 - stxdw [r7+0], r2 - -jmp_0778: - stxdw [r8+0], r2 - stxdw [r3+0], r4 - stxdw [r2+0], r3 - jeq r4, 0, jmp_07d8 - ldxdw r6, [r4+16] - mov32 r5, 1 - jeq r2, r6, jmp_07b8 - mov32 r5, 0 + add64 r2, r3 + stxdw [r2+8], r4 + ja jmp_07c0 jmp_07b8: - lsh64 r5, 3 - add64 r4, r5 - stxdw [r4+8], r3 - ja jmp_07e8 - -jmp_07d8: - ldxdw r4, [r10+0] - stxdw [r4+0], r3 + stxdw [r3+0], r4 -jmp_07e8: - stb [r1+28], 0 - stb [r2+28], 1 +jmp_07c0: + stb [r4+28], 0 + stb [r1+28], 1 -jmp_07f8: +jmp_07d0: exit -jmp_0800: - jne r5, 0, jmp_0cd8 - jne r3, 1, jmp_0c58 - jne r4, 4, jmp_0c68 +jmp_07d8: + jne r5, 0, jmp_0cb0 + jne r3, 1, jmp_0c30 + jne r4, 4, jmp_0c40 ldxdw r2, [r1+88] - jne r2, 0, jmp_0c78 + jne r2, 0, jmp_0c50 ldxb r2, [r1+10344] - jne r2, 255, jmp_0c88 + jne r2, 255, jmp_0c60 ldxdw r2, [r1+10424] - jne r2, 0, jmp_0ce8 + jne r2, 0, jmp_0cc0 ldxb r2, [r1+20680] - jne r2, 255, jmp_0c98 + jne r2, 255, jmp_0c70 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0ca8 + jne r2, 14, jmp_0c80 ldxb r2, [r1+31032] - jne r2, 255, jmp_0cc8 + jne r2, 255, jmp_0ca0 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_07f8 + jne r3, r2, jmp_07d0 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_07f8 + jne r3, r2, jmp_07d0 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_07f8 + jne r3, r2, jmp_07d0 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_07f8 + jne r2, r3, jmp_07d0 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 - add64 r4, 104 + add64 r4, 168 mov64 r5, r10 - add64 r5, 15 + add64 r5, 79 mov64 r7, r1 mov64 r2, 0 mov64 r3, r6 call sol_try_find_program_address mov64 r0, 10 - ldxdw r1, [r10+104] + ldxdw r1, [r10+168] ldxdw r2, [r7+10352] - jne r1, r2, jmp_07f8 - ldxdw r1, [r10+112] + jne r1, r2, jmp_07d0 + ldxdw r1, [r10+176] ldxdw r2, [r7+10360] - jne r1, r2, jmp_07f8 - ldxdw r1, [r10+120] + jne r1, r2, jmp_07d0 + ldxdw r1, [r10+184] ldxdw r2, [r7+10368] - jne r1, r2, jmp_07f8 - ldxdw r1, [r10+128] + jne r1, r2, jmp_07d0 + ldxdw r1, [r10+192] ldxdw r2, [r7+10376] - jne r1, r2, jmp_07f8 + jne r1, r2, jmp_07d0 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] ldxdw r3, [r6+24] - stxdw [r10+60], r3 + stxdw [r10+124], r3 ldxdw r3, [r6+16] - stxdw [r10+52], r3 + stxdw [r10+116], r3 ldxdw r3, [r6+8] - stxdw [r10+44], r3 + stxdw [r10+108], r3 ldxdw r3, [r6+0] - stxdw [r10+36], r3 + stxdw [r10+100], r3 lmul64 r2, 152 - stxdw [r10+20], r2 - stdw [r10+28], 24 - stw [r10+16], 0 - stxdw [r10+88], r1 + stxdw [r10+84], r2 + stdw [r10+92], 24 + stw [r10+80], 0 + stxdw [r10+152], r1 mov64 r2, r7 add64 r2, 16 - stxdw [r10+72], r2 - sth [r10+96], 257 - sth [r10+80], 257 + stxdw [r10+136], r2 + sth [r10+160], 257 + sth [r10+144], 257 mov64 r3, r7 add64 r3, 10384 - stxdw [r10+192], r3 + stxdw [r10+256], r3 mov64 r3, r7 add64 r3, 10432 - stxdw [r10+184], r3 + stxdw [r10+248], r3 mov64 r3, r7 add64 r3, 10416 - stxdw [r10+168], r3 - stxdw [r10+160], r1 + stxdw [r10+232], r3 + stxdw [r10+224], r1 mov64 r1, r7 add64 r1, 48 - stxdw [r10+136], r1 + stxdw [r10+200], r1 mov64 r1, r7 add64 r1, 96 - stxdw [r10+128], r1 + stxdw [r10+192], r1 mov64 r1, r7 add64 r1, 80 - stxdw [r10+112], r1 - stxdw [r10+104], r2 - stb [r10+210], 0 - sth [r10+208], 257 - stdw [r10+200], 0 - stdw [r10+176], 0 - stb [r10+154], 0 - sth [r10+152], 257 - stdw [r10+144], 0 - stdw [r10+120], 0 + stxdw [r10+176], r1 + stxdw [r10+168], r2 + stb [r10+274], 0 + sth [r10+272], 257 + stdw [r10+264], 0 stdw [r10+240], 0 - stdw [r10+232], 0 - stdw [r10+224], 0 - stdw [r10+216], 0 + stb [r10+218], 0 + sth [r10+216], 257 + stdw [r10+208], 0 + stdw [r10+184], 0 + stdw [r10+304], 0 + stdw [r10+296], 0 + stdw [r10+288], 0 + stdw [r10+280], 0 mov64 r1, r10 - add64 r1, 16 - stxdw [r10+272], r1 + add64 r1, 80 + stxdw [r10+336], r1 mov64 r1, r10 - add64 r1, 72 - stxdw [r10+256], r1 + add64 r1, 136 + stxdw [r10+320], r1 mov64 r1, r10 - add64 r1, 216 - stxdw [r10+248], r1 - stdw [r10+280], 52 - stdw [r10+264], 2 + add64 r1, 280 + stxdw [r10+312], r1 + stdw [r10+344], 52 + stdw [r10+328], 2 mov64 r1, r10 - add64 r1, 15 - stxdw [r10+288], r1 - stdw [r10+296], 1 + add64 r1, 79 + stxdw [r10+352], r1 + stdw [r10+360], 1 mov64 r1, r10 - add64 r1, 288 - stxdw [r10+304], r1 - stdw [r10+312], 1 + add64 r1, 352 + stxdw [r10+368], r1 + stdw [r10+376], 1 mov64 r1, r10 - add64 r1, 248 + add64 r1, 312 mov64 r2, r10 - add64 r2, 104 + add64 r2, 168 mov64 r4, r10 - add64 r4, 304 + add64 r4, 368 mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c @@ -441,42 +434,42 @@ jmp_0800: stxdw [r7+10448], r1 ja jmp_05d8 -jmp_0c58: +jmp_0c30: mov64 r0, 12 - ja jmp_07f8 + ja jmp_07d0 -jmp_0c68: +jmp_0c40: mov64 r0, 1 - ja jmp_07f8 + ja jmp_07d0 -jmp_0c78: +jmp_0c50: mov64 r0, 2 - ja jmp_07f8 + ja jmp_07d0 -jmp_0c88: +jmp_0c60: mov64 r0, 5 - ja jmp_07f8 + ja jmp_07d0 -jmp_0c98: +jmp_0c70: mov64 r0, 6 - ja jmp_07f8 + ja jmp_07d0 -jmp_0ca8: +jmp_0c80: mov64 r0, 4 - ja jmp_07f8 + ja jmp_07d0 -jmp_0cb8: +jmp_0c90: mov64 r0, 13 - ja jmp_07f8 + ja jmp_07d0 -jmp_0cc8: +jmp_0ca0: mov64 r0, 7 - ja jmp_07f8 + ja jmp_07d0 -jmp_0cd8: +jmp_0cb0: mov64 r0, 11 - ja jmp_07f8 + ja jmp_07d0 -jmp_0ce8: +jmp_0cc0: mov64 r0, 3 - ja jmp_07f8 + ja jmp_07d0 diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt index 91fda2d0..8f54fed3 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup.txt @@ -4,10 +4,10 @@ insert_get_child_dir: ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; jgt r4, r5, insert_get_child_dir_branch_r insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; ja insert_fixup_main insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; insert_fixup_main: # r2 := parent @@ -39,13 +39,10 @@ insert_fixup_check_case_5_6_dir_l: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_l: - ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[right]; + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[R]; jne r9, r8, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - # rotate_subtree(tree_header, parent, LEFT) - # subtree=r2(parent), grandparent=r3(non-null), dir=L, opp=R - # --------------------------------------------------------------------- ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; @@ -60,9 +57,6 @@ insert_fixup_case_5_dir_l_skip: mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_l: - # rotate_subtree(tree_header, grandparent, RIGHT) - # subtree=r3(grandparent), new_root=r2(parent), dir=R, opp=L - # --------------------------------------------------------------------- ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; @@ -94,13 +88,10 @@ insert_fixup_check_case_5_6_dir_r: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_r: - ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[left]; + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[L]; jne r9, r8, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - # rotate_subtree(tree_header, parent, RIGHT) - # subtree=r2(parent), grandparent=r3(non-null), dir=R, opp=L - # --------------------------------------------------------------------- ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; @@ -115,9 +106,6 @@ insert_fixup_case_5_dir_r_skip: mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_r: - # rotate_subtree(tree_header, grandparent, LEFT) - # subtree=r3(grandparent), new_root=r2(parent), dir=L, opp=R - # --------------------------------------------------------------------- ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index 0b3f37fa..d8ac2c5b 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -12,8 +12,8 @@ insert_search_loop: mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[L]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[R]; ja insert_search_loop \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup.txt b/examples/tree/artifacts/snippets/rs/insert-fixup.txt index e951c2d1..6a898f68 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup.txt @@ -24,15 +24,63 @@ let dir = direction(parent) as usize; let uncle = (*grandparent).child[opposite(dir)]; if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5. + // Case 5: rotate parent in dir. + // + // Grandparent is guaranteed non-null by the case 4 check, so no + // root-replacement path is needed. Parent is known to be + // grandparent.child[dir] from the direction() call, so the child + // pointer update is hardcoded without comparison. if node == (*parent).child[opposite(dir)] { - rotate_subtree(tree_header, parent, dir); + let new_root = (*parent).child[opposite(dir)]; + let new_child = (*new_root).child[dir]; + + (*parent).child[opposite(dir)] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[dir] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[dir] = new_root; + node = parent; - parent = (*grandparent).child[dir]; + parent = new_root; + } + + // Case 6: rotate grandparent in opposite(dir). + // + // The new root of this rotation is parent + // (= grandparent.child[dir]), which the caller already has, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), so + // the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated to + // dir, so the pointer comparison is also retained. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[opposite(dir)]; + + (*grandparent).child[dir] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[opposite(dir)] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } } - // Case 6. - rotate_subtree(tree_header, grandparent, opposite(dir)); (*parent).color = Color::Black; (*grandparent).color = Color::Red; return SUCCESS; diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 17b2b41b..02744479 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,10 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction discriminator | 7 | 12 | +5 | +71.4% | +| Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index e06b9339..ac84fbbb 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,8 +1,8 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 107 | 140 | +33 | +30.8% | -| User has insufficient Lamports | 2596 | 107 | 140 | +33 | +30.8% | -| CreateAccount happy path | 2596 | 111 | 149 | +38 | +34.2% | +| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | +| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | +| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 @@ -10,7 +10,7 @@ test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2586 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -22,7 +22,7 @@ test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 [ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2736 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -32,5 +32,5 @@ test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2745 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index 278c543a..a7dcd6ae 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,122 +1,122 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 8 | 13 | +5 | +62.5% | -| Too few accounts | 9 | 14 | +5 | +55.6% | -| Too many accounts | 9 | 14 | +5 | +55.6% | -| User has nonzero data length | 11 | 16 | +5 | +45.5% | -| Tree account is duplicate | 13 | 18 | +5 | +38.5% | -| Tree has nonzero data length | 15 | 20 | +5 | +33.3% | -| System program is duplicate | 17 | 22 | +5 | +29.4% | -| System program wrong data length | 19 | 24 | +5 | +26.3% | -| Rent sysvar is duplicate | 21 | 26 | +5 | +23.8% | -| Rent address mismatch word 0 | 24 | 28 | +4 | +16.7% | -| Rent address mismatch word 1 | 24 | 28 | +4 | +16.7% | -| Rent address mismatch word 2 | 27 | 32 | +5 | +18.5% | -| Rent address mismatch word 3 | 27 | 32 | +5 | +18.5% | -| Rent address mismatch word 4 | 30 | 36 | +6 | +20.0% | -| Rent address mismatch word 5 | 30 | 36 | +6 | +20.0% | -| Rent address mismatch word 6 | 33 | 39 | +6 | +18.2% | -| Rent address mismatch word 7 | 33 | 39 | +6 | +18.2% | +| Invalid instruction data length | 8 | 10 | +2 | +25.0% | +| Too few accounts | 9 | 11 | +2 | +22.2% | +| Too many accounts | 9 | 11 | +2 | +22.2% | +| User has nonzero data length | 11 | 13 | +2 | +18.2% | +| Tree account is duplicate | 13 | 15 | +2 | +15.4% | +| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | +| System program is duplicate | 17 | 19 | +2 | +11.8% | +| System program wrong data length | 19 | 21 | +2 | +10.5% | +| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | +| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | +| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | +| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | +| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 8a45a489..49588334 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,31 +1,31 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 44 | 56 | +12 | +27.3% | -| PDA mismatch chunk 2 | 1500 | 47 | 59 | +12 | +25.5% | -| PDA mismatch chunk 3 | 1500 | 50 | 62 | +12 | +24.0% | -| PDA mismatch chunk 4 | 1500 | 53 | 65 | +12 | +22.6% | +| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | +| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | +| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | +| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1556 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1559 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1562 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1565 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt index 77112f51..9d599f65 100644 --- a/examples/tree/artifacts/tests/insert/result.txt +++ b/examples/tree/artifacts/tests/insert/result.txt @@ -1,27 +1,27 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| Instruction data too short | 0 | 7 | 12 | +5 | +71.4% | -| Instruction data too long | 0 | 7 | 12 | +5 | +71.4% | -| Insert skip alloc | 0 | 25 | 29 | +4 | +16.0% | -| Insert alloc happy path | 1096 | 101 | 134 | +33 | +32.7% | +| Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | +| Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | +| Insert skip alloc | 0 | 25 | 27 | +2 | +8.0% | +| Insert alloc happy path | 1096 | 101 | 129 | +28 | +27.7% | test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -31,5 +31,5 @@ test tests::test_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1230 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1225 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc_checks/result.txt b/examples/tree/artifacts/tests/insert_alloc_checks/result.txt index e20d8d5c..0453694c 100644 --- a/examples/tree/artifacts/tests/insert_alloc_checks/result.txt +++ b/examples/tree/artifacts/tests/insert_alloc_checks/result.txt @@ -1,59 +1,59 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Wrong N accounts for allocation | 15 | 22 | +7 | +46.7% | -| System program is duplicate | 23 | 30 | +7 | +30.4% | -| System program wrong data length | 25 | 32 | +7 | +28.0% | -| Rent sysvar is duplicate | 27 | 34 | +7 | +25.9% | -| Rent address mismatch chunk 0 | 30 | 36 | +6 | +20.0% | -| Rent address mismatch chunk 1 | 33 | 40 | +7 | +21.2% | -| Rent address mismatch chunk 2 | 36 | 44 | +8 | +22.2% | -| Rent address mismatch chunk 3 | 39 | 49 | +10 | +25.6% | +| Wrong N accounts for allocation | 15 | 19 | +4 | +26.7% | +| System program is duplicate | 23 | 27 | +4 | +17.4% | +| System program wrong data length | 25 | 29 | +4 | +16.0% | +| Rent sysvar is duplicate | 27 | 31 | +4 | +14.8% | +| Rent address mismatch chunk 0 | 30 | 34 | +4 | +13.3% | +| Rent address mismatch chunk 1 | 33 | 38 | +5 | +15.2% | +| Rent address mismatch chunk 2 | 36 | 42 | +6 | +16.7% | +| Rent address mismatch chunk 3 | 39 | 46 | +7 | +17.9% | test tests::test_insert_alloc_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 46 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/result.txt b/examples/tree/artifacts/tests/insert_search/result.txt index afc8e18a..36d2d1ba 100644 --- a/examples/tree/artifacts/tests/insert_search/result.txt +++ b/examples/tree/artifacts/tests/insert_search/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Dup at root | 26 | 36 | +10 | +38.5% | -| Dup in left | 32 | 47 | +15 | +46.9% | -| Dup in right | 33 | 45 | +12 | +36.4% | +| Dup at root | 26 | 33 | +7 | +26.9% | +| Dup in left | 32 | 44 | +12 | +37.5% | +| Dup in right | 33 | 42 | +9 | +27.3% | test tests::test_insert_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 387e9230..7c18e586 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,136 +1,136 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Empty tree | 25 | 29 | +4 | +16.0% | -| Case 1: left child | 36 | 52 | +16 | +44.4% | -| Case 1: right child | 36 | 49 | +13 | +36.1% | -| Case 4: left child | 39 | 56 | +17 | +43.6% | -| Case 4: right child | 39 | 53 | +14 | +35.9% | -| Case 2+3: left-left | 56 | 88 | +32 | +57.1% | -| Case 2+3: left-right | 56 | 85 | +29 | +51.8% | -| Case 2+3: right-left | 57 | 85 | +28 | +49.1% | -| Case 2+3: right-right | 57 | 82 | +25 | +43.9% | -| Case 2+1: left | 64 | 102 | +38 | +59.4% | -| Case 2+1: right | 66 | 94 | +28 | +42.4% | -| Case 6: left-left null uncle | 61 | 109 | +48 | +78.7% | -| Case 6: right-right null uncle | 62 | 103 | +41 | +66.1% | -| Case 6: left-left black uncle | 63 | 111 | +48 | +76.2% | -| Case 6: right-right black uncle | 64 | 105 | +41 | +64.1% | -| Case 5+6: left-right null uncle | 71 | 130 | +59 | +83.1% | -| Case 5+6: right-left null uncle | 72 | 130 | +58 | +80.6% | -| Case 5+6: left-right black uncle | 73 | 132 | +59 | +80.8% | -| Case 5+6: right-left black uncle | 74 | 132 | +58 | +78.4% | +| Empty tree | 25 | 27 | +2 | +8.0% | +| Case 1: left child | 36 | 50 | +14 | +38.9% | +| Case 1: right child | 36 | 47 | +11 | +30.6% | +| Case 4: left child | 39 | 54 | +15 | +38.5% | +| Case 4: right child | 39 | 51 | +12 | +30.8% | +| Case 2+3: left-left | 56 | 86 | +30 | +53.6% | +| Case 2+3: left-right | 56 | 83 | +27 | +48.2% | +| Case 2+3: right-left | 57 | 83 | +26 | +45.6% | +| Case 2+3: right-right | 57 | 80 | +23 | +40.4% | +| Case 2+1: left | 64 | 98 | +34 | +53.1% | +| Case 2+1: right | 66 | 90 | +24 | +36.4% | +| Case 6: left-left null uncle | 61 | 101 | +40 | +65.6% | +| Case 6: right-right null uncle | 62 | 95 | +33 | +53.2% | +| Case 6: left-left black uncle | 63 | 103 | +40 | +63.5% | +| Case 6: right-right black uncle | 64 | 97 | +33 | +51.6% | +| Case 5+6: left-right null uncle | 71 | 120 | +49 | +69.0% | +| Case 5+6: right-left null uncle | 72 | 120 | +48 | +66.7% | +| Case 5+6: left-right black uncle | 73 | 122 | +49 | +67.1% | +| Case 5+6: right-left black uncle | 74 | 122 | +48 | +64.9% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 86 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 94 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 90 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 101 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 111 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 120 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 130 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 120 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 132 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/specs/rotate-subtree-specialization.md b/examples/tree/specs/rotate-subtree-specialization.md new file mode 100644 index 00000000..1117ece1 --- /dev/null +++ b/examples/tree/specs/rotate-subtree-specialization.md @@ -0,0 +1,131 @@ +# Rotate subtree specialization + +## Scope + +Inline the two `rotate_subtree` calls in the insert fixup case 5/6 +block of `program.rs` with specialized logic that exploits +invariants known at each call site. This matches the assembly, +where each rotation is expanded inline with hardcoded directions. +The generic `rotate_subtree` is preserved for potential use by +delete or other operations. + +## Convention + +`dir` is "the direction of parent relative to grandparent", +computed by `direction(parent)`. All comments reference `dir` and +`opposite(dir)` rather than concrete LEFT/RIGHT. + +## Case 5: rotate(parent, dir) + +Replace `rotate_subtree(tree_header, parent, dir)` with: + +```rust +// Case 5: rotate parent in dir. +// +// Grandparent is guaranteed non-null by the case 4 check, so +// no root-replacement path is needed. Parent is known to be +// grandparent.child[dir] from the direction() call, so the +// child pointer update is hardcoded without comparison. +{ + let new_root = (*parent).child[opposite(dir)]; + let new_child = (*new_root).child[dir]; + + (*parent).child[opposite(dir)] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[dir] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[dir] = new_root; + + node = parent; + parent = new_root; +} +``` + +Optimizations vs generic `rotate_subtree`: + +- **No null check on grandparent**: Case 4 already checked and + returned if grandparent were null. +- **No pointer comparison for child update**: Parent is + `grandparent.child[dir]` by definition, so + `grandparent.child[dir] = new_root` is correct without + comparing `subtree == parent.child[DIR_R]`. +- **No `tree` parameter needed**: The root is never updated. + +The `parent = (*grandparent).child[dir]` load from the original +code is replaced by `parent = new_root`, which is the same pointer +(the rotation placed new_root at `grandparent.child[dir]`). + +## Case 6: rotate(grandparent, opposite(dir)) + +Replace `rotate_subtree(tree_header, grandparent, opposite(dir))` +with: + +```rust +// Case 6: rotate grandparent in opposite(dir). +// +// The new root of this rotation is parent +// (= grandparent.child[dir]), which the caller already has, +// eliminating the generic version's load of +// subtree.child[opposite(direction)]. +// +// Great-grandparent may be null (grandparent could be root), +// so the null check and root-replacement path are retained. +// Grandparent's position under great-grandparent is unrelated +// to dir, so the pointer comparison is also retained. +{ + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[opposite(dir)]; + + (*grandparent).child[dir] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[opposite(dir)] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } +} +``` + +Optimizations vs generic `rotate_subtree`: + +- **No new_root load**: The generic version loads + `subtree.child[opposite(direction)]`. Here, new_root is + `parent`, already in scope. +- **Great-grandparent null check retained**: Grandparent may be + root. +- **Pointer comparison retained**: `dir` describes parent's + position under grandparent, not grandparent's position under + great-grandparent. + +## Resulting caller + +```rust +if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5. + if node == (*parent).child[opposite(dir)] { + // + } + + // Case 6. + // + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; +} +``` diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index bd141bf2..366b1c34 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -355,15 +355,63 @@ unsafe fn insert( let dir = direction(parent) as usize; let uncle = (*grandparent).child[opposite(dir)]; if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5. + // Case 5: rotate parent in dir. + // + // Grandparent is guaranteed non-null by the case 4 check, so no + // root-replacement path is needed. Parent is known to be + // grandparent.child[dir] from the direction() call, so the child + // pointer update is hardcoded without comparison. if node == (*parent).child[opposite(dir)] { - rotate_subtree(tree_header, parent, dir); + let new_root = (*parent).child[opposite(dir)]; + let new_child = (*new_root).child[dir]; + + (*parent).child[opposite(dir)] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[dir] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[dir] = new_root; + node = parent; - parent = (*grandparent).child[dir]; + parent = new_root; + } + + // Case 6: rotate grandparent in opposite(dir). + // + // The new root of this rotation is parent + // (= grandparent.child[dir]), which the caller already has, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), so + // the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated to + // dir, so the pointer comparison is also retained. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[opposite(dir)]; + + (*grandparent).child[dir] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[opposite(dir)] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } } - // Case 6. - rotate_subtree(tree_header, grandparent, opposite(dir)); (*parent).color = Color::Black; (*grandparent).color = Color::Red; return SUCCESS; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a5b34a20..ace4c790 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -676,10 +676,10 @@ insert_search_loop: mov64 r0, E_KEY_EXISTS # Error if key already exists. exit insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[left]; + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[L]; ja insert_search_loop insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[right]; + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[R]; ja insert_search_loop # ANCHOR_END: insert-search @@ -704,10 +704,10 @@ insert_get_child_dir: ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; jgt r4, r5, insert_get_child_dir_branch_r insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[left] = node; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; ja insert_fixup_main insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[right] = node; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; insert_fixup_main: # r2 := parent @@ -739,13 +739,10 @@ insert_fixup_check_case_5_6_dir_l: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_l: - ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[right]; + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[R]; jne r9, r8, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - # rotate_subtree(tree_header, parent, LEFT) - # subtree=r2(parent), grandparent=r3(non-null), dir=L, opp=R - # --------------------------------------------------------------------- ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; @@ -760,9 +757,6 @@ insert_fixup_case_5_dir_l_skip: mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_l: - # rotate_subtree(tree_header, grandparent, RIGHT) - # subtree=r3(grandparent), new_root=r2(parent), dir=R, opp=L - # --------------------------------------------------------------------- ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; @@ -794,13 +788,10 @@ insert_fixup_check_case_5_6_dir_r: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_r: - ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[left]; + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[L]; jne r9, r8, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - # rotate_subtree(tree_header, parent, RIGHT) - # subtree=r2(parent), grandparent=r3(non-null), dir=R, opp=L - # --------------------------------------------------------------------- ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; @@ -815,9 +806,6 @@ insert_fixup_case_5_dir_r_skip: mov64 r2, r6 # parent = new_root; insert_fixup_case_6_dir_r: - # rotate_subtree(tree_header, grandparent, LEFT) - # subtree=r3(grandparent), new_root=r2(parent), dir=L, opp=R - # --------------------------------------------------------------------- ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; From 11a4524bf638a344d2355e8347d29dca6e4ea01a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:26:09 -0700 Subject: [PATCH 200/263] Begin optimizing --- .../artifacts/snippets/asm/insert-fixup.txt | 10 +- .../specs/insert-fixup-hardcoded-branches.md | 248 ++++++++++++++++++ examples/tree/src/tree/tree.s | 10 +- 3 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 examples/tree/specs/insert-fixup-hardcoded-branches.md diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt index 8f54fed3..02d7c0d4 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup.txt @@ -39,11 +39,10 @@ insert_fixup_check_case_5_6_dir_l: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_l: - ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[R]; - jne r9, r8, insert_fixup_case_6_dir_l + ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; + jne r9, r6, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; jeq r8, NULL, insert_fixup_case_5_dir_l_skip @@ -88,11 +87,10 @@ insert_fixup_check_case_5_6_dir_r: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_r: - ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[L]; - jne r9, r8, insert_fixup_case_6_dir_r + ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; + jne r9, r6, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; jeq r8, NULL, insert_fixup_case_5_dir_r_skip diff --git a/examples/tree/specs/insert-fixup-hardcoded-branches.md b/examples/tree/specs/insert-fixup-hardcoded-branches.md new file mode 100644 index 00000000..8455414b --- /dev/null +++ b/examples/tree/specs/insert-fixup-hardcoded-branches.md @@ -0,0 +1,248 @@ +# Insert fixup hardcoded branches + +## Scope + +Replace computed `dir`/`opposite(dir)` indexing in the insert fixup +loop of `program.rs` with explicit `dir_l`/`dir_r` branches that +use hardcoded `child[DIR_L]` and `child[DIR_R]` accesses. This +matches the assembly, where cases 5/6 are expanded into separate +`dir_l` and `dir_r` labels with constant offsets. + +## Problem + +The current Rust code computes `dir` at runtime via `direction()` +and indexes children with `child[dir]` / `child[opposite(dir)]`. +The compiler cannot resolve these to constant offsets, so every +child access compiles to a shift-add-load sequence (~3 instructions) +instead of a single load with a constant offset. This causes: + +- ~14 extra ALU instructions for computed indexing. +- 3 stack spills + 3 reloads from register pressure. +- 2 extra instructions for `direction()` (pointer comparison + + bool materialization vs. direct branch). + +Total overhead: ~18 instructions (42%) vs. the hand-written +assembly on the case 5+6 critical path. + +## Approach + +### Direction check + +Replace `direction()` + runtime `dir` variable with an early branch +on `parent == (*grandparent).child[DIR_L]`. Each arm has fully +hardcoded child accesses. The `direction()` and `opposite()` +functions become unused and are removed. + +### Uncle computation + +Move inside each branch with a hardcoded child index: + +```rust +if parent == (*grandparent).child[tree::DIR_L] { + let uncle = (*grandparent).child[tree::DIR_R]; + ... +} else { + let uncle = (*grandparent).child[tree::DIR_L]; + ... +} +``` + +### Case 5 redundant load + +The current code loads `(*parent).child[opposite(dir)]` twice: +once for the case 5 check and once as `new_root`. Hoist into a +local: + +```rust +let pivot = (*parent).child[tree::DIR_R]; // dir_l variant +if node == pivot { + // pivot is new_root — no second load +} +``` + +### Case 5/6 bodies + +Identical to the current inline expansions from +`rotate-subtree-specialization.md`, but with every `child[dir]` +and `child[opposite(dir)]` replaced by `child[DIR_L]` or +`child[DIR_R]`. + +### Case 2 and recolor + +Case 2 (red uncle recolor) and the case 6 recolor + return are +shared across both branches. Case 2 is placed after the +`dir_l`/`dir_r` block using a shared `uncle` binding. The case +5/6 recolor remains inside the uncle-is-black guard (both +branches return SUCCESS). + +## Resulting code + +```rust +// ANCHOR: insert-fixup +// Get child direction, set at parent. +let child_dir = (key > (*parent).key) as usize; +(*parent).child[child_dir] = node; + +// Main insert fixup. +loop { + // Case 1. + if (*parent).color == Color::Black { + return SUCCESS; + } + + let grandparent = (*parent).parent; + if grandparent.is_null() { + // Case 4. + (*parent).color = Color::Black; + return SUCCESS; + } + + let uncle; + if parent == (*grandparent).child[tree::DIR_L] { + // dir_l: parent is left child of grandparent. + uncle = (*grandparent).child[tree::DIR_R]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_l: rotate parent LEFT. + let pivot = (*parent).child[tree::DIR_R]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_L]; + + (*parent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_L] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_L] = new_root; + + node = parent; + parent = new_root; + } + + // Case 6 dir_l: rotate grandparent RIGHT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_R]; + + (*grandparent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_R] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + } else { + // dir_r: parent is right child of grandparent. + uncle = (*grandparent).child[tree::DIR_L]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_r: rotate parent RIGHT. + let pivot = (*parent).child[tree::DIR_L]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_R]; + + (*parent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_R] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_R] = new_root; + + node = parent; + parent = new_root; + } + + // Case 6 dir_r: rotate grandparent LEFT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_L]; + + (*grandparent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_L] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + } + + // Case 2. + (*parent).color = Color::Black; + (*uncle).color = Color::Black; + (*grandparent).color = Color::Red; + node = grandparent; + + parent = (*node).parent; + if parent.is_null() { + break; + } +} +// Case 3. +SUCCESS +// ANCHOR_END: insert-fixup +``` + +## Diff from current code + +The `dir_l` and `dir_r` blocks are exact mirrors: every +`child[DIR_L]` swaps with `child[DIR_R]`. + +## Functions removed + +- `direction()` — no longer called; the branch replaces it. +- `opposite()` — no longer called; hardcoded indices replace it. + +Both are currently only used in the insert fixup loop. If a future +operation (e.g. delete) needs them, they can be re-added. + +## Child direction assignment + +The initial `let dir = if key > ... { DIR_R } else { DIR_L }` +before the loop is replaced with `let child_dir = (key > (*parent).key) as usize` to use branchless bool-to-index. This +matches the existing search pattern in `program.rs:616`. + +## Verification + +After the change, rebuild and compare the disassembly to confirm +that all `child[]` accesses use constant offsets (+8 or +16) and +that no stack spills remain in the fixup loop. diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index ace4c790..fd698998 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -739,11 +739,10 @@ insert_fixup_check_case_5_6_dir_l: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_l: - ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = parent.child[R]; - jne r9, r8, insert_fixup_case_6_dir_l + ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; + jne r9, r6, insert_fixup_case_6_dir_l insert_fixup_case_5_dir_l: - ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; jeq r8, NULL, insert_fixup_case_5_dir_l_skip @@ -788,11 +787,10 @@ insert_fixup_check_case_5_6_dir_r: jne r8, TREE_COLOR_B, insert_fixup_case_2 insert_fixup_case_5_6_dir_r: - ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = parent.child[L]; - jne r9, r8, insert_fixup_case_6_dir_r + ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; + jne r9, r6, insert_fixup_case_6_dir_r insert_fixup_case_5_dir_r: - ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; jeq r8, NULL, insert_fixup_case_5_dir_r_skip From dd42760d72c8cd9601e2a12fbad422c1e9fb221f Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:29:47 -0700 Subject: [PATCH 201/263] Inline sidewise cases --- examples/tree/artifacts/dumps/asm.txt | 266 +++--- examples/tree/artifacts/dumps/rs.txt | 786 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 487 +++++------ .../artifacts/snippets/rs/insert-fixup.txt | 158 ++-- .../artifacts/tests/insert_to_tree/result.txt | 72 +- examples/tree/src/program.rs | 186 +++-- 6 files changed, 1012 insertions(+), 943 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 1ed3b84d..0b49a871 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3408 (bytes into file) + Start of section headers 3392 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xd50 +There are 7 section headers, starting at offset 0xd40 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000ac8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000bb0 000bb0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000c50 000c50 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000cb0 000cb0 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000cf0 000cf0 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000d20 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000ab8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000ba0 000ba0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000c40 000c40 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000ca0 000ca0 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000ce0 000ce0 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000d10 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ac8 0x000ac8 R E 0x1000 - LOAD 0x000c50 0x0000000000000c50 0x0000000000000c50 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000bb0 0x0000000000000bb0 0x0000000000000bb0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ab8 0x000ab8 R E 0x1000 + LOAD 0x000c40 0x0000000000000c40 0x0000000000000c40 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000ba0 0x0000000000000ba0 0x0000000000000ba0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xbb0 contains 10 entries +Dynamic section at offset 0xba0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xcf0 + 0x0000000000000011 (REL) 0xce0 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xc50 + 0x0000000000000006 (SYMTAB) 0xc40 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xcb0 + 0x0000000000000005 (STRTAB) 0xca0 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xcf0 contains 3 entries +Relocation section '.rel.dyn' at offset 0xce0 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 3b 01 01 00 00 00 if r9 != 0x1 goto +0x13b - 37 55 08 3c 01 04 00 00 00 if r8 != 0x4 goto +0x13c + 36 55 09 39 01 01 00 00 00 if r9 != 0x1 goto +0x139 + 37 55 08 3a 01 04 00 00 00 if r8 != 0x4 goto +0x13a 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 4c 01 00 00 00 00 if r9 != 0x0 goto +0x14c + 39 55 09 4a 01 00 00 00 00 if r9 != 0x0 goto +0x14a 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 48 01 ff 00 00 00 if r9 != 0xff goto +0x148 + 41 55 09 46 01 ff 00 00 00 if r9 != 0xff goto +0x146 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 44 01 00 00 00 00 if r9 != 0x0 goto +0x144 + 43 55 09 42 01 00 00 00 00 if r9 != 0x0 goto +0x142 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 40 01 ff 00 00 00 if r9 != 0xff goto +0x140 + 45 55 09 3e 01 ff 00 00 00 if r9 != 0xff goto +0x13e 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 3c 01 0e 00 00 00 if r9 != 0xe goto +0x13c + 47 55 09 3a 01 0e 00 00 00 if r9 != 0xe goto +0x13a 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 38 01 ff 00 00 00 if r9 != 0xff goto +0x138 + 49 55 09 36 01 ff 00 00 00 if r9 != 0xff goto +0x136 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 32 01 00 00 00 00 if r9 != r8 goto +0x132 + 53 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 2e 01 00 00 00 00 if r9 != r8 goto +0x12e + 57 5d 89 2c 01 00 00 00 00 if r9 != r8 goto +0x12c 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 2a 01 00 00 00 00 if r9 != r8 goto +0x12a + 61 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 27 01 00 00 00 00 if r9 != r8 goto +0x127 + 64 5d 89 25 01 00 00 00 00 if r9 != r8 goto +0x125 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 1a 01 00 00 00 00 if r9 != r8 goto +0x11a + 75 5d 89 18 01 00 00 00 00 if r9 != r8 goto +0x118 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 17 01 00 00 00 00 if r9 != r8 goto +0x117 + 78 5d 89 15 01 00 00 00 00 if r9 != r8 goto +0x115 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 14 01 00 00 00 00 if r9 != r8 goto +0x114 + 81 5d 89 12 01 00 00 00 00 if r9 != r8 goto +0x112 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 11 01 00 00 00 00 if r9 != r8 goto +0x111 + 84 5d 89 0f 01 00 00 00 00 if r9 != r8 goto +0x10f 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 ce 00 05 00 00 00 if r9 != 0x5 goto +0xce - 146 a5 08 cf 00 02 00 00 00 if r8 < 0x2 goto +0xcf + 145 55 09 cc 00 05 00 00 00 if r9 != 0x5 goto +0xcc + 146 a5 08 cd 00 02 00 00 00 if r8 < 0x2 goto +0xcd 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 df 00 00 00 00 00 if r9 != 0x0 goto +0xdf + 148 55 09 dd 00 00 00 00 00 if r9 != 0x0 goto +0xdd 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 db 00 ff 00 00 00 if r9 != 0xff goto +0xdb + 150 55 09 d9 00 ff 00 00 00 if r9 != 0xff goto +0xd9 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 ca 00 04 00 00 00 if r8 != 0x4 goto +0xca + 153 55 08 c8 00 04 00 00 00 if r8 != 0x4 goto +0xc8 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 cc 00 ff 00 00 00 if r8 != 0xff goto +0xcc + 161 55 08 ca 00 ff 00 00 00 if r8 != 0xff goto +0xca 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 c8 00 0e 00 00 00 if r8 != 0xe goto +0xc8 + 163 55 08 c6 00 0e 00 00 00 if r8 != 0xe goto +0xc6 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 c4 00 ff 00 00 00 if r8 != 0xff goto +0xc4 + 165 55 08 c2 00 ff 00 00 00 if r8 != 0xff goto +0xc2 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 be 00 00 00 00 00 if r8 != r4 goto +0xbe + 169 5d 48 bc 00 00 00 00 00 if r8 != r4 goto +0xbc 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 ba 00 00 00 00 00 if r8 != r4 goto +0xba + 173 5d 48 b8 00 00 00 00 00 if r8 != r4 goto +0xb8 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 b6 00 00 00 00 00 if r8 != r4 goto +0xb6 + 177 5d 48 b4 00 00 00 00 00 if r8 != r4 goto +0xb4 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 b3 00 00 00 00 00 if r8 != r4 goto +0xb3 + 180 5d 48 b1 00 00 00 00 00 if r8 != r4 goto +0xb1 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -319,107 +319,105 @@ Disassembly of section .text 267 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 268 95 00 00 00 00 00 00 00 exit 269 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) - 270 2d 45 24 00 00 00 00 00 if r5 > r4 goto +0x24 + 270 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 271 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) 272 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 273 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 274 55 08 44 00 00 00 00 00 if r8 != 0x0 goto +0x44 - 275 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) - 276 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb - 277 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) - 278 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) - 279 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 - 280 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 281 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 282 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 - 283 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 284 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 285 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 - 286 bf 29 00 00 00 00 00 00 r9 = r2 - 287 bf 62 00 00 00 00 00 00 r2 = r6 - 288 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 289 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) - 290 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 - 291 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 292 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 293 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 - 294 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 295 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 296 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 297 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 298 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 299 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 300 05 00 03 00 00 00 00 00 goto +0x3 - 301 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 302 05 00 01 00 00 00 00 00 goto +0x1 - 303 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 304 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 305 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 306 95 00 00 00 00 00 00 00 exit - 307 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) - 308 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 309 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 310 55 08 20 00 00 00 00 00 if r8 != 0x0 goto +0x20 - 311 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 312 5d 89 0b 00 00 00 00 00 if r9 != r8 goto +0xb - 313 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) - 314 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) - 315 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 - 316 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 317 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 318 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 - 319 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 320 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 321 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 - 322 bf 29 00 00 00 00 00 00 r9 = r2 - 323 bf 62 00 00 00 00 00 00 r2 = r6 - 324 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 325 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 326 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 - 327 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 328 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 329 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 - 330 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 331 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 332 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 333 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 334 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 335 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 336 05 00 03 00 00 00 00 00 goto +0x3 - 337 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 338 05 00 01 00 00 00 00 00 goto +0x1 - 339 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 340 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 341 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 342 95 00 00 00 00 00 00 00 exit - 343 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 344 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 - 345 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 346 bf 39 00 00 00 00 00 00 r9 = r3 - 347 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) - 348 55 02 a9 ff 00 00 00 00 if r2 != 0x0 goto -0x57 + 274 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 + 275 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) + 276 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 277 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) + 278 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 + 279 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 280 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 281 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 + 282 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 283 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 284 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 + 285 bf 29 00 00 00 00 00 00 r9 = r2 + 286 bf 62 00 00 00 00 00 00 r2 = r6 + 287 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 288 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 289 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 + 290 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 291 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 292 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 + 293 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 294 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 295 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 296 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 297 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 298 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 299 05 00 03 00 00 00 00 00 goto +0x3 + 300 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 301 05 00 01 00 00 00 00 00 goto +0x1 + 302 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 303 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 304 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 305 95 00 00 00 00 00 00 00 exit + 306 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 307 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 308 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 309 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f + 310 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 311 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 312 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 313 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 314 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 315 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 316 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 317 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 318 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 319 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 320 bf 29 00 00 00 00 00 00 r9 = r2 + 321 bf 62 00 00 00 00 00 00 r2 = r6 + 322 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 323 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 324 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 325 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 326 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 327 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 328 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 329 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 330 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 331 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 332 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 333 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 334 05 00 03 00 00 00 00 00 goto +0x3 + 335 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 336 05 00 01 00 00 00 00 00 goto +0x1 + 337 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 338 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 339 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 340 95 00 00 00 00 00 00 00 exit + 341 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 342 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 343 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 344 bf 39 00 00 00 00 00 00 r9 = r3 + 345 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 346 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 + 347 95 00 00 00 00 00 00 00 exit + 348 b7 00 00 00 09 00 00 00 r0 = 0x9 349 95 00 00 00 00 00 00 00 exit - 350 b7 00 00 00 09 00 00 00 r0 = 0x9 + 350 b7 00 00 00 0c 00 00 00 r0 = 0xc 351 95 00 00 00 00 00 00 00 exit - 352 b7 00 00 00 0c 00 00 00 r0 = 0xc + 352 b7 00 00 00 01 00 00 00 r0 = 0x1 353 95 00 00 00 00 00 00 00 exit - 354 b7 00 00 00 01 00 00 00 r0 = 0x1 + 354 b7 00 00 00 0d 00 00 00 r0 = 0xd 355 95 00 00 00 00 00 00 00 exit - 356 b7 00 00 00 0d 00 00 00 r0 = 0xd + 356 b7 00 00 00 0a 00 00 00 r0 = 0xa 357 95 00 00 00 00 00 00 00 exit - 358 b7 00 00 00 0a 00 00 00 r0 = 0xa + 358 b7 00 00 00 08 00 00 00 r0 = 0x8 359 95 00 00 00 00 00 00 00 exit - 360 b7 00 00 00 08 00 00 00 r0 = 0x8 + 360 b7 00 00 00 07 00 00 00 r0 = 0x7 361 95 00 00 00 00 00 00 00 exit - 362 b7 00 00 00 07 00 00 00 r0 = 0x7 + 362 b7 00 00 00 04 00 00 00 r0 = 0x4 363 95 00 00 00 00 00 00 00 exit - 364 b7 00 00 00 04 00 00 00 r0 = 0x4 + 364 b7 00 00 00 06 00 00 00 r0 = 0x6 365 95 00 00 00 00 00 00 00 exit - 366 b7 00 00 00 06 00 00 00 r0 = 0x6 + 366 b7 00 00 00 03 00 00 00 r0 = 0x3 367 95 00 00 00 00 00 00 00 exit - 368 b7 00 00 00 03 00 00 00 r0 = 0x3 + 368 b7 00 00 00 05 00 00 00 r0 = 0x5 369 95 00 00 00 00 00 00 00 exit - 370 b7 00 00 00 05 00 00 00 r0 = 0x5 - 371 95 00 00 00 00 00 00 00 exit - 372 b7 00 00 00 02 00 00 00 r0 = 0x2 - 373 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 370 b7 00 00 00 02 00 00 00 r0 = 0x2 + 371 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index e8a27552..7bbfc638 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 5872 (bytes into file) + Start of section headers 5840 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x16f0 +There are 8 section headers, starting at offset 0x16d0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000ce0 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000e00 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000e08 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000e08 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000e08 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001180 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 0011be 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000cc0 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000de0 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000de8 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000de8 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000de8 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001160 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00119e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000ce0 0x000ce0 E 0x8 - LOAD 0x000e00 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000e08 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000e08 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000cc0 0x000cc0 E 0x8 + LOAD 0x000de0 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000de8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000de8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3296 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3264 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,27 +104,27 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 80 fe ff ff add64 r10, -0x180 + 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 f6 00 01 00 00 00 jne r5, 0x1, +0xf6 - 28 55 03 80 01 05 00 00 00 jne r3, 0x5, +0x180 - 30 a5 04 81 01 02 00 00 00 jlt r4, 0x2, +0x181 + 20 55 05 f2 00 01 00 00 00 jne r5, 0x1, +0xf2 + 28 55 03 7c 01 05 00 00 00 jne r3, 0x5, +0x17c + 30 a5 04 7d 01 02 00 00 00 jlt r4, 0x2, +0x17d 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 81 01 00 00 00 00 jne r3, 0x0, +0x181 + 40 55 03 7d 01 00 00 00 00 jne r3, 0x0, +0x17d 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 81 01 ff 00 00 00 jne r3, 0xff, +0x181 + 50 55 03 7d 01 ff 00 00 00 jne r3, 0xff, +0x17d 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 70 15 03 3d 00 00 00 00 00 jeq r3, 0x0, +0x3d + 70 15 03 43 00 00 00 00 00 jeq r3, 0x0, +0x43 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 98 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - a0 15 04 a3 00 00 00 00 00 jeq r4, 0x0, +0xa3 + a0 15 04 a9 00 00 00 00 00 jeq r4, 0x0, +0xa9 a8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] b0 05 00 04 00 00 00 00 00 ja +0x4 b8 bf 25 00 00 00 00 00 00 mov64 r5, r2 @@ -139,380 +139,376 @@ Disassembly of section .text 100 b7 04 00 00 08 00 00 00 mov64 r4, 0x8 108 ad 50 f5 ff 00 00 00 00 jlt r0, r5, -0xb 110 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - 118 05 00 d6 00 00 00 00 00 ja +0xd6 - 120 9f 6a 40 00 00 00 00 00 stxdw [r10 + 0x40], r6 - 128 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 130 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 138 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 140 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] - 148 b4 01 00 00 01 00 00 00 mov32 w1, 0x1 - 150 2d 54 01 00 00 00 00 00 jgt r4, r5, +0x1 - 158 b4 01 00 00 00 00 00 00 mov32 w1, 0x0 - 160 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 - 168 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 170 0f 14 00 00 00 00 00 00 add64 r4, r1 - 178 9f 34 08 00 00 00 00 00 stxdw [r4 + 0x8], r3 - 180 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 188 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] - 190 15 01 c7 00 00 00 00 00 jeq r1, 0x0, +0xc7 - 198 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] - 1a0 15 01 8f 00 00 00 00 00 jeq r1, 0x0, +0x8f - 1a8 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] - 1b0 b4 05 00 00 01 00 00 00 mov32 w5, 0x1 - 1b8 1d 42 01 00 00 00 00 00 jeq r2, r4, +0x1 - 1c0 b4 05 00 00 00 00 00 00 mov32 w5, 0x0 - 1c8 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 1d0 07 08 00 00 08 00 00 00 add64 r8, 0x8 - 1d8 bf 57 00 00 00 00 00 00 mov64 r7, r5 - 1e0 a7 07 00 00 01 00 00 00 xor64 r7, 0x1 - 1e8 bf 74 00 00 00 00 00 00 mov64 r4, r7 - 1f0 67 04 00 00 03 00 00 00 lsh64 r4, 0x3 - 1f8 bf 89 00 00 00 00 00 00 mov64 r9, r8 - 200 0f 49 00 00 00 00 00 00 add64 r9, r4 - 208 9c 99 00 00 00 00 00 00 ldxdw r9, [r9 + 0x0] - 210 15 09 7a 00 00 00 00 00 jeq r9, 0x0, +0x7a - 218 2c 96 1c 00 00 00 00 00 ldxb w6, [r9 + 0x1c] - 220 15 06 78 00 00 00 00 00 jeq r6, 0x0, +0x78 - 228 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 230 27 09 1c 00 00 00 00 00 stb [r9 + 0x1c], 0x0 - 238 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 240 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 248 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 250 55 02 e6 ff 00 00 00 00 jne r2, 0x0, -0x1a - 258 05 00 ae 00 00 00 00 00 ja +0xae - 260 55 04 45 01 04 00 00 00 jne r4, 0x4, +0x145 - 268 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 270 bf 35 00 00 00 00 00 00 mov64 r5, r3 - 278 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 280 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - 288 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 290 0f 54 00 00 00 00 00 00 add64 r4, r5 - 298 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2a0 55 05 39 01 ff 00 00 00 jne r5, 0xff, +0x139 - 2a8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2b0 55 05 39 01 0e 00 00 00 jne r5, 0xe, +0x139 - 2b8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2c0 55 05 3b 01 ff 00 00 00 jne r5, 0xff, +0x13b - 2c8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 2d0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 2d8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 2e0 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] - 2e8 5d 57 9c 00 00 00 00 00 jne r7, r5, +0x9c - 2f0 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 2f8 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 300 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] - 308 5d 57 98 00 00 00 00 00 jne r7, r5, +0x98 - 310 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 318 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 320 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] - 328 5d 57 94 00 00 00 00 00 jne r7, r5, +0x94 - 330 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 338 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 340 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 348 5d 52 90 00 00 00 00 00 jne r2, r5, +0x90 - 350 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 358 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 360 9f 2a 74 01 00 00 00 00 stxdw [r10 + 0x174], r2 - 368 87 0a 70 01 02 00 00 00 stw [r10 + 0x170], 0x2 - 370 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 378 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 380 9f 4a 28 01 00 00 00 00 stxdw [r10 + 0x128], r4 - 388 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 390 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 398 9f 2a 18 01 00 00 00 00 stxdw [r10 + 0x118], r2 - 3a0 37 0a 30 01 01 00 00 00 sth [r10 + 0x130], 0x1 - 3a8 37 0a 20 01 01 01 00 00 sth [r10 + 0x120], 0x101 - 3b0 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 3b8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3c0 9f 5a 00 01 00 00 00 00 stxdw [r10 + 0x100], r5 - 3c8 9f 6a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r6 - 3d0 9f 3a f0 00 00 00 00 00 stxdw [r10 + 0xf0], r3 - 3d8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 3e0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 3e8 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 - 3f0 9f 4a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r4 - 3f8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 400 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 408 9f 3a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r3 - 410 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 418 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 420 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 118 05 00 b8 00 00 00 00 00 ja +0xb8 + 120 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 128 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 130 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 138 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] + 140 b4 01 00 00 01 00 00 00 mov32 w1, 0x1 + 148 2d 54 01 00 00 00 00 00 jgt r4, r5, +0x1 + 150 b4 01 00 00 00 00 00 00 mov32 w1, 0x0 + 158 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + 160 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 168 0f 14 00 00 00 00 00 00 add64 r4, r1 + 170 9f 34 08 00 00 00 00 00 stxdw [r4 + 0x8], r3 + 178 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 180 05 00 06 00 00 00 00 00 ja +0x6 + 188 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 190 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 198 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 1a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 1a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 1b0 15 02 a5 00 00 00 00 00 jeq r2, 0x0, +0xa5 + 1b8 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 1c0 15 01 a3 00 00 00 00 00 jeq r1, 0x0, +0xa3 + 1c8 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] + 1d0 15 01 a0 00 00 00 00 00 jeq r1, 0x0, +0xa0 + 1d8 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] + 1e0 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 + 1e8 15 04 85 00 00 00 00 00 jeq r4, 0x0, +0x85 + 1f0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 1f8 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf + 200 05 00 82 00 00 00 00 00 ja +0x82 + 208 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] + 210 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 + 218 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 220 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 + 228 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] + 230 1d 43 a3 00 00 00 00 00 jeq r3, r4, +0xa3 + 238 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 240 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 248 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 250 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 258 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 260 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 268 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 270 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 + 278 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 280 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e + 288 05 00 85 00 00 00 00 00 ja +0x85 + 290 55 04 3b 01 04 00 00 00 jne r4, 0x4, +0x13b + 298 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 2a0 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 2a8 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 2b0 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 2b8 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 2c0 0f 54 00 00 00 00 00 00 add64 r4, r5 + 2c8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 2d0 55 05 2f 01 ff 00 00 00 jne r5, 0xff, +0x12f + 2d8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2e0 55 05 2f 01 0e 00 00 00 jne r5, 0xe, +0x12f + 2e8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2f0 55 05 31 01 ff 00 00 00 jne r5, 0xff, +0x131 + 2f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 300 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 308 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 310 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 318 5d 57 78 00 00 00 00 00 jne r7, r5, +0x78 + 320 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 328 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 330 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 338 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 + 340 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 348 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 350 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 358 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 + 360 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 368 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 370 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 378 5d 52 6c 00 00 00 00 00 jne r2, r5, +0x6c + 380 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 388 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 390 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 + 398 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 3a0 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 3a8 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 3b0 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 3b8 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 3c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 3c8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 + 3d0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 + 3d8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 3e0 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3e8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3f0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 + 3f8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 + 400 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 408 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 410 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 418 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 420 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 428 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 430 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 438 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 - 440 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 - 448 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 - 450 37 0a 10 01 00 01 00 00 sth [r10 + 0x110], 0x100 - 458 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 460 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 - 468 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 - 470 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 - 478 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 - 480 97 0a 50 01 00 00 00 00 stdw [r10 + 0x150], 0x0 - 488 97 0a 48 01 00 00 00 00 stdw [r10 + 0x148], 0x0 - 490 97 0a 40 01 00 00 00 00 stdw [r10 + 0x140], 0x0 - 498 97 0a 38 01 00 00 00 00 stdw [r10 + 0x138], 0x0 - 4a0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4a8 07 02 00 00 70 01 00 00 add64 r2, 0x170 - 4b0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 4b8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4c0 07 02 00 00 18 01 00 00 add64 r2, 0x118 - 4c8 9f 2a 58 00 00 00 00 00 stxdw [r10 + 0x58], r2 + 430 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 438 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 440 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 448 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 450 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 458 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 460 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 468 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 470 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 478 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 480 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 + 488 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 490 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 498 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 4a0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 4a8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 4b0 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 + 4b8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 4c0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 + 4c8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 4d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d8 07 02 00 00 38 01 00 00 add64 r2, 0x138 - 4e0 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 - 4e8 97 0a 70 00 0c 00 00 00 stdw [r10 + 0x70], 0xc - 4f0 97 0a 60 00 02 00 00 00 stdw [r10 + 0x60], 0x2 - 4f8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 500 97 0a 88 00 00 00 00 00 stdw [r10 + 0x88], 0x0 - 508 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 510 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 518 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 520 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 - 528 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 530 07 04 00 00 88 00 00 00 add64 r4, 0x88 - 538 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 540 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 548 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 550 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 558 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 560 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 568 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 570 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 - 578 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] - 580 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 588 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 590 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - 598 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 5a0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] - 5a8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 5b0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - 5b8 55 04 5d ff 00 00 00 00 jne r4, 0x0, -0xa3 - 5c0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 - 5c8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 5d0 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 - 5d8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 5e0 05 00 3d 00 00 00 00 00 ja +0x3d - 5e8 bf 29 00 00 00 00 00 00 mov64 r9, r2 - 5f0 0f 49 00 00 00 00 00 00 add64 r9, r4 - 5f8 9c 94 08 00 00 00 00 00 ldxdw r4, [r9 + 0x8] - 600 1d 43 05 00 00 00 00 00 jeq r3, r4, +0x5 - 608 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 610 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 618 05 00 1c 00 00 00 00 00 ja +0x1c - 620 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 628 05 00 34 00 00 00 00 00 ja +0x34 - 630 07 09 00 00 08 00 00 00 add64 r9, 0x8 - 638 bf 56 00 00 00 00 00 00 mov64 r6, r5 - 640 67 06 00 00 03 00 00 00 lsh64 r6, 0x3 - 648 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 650 07 03 00 00 08 00 00 00 add64 r3, 0x8 - 658 9f 3a 28 00 00 00 00 00 stxdw [r10 + 0x28], r3 - 660 9f 6a 30 00 00 00 00 00 stxdw [r10 + 0x30], r6 - 668 0f 63 00 00 00 00 00 00 add64 r3, r6 - 670 9f 3a 38 00 00 00 00 00 stxdw [r10 + 0x38], r3 - 678 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] - 680 9f 39 00 00 00 00 00 00 stxdw [r9 + 0x0], r3 - 688 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 690 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 698 9c a3 38 00 00 00 00 00 ldxdw r3, [r10 + 0x38] - 6a0 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 6a8 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 6b0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 6b8 bf 82 00 00 00 00 00 00 mov64 r2, r8 - 6c0 9c a3 30 00 00 00 00 00 ldxdw r3, [r10 + 0x30] - 6c8 0f 32 00 00 00 00 00 00 add64 r2, r3 - 6d0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 6d8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 6e0 67 02 00 00 03 00 00 00 lsh64 r2, 0x3 - 6e8 9c a3 28 00 00 00 00 00 ldxdw r3, [r10 + 0x28] - 6f0 0f 23 00 00 00 00 00 00 add64 r3, r2 - 6f8 9c 33 00 00 00 00 00 00 ldxdw r3, [r3 + 0x0] - 700 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 - 708 0f 58 00 00 00 00 00 00 add64 r8, r5 - 710 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 718 9f 38 00 00 00 00 00 00 stxdw [r8 + 0x0], r3 - 720 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 - 728 bf 45 00 00 00 00 00 00 mov64 r5, r4 - 730 0f 75 00 00 00 00 00 00 add64 r5, r7 - 738 07 05 00 00 08 00 00 00 add64 r5, 0x8 - 740 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 748 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 750 9f 15 00 00 00 00 00 00 stxdw [r5 + 0x0], r1 - 758 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 760 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 768 9c a3 40 00 00 00 00 00 ldxdw r3, [r10 + 0x40] - 770 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 - 778 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] - 780 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 - 788 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 - 790 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 - 798 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 - 7a0 0f 32 00 00 00 00 00 00 add64 r2, r3 - 7a8 07 02 00 00 08 00 00 00 add64 r2, 0x8 - 7b0 bf 23 00 00 00 00 00 00 mov64 r3, r2 - 7b8 9f 43 00 00 00 00 00 00 stxdw [r3 + 0x0], r4 - 7c0 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 7c8 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 7d0 9d 00 00 00 00 00 00 00 return - 7d8 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c - 7e0 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 7e8 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 7f0 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 7f8 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 800 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 808 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 810 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 818 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 - 820 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 828 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 830 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 838 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 840 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 848 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 850 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 858 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 860 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 868 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 870 5d 23 eb ff 00 00 00 00 jne r3, r2, -0x15 - 878 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 880 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 888 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 890 5d 23 e7 ff 00 00 00 00 jne r3, r2, -0x19 - 898 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 8a0 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 8a8 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 8b0 5d 23 e3 ff 00 00 00 00 jne r3, r2, -0x1d - 8b8 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 8c0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 8c8 5d 32 e0 ff 00 00 00 00 jne r2, r3, -0x20 - 8d0 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 8d8 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 8e0 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 8e8 07 04 00 00 a8 00 00 00 add64 r4, 0xa8 - 8f0 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 8f8 07 05 00 00 4f 00 00 00 add64 r5, 0x4f - 900 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 908 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 910 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 918 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 920 9c a1 a8 00 00 00 00 00 ldxdw r1, [r10 + 0xa8] - 928 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 930 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f - 938 9c a1 b0 00 00 00 00 00 ldxdw r1, [r10 + 0xb0] - 940 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 948 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c - 950 9c a1 b8 00 00 00 00 00 ldxdw r1, [r10 + 0xb8] - 958 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 960 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 - 968 9c a1 c0 00 00 00 00 00 ldxdw r1, [r10 + 0xc0] - 970 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 978 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 - 980 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 988 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 990 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 998 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 9a0 9f 3a 7c 00 00 00 00 00 stxdw [r10 + 0x7c], r3 - 9a8 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 9b0 9f 3a 74 00 00 00 00 00 stxdw [r10 + 0x74], r3 - 9b8 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 9c0 9f 3a 6c 00 00 00 00 00 stxdw [r10 + 0x6c], r3 - 9c8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 9d0 9f 3a 64 00 00 00 00 00 stxdw [r10 + 0x64], r3 - 9d8 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 9e0 9f 2a 54 00 00 00 00 00 stxdw [r10 + 0x54], r2 - 9e8 97 0a 5c 00 18 00 00 00 stdw [r10 + 0x5c], 0x18 - 9f0 87 0a 50 00 00 00 00 00 stw [r10 + 0x50], 0x0 - 9f8 9f 1a 98 00 00 00 00 00 stxdw [r10 + 0x98], r1 - a00 bf 72 00 00 00 00 00 00 mov64 r2, r7 - a08 07 02 00 00 10 00 00 00 add64 r2, 0x10 - a10 9f 2a 88 00 00 00 00 00 stxdw [r10 + 0x88], r2 - a18 37 0a a0 00 01 01 00 00 sth [r10 + 0xa0], 0x101 - a20 37 0a 90 00 01 01 00 00 sth [r10 + 0x90], 0x101 - a28 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a30 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - a38 9f 3a 00 01 00 00 00 00 stxdw [r10 + 0x100], r3 - a40 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a48 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - a50 9f 3a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r3 - a58 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a60 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - a68 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 - a70 9f 1a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r1 - a78 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a80 07 01 00 00 30 00 00 00 add64 r1, 0x30 - a88 9f 1a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r1 - a90 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a98 07 01 00 00 60 00 00 00 add64 r1, 0x60 - aa0 9f 1a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r1 - aa8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - ab0 07 01 00 00 50 00 00 00 add64 r1, 0x50 - ab8 9f 1a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r1 - ac0 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 - ac8 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 - ad0 37 0a 10 01 01 01 00 00 sth [r10 + 0x110], 0x101 - ad8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - ae0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - ae8 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 - af0 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 - af8 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 - b00 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 - b08 97 0a 30 01 00 00 00 00 stdw [r10 + 0x130], 0x0 - b10 97 0a 28 01 00 00 00 00 stdw [r10 + 0x128], 0x0 - b18 97 0a 20 01 00 00 00 00 stdw [r10 + 0x120], 0x0 - b20 97 0a 18 01 00 00 00 00 stdw [r10 + 0x118], 0x0 - b28 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b30 07 01 00 00 50 00 00 00 add64 r1, 0x50 - b38 9f 1a 50 01 00 00 00 00 stxdw [r10 + 0x150], r1 - b40 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b48 07 01 00 00 88 00 00 00 add64 r1, 0x88 - b50 9f 1a 40 01 00 00 00 00 stxdw [r10 + 0x140], r1 - b58 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b60 07 01 00 00 18 01 00 00 add64 r1, 0x118 - b68 9f 1a 38 01 00 00 00 00 stxdw [r10 + 0x138], r1 - b70 97 0a 58 01 34 00 00 00 stdw [r10 + 0x158], 0x34 - b78 97 0a 48 01 02 00 00 00 stdw [r10 + 0x148], 0x2 + 4d8 07 02 00 00 30 01 00 00 add64 r2, 0x130 + 4e0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 4e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4f0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 + 4f8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 500 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 508 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 + 510 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 + 518 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc + 520 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 + 528 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 + 530 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 538 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 540 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 548 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 550 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 558 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 560 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 568 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 570 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 578 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 580 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 588 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 590 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 598 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 5a0 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 5a8 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] + 5b0 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 5b8 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 5c0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 5c8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 5d0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5d8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5e0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + 5e8 55 04 57 ff 00 00 00 00 jne r4, 0x0, -0xa9 + 5f0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5f8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 600 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 + 608 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 610 05 00 19 00 00 00 00 00 ja +0x19 + 618 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] + 620 1d 43 18 00 00 00 00 00 jeq r3, r4, +0x18 + 628 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 630 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 638 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 640 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 648 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 650 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 658 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 660 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 + 668 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 670 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 + 678 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] + 680 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 + 688 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 + 690 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 + 698 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 + 6a0 0f 32 00 00 00 00 00 00 add64 r2, r3 + 6a8 07 02 00 00 08 00 00 00 add64 r2, 0x8 + 6b0 bf 26 00 00 00 00 00 00 mov64 r6, r2 + 6b8 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + 6c0 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 6c8 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 6d0 05 00 01 00 00 00 00 00 ja +0x1 + 6d8 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 6e0 9d 00 00 00 00 00 00 00 return + 6e8 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 6f0 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 + 6f8 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 700 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 708 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 710 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 + 718 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 720 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 + 728 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 730 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 738 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 740 55 03 e1 ff 00 00 00 00 jne r3, 0x0, -0x1f + 748 05 00 e1 ff 00 00 00 00 ja -0x1f + 750 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 758 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 + 760 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 768 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 770 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 778 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 + 780 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 788 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 + 790 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 798 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 7a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 7a8 55 03 56 ff 00 00 00 00 jne r3, 0x0, -0xaa + 7b0 05 00 56 ff 00 00 00 00 ja -0xaa + 7b8 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c + 7c0 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 7c8 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 7d0 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 7d8 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 7e0 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 7e8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7f0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 7f8 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 + 800 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 808 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 810 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 818 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 820 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 828 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 830 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 838 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 840 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 848 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 850 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f + 858 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 860 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 868 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 870 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 + 878 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 880 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 888 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 890 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 + 898 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 8a0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 8a8 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a + 8b0 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 8b8 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 8c0 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 8c8 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 8d0 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 8d8 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 8e0 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 8e8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 8f0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 8f8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 900 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 908 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 910 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f + 918 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 920 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 928 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c + 930 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 938 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 940 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 + 948 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 950 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 958 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 + 960 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 968 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 970 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 978 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 980 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + 988 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 990 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + 998 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 9a0 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + 9a8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 9b0 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + 9b8 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 9c0 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + 9c8 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + 9d0 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + 9d8 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 9e0 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 9e8 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 9f0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 9f8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + a00 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + a08 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a10 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + a18 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + a20 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a28 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + a30 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + a38 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a40 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + a48 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + a50 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + a58 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a60 07 01 00 00 30 00 00 00 add64 r1, 0x30 + a68 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + a70 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a78 07 01 00 00 60 00 00 00 add64 r1, 0x60 + a80 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + a88 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a90 07 01 00 00 50 00 00 00 add64 r1, 0x50 + a98 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + aa0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + aa8 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + ab0 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + ab8 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + ac0 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + ac8 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + ad0 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + ad8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + ae0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + ae8 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + af0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + af8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + b00 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + b08 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b10 07 01 00 00 10 00 00 00 add64 r1, 0x10 + b18 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + b20 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b28 07 01 00 00 48 00 00 00 add64 r1, 0x48 + b30 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + b38 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b40 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + b48 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + b50 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + b58 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + b60 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b68 07 01 00 00 0f 00 00 00 add64 r1, 0xf + b70 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + b78 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 b80 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b88 07 01 00 00 4f 00 00 00 add64 r1, 0x4f - b90 9f 1a 60 01 00 00 00 00 stxdw [r10 + 0x160], r1 - b98 97 0a 68 01 01 00 00 00 stdw [r10 + 0x168], 0x1 + b88 07 01 00 00 20 01 00 00 add64 r1, 0x120 + b90 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + b98 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 ba0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ba8 07 01 00 00 60 01 00 00 add64 r1, 0x160 - bb0 9f 1a 70 01 00 00 00 00 stxdw [r10 + 0x170], r1 - bb8 97 0a 78 01 01 00 00 00 stdw [r10 + 0x178], 0x1 - bc0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bc8 07 01 00 00 38 01 00 00 add64 r1, 0x138 - bd0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - bd8 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 - be0 bf a4 00 00 00 00 00 00 mov64 r4, r10 - be8 07 04 00 00 70 01 00 00 add64 r4, 0x170 - bf0 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - bf8 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - c00 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - c08 bf 71 00 00 00 00 00 00 mov64 r1, r7 - c10 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - c18 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - c20 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - c28 05 00 74 ff 00 00 00 00 ja -0x8c - c30 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - c38 05 00 72 ff 00 00 00 00 ja -0x8e - c40 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - c48 05 00 70 ff 00 00 00 00 ja -0x90 - c50 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c58 05 00 6e ff 00 00 00 00 ja -0x92 - c60 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - c68 05 00 6c ff 00 00 00 00 ja -0x94 - c70 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - c78 05 00 6a ff 00 00 00 00 ja -0x96 - c80 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - c88 05 00 68 ff 00 00 00 00 ja -0x98 - c90 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - c98 05 00 66 ff 00 00 00 00 ja -0x9a - ca0 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - ca8 05 00 64 ff 00 00 00 00 ja -0x9c - cb0 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - cb8 05 00 62 ff 00 00 00 00 ja -0x9e - cc0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - cc8 05 00 60 ff 00 00 00 00 ja -0xa0 - cd0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - cd8 05 00 5e ff 00 00 00 00 ja -0xa2 \ No newline at end of file + ba8 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + bb0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + bb8 07 02 00 00 68 00 00 00 add64 r2, 0x68 + bc0 bf a4 00 00 00 00 00 00 mov64 r4, r10 + bc8 07 04 00 00 30 01 00 00 add64 r4, 0x130 + bd0 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + bd8 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + be0 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + be8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + bf0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + bf8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + c00 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + c08 05 00 5a ff 00 00 00 00 ja -0xa6 + c10 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + c18 05 00 58 ff 00 00 00 00 ja -0xa8 + c20 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + c28 05 00 56 ff 00 00 00 00 ja -0xaa + c30 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + c38 05 00 54 ff 00 00 00 00 ja -0xac + c40 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + c48 05 00 52 ff 00 00 00 00 ja -0xae + c50 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + c58 05 00 50 ff 00 00 00 00 ja -0xb0 + c60 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + c68 05 00 4e ff 00 00 00 00 ja -0xb2 + c70 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + c78 05 00 4c ff 00 00 00 00 ja -0xb4 + c80 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + c88 05 00 4a ff 00 00 00 00 ja -0xb6 + c90 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + c98 05 00 48 ff 00 00 00 00 ja -0xb8 + ca0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + ca8 05 00 46 ff 00 00 00 00 ja -0xba + cb0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + cb8 05 00 44 ff 00 00 00 00 ja -0xbc \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 7f3b4d2e..69fda107 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,27 +1,27 @@ .globl entrypoint entrypoint: - add64 r10, -384 + add64 r10, -320 ldxdw r4, [r1+0] ldxdw r3, [r2-8] ldxb r5, [r2+0] - jne r5, 1, jmp_07d8 - jne r3, 5, jmp_0c30 - jlt r4, 2, jmp_0c40 + jne r5, 1, jmp_07b0 + jne r3, 5, jmp_0c08 + jlt r4, 2, jmp_0c18 ldxdw r3, [r1+88] - jne r3, 0, jmp_0c50 + jne r3, 0, jmp_0c28 ldxb r3, [r1+10344] - jne r3, 255, jmp_0c60 + jne r3, 255, jmp_0c38 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] - jeq r3, 0, jmp_0260 + jeq r3, 0, jmp_0298 ldxdw r4, [r3+0] stxdw [r1+10440], r4 ldxw r1, [r2+1] stxw [r3+24], r1 ldxdw r4, [r6+0] - jeq r4, 0, jmp_05c0 + jeq r4, 0, jmp_05f8 jmp_00a8: ldxh r1, [r2+1] @@ -42,58 +42,75 @@ jmp_00d8: mov64 r4, 8 jlt r0, r5, jmp_00b8 mov64 r0, 14 - ja jmp_07d0 + ja jmp_06d8 jmp_0120: - stxdw [r10+64], r6 stxdw [r3+0], r2 stb [r3+28], 1 mov64 r4, r1 ldxh r5, [r2+24] mov32 r1, 1 - jgt r4, r5, jmp_0160 + jgt r4, r5, jmp_0158 mov32 r1, 0 -jmp_0160: +jmp_0158: lsh64 r1, 3 mov64 r4, r2 add64 r4, r1 stxdw [r4+8], r3 mov64 r0, 0 + ja jmp_01b8 jmp_0188: + stb [r2+28], 0 + stb [r4+28], 0 + stb [r1+28], 1 + ldxdw r2, [r1+0] + mov64 r3, r1 + jeq r2, 0, jmp_06d8 + +jmp_01b8: ldxb r1, [r2+28] - jeq r1, 0, jmp_07d0 + jeq r1, 0, jmp_06d8 ldxdw r1, [r2+0] - jeq r1, 0, jmp_0620 + jeq r1, 0, jmp_06d0 + ldxdw r4, [r1+8] + jeq r2, r4, jmp_0208 + jeq r4, 0, jmp_0620 + ldxb r5, [r4+28] + jne r5, 0, jmp_0188 + ja jmp_0620 + +jmp_0208: ldxdw r4, [r1+16] - mov32 r5, 1 - jeq r2, r4, jmp_01c8 - mov32 r5, 0 + jeq r4, 0, jmp_0228 + ldxb r5, [r4+28] + jne r5, 0, jmp_0188 -jmp_01c8: - mov64 r8, r1 - add64 r8, 8 - mov64 r7, r5 - xor64 r7, 1 - mov64 r4, r7 - lsh64 r4, 3 - mov64 r9, r8 - add64 r9, r4 - ldxdw r9, [r9+0] - jeq r9, 0, jmp_05e8 - ldxb r6, [r9+28] - jeq r6, 0, jmp_05e8 - stb [r2+28], 0 - stb [r9+28], 0 - stb [r1+28], 1 +jmp_0228: + ldxdw r4, [r2+16] + jeq r3, r4, jmp_0748 + mov64 r3, r4 + mov64 r4, r2 + stxdw [r1+8], r3 ldxdw r2, [r1+0] - mov64 r3, r1 - jne r2, 0, jmp_0188 - ja jmp_07d0 + jeq r3, 0, jmp_0268 jmp_0260: - jne r4, 4, jmp_0c90 + stxdw [r3+0], r1 + +jmp_0268: + stxdw [r4+0], r2 + stxdw [r4+16], r1 + stxdw [r1+0], r4 + jne r2, 0, jmp_0680 + +jmp_0288: + stxdw [r6+0], r4 + ja jmp_06b8 + +jmp_0298: + jne r4, 4, jmp_0c68 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -101,89 +118,89 @@ jmp_0260: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0c70 + jne r5, 255, jmp_0c48 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0c80 + jne r5, 14, jmp_0c58 ldxb r5, [r4+31032] - jne r5, 255, jmp_0ca0 + jne r5, 255, jmp_0c78 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 ldxdw r7, [r4+31040] - jne r7, r5, jmp_07d0 + jne r7, r5, jmp_06d8 mov32 r5, 1288277025 hor64 r5, 2146519613 ldxdw r7, [r4+31048] - jne r7, r5, jmp_07d0 + jne r7, r5, jmp_06d8 mov32 r5, 149871192 hor64 r5, 1157472667 ldxdw r7, [r4+31056] - jne r7, r5, jmp_07d0 + jne r7, r5, jmp_06d8 mov64 r7, r2 ldxdw r2, [r4+31064] mov32 r5, -1965433885 - jne r2, r5, jmp_07d0 + jne r2, r5, jmp_06d8 ldxdw r2, [r4+31120] lmul64 r2, 29 - stxdw [r10+372], r2 - stw [r10+368], 2 + stxdw [r10+308], r2 + stw [r10+304], 2 mov64 r4, r1 add64 r4, 10352 - stxdw [r10+296], r4 + stxdw [r10+232], r4 mov64 r2, r1 add64 r2, 16 - stxdw [r10+280], r2 - sth [r10+304], 1 - sth [r10+288], 257 + stxdw [r10+216], r2 + sth [r10+240], 1 + sth [r10+224], 257 mov64 r5, r1 add64 r5, 10384 - stxdw [r10+256], r5 - stxdw [r10+248], r6 - stxdw [r10+240], r3 + stxdw [r10+192], r5 + stxdw [r10+184], r6 + stxdw [r10+176], r3 mov64 r3, r1 add64 r3, 10416 - stxdw [r10+232], r3 - stxdw [r10+224], r4 + stxdw [r10+168], r3 + stxdw [r10+160], r4 mov64 r3, r1 add64 r3, 48 - stxdw [r10+200], r3 + stxdw [r10+136], r3 mov64 r3, r1 add64 r3, 96 - stxdw [r10+192], r3 + stxdw [r10+128], r3 mov64 r3, r1 add64 r3, 80 - stxdw [r10+176], r3 - stxdw [r10+168], r2 - stb [r10+274], 0 - sth [r10+272], 256 + stxdw [r10+112], r3 + stxdw [r10+104], r2 + stb [r10+210], 0 + sth [r10+208], 256 + stdw [r10+200], 0 + stb [r10+154], 0 + sth [r10+152], 257 + stdw [r10+144], 0 + stdw [r10+120], 0 + stdw [r10+272], 0 stdw [r10+264], 0 - stb [r10+218], 0 - sth [r10+216], 257 - stdw [r10+208], 0 - stdw [r10+184], 0 - stdw [r10+336], 0 - stdw [r10+328], 0 - stdw [r10+320], 0 - stdw [r10+312], 0 + stdw [r10+256], 0 + stdw [r10+248], 0 mov64 r2, r10 - add64 r2, 368 - stxdw [r10+104], r2 + add64 r2, 304 + stxdw [r10+40], r2 mov64 r2, r10 - add64 r2, 280 - stxdw [r10+88], r2 + add64 r2, 216 + stxdw [r10+24], r2 mov64 r2, r10 - add64 r2, 312 - stxdw [r10+80], r2 - stdw [r10+112], 12 - stdw [r10+96], 2 - stdw [r10+144], 0 - stdw [r10+136], 0 + add64 r2, 248 + stxdw [r10+16], r2 + stdw [r10+48], 12 + stdw [r10+32], 2 + stdw [r10+80], 0 + stdw [r10+72], 0 mov64 r3, r10 - add64 r3, 80 + add64 r3, 16 mov64 r2, r10 - add64 r2, 168 + add64 r2, 104 mov64 r4, r10 - add64 r4, 136 + add64 r4, 72 mov64 r8, r1 mov64 r1, r3 mov64 r3, 2 @@ -202,274 +219,266 @@ jmp_0260: ldxdw r4, [r6+0] jne r4, 0, jmp_00a8 -jmp_05c0: +jmp_05f8: stdw [r3+0], 0 stb [r3+28], 1 stxdw [r6+0], r3 -jmp_05d8: +jmp_0610: mov64 r0, 0 - ja jmp_07d0 - -jmp_05e8: - mov64 r9, r2 - add64 r9, r4 - ldxdw r4, [r9+8] - jeq r3, r4, jmp_0630 - mov64 r3, r4 - mov64 r4, r2 - ja jmp_0700 + ja jmp_06d8 jmp_0620: - stb [r2+28], 0 - ja jmp_07d0 - -jmp_0630: - add64 r9, 8 - mov64 r6, r5 - lsh64 r6, 3 + ldxdw r4, [r2+8] + jeq r3, r4, jmp_06e0 mov64 r3, r4 - add64 r3, 8 - stxdw [r10+40], r3 - stxdw [r10+48], r6 - add64 r3, r6 - stxdw [r10+56], r3 - ldxdw r3, [r3+0] - stxdw [r9+0], r3 - jeq r3, 0, jmp_0698 - stxdw [r3+0], r2 - -jmp_0698: - ldxdw r3, [r10+56] - stxdw [r3+0], r2 - stxdw [r4+0], r1 - stxdw [r2+0], r4 - mov64 r2, r8 - ldxdw r3, [r10+48] - add64 r2, r3 - stxdw [r2+0], r4 - mov64 r2, r7 - lsh64 r2, 3 - ldxdw r3, [r10+40] - add64 r3, r2 - ldxdw r3, [r3+0] - -jmp_0700: - lsh64 r5, 3 - add64 r8, r5 + mov64 r4, r2 + stxdw [r1+16], r3 ldxdw r2, [r1+0] - stxdw [r8+0], r3 - lsh64 r7, 3 - mov64 r5, r4 - add64 r5, r7 - add64 r5, 8 - jeq r3, 0, jmp_0750 + jeq r3, 0, jmp_0660 + +jmp_0658: stxdw [r3+0], r1 -jmp_0750: - stxdw [r5+0], r1 +jmp_0660: stxdw [r4+0], r2 + stxdw [r4+8], r1 stxdw [r1+0], r4 - ldxdw r3, [r10+64] - jeq r2, 0, jmp_07b8 + jeq r2, 0, jmp_0288 + +jmp_0680: ldxdw r5, [r2+16] mov32 r3, 1 - jeq r1, r5, jmp_0798 + jeq r1, r5, jmp_06a0 mov32 r3, 0 -jmp_0798: +jmp_06a0: lsh64 r3, 3 add64 r2, r3 stxdw [r2+8], r4 - ja jmp_07c0 - -jmp_07b8: - stxdw [r3+0], r4 -jmp_07c0: +jmp_06b8: stb [r4+28], 0 stb [r1+28], 1 + ja jmp_06d8 -jmp_07d0: +jmp_06d0: + stb [r2+28], 0 + +jmp_06d8: exit -jmp_07d8: - jne r5, 0, jmp_0cb0 - jne r3, 1, jmp_0c30 - jne r4, 4, jmp_0c40 +jmp_06e0: + ldxdw r3, [r4+16] + stxdw [r2+8], r3 + jeq r3, 0, jmp_0700 + stxdw [r3+0], r2 + +jmp_0700: + stxdw [r4+0], r1 + stxdw [r4+16], r2 + stxdw [r2+0], r4 + stxdw [r1+16], r4 + ldxdw r3, [r4+8] + stxdw [r1+16], r3 + ldxdw r2, [r1+0] + jne r3, 0, jmp_0658 + ja jmp_0660 + +jmp_0748: + ldxdw r3, [r4+8] + stxdw [r2+16], r3 + jeq r3, 0, jmp_0768 + stxdw [r3+0], r2 + +jmp_0768: + stxdw [r4+0], r1 + stxdw [r4+8], r2 + stxdw [r2+0], r4 + stxdw [r1+8], r4 + ldxdw r3, [r4+16] + stxdw [r1+8], r3 + ldxdw r2, [r1+0] + jne r3, 0, jmp_0260 + ja jmp_0268 + +jmp_07b0: + jne r5, 0, jmp_0c88 + jne r3, 1, jmp_0c08 + jne r4, 4, jmp_0c18 ldxdw r2, [r1+88] - jne r2, 0, jmp_0c50 + jne r2, 0, jmp_0c28 ldxb r2, [r1+10344] - jne r2, 255, jmp_0c60 + jne r2, 255, jmp_0c38 ldxdw r2, [r1+10424] - jne r2, 0, jmp_0cc0 + jne r2, 0, jmp_0c98 ldxb r2, [r1+20680] - jne r2, 255, jmp_0c70 + jne r2, 255, jmp_0c48 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0c80 + jne r2, 14, jmp_0c58 ldxb r2, [r1+31032] - jne r2, 255, jmp_0ca0 + jne r2, 255, jmp_0c78 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_07d0 + jne r3, r2, jmp_06d8 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_07d0 + jne r3, r2, jmp_06d8 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_07d0 + jne r3, r2, jmp_06d8 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_07d0 + jne r2, r3, jmp_06d8 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 - add64 r4, 168 + add64 r4, 104 mov64 r5, r10 - add64 r5, 79 + add64 r5, 15 mov64 r7, r1 mov64 r2, 0 mov64 r3, r6 call sol_try_find_program_address mov64 r0, 10 - ldxdw r1, [r10+168] + ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_07d0 - ldxdw r1, [r10+176] + jne r1, r2, jmp_06d8 + ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_07d0 - ldxdw r1, [r10+184] + jne r1, r2, jmp_06d8 + ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_07d0 - ldxdw r1, [r10+192] + jne r1, r2, jmp_06d8 + ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_07d0 + jne r1, r2, jmp_06d8 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] ldxdw r3, [r6+24] - stxdw [r10+124], r3 + stxdw [r10+60], r3 ldxdw r3, [r6+16] - stxdw [r10+116], r3 + stxdw [r10+52], r3 ldxdw r3, [r6+8] - stxdw [r10+108], r3 + stxdw [r10+44], r3 ldxdw r3, [r6+0] - stxdw [r10+100], r3 + stxdw [r10+36], r3 lmul64 r2, 152 - stxdw [r10+84], r2 - stdw [r10+92], 24 - stw [r10+80], 0 - stxdw [r10+152], r1 + stxdw [r10+20], r2 + stdw [r10+28], 24 + stw [r10+16], 0 + stxdw [r10+88], r1 mov64 r2, r7 add64 r2, 16 - stxdw [r10+136], r2 - sth [r10+160], 257 - sth [r10+144], 257 + stxdw [r10+72], r2 + sth [r10+96], 257 + sth [r10+80], 257 mov64 r3, r7 add64 r3, 10384 - stxdw [r10+256], r3 + stxdw [r10+192], r3 mov64 r3, r7 add64 r3, 10432 - stxdw [r10+248], r3 + stxdw [r10+184], r3 mov64 r3, r7 add64 r3, 10416 - stxdw [r10+232], r3 - stxdw [r10+224], r1 + stxdw [r10+168], r3 + stxdw [r10+160], r1 mov64 r1, r7 add64 r1, 48 - stxdw [r10+200], r1 + stxdw [r10+136], r1 mov64 r1, r7 add64 r1, 96 - stxdw [r10+192], r1 + stxdw [r10+128], r1 mov64 r1, r7 add64 r1, 80 - stxdw [r10+176], r1 - stxdw [r10+168], r2 - stb [r10+274], 0 - sth [r10+272], 257 - stdw [r10+264], 0 + stxdw [r10+112], r1 + stxdw [r10+104], r2 + stb [r10+210], 0 + sth [r10+208], 257 + stdw [r10+200], 0 + stdw [r10+176], 0 + stb [r10+154], 0 + sth [r10+152], 257 + stdw [r10+144], 0 + stdw [r10+120], 0 stdw [r10+240], 0 - stb [r10+218], 0 - sth [r10+216], 257 - stdw [r10+208], 0 - stdw [r10+184], 0 - stdw [r10+304], 0 - stdw [r10+296], 0 - stdw [r10+288], 0 - stdw [r10+280], 0 + stdw [r10+232], 0 + stdw [r10+224], 0 + stdw [r10+216], 0 mov64 r1, r10 - add64 r1, 80 - stxdw [r10+336], r1 + add64 r1, 16 + stxdw [r10+272], r1 mov64 r1, r10 - add64 r1, 136 - stxdw [r10+320], r1 + add64 r1, 72 + stxdw [r10+256], r1 mov64 r1, r10 - add64 r1, 280 - stxdw [r10+312], r1 - stdw [r10+344], 52 - stdw [r10+328], 2 + add64 r1, 216 + stxdw [r10+248], r1 + stdw [r10+280], 52 + stdw [r10+264], 2 mov64 r1, r10 - add64 r1, 79 - stxdw [r10+352], r1 - stdw [r10+360], 1 + add64 r1, 15 + stxdw [r10+288], r1 + stdw [r10+296], 1 mov64 r1, r10 - add64 r1, 352 - stxdw [r10+368], r1 - stdw [r10+376], 1 + add64 r1, 288 + stxdw [r10+304], r1 + stdw [r10+312], 1 mov64 r1, r10 - add64 r1, 312 + add64 r1, 248 mov64 r2, r10 - add64 r2, 168 + add64 r2, 104 mov64 r4, r10 - add64 r4, 368 + add64 r4, 304 mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - ja jmp_05d8 + ja jmp_0610 -jmp_0c30: +jmp_0c08: mov64 r0, 12 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c40: +jmp_0c18: mov64 r0, 1 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c50: +jmp_0c28: mov64 r0, 2 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c60: +jmp_0c38: mov64 r0, 5 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c70: +jmp_0c48: mov64 r0, 6 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c80: +jmp_0c58: mov64 r0, 4 - ja jmp_07d0 + ja jmp_06d8 -jmp_0c90: +jmp_0c68: mov64 r0, 13 - ja jmp_07d0 + ja jmp_06d8 -jmp_0ca0: +jmp_0c78: mov64 r0, 7 - ja jmp_07d0 + ja jmp_06d8 -jmp_0cb0: +jmp_0c88: mov64 r0, 11 - ja jmp_07d0 + ja jmp_06d8 -jmp_0cc0: +jmp_0c98: mov64 r0, 3 - ja jmp_07d0 + ja jmp_06d8 diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup.txt b/examples/tree/artifacts/snippets/rs/insert-fixup.txt index 6a898f68..533e0f5e 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup.txt @@ -1,10 +1,6 @@ // Get child direction, set at parent. - let dir = if (key > (*parent).key) { - tree::DIR_R - } else { - tree::DIR_L - }; - (*parent).child[dir] = node; + let child_dir = (key > (*parent).key) as usize; + (*parent).child[child_dir] = node; // Main insert fixup. loop { @@ -20,70 +16,114 @@ return SUCCESS; } - // Case 5/6. - let dir = direction(parent) as usize; - let uncle = (*grandparent).child[opposite(dir)]; - if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5: rotate parent in dir. - // - // Grandparent is guaranteed non-null by the case 4 check, so no - // root-replacement path is needed. Parent is known to be - // grandparent.child[dir] from the direction() call, so the child - // pointer update is hardcoded without comparison. - if node == (*parent).child[opposite(dir)] { - let new_root = (*parent).child[opposite(dir)]; - let new_child = (*new_root).child[dir]; - - (*parent).child[opposite(dir)] = new_child; - if !new_child.is_null() { - (*new_child).parent = parent; + // Determine direction and uncle with hardcoded child indices. + let uncle; + if parent == (*grandparent).child[tree::DIR_L] { + // dir_l: parent is left child of grandparent. + uncle = (*grandparent).child[tree::DIR_R]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_l: rotate parent LEFT. + let pivot = (*parent).child[tree::DIR_R]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_L]; + + (*parent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_L] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_L] = new_root; + + node = parent; + parent = new_root; } - (*new_root).child[dir] = parent; - (*new_root).parent = grandparent; - (*parent).parent = new_root; + // Case 6 dir_l: rotate grandparent RIGHT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_R]; - (*grandparent).child[dir] = new_root; + (*grandparent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } - node = parent; - parent = new_root; + (*parent).child[tree::DIR_R] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; } + } else { + // dir_r: parent is right child of grandparent. + uncle = (*grandparent).child[tree::DIR_L]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_r: rotate parent RIGHT. + let pivot = (*parent).child[tree::DIR_L]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_R]; + + (*parent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } - // Case 6: rotate grandparent in opposite(dir). - // - // The new root of this rotation is parent - // (= grandparent.child[dir]), which the caller already has, - // eliminating the generic version's load of - // subtree.child[opposite(direction)]. - // - // Great-grandparent may be null (grandparent could be root), so - // the null check and root-replacement path are retained. - // Grandparent's position under great-grandparent is unrelated to - // dir, so the pointer comparison is also retained. - { - let great_grandparent = (*grandparent).parent; - let new_child = (*parent).child[opposite(dir)]; - - (*grandparent).child[dir] = new_child; - if !new_child.is_null() { - (*new_child).parent = grandparent; + (*new_root).child[tree::DIR_R] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_R] = new_root; + + node = parent; + parent = new_root; } - (*parent).child[opposite(dir)] = grandparent; - (*parent).parent = great_grandparent; - (*grandparent).parent = parent; + // Case 6 dir_r: rotate grandparent LEFT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_L]; + + (*grandparent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_L] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; - if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; - } else { - (*tree_header).root = parent; + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } } - } - (*parent).color = Color::Black; - (*grandparent).color = Color::Red; - return SUCCESS; + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } } // Case 2. diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 7c18e586..2279eddf 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -3,22 +3,22 @@ | Empty tree | 25 | 27 | +2 | +8.0% | | Case 1: left child | 36 | 50 | +14 | +38.9% | | Case 1: right child | 36 | 47 | +11 | +30.6% | -| Case 4: left child | 39 | 54 | +15 | +38.5% | -| Case 4: right child | 39 | 51 | +12 | +30.8% | -| Case 2+3: left-left | 56 | 86 | +30 | +53.6% | -| Case 2+3: left-right | 56 | 83 | +27 | +48.2% | -| Case 2+3: right-left | 57 | 83 | +26 | +45.6% | -| Case 2+3: right-right | 57 | 80 | +23 | +40.4% | -| Case 2+1: left | 64 | 98 | +34 | +53.1% | -| Case 2+1: right | 66 | 90 | +24 | +36.4% | -| Case 6: left-left null uncle | 61 | 101 | +40 | +65.6% | -| Case 6: right-right null uncle | 62 | 95 | +33 | +53.2% | -| Case 6: left-left black uncle | 63 | 103 | +40 | +63.5% | -| Case 6: right-right black uncle | 64 | 97 | +33 | +51.6% | -| Case 5+6: left-right null uncle | 71 | 120 | +49 | +69.0% | -| Case 5+6: right-left null uncle | 72 | 120 | +48 | +66.7% | -| Case 5+6: left-right black uncle | 73 | 122 | +49 | +67.1% | -| Case 5+6: right-left black uncle | 74 | 122 | +48 | +64.9% | +| Case 4: left child | 39 | 53 | +14 | +35.9% | +| Case 4: right child | 39 | 50 | +11 | +28.2% | +| Case 2+3: left-left | 56 | 75 | +19 | +33.9% | +| Case 2+3: left-right | 56 | 72 | +16 | +28.6% | +| Case 2+3: right-left | 57 | 72 | +15 | +26.3% | +| Case 2+3: right-right | 57 | 69 | +12 | +21.1% | +| Case 2+1: left | 64 | 88 | +24 | +37.5% | +| Case 2+1: right | 66 | 80 | +14 | +21.2% | +| Case 6: left-left null uncle | 61 | 83 | +22 | +36.1% | +| Case 6: right-right null uncle | 62 | 76 | +14 | +22.6% | +| Case 6: left-left black uncle | 63 | 85 | +22 | +34.9% | +| Case 6: right-right black uncle | 64 | 79 | +15 | +23.4% | +| Case 5+6: left-right null uncle | 70 | 87 | +17 | +24.3% | +| Case 5+6: right-left null uncle | 71 | 86 | +15 | +21.1% | +| Case 5+6: left-right black uncle | 72 | 89 | +17 | +23.6% | +| Case 5+6: right-left black uncle | 73 | 89 | +16 | +21.9% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -42,95 +42,95 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 86 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 90 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 101 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 79 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 120 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 120 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 86 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 89 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 89 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 366b1c34..c491cbc2 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,7 +9,7 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, Color, - CreateAccountInstructionData, Direction, InitializeInstruction, InsertInstruction, + CreateAccountInstructionData, InitializeInstruction, InsertInstruction, SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TransferInstructionData, TreeHeader, TreeNode, }; @@ -330,12 +330,8 @@ unsafe fn insert( // ANCHOR: insert-fixup // Get child direction, set at parent. - let dir = if (key > (*parent).key) { - tree::DIR_R - } else { - tree::DIR_L - }; - (*parent).child[dir] = node; + let child_dir = (key > (*parent).key) as usize; + (*parent).child[child_dir] = node; // Main insert fixup. loop { @@ -351,70 +347,114 @@ unsafe fn insert( return SUCCESS; } - // Case 5/6. - let dir = direction(parent) as usize; - let uncle = (*grandparent).child[opposite(dir)]; - if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5: rotate parent in dir. - // - // Grandparent is guaranteed non-null by the case 4 check, so no - // root-replacement path is needed. Parent is known to be - // grandparent.child[dir] from the direction() call, so the child - // pointer update is hardcoded without comparison. - if node == (*parent).child[opposite(dir)] { - let new_root = (*parent).child[opposite(dir)]; - let new_child = (*new_root).child[dir]; - - (*parent).child[opposite(dir)] = new_child; - if !new_child.is_null() { - (*new_child).parent = parent; + // Determine direction and uncle with hardcoded child indices. + let uncle; + if parent == (*grandparent).child[tree::DIR_L] { + // dir_l: parent is left child of grandparent. + uncle = (*grandparent).child[tree::DIR_R]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_l: rotate parent LEFT. + let pivot = (*parent).child[tree::DIR_R]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_L]; + + (*parent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_L] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_L] = new_root; + + node = parent; + parent = new_root; } - (*new_root).child[dir] = parent; - (*new_root).parent = grandparent; - (*parent).parent = new_root; - - (*grandparent).child[dir] = new_root; + // Case 6 dir_l: rotate grandparent RIGHT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_R]; + + (*grandparent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_R] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } - node = parent; - parent = new_root; + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; } - - // Case 6: rotate grandparent in opposite(dir). - // - // The new root of this rotation is parent - // (= grandparent.child[dir]), which the caller already has, - // eliminating the generic version's load of - // subtree.child[opposite(direction)]. - // - // Great-grandparent may be null (grandparent could be root), so - // the null check and root-replacement path are retained. - // Grandparent's position under great-grandparent is unrelated to - // dir, so the pointer comparison is also retained. - { - let great_grandparent = (*grandparent).parent; - let new_child = (*parent).child[opposite(dir)]; - - (*grandparent).child[dir] = new_child; - if !new_child.is_null() { - (*new_child).parent = grandparent; + } else { + // dir_r: parent is right child of grandparent. + uncle = (*grandparent).child[tree::DIR_L]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_r: rotate parent RIGHT. + let pivot = (*parent).child[tree::DIR_L]; + if node == pivot { + let new_root = pivot; + let new_child = (*new_root).child[tree::DIR_R]; + + (*parent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_R] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_R] = new_root; + + node = parent; + parent = new_root; } - (*parent).child[opposite(dir)] = grandparent; - (*parent).parent = great_grandparent; - (*grandparent).parent = parent; - - if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; - } else { - (*tree_header).root = parent; + // Case 6 dir_r: rotate grandparent LEFT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_L]; + + (*grandparent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_L] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } } - } - (*parent).color = Color::Black; - (*grandparent).color = Color::Red; - return SUCCESS; + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } } // Case 2. @@ -588,21 +628,6 @@ unsafe fn initialize( SUCCESS } -/// Return the direction of the node with respect to its parent. -#[inline(always)] -unsafe fn direction(node: *const TreeNode) -> Direction { - if node == (*(*node).parent).child[tree::DIR_R] { - Direction::Right - } else { - Direction::Left - } -} - -#[inline(always)] -const fn opposite(direction: usize) -> usize { - 1 - direction -} - #[inline(always)] unsafe fn search(tree_header: *const TreeHeader, key: u16) -> *mut TreeNode { let mut node = (*tree_header).root; @@ -626,10 +651,11 @@ unsafe fn rotate_subtree( direction: usize, ) -> *mut TreeNode { let parent = (*subtree).parent; - let new_root = (*subtree).child[opposite(direction)]; + let opposite = 1 - direction; + let new_root = (*subtree).child[opposite]; let new_child = (*new_root).child[direction]; - (*subtree).child[opposite(direction)] = new_child; + (*subtree).child[opposite] = new_child; if !new_child.is_null() { (*new_child).parent = subtree; From f2f71b30058ac842adc71c78d6d38bbea79a1634 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:46:01 -0700 Subject: [PATCH 202/263] Add back parity, anchors --- .../snippets/asm/insert-fixup-case-1.txt | 8 + .../snippets/asm/insert-fixup-case-2-3.txt | 13 ++ .../snippets/asm/insert-fixup-case-4.txt | 7 + .../asm/insert-fixup-case-5-6-dir-l.txt | 53 +++++++ .../asm/insert-fixup-case-5-6-dir-r.txt | 47 ++++++ .../snippets/asm/insert-fixup-child-dir.txt | 10 ++ .../artifacts/snippets/asm/insert-fixup.txt | 143 ------------------ .../snippets/rs/insert-fixup-case-1.txt | 4 + .../snippets/rs/insert-fixup-case-2-3.txt | 14 ++ .../snippets/rs/insert-fixup-case-4.txt | 6 + .../rs/insert-fixup-case-5-6-dir-l.txt | 69 +++++++++ .../rs/insert-fixup-case-5-6-dir-r.txt | 53 +++++++ .../snippets/rs/insert-fixup-child-dir.txt | 3 + .../artifacts/snippets/rs/insert-fixup.txt | 142 ----------------- examples/tree/src/program.rs | 62 ++++++-- examples/tree/src/tree/tree.s | 14 +- 16 files changed, 349 insertions(+), 299 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-case-1.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-case-4.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt create mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt delete mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-case-2-3.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-case-4.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt create mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt delete mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup.txt diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-1.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-1.txt new file mode 100644 index 00000000..e089ddb2 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-1.txt @@ -0,0 +1,8 @@ +insert_fixup_main: + # r2 := parent + # r5 := parent.key + # Case 1. # r9 := node + # --------------------------------------------------------------------- + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + jne r6, TREE_COLOR_B, insert_fixup_check_case_4 + exit # If parent is black, tree is still valid, so exit. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt new file mode 100644 index 00000000..8a90b911 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt @@ -0,0 +1,13 @@ +insert_fixup_case_2: + # r2 := parent + # r3 := grandparent + # r7 := uncle + # r9 := node + # --------------------------------------------------------------------- + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + mov64 r9, r3 # node = grandparent; + ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # parent = node.parent; + jne r2, NULL, insert_fixup_main + exit # Case 3. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-4.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-4.txt new file mode 100644 index 00000000..fe17101b --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-4.txt @@ -0,0 +1,7 @@ +insert_fixup_check_case_4: + # Check case 4. + # --------------------------------------------------------------------- + ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; + jne r3, NULL, insert_fixup_check_case_5_6 + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt new file mode 100644 index 00000000..f7f5f861 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt @@ -0,0 +1,53 @@ +insert_fixup_check_case_5_6: + # Get uncle and check for case 5 or 6. + # --------------------------------------------------------------------- + ldxh r4, [r3 + TREE_NODE_KEY_OFF] # r4 = grandparent.key; + jgt r5, r4, insert_fixup_check_case_5_6_dir_r + +insert_fixup_check_case_5_6_dir_l: + ldxdw r7, [r3 + TREE_NODE_CHILD_R_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_l + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_l: + ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; + jne r9, r6, insert_fixup_case_6_dir_l + +insert_fixup_case_5_dir_l: + ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_l_skip: + stxdw [r6 + TREE_NODE_CHILD_L_OFF], r2 # new_root.child[L] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r6 # grandparent.child[L] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; + +insert_fixup_case_6_dir_l: + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; + stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_l_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_l_skip: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r3 # parent.child[R] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_l_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_l_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_l_color +insert_fixup_case_6_dir_l_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_l_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt new file mode 100644 index 00000000..86e9c014 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt @@ -0,0 +1,47 @@ +insert_fixup_check_case_5_6_dir_r: + ldxdw r7, [r3 + TREE_NODE_CHILD_L_OFF] # r7 = uncle; + jeq r7, NULL, insert_fixup_case_5_6_dir_r + ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; + jne r8, TREE_COLOR_B, insert_fixup_case_2 + +insert_fixup_case_5_6_dir_r: + ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; + jne r9, r6, insert_fixup_case_6_dir_r + +insert_fixup_case_5_dir_r: + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; + jeq r8, NULL, insert_fixup_case_5_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; +insert_fixup_case_5_dir_r_skip: + stxdw [r6 + TREE_NODE_CHILD_R_OFF], r2 # new_root.child[R] = parent; + stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r6 # grandparent.child[R] = new_root; + mov64 r9, r2 # node = old parent; + mov64 r2, r6 # parent = new_root; + +insert_fixup_case_6_dir_r: + ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; + ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; + stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; + jeq r8, NULL, insert_fixup_case_6_dir_r_skip + stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; +insert_fixup_case_6_dir_r_skip: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r3 # parent.child[L] = grandparent; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; + stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; + jeq r4, NULL, insert_fixup_case_6_dir_r_root + ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; + jne r3, r8, insert_fixup_case_6_dir_r_left + stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_left: + stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; + ja insert_fixup_case_6_dir_r_color +insert_fixup_case_6_dir_r_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; +insert_fixup_case_6_dir_r_color: + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt new file mode 100644 index 00000000..5e842679 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt @@ -0,0 +1,10 @@ +insert_get_child_dir: + # Get child direction, set at parent. + # --------------------------------------------------------------------- + ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; + jgt r4, r5, insert_get_child_dir_branch_r +insert_get_child_dir_branch_l: + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; + ja insert_fixup_main +insert_get_child_dir_branch_r: + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup.txt b/examples/tree/artifacts/snippets/asm/insert-fixup.txt deleted file mode 100644 index 02d7c0d4..00000000 --- a/examples/tree/artifacts/snippets/asm/insert-fixup.txt +++ /dev/null @@ -1,143 +0,0 @@ -insert_get_child_dir: - # Get child direction, set at parent. - # --------------------------------------------------------------------- - ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; - jgt r4, r5, insert_get_child_dir_branch_r -insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; - ja insert_fixup_main -insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; - -insert_fixup_main: - # r2 := parent - # r5 := parent.key - # Case 1. # r9 := node - # --------------------------------------------------------------------- - ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; - jne r6, TREE_COLOR_B, insert_fixup_check_case_4 - exit # If parent is black, tree is still valid, so exit. - -insert_fixup_check_case_4: - # Check case 4. - # --------------------------------------------------------------------- - ldxdw r3, [r2 + TREE_NODE_PARENT_OFF] # r3 = grandparent; - jne r3, NULL, insert_fixup_check_case_5_6 - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; - exit - -insert_fixup_check_case_5_6: - # Get uncle and check for case 5 or 6. - # --------------------------------------------------------------------- - ldxh r4, [r3 + TREE_NODE_KEY_OFF] # r4 = grandparent.key; - jgt r5, r4, insert_fixup_check_case_5_6_dir_r - -insert_fixup_check_case_5_6_dir_l: - ldxdw r7, [r3 + TREE_NODE_CHILD_R_OFF] # r7 = uncle; - jeq r7, NULL, insert_fixup_case_5_6_dir_l - ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; - jne r8, TREE_COLOR_B, insert_fixup_case_2 - -insert_fixup_case_5_6_dir_l: - ldxdw r6, [r2 + TREE_NODE_CHILD_R_OFF] # r6 = new_root = parent.child[R]; - jne r9, r6, insert_fixup_case_6_dir_l - -insert_fixup_case_5_dir_l: - ldxdw r8, [r6 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = new_root.child[L]; - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r8 # parent.child[R] = new_child; - jeq r8, NULL, insert_fixup_case_5_dir_l_skip - stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; -insert_fixup_case_5_dir_l_skip: - stxdw [r6 + TREE_NODE_CHILD_L_OFF], r2 # new_root.child[L] = parent; - stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; - stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; - stxdw [r3 + TREE_NODE_CHILD_L_OFF], r6 # grandparent.child[L] = new_root; - mov64 r9, r2 # node = old parent; - mov64 r2, r6 # parent = new_root; - -insert_fixup_case_6_dir_l: - ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; - ldxdw r8, [r2 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = parent.child[R]; - stxdw [r3 + TREE_NODE_CHILD_L_OFF], r8 # grandparent.child[L] = new_child; - jeq r8, NULL, insert_fixup_case_6_dir_l_skip - stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; -insert_fixup_case_6_dir_l_skip: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r3 # parent.child[R] = grandparent; - stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; - stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; - jeq r4, NULL, insert_fixup_case_6_dir_l_root - ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; - jne r3, r8, insert_fixup_case_6_dir_l_left - stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_l_color -insert_fixup_case_6_dir_l_left: - stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_l_color -insert_fixup_case_6_dir_l_root: - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_l_color: - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; - stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; - exit - -insert_fixup_check_case_5_6_dir_r: - ldxdw r7, [r3 + TREE_NODE_CHILD_L_OFF] # r7 = uncle; - jeq r7, NULL, insert_fixup_case_5_6_dir_r - ldxb r8, [r7 + TREE_NODE_COLOR_OFF] # r8 = uncle.color; - jne r8, TREE_COLOR_B, insert_fixup_case_2 - -insert_fixup_case_5_6_dir_r: - ldxdw r6, [r2 + TREE_NODE_CHILD_L_OFF] # r6 = new_root = parent.child[L]; - jne r9, r6, insert_fixup_case_6_dir_r - -insert_fixup_case_5_dir_r: - ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = new_child = new_root.child[R]; - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r8 # parent.child[L] = new_child; - jeq r8, NULL, insert_fixup_case_5_dir_r_skip - stxdw [r8 + TREE_NODE_PARENT_OFF], r2 # new_child.parent = parent; -insert_fixup_case_5_dir_r_skip: - stxdw [r6 + TREE_NODE_CHILD_R_OFF], r2 # new_root.child[R] = parent; - stxdw [r6 + TREE_NODE_PARENT_OFF], r3 # new_root.parent = grandparent; - stxdw [r2 + TREE_NODE_PARENT_OFF], r6 # parent.parent = new_root; - stxdw [r3 + TREE_NODE_CHILD_R_OFF], r6 # grandparent.child[R] = new_root; - mov64 r9, r2 # node = old parent; - mov64 r2, r6 # parent = new_root; - -insert_fixup_case_6_dir_r: - ldxdw r4, [r3 + TREE_NODE_PARENT_OFF] # r4 = great-grandparent; - ldxdw r8, [r2 + TREE_NODE_CHILD_L_OFF] # r8 = new_child = parent.child[L]; - stxdw [r3 + TREE_NODE_CHILD_R_OFF], r8 # grandparent.child[R] = new_child; - jeq r8, NULL, insert_fixup_case_6_dir_r_skip - stxdw [r8 + TREE_NODE_PARENT_OFF], r3 # new_child.parent = grandparent; -insert_fixup_case_6_dir_r_skip: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r3 # parent.child[L] = grandparent; - stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # parent.parent = great-grandparent; - stxdw [r3 + TREE_NODE_PARENT_OFF], r2 # grandparent.parent = parent; - jeq r4, NULL, insert_fixup_case_6_dir_r_root - ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; - jne r3, r8, insert_fixup_case_6_dir_r_left - stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_r_color -insert_fixup_case_6_dir_r_left: - stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_r_color -insert_fixup_case_6_dir_r_root: - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_r_color: - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; - stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; - exit - -insert_fixup_case_2: - # r2 := parent - # r3 := grandparent - # r7 := uncle - # r9 := node - # --------------------------------------------------------------------- - stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; - stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; - stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; - mov64 r9, r3 # node = grandparent; - ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # parent = node.parent; - jne r2, NULL, insert_fixup_main - exit # Case 3. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt new file mode 100644 index 00000000..a7003047 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt @@ -0,0 +1,4 @@ + // Case 1. + if (*parent).color == Color::Black { + return SUCCESS; + } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-2-3.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-2-3.txt new file mode 100644 index 00000000..82d0bc0e --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-2-3.txt @@ -0,0 +1,14 @@ + // Case 2. + (*parent).color = Color::Black; + (*uncle).color = Color::Black; + (*grandparent).color = Color::Red; + node = grandparent; + + parent = (*node).parent; + if parent.is_null() { + break; + } + } + // Case 3. + SUCCESS +} \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-4.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-4.txt new file mode 100644 index 00000000..8c6a6708 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-4.txt @@ -0,0 +1,6 @@ + let grandparent = (*parent).parent; + if grandparent.is_null() { + // Case 4. + (*parent).color = Color::Black; + return SUCCESS; + } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt new file mode 100644 index 00000000..ff96a325 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt @@ -0,0 +1,69 @@ + // Determine direction and uncle with hardcoded child indices. + let uncle; + if parent == (*grandparent).child[tree::DIR_L] { + // dir_l: parent is left child of grandparent. + uncle = (*grandparent).child[tree::DIR_R]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_l: rotate parent in DIR_L. + // + // Grandparent is guaranteed non-null by the case 4 check, so + // no root-replacement path is needed. Parent is known to be + // grandparent.child[DIR_L] from the dir_l branch, so the + // child pointer update is hardcoded without comparison. + if node == (*parent).child[tree::DIR_R] { + let new_root = (*parent).child[tree::DIR_R]; + let new_child = (*new_root).child[tree::DIR_L]; + + (*parent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_L] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_L] = new_root; + + node = parent; + parent = new_root; + } + + // Case 6 dir_l: rotate grandparent in DIR_R. + // + // The new root of this rotation is parent + // (= grandparent.child[DIR_L]), already in scope, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), + // so the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated + // to dir, so the pointer comparison is also retained. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_R]; + + (*grandparent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_R] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt new file mode 100644 index 00000000..d91580b9 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt @@ -0,0 +1,53 @@ + } else { + // dir_r: parent is right child of grandparent. + uncle = (*grandparent).child[tree::DIR_L]; + if uncle.is_null() || (*uncle).color == Color::Black { + // Case 5 dir_r: rotate parent RIGHT. + let new_root = (*parent).child[tree::DIR_L]; + if node == new_root { + let new_child = (*new_root).child[tree::DIR_R]; + + (*parent).child[tree::DIR_L] = new_child; + if !new_child.is_null() { + (*new_child).parent = parent; + } + + (*new_root).child[tree::DIR_R] = parent; + (*new_root).parent = grandparent; + (*parent).parent = new_root; + + (*grandparent).child[tree::DIR_R] = new_root; + + node = parent; + parent = new_root; + } + + // Case 6 dir_r: rotate grandparent LEFT. + { + let great_grandparent = (*grandparent).parent; + let new_child = (*parent).child[tree::DIR_L]; + + (*grandparent).child[tree::DIR_R] = new_child; + if !new_child.is_null() { + (*new_child).parent = grandparent; + } + + (*parent).child[tree::DIR_L] = grandparent; + (*parent).parent = great_grandparent; + (*grandparent).parent = parent; + + if !great_grandparent.is_null() { + let idx = (grandparent + == (*great_grandparent).child[tree::DIR_R]) + as usize; + (*great_grandparent).child[idx] = parent; + } else { + (*tree_header).root = parent; + } + } + + (*parent).color = Color::Black; + (*grandparent).color = Color::Red; + return SUCCESS; + } + } \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt new file mode 100644 index 00000000..f2fe2dcf --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt @@ -0,0 +1,3 @@ + // Get child direction, set at parent. + let child_dir = (key > (*parent).key) as usize; + (*parent).child[child_dir] = node; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup.txt b/examples/tree/artifacts/snippets/rs/insert-fixup.txt deleted file mode 100644 index 533e0f5e..00000000 --- a/examples/tree/artifacts/snippets/rs/insert-fixup.txt +++ /dev/null @@ -1,142 +0,0 @@ - // Get child direction, set at parent. - let child_dir = (key > (*parent).key) as usize; - (*parent).child[child_dir] = node; - - // Main insert fixup. - loop { - // Case 1. - if (*parent).color == Color::Black { - return SUCCESS; - } - - let grandparent = (*parent).parent; - if grandparent.is_null() { - // Case 4. - (*parent).color = Color::Black; - return SUCCESS; - } - - // Determine direction and uncle with hardcoded child indices. - let uncle; - if parent == (*grandparent).child[tree::DIR_L] { - // dir_l: parent is left child of grandparent. - uncle = (*grandparent).child[tree::DIR_R]; - if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5 dir_l: rotate parent LEFT. - let pivot = (*parent).child[tree::DIR_R]; - if node == pivot { - let new_root = pivot; - let new_child = (*new_root).child[tree::DIR_L]; - - (*parent).child[tree::DIR_R] = new_child; - if !new_child.is_null() { - (*new_child).parent = parent; - } - - (*new_root).child[tree::DIR_L] = parent; - (*new_root).parent = grandparent; - (*parent).parent = new_root; - - (*grandparent).child[tree::DIR_L] = new_root; - - node = parent; - parent = new_root; - } - - // Case 6 dir_l: rotate grandparent RIGHT. - { - let great_grandparent = (*grandparent).parent; - let new_child = (*parent).child[tree::DIR_R]; - - (*grandparent).child[tree::DIR_L] = new_child; - if !new_child.is_null() { - (*new_child).parent = grandparent; - } - - (*parent).child[tree::DIR_R] = grandparent; - (*parent).parent = great_grandparent; - (*grandparent).parent = parent; - - if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; - (*great_grandparent).child[idx] = parent; - } else { - (*tree_header).root = parent; - } - } - - (*parent).color = Color::Black; - (*grandparent).color = Color::Red; - return SUCCESS; - } - } else { - // dir_r: parent is right child of grandparent. - uncle = (*grandparent).child[tree::DIR_L]; - if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5 dir_r: rotate parent RIGHT. - let pivot = (*parent).child[tree::DIR_L]; - if node == pivot { - let new_root = pivot; - let new_child = (*new_root).child[tree::DIR_R]; - - (*parent).child[tree::DIR_L] = new_child; - if !new_child.is_null() { - (*new_child).parent = parent; - } - - (*new_root).child[tree::DIR_R] = parent; - (*new_root).parent = grandparent; - (*parent).parent = new_root; - - (*grandparent).child[tree::DIR_R] = new_root; - - node = parent; - parent = new_root; - } - - // Case 6 dir_r: rotate grandparent LEFT. - { - let great_grandparent = (*grandparent).parent; - let new_child = (*parent).child[tree::DIR_L]; - - (*grandparent).child[tree::DIR_R] = new_child; - if !new_child.is_null() { - (*new_child).parent = grandparent; - } - - (*parent).child[tree::DIR_L] = grandparent; - (*parent).parent = great_grandparent; - (*grandparent).parent = parent; - - if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; - (*great_grandparent).child[idx] = parent; - } else { - (*tree_header).root = parent; - } - } - - (*parent).color = Color::Black; - (*grandparent).color = Color::Red; - return SUCCESS; - } - } - - // Case 2. - (*parent).color = Color::Black; - (*uncle).color = Color::Black; - (*grandparent).color = Color::Red; - node = grandparent; - - parent = (*node).parent; - if parent.is_null() { - break; - } - } - // Case 3. - SUCCESS -} \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index c491cbc2..e536ba40 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -328,35 +328,45 @@ unsafe fn insert( } // ANCHOR_END: insert-to-tree - // ANCHOR: insert-fixup + // ANCHOR: insert-fixup-child-dir // Get child direction, set at parent. let child_dir = (key > (*parent).key) as usize; (*parent).child[child_dir] = node; + // ANCHOR_END: insert-fixup-child-dir // Main insert fixup. loop { + // ANCHOR: insert-fixup-case-1 // Case 1. if (*parent).color == Color::Black { return SUCCESS; } + // ANCHOR_END: insert-fixup-case-1 + // ANCHOR: insert-fixup-case-4 let grandparent = (*parent).parent; if grandparent.is_null() { // Case 4. (*parent).color = Color::Black; return SUCCESS; } + // ANCHOR_END: insert-fixup-case-4 + // ANCHOR: insert-fixup-case-5-6-dir-l // Determine direction and uncle with hardcoded child indices. let uncle; if parent == (*grandparent).child[tree::DIR_L] { // dir_l: parent is left child of grandparent. uncle = (*grandparent).child[tree::DIR_R]; if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5 dir_l: rotate parent LEFT. - let pivot = (*parent).child[tree::DIR_R]; - if node == pivot { - let new_root = pivot; + // Case 5 dir_l: rotate parent in DIR_L. + // + // Grandparent is guaranteed non-null by the case 4 check, so + // no root-replacement path is needed. Parent is known to be + // grandparent.child[DIR_L] from the dir_l branch, so the + // child pointer update is hardcoded without comparison. + if node == (*parent).child[tree::DIR_R] { + let new_root = (*parent).child[tree::DIR_R]; let new_child = (*new_root).child[tree::DIR_L]; (*parent).child[tree::DIR_R] = new_child; @@ -374,7 +384,17 @@ unsafe fn insert( parent = new_root; } - // Case 6 dir_l: rotate grandparent RIGHT. + // Case 6 dir_l: rotate grandparent in DIR_R. + // + // The new root of this rotation is parent + // (= grandparent.child[DIR_L]), already in scope, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), + // so the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated + // to dir, so the pointer comparison is also retained. { let great_grandparent = (*grandparent).parent; let new_child = (*parent).child[tree::DIR_R]; @@ -402,14 +422,20 @@ unsafe fn insert( (*grandparent).color = Color::Red; return SUCCESS; } + // ANCHOR_END: insert-fixup-case-5-6-dir-l + // ANCHOR: insert-fixup-case-5-6-dir-r } else { // dir_r: parent is right child of grandparent. uncle = (*grandparent).child[tree::DIR_L]; if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5 dir_r: rotate parent RIGHT. - let pivot = (*parent).child[tree::DIR_L]; - if node == pivot { - let new_root = pivot; + // Case 5 dir_r: rotate parent in DIR_R. + // + // Grandparent is guaranteed non-null by the case 4 check, so + // no root-replacement path is needed. Parent is known to be + // grandparent.child[DIR_R] from the dir_r branch, so the + // child pointer update is hardcoded without comparison. + if node == (*parent).child[tree::DIR_L] { + let new_root = (*parent).child[tree::DIR_L]; let new_child = (*new_root).child[tree::DIR_R]; (*parent).child[tree::DIR_L] = new_child; @@ -427,7 +453,17 @@ unsafe fn insert( parent = new_root; } - // Case 6 dir_r: rotate grandparent LEFT. + // Case 6 dir_r: rotate grandparent in DIR_L. + // + // The new root of this rotation is parent + // (= grandparent.child[DIR_R]), already in scope, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), + // so the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated + // to dir, so the pointer comparison is also retained. { let great_grandparent = (*grandparent).parent; let new_child = (*parent).child[tree::DIR_L]; @@ -456,7 +492,9 @@ unsafe fn insert( return SUCCESS; } } + // ANCHOR_END: insert-fixup-case-5-6-dir-r + // ANCHOR: insert-fixup-case-2-3 // Case 2. (*parent).color = Color::Black; (*uncle).color = Color::Black; @@ -471,7 +509,7 @@ unsafe fn insert( // Case 3. SUCCESS } -// ANCHOR_END: insert-fixup +// ANCHOR_END: insert-fixup-case-2-3 // ANCHOR: initialize-input-checks #[inline(always)] diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index fd698998..d47f721d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -697,7 +697,7 @@ insert_to_tree: exit # Parent is null, new node at root. # ANCHOR_END: insert-to-tree -# ANCHOR: insert-fixup +# ANCHOR: insert-fixup-child-dir insert_get_child_dir: # Get child direction, set at parent. # --------------------------------------------------------------------- @@ -708,7 +708,9 @@ insert_get_child_dir_branch_l: ja insert_fixup_main insert_get_child_dir_branch_r: stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; +# ANCHOR_END: insert-fixup-child-dir +# ANCHOR: insert-fixup-case-1 insert_fixup_main: # r2 := parent # r5 := parent.key @@ -717,7 +719,9 @@ insert_fixup_main: ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; jne r6, TREE_COLOR_B, insert_fixup_check_case_4 exit # If parent is black, tree is still valid, so exit. +# ANCHOR_END: insert-fixup-case-1 +# ANCHOR: insert-fixup-case-4 insert_fixup_check_case_4: # Check case 4. # --------------------------------------------------------------------- @@ -725,7 +729,9 @@ insert_fixup_check_case_4: jne r3, NULL, insert_fixup_check_case_5_6 stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; exit +# ANCHOR_END: insert-fixup-case-4 +# ANCHOR: insert-fixup-case-5-6-dir-l insert_fixup_check_case_5_6: # Get uncle and check for case 5 or 6. # --------------------------------------------------------------------- @@ -779,7 +785,9 @@ insert_fixup_case_6_dir_l_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit +# ANCHOR_END: insert-fixup-case-5-6-dir-l +# ANCHOR: insert-fixup-case-5-6-dir-r insert_fixup_check_case_5_6_dir_r: ldxdw r7, [r3 + TREE_NODE_CHILD_L_OFF] # r7 = uncle; jeq r7, NULL, insert_fixup_case_5_6_dir_r @@ -827,7 +835,9 @@ insert_fixup_case_6_dir_r_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit +# ANCHOR_END: insert-fixup-case-5-6-dir-r +# ANCHOR: insert-fixup-case-2-3 insert_fixup_case_2: # r2 := parent # r3 := grandparent @@ -841,7 +851,7 @@ insert_fixup_case_2: ldxdw r2, [r9 + TREE_NODE_PARENT_OFF] # parent = node.parent; jne r2, NULL, insert_fixup_main exit # Case 3. -# ANCHOR_END: insert-fixup +# ANCHOR_END: insert-fixup-case-2-3 e_instruction_data: From 963a0f4a6a6e1fe4a21af999490cb04635c21812 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:04:33 -0700 Subject: [PATCH 203/263] Update listings --- docs/src/examples/tree.md | 136 +++++++++++++++++- .../snippets/rs/insert-fixup-case-1.txt | 2 + .../rs/insert-fixup-case-5-6-dir-l.txt | 4 +- .../rs/insert-fixup-case-5-6-dir-r.txt | 27 +++- examples/tree/src/program.rs | 16 +-- 5 files changed, 162 insertions(+), 23 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index a15352be..7873cfcf 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -149,24 +149,154 @@ not available in Rust, since the compiler enforces ## Insert +### Input checks + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-input-checks.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-input-checks.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + +### Allocate + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-allocate.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-allocate.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + +### Search + ::: details Implementations ::: code-group -<<< ../../../examples/tree/artifacts/snippets/asm/insert.txt{asm} [Assembly] +<<< ../../../examples/tree/artifacts/snippets/asm/insert-search.txt{asm} [Assembly] -<<< ../../../examples/tree/artifacts/snippets/rs/insert.txt{rs} [Rust] +<<< ../../../examples/tree/artifacts/snippets/rs/insert-search.txt{rs} [Rust] ::: ::: details Benchmarking - + + +::: + + + +### Insert fixup + + + +::: details Insert to tree + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-to-tree.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-to-tree.txt{rs} [Rust] ::: +::: details Child direction + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt{rs} [Rust] + +::: + +::: details Case 1 + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-case-1.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt{rs} [Rust] + +::: + +::: details Case 4 + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-case-4.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-case-4.txt{rs} [Rust] + +::: + +::: details Cases 5 and 6 (left) + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt{rs} [Rust] + +::: + +::: details Cases 5 and 6 (right) + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt{rs} [Rust] + +::: + +::: details Cases 2 and 3 + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-case-2-3.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + ## :white_check_mark: All tests ::: details `tests.rs` diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt index a7003047..29d599e9 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-1.txt @@ -1,3 +1,5 @@ + // Main insert fixup. + loop { // Case 1. if (*parent).color == Color::Black { return SUCCESS; diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt index ff96a325..8789e0aa 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt @@ -54,9 +54,7 @@ (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; (*great_grandparent).child[idx] = parent; } else { (*tree_header).root = parent; diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt index d91580b9..f5120efa 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt @@ -2,9 +2,14 @@ // dir_r: parent is right child of grandparent. uncle = (*grandparent).child[tree::DIR_L]; if uncle.is_null() || (*uncle).color == Color::Black { - // Case 5 dir_r: rotate parent RIGHT. - let new_root = (*parent).child[tree::DIR_L]; - if node == new_root { + // Case 5 dir_r: rotate parent in DIR_R. + // + // Grandparent is guaranteed non-null by the case 4 check, so + // no root-replacement path is needed. Parent is known to be + // grandparent.child[DIR_R] from the dir_r branch, so the + // child pointer update is hardcoded without comparison. + if node == (*parent).child[tree::DIR_L] { + let new_root = (*parent).child[tree::DIR_L]; let new_child = (*new_root).child[tree::DIR_R]; (*parent).child[tree::DIR_L] = new_child; @@ -22,7 +27,17 @@ parent = new_root; } - // Case 6 dir_r: rotate grandparent LEFT. + // Case 6 dir_r: rotate grandparent in DIR_L. + // + // The new root of this rotation is parent + // (= grandparent.child[DIR_R]), already in scope, + // eliminating the generic version's load of + // subtree.child[opposite(direction)]. + // + // Great-grandparent may be null (grandparent could be root), + // so the null check and root-replacement path are retained. + // Grandparent's position under great-grandparent is unrelated + // to dir, so the pointer comparison is also retained. { let great_grandparent = (*grandparent).parent; let new_child = (*parent).child[tree::DIR_L]; @@ -37,9 +52,7 @@ (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; (*great_grandparent).child[idx] = parent; } else { (*tree_header).root = parent; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index e536ba40..3ea72cd6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,9 +9,9 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, Color, - CreateAccountInstructionData, InitializeInstruction, InsertInstruction, - SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, - TransferInstructionData, TreeHeader, TreeNode, + CreateAccountInstructionData, InitializeInstruction, InsertInstruction, SolAccountInfo, + SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TransferInstructionData, + TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -334,9 +334,9 @@ unsafe fn insert( (*parent).child[child_dir] = node; // ANCHOR_END: insert-fixup-child-dir + // ANCHOR: insert-fixup-case-1 // Main insert fixup. loop { - // ANCHOR: insert-fixup-case-1 // Case 1. if (*parent).color == Color::Black { return SUCCESS; @@ -409,9 +409,7 @@ unsafe fn insert( (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; (*great_grandparent).child[idx] = parent; } else { (*tree_header).root = parent; @@ -478,9 +476,7 @@ unsafe fn insert( (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent - == (*great_grandparent).child[tree::DIR_R]) - as usize; + let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; (*great_grandparent).child[idx] = parent; } else { (*tree_header).root = parent; From 8199812589e075444d3bd0cd0fca412584b30f39 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:06:09 -0700 Subject: [PATCH 204/263] Spec out more tests --- examples/tree/specs/insert-tests.md | 233 ++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/examples/tree/specs/insert-tests.md b/examples/tree/specs/insert-tests.md index d10ba298..c59a17b9 100644 --- a/examples/tree/specs/insert-tests.md +++ b/examples/tree/specs/insert-tests.md @@ -277,6 +277,239 @@ After: Right-left variants: mirror of above (insert key=12, parent is R(15), double rotation goes right then left). +### Case 6: non-null great-grandparent + +The existing case 6 tests have grandparent as root, so +great-grandparent is always null and the root-replacement path fires. +These variants place the rotation under a non-root grandparent to +cover the great-grandparent child pointer update branches in the +assembly (`insert_fixup_case_6_dir_l_left`, +`insert_fixup_case_6_dir_r_left`, and their fall-through +counterparts). + +Left-left, GP is left child of GGP (insert key=1): + +```text +Before: + Header: root=N0 top=N4 next= + N0: B key=20 parent=-- L=N1 R=N3 + N1: B key=10 parent=N0 L=N2 R=-- + N2: R key=5 parent=N1 L=-- R=-- + N3: B key=25 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=20 parent=-- L=N2 R=N3 + N1: R key=10 parent=N2 L=-- R=-- <- recolored R + N2: B key=5 parent=N0 L=N4 R=N1 <- recolored B + N3: B key=25 parent=N0 L=-- R=-- + N4: R key=1 parent=N2 L=-- R=-- <- inserted +``` + +Covers: GGP non-null, GP is left child of GGP (dir_l path, +`insert_fixup_case_6_dir_l_left`). + +Left-left, GP is right child of GGP (insert key=10): + +```text +Before: + Header: root=N0 top=N4 next= + N0: B key=5 parent=-- L=N1 R=N2 + N1: B key=3 parent=N0 L=-- R=-- + N2: B key=20 parent=N0 L=N3 R=-- + N3: R key=15 parent=N2 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=5 parent=-- L=N1 R=N3 + N1: B key=3 parent=N0 L=-- R=-- + N2: R key=20 parent=N3 L=-- R=-- <- recolored R + N3: B key=15 parent=N0 L=N4 R=N2 <- recolored B + N4: R key=10 parent=N3 L=-- R=-- <- inserted +``` + +Covers: GGP non-null, GP is right child of GGP (dir_l path, +fall-through at `jne r3, r8`). + +Right-right, GP is right child of GGP (insert key=25): + +```text +Before: + Header: root=N0 top=N4 next= + N0: B key=5 parent=-- L=N1 R=N2 + N1: B key=3 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=N3 + N3: R key=20 parent=N2 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=5 parent=-- L=N1 R=N3 + N1: B key=3 parent=N0 L=-- R=-- + N2: R key=15 parent=N3 L=-- R=-- <- recolored R + N3: B key=20 parent=N0 L=N2 R=N4 <- recolored B + N4: R key=25 parent=N3 L=-- R=-- <- inserted +``` + +Covers: GGP non-null, GP is right child of GGP (dir_r path, +fall-through at `jne r3, r8`). + +Right-right, GP is left child of GGP (insert key=17): + +```text +Before: + Header: root=N0 top=N4 next= + N0: B key=20 parent=-- L=N1 R=N3 + N1: B key=10 parent=N0 L=-- R=N2 + N2: R key=15 parent=N1 L=-- R=-- + N3: B key=25 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=-- next= + N0: B key=20 parent=-- L=N2 R=N3 + N1: R key=10 parent=N2 L=-- R=-- <- recolored R + N2: B key=15 parent=N0 L=N1 R=N4 <- recolored B + N3: B key=25 parent=N0 L=-- R=-- + N4: R key=17 parent=N2 L=-- R=-- <- inserted +``` + +Covers: GGP non-null, GP is left child of GGP (dir_r path, +`insert_fixup_case_6_dir_r_left`). + +### Case 2 + 6: non-null new_child in rotation + +The existing case 6 tests have null `new_child` in the rotation +(parent has no child on the transferred side). These variants use +case 2 propagation to reach case 6 with a populated subtree, so the +`new_child` pointer is non-null and the reparenting branch fires +(`insert_fixup_case_6_dir_l_skip` / `dir_r_skip` fall-through). + +Dir_l variant (insert key=1): + +```text +Before: + Header: root=N0 top=N7 next= + N0: B key=20 parent=-- L=N1 R=N3 + N1: R key=10 parent=N0 L=N2 R=N6 + N2: B key=5 parent=N1 L=N4 R=N5 + N3: B key=25 parent=N0 L=-- R=-- + N4: R key=3 parent=N2 L=-- R=-- + N5: R key=7 parent=N2 L=-- R=-- + N6: B key=15 parent=N1 L=-- R=-- + +After: + Header: root=N1 top=-- next= + N0: R key=20 parent=N1 L=N6 R=N3 <- recolored R + N1: B key=10 parent=-- L=N2 R=N0 <- recolored B, new root + N2: R key=5 parent=N1 L=N4 R=N5 <- recolored R (case 2) + N3: B key=25 parent=N0 L=-- R=-- + N4: B key=3 parent=N2 L=N7 R=-- <- recolored B (case 2) + N5: B key=7 parent=N2 L=-- R=-- <- recolored B (case 2) + N6: B key=15 parent=N0 L=-- R=-- <- reparented + N7: R key=1 parent=N4 L=-- R=-- <- inserted +``` + +Path: insert at N4.L → case 2 (uncle N5 red) recolors +N4/N5/N2 → node=N2, parent=N1 → case 6 dir_l rotates N0 +right with `new_child = N6` (non-null). + +Dir_r variant (insert key=30): + +```text +Before: + Header: root=N0 top=N7 next= + N0: B key=5 parent=-- L=N1 R=N2 + N1: B key=3 parent=N0 L=-- R=-- + N2: R key=15 parent=N0 L=N3 R=N4 + N3: B key=10 parent=N2 L=-- R=-- + N4: B key=20 parent=N2 L=N5 R=N6 + N5: R key=17 parent=N4 L=-- R=-- + N6: R key=25 parent=N4 L=-- R=-- + +After: + Header: root=N2 top=-- next= + N0: R key=5 parent=N2 L=N1 R=N3 <- recolored R + N1: B key=3 parent=N0 L=-- R=-- + N2: B key=15 parent=-- L=N0 R=N4 <- recolored B, new root + N3: B key=10 parent=N0 L=-- R=-- <- reparented + N4: R key=20 parent=N2 L=N5 R=N6 <- recolored R (case 2) + N5: B key=17 parent=N4 L=-- R=-- <- recolored B (case 2) + N6: B key=25 parent=N4 L=-- R=N7 <- recolored B (case 2) + N7: R key=30 parent=N6 L=-- R=-- <- inserted +``` + +Path: insert at N6.R → case 2 (uncle N5 red) recolors +N5/N6/N4 → node=N4, parent=N2 → case 6 dir_r rotates N0 +left with `new_child = N3` (non-null). + +### Case 2 + 5 + 6: non-null new_child in rotations + +The existing case 5+6 tests have null `new_child` in both rotations. +These variants use case 2 propagation to reach case 5 with a +populated subtree, producing non-null `new_child` in both the case 5 +and case 6 rotations (`insert_fixup_case_5_dir_l_skip` / +`dir_r_skip` and `insert_fixup_case_6_dir_l_skip` / `dir_r_skip` +fall-through). + +Dir_l variant (insert key=11): + +```text +Before: + Header: root=N0 top=N7 next= + N0: B key=20 parent=-- L=N1 R=N4 + N1: R key=10 parent=N0 L=N2 R=N3 + N2: B key=5 parent=N1 L=-- R=-- + N3: B key=15 parent=N1 L=N5 R=N6 + N4: B key=25 parent=N0 L=-- R=-- + N5: R key=12 parent=N3 L=-- R=-- + N6: R key=17 parent=N3 L=-- R=-- + +After: + Header: root=N3 top=-- next= + N0: R key=20 parent=N3 L=N6 R=N4 <- recolored R + N1: R key=10 parent=N3 L=N2 R=N5 <- reparented + N2: B key=5 parent=N1 L=-- R=-- + N3: B key=15 parent=-- L=N1 R=N0 <- recolored B, new root + N4: B key=25 parent=N0 L=-- R=-- + N5: B key=12 parent=N1 L=N7 R=-- <- recolored B, reparented + N6: B key=17 parent=N0 L=-- R=-- <- recolored B, reparented + N7: R key=11 parent=N5 L=-- R=-- <- inserted +``` + +Path: insert at N5.L → case 2 (uncle N6 red) recolors +N5/N6/N3 → node=N3, parent=N1 → case 5 dir_l rotates N1 +left with `new_child = N5` (non-null) → case 6 dir_l rotates +N0 right with `new_child = N6` (non-null). + +Dir_r variant (insert key=18): + +```text +Before: + Header: root=N0 top=N7 next= + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=20 parent=N0 L=N3 R=N4 + N3: B key=15 parent=N2 L=N5 R=N6 + N4: B key=25 parent=N2 L=-- R=-- + N5: R key=12 parent=N3 L=-- R=-- + N6: R key=17 parent=N3 L=-- R=-- + +After: + Header: root=N3 top=-- next= + N0: R key=10 parent=N3 L=N1 R=N5 <- recolored R + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=20 parent=N3 L=N6 R=N4 <- reparented + N3: B key=15 parent=-- L=N0 R=N2 <- recolored B, new root + N4: B key=25 parent=N2 L=-- R=-- + N5: B key=12 parent=N0 L=-- R=-- <- recolored B, reparented + N6: B key=17 parent=N2 L=-- R=N7 <- recolored B, reparented + N7: R key=18 parent=N6 L=-- R=-- <- inserted +``` + +Path: insert at N6.R → case 2 (uncle N5 red) recolors +N5/N6/N3 → node=N3, parent=N2 → case 5 dir_r rotates N2 +right with `new_child = N6` (non-null) → case 6 dir_r rotates +N0 left with `new_child = N5` (non-null). + ## Multi-insert integration tests A handful of sequential-insert tests to validate that chained From 42abd151d5ba950c9d6c78ea52227a0c750f50ca Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:11:01 -0700 Subject: [PATCH 205/263] Clean up tests --- docs/src/examples/tree.md | 2 +- .../artifacts/tests/insert_to_tree/result.txt | 56 ++++ examples/tree/src/tests/insert_tree.rs | 274 ++++++++++++++++++ 3 files changed, 331 insertions(+), 1 deletion(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 7873cfcf..d28edf32 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -291,7 +291,7 @@ not available in Rust, since the compiler enforces ::: details Benchmarking - + ::: diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 2279eddf..abe93663 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -19,6 +19,14 @@ | Case 5+6: right-left null uncle | 71 | 86 | +15 | +21.1% | | Case 5+6: left-right black uncle | 72 | 89 | +17 | +23.6% | | Case 5+6: right-left black uncle | 73 | 89 | +16 | +21.9% | +| Case 6: GGP non-null, LL GP-left | 70 | 101 | +31 | +44.3% | +| Case 6: GGP non-null, LL GP-right | 71 | 98 | +27 | +38.0% | +| Case 6: GGP non-null, RR GP-right | 72 | 92 | +20 | +27.8% | +| Case 6: GGP non-null, RR GP-left | 71 | 95 | +24 | +33.8% | +| Case 2+6: non-null new_child dir_l | 92 | 124 | +32 | +34.8% | +| Case 2+6: non-null new_child dir_r | 95 | 113 | +18 | +18.9% | +| Case 2+5+6: non-null new_child dir_l | 103 | 129 | +26 | +25.2% | +| Case 2+5+6: non-null new_child dir_r | 104 | 122 | +18 | +17.3% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -133,4 +141,52 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 89 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 101 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 92 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 92 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 124 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 113 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 129 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 104 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/tests/insert_tree.rs b/examples/tree/src/tests/insert_tree.rs index 120364ad..324cf84b 100644 --- a/examples/tree/src/tests/insert_tree.rs +++ b/examples/tree/src/tests/insert_tree.rs @@ -373,6 +373,17 @@ pub(super) enum InsertTreeCase { Case56RightNull, Case56LeftBlack, Case56RightBlack, + // Case 6: non-null great-grandparent. + Case6GgpLeftLeft, + Case6GgpLeftRight, + Case6GgpRightRight, + Case6GgpRightLeft, + // Case 2+6: non-null new_child in rotation. + Case26Left, + Case26Right, + // Case 2+5+6: non-null new_child in rotations. + Case256Left, + Case256Right, } impl InsertTreeCase { @@ -402,6 +413,14 @@ impl InsertTreeCase { Self::Case56RightNull, Self::Case56LeftBlack, Self::Case56RightBlack, + Self::Case6GgpLeftLeft, + Self::Case6GgpLeftRight, + Self::Case6GgpRightRight, + Self::Case6GgpRightLeft, + Self::Case26Left, + Self::Case26Right, + Self::Case256Left, + Self::Case256Right, ]; } @@ -430,6 +449,14 @@ impl TestCase for InsertTreeCase { Self::Case56RightNull => "Case 5+6: right-left null uncle", Self::Case56LeftBlack => "Case 5+6: left-right black uncle", Self::Case56RightBlack => "Case 5+6: right-left black uncle", + Self::Case6GgpLeftLeft => "Case 6: GGP non-null, LL GP-left", + Self::Case6GgpLeftRight => "Case 6: GGP non-null, LL GP-right", + Self::Case6GgpRightRight => "Case 6: GGP non-null, RR GP-right", + Self::Case6GgpRightLeft => "Case 6: GGP non-null, RR GP-left", + Self::Case26Left => "Case 2+6: non-null new_child dir_l", + Self::Case26Right => "Case 2+6: non-null new_child dir_r", + Self::Case256Left => "Case 2+5+6: non-null new_child dir_l", + Self::Case256Right => "Case 2+5+6: non-null new_child dir_r", } } @@ -875,6 +902,253 @@ impl TestCase for InsertTreeCase { }; run_success(lang, &desc, 12, &exp) } + + // ----- Case 6: non-null great-grandparent ----- + + // LL, GP is left child of GGP. Insert 1. + // B(20) root, B(10) left with R(5) left, B(25) right. + // Case 6 dir_l rotates GP=B(10) right under GGP=B(20). + // GGP.child[L] = parent (GP was left child). + Self::Case6GgpLeftLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, B, Some(0), Some(2), None), + node(5, R, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(2), Some(3)), + expected(10, 10, R, Some(2), None, None), + expected(5, 5, B, Some(0), Some(4), Some(1)), + expected(25, 25, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // LL, GP is right child of GGP. Insert 10. + // B(5) root, B(3) left, B(20) right with R(15) left. + // Case 6 dir_l rotates GP=B(20) right under GGP=B(5). + // GGP.child[R] = parent (GP was right child). + Self::Case6GgpLeftRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(20, B, Some(0), Some(3), None), + node(15, R, Some(2), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(5, 5, B, None, Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(20, 20, R, Some(3), None, None), + expected(15, 15, B, Some(0), Some(4), Some(2)), + expected(10, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 10, &exp) + } + // RR, GP is right child of GGP. Insert 25. + // B(5) root, B(3) left, B(15) right with R(20) right. + // Case 6 dir_r rotates GP=B(15) left under GGP=B(5). + // GGP.child[R] = parent (GP was right child). + Self::Case6GgpRightRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(5, 5, B, None, Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(15, 15, R, Some(3), None, None), + expected(20, 20, B, Some(0), Some(2), Some(4)), + expected(25, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 25, &exp) + } + // RR, GP is left child of GGP. Insert 17. + // B(20) root, B(10) left with R(15) right, B(25) right. + // Case 6 dir_r rotates GP=B(10) left under GGP=B(20). + // GGP.child[L] = parent (GP was left child). + Self::Case6GgpRightLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, B, Some(0), None, Some(2)), + node(15, R, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(2), Some(3)), + expected(10, 10, R, Some(2), None, None), + expected(15, 15, B, Some(0), Some(1), Some(4)), + expected(25, 25, B, Some(0), None, None), + expected(17, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 17, &exp) + } + + // ----- Case 2+6: non-null new_child in rotation ----- + + // Dir_l: insert 1 into 7-node tree. + // Case 2 recolors at bottom, then case 6 dir_l rotates with + // new_child = B(15) non-null. + Self::Case26Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, R, Some(0), Some(2), Some(6)), + node(5, B, Some(1), Some(4), Some(5)), + node(25, B, Some(0), None, None), + node(3, R, Some(2), None, None), + node(7, R, Some(2), None, None), + node(15, B, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(20, 20, R, Some(1), Some(6), Some(3)), + expected(10, 10, B, None, Some(2), Some(0)), + expected(5, 5, R, Some(1), Some(4), Some(5)), + expected(25, 25, B, Some(0), None, None), + expected(3, 3, B, Some(2), Some(7), None), + expected(7, 7, B, Some(2), None, None), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(4), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Dir_r: insert 30 into 7-node tree. + // Case 2 recolors at bottom, then case 6 dir_r rotates with + // new_child = B(10) non-null. + Self::Case26Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(15, R, Some(0), Some(3), Some(4)), + node(10, B, Some(2), None, None), + node(20, B, Some(2), Some(5), Some(6)), + node(17, R, Some(4), None, None), + node(25, R, Some(4), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(5, 5, R, Some(2), Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(15, 15, B, None, Some(0), Some(4)), + expected(10, 10, B, Some(0), None, None), + expected(20, 20, R, Some(2), Some(5), Some(6)), + expected(17, 17, B, Some(4), None, None), + expected(25, 25, B, Some(4), None, Some(7)), + expected(30, TEST_VALUE, R, Some(6), None, None), + ], + }; + run_success(lang, &desc, 30, &exp) + } + + // ----- Case 2+5+6: non-null new_child in rotations ----- + + // Dir_l: insert 11 into 7-node tree. + // Case 2 recolors at bottom, then case 5 dir_l rotates with + // new_child = B(12) non-null, then case 6 dir_l rotates with + // new_child = B(17) non-null. + Self::Case256Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(4)), + node(10, R, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(15, B, Some(1), Some(5), Some(6)), + node(25, B, Some(0), None, None), + node(12, R, Some(3), None, None), + node(17, R, Some(3), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(20, 20, R, Some(3), Some(6), Some(4)), + expected(10, 10, R, Some(3), Some(2), Some(5)), + expected(5, 5, B, Some(1), None, None), + expected(15, 15, B, None, Some(1), Some(0)), + expected(25, 25, B, Some(0), None, None), + expected(12, 12, B, Some(1), Some(7), None), + expected(17, 17, B, Some(0), None, None), + expected(11, TEST_VALUE, R, Some(5), None, None), + ], + }; + run_success(lang, &desc, 11, &exp) + } + // Dir_r: insert 18 into 7-node tree. + // Case 2 recolors at bottom, then case 5 dir_r rotates with + // new_child = B(17) non-null, then case 6 dir_r rotates with + // new_child = B(12) non-null. + Self::Case256Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(4)), + node(15, B, Some(2), Some(5), Some(6)), + node(25, B, Some(2), None, None), + node(12, R, Some(3), None, None), + node(17, R, Some(3), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), Some(1), Some(5)), + expected(5, 5, B, Some(0), None, None), + expected(20, 20, R, Some(3), Some(6), Some(4)), + expected(15, 15, B, None, Some(0), Some(2)), + expected(25, 25, B, Some(2), None, None), + expected(12, 12, B, Some(0), None, None), + expected(17, 17, B, Some(2), None, Some(7)), + expected(18, TEST_VALUE, R, Some(6), None, None), + ], + }; + run_success(lang, &desc, 18, &exp) + } } } } From 95b4db9a13849d402f6251ead09e2898fa6d5631 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:27:34 -0700 Subject: [PATCH 206/263] Refactor tests --- .../tree/artifacts/tests/insert/result.txt | 35 - examples/tree/artifacts/tests/insert/test.txt | 4 - .../artifacts/tests/insert_alloc/result.txt | 14 + .../artifacts/tests/insert_alloc/test.txt | 4 + .../tests/insert_input_checks/result.txt | 17 + .../tests/insert_input_checks/test.txt | 4 + .../artifacts/tests/insert_search/test.txt | 2 +- .../artifacts/tests/insert_to_tree/test.txt | 2 +- examples/tree/src/tests.rs | 14 +- examples/tree/src/tests/insert.rs | 1267 ++++++++++++++++- examples/tree/src/tests/insert_tree.rs | 1154 --------------- 11 files changed, 1251 insertions(+), 1266 deletions(-) delete mode 100644 examples/tree/artifacts/tests/insert/result.txt delete mode 100644 examples/tree/artifacts/tests/insert/test.txt create mode 100644 examples/tree/artifacts/tests/insert_alloc/result.txt create mode 100644 examples/tree/artifacts/tests/insert_alloc/test.txt create mode 100644 examples/tree/artifacts/tests/insert_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/insert_input_checks/test.txt delete mode 100644 examples/tree/src/tests/insert_tree.rs diff --git a/examples/tree/artifacts/tests/insert/result.txt b/examples/tree/artifacts/tests/insert/result.txt deleted file mode 100644 index 9d599f65..00000000 --- a/examples/tree/artifacts/tests/insert/result.txt +++ /dev/null @@ -1,35 +0,0 @@ -| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | -|-----------|----------------|---------------|----------------|----------|------------| -| Instruction data too short | 0 | 7 | 9 | +2 | +28.6% | -| Instruction data too long | 0 | 7 | 9 | +2 | +28.6% | -| Insert skip alloc | 0 | 25 | 27 | +2 | +8.0% | -| Insert alloc happy path | 1096 | 101 | 129 | +28 | +27.7% | -test tests::test_insert ... ok -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1197 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] -[ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1225 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert/test.txt b/examples/tree/artifacts/tests/insert/test.txt deleted file mode 100644 index ee37483c..00000000 --- a/examples/tree/artifacts/tests/insert/test.txt +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, false, false); -} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc/result.txt b/examples/tree/artifacts/tests/insert_alloc/result.txt new file mode 100644 index 00000000..e485c24c --- /dev/null +++ b/examples/tree/artifacts/tests/insert_alloc/result.txt @@ -0,0 +1,14 @@ +| Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | +|-----------|----------------|---------------|----------------|----------|------------| +| Insert alloc happy path | 1096 | 101 | 129 | +28 | +27.7% | +test tests::test_insert_alloc ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1197 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 1225 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc/test.txt b/examples/tree/artifacts/tests/insert_alloc/test.txt new file mode 100644 index 00000000..7565fb2a --- /dev/null +++ b/examples/tree/artifacts/tests/insert_alloc/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert_alloc() { + print_comparison_table(insert::InsertCase::ALLOC_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_input_checks/result.txt b/examples/tree/artifacts/tests/insert_input_checks/result.txt new file mode 100644 index 00000000..fe6bb963 --- /dev/null +++ b/examples/tree/artifacts/tests/insert_input_checks/result.txt @@ -0,0 +1,17 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Instruction data too short | 7 | 9 | +2 | +28.6% | +| Instruction data too long | 7 | 9 | +2 | +28.6% | +test tests::test_insert_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_input_checks/test.txt b/examples/tree/artifacts/tests/insert_input_checks/test.txt new file mode 100644 index 00000000..b127bee7 --- /dev/null +++ b/examples/tree/artifacts/tests/insert_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_insert_input_checks() { + print_comparison_table(insert::InsertCase::INPUT_CASES, false, false); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/test.txt b/examples/tree/artifacts/tests/insert_search/test.txt index 06d36d40..d25d7800 100644 --- a/examples/tree/artifacts/tests/insert_search/test.txt +++ b/examples/tree/artifacts/tests/insert_search/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_search() { - print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, false, false); + print_comparison_table(insert::InsertCase::SEARCH_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/test.txt b/examples/tree/artifacts/tests/insert_to_tree/test.txt index 4077243e..9b42b922 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/test.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_to_tree() { - print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, false, false); + print_comparison_table(insert::InsertCase::TREE_CASES, false, false); } \ No newline at end of file diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index f7b32b2a..d501f76e 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,7 +1,6 @@ mod entrypoint; mod init; mod insert; -mod insert_tree; use mollusk_svm::result::ProgramResult as MolluskResult; use solana_sdk::account::Account; @@ -169,8 +168,8 @@ fn test_entrypoint_branching() { } #[test] -fn test_insert() { - print_comparison_table(insert::InsertCase::CASES, false, false); +fn test_insert_input_checks() { + print_comparison_table(insert::InsertCase::INPUT_CASES, false, false); } #[test] @@ -178,6 +177,11 @@ fn test_insert_alloc_checks() { print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES, false, false); } +#[test] +fn test_insert_alloc() { + print_comparison_table(insert::InsertCase::ALLOC_CASES, false, false); +} + #[test] fn test_initialize_input_checks() { print_comparison_table(init::InitCase::CASES, false, false); @@ -195,10 +199,10 @@ fn test_initialize_create_account() { #[test] fn test_insert_search() { - print_comparison_table(insert_tree::InsertTreeCase::SEARCH_CASES, false, false); + print_comparison_table(insert::InsertCase::SEARCH_CASES, false, false); } #[test] fn test_insert_to_tree() { - print_comparison_table(insert_tree::InsertTreeCase::TREE_CASES, false, false); + print_comparison_table(insert::InsertCase::TREE_CASES, false, false); } diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 72a5c83e..2b0e67c2 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -4,13 +4,17 @@ use mollusk_svm::result::{Check, Config}; use pinocchio::sysvars::rent::Rent; use solana_sdk::instruction::AccountMeta; use tree_interface::{ - cpi, input_buffer, tree, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, - StackNode, TreeHeader, TreeNode, + cpi, input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, + InstructionHeader, StackNode, TreeHeader, TreeNode, }; const TEST_KEY: u16 = 42; const TEST_VALUE: u16 = 1; +// --------------------------------------------------------------------------- +// Helpers: allocation setup +// --------------------------------------------------------------------------- + fn insert_instruction_data() -> InsertInstruction { InsertInstruction { header: InstructionHeader { @@ -127,70 +131,525 @@ fn insert_alloc_address_mismatch( check_error(&setup, &instruction, &accounts, expected_error) } +// --------------------------------------------------------------------------- +// Helpers: tree description types +// --------------------------------------------------------------------------- + +struct NodeDesc { + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +} + +struct TreeDesc<'a> { + root: Option, + nodes: &'a [NodeDesc], +} + +/// Compute the virtual address of node slot `i` in the tree account. +fn node_vaddr(i: usize) -> u64 { + MM_INPUT_START + + input_buffer::TREE_DATA_OFF as u64 + + size_of::() as u64 + + (i as u64) * (size_of::() as u64) +} + +/// Convert an optional node index to a virtual address (0 for None). +fn opt_vaddr(idx: Option) -> u64 { + match idx { + Some(i) => node_vaddr(i), + None => 0, + } +} + +// --------------------------------------------------------------------------- +// Helper: build tree account data +// --------------------------------------------------------------------------- + +/// Build tree account data with pre-existing nodes and one free StackNode. +/// +/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] | free_slot +/// +/// - `header.root` → virtual address of `nodes[root]`, or null. +/// - `header.top` → virtual address of the free slot (index = nodes.len()). +/// - `header.next` → 0 (unused in skip-alloc path). +fn build_tree_account(desc: &TreeDesc, program_id: &Pubkey) -> (Pubkey, Account) { + let n = desc.nodes.len(); + // N existing nodes + 1 free slot. + let data_len = size_of::() + (n + 1) * size_of::(); + let mut data = vec![0u8; data_len]; + + // Write header. + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = opt_vaddr(desc.root) as *mut TreeNode; + (*header).top = node_vaddr(n) as *mut StackNode; + (*header).next = core::ptr::null_mut(); + } + + // Write existing nodes. + for (i, node) in desc.nodes.iter().enumerate() { + let offset = size_of::() + i * size_of::(); + let ptr = unsafe { data.as_mut_ptr().add(offset) as *mut TreeNode }; + unsafe { + (*ptr).parent = opt_vaddr(node.parent) as *mut TreeNode; + (*ptr).child[tree::DIR_L] = opt_vaddr(node.left) as *mut TreeNode; + (*ptr).child[tree::DIR_R] = opt_vaddr(node.right) as *mut TreeNode; + (*ptr).key = node.key; + (*ptr).value = node.value; + (*ptr).color = core::mem::transmute(node.color); + } + } + + // Free slot is already zeroed (StackNode.next = null). + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} + +// --------------------------------------------------------------------------- +// Helper: assert tree account (full state) +// --------------------------------------------------------------------------- + +struct ExpectedNode { + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +} + +struct ExpectedTree { + root: Option, + top: Option, + nodes: Vec, +} + +/// Assert every field of the tree account data against expected state. +/// Returns Ok(()) on match, Err(description) on mismatch. +fn assert_tree_account(data: &[u8], expected: &ExpectedTree) -> Result<(), String> { + let mut errors = Vec::new(); + let n = expected.nodes.len(); + + // Check data length. + let expected_len = size_of::() + n * size_of::(); + if data.len() != expected_len { + errors.push(format!( + "data len: expected {}, got {}", + expected_len, + data.len() + )); + } + + // Check header. + let header = data.as_ptr() as *const TreeHeader; + unsafe { + let root_addr = (*header).root as u64; + let expected_root = opt_vaddr(expected.root); + if root_addr != expected_root { + errors.push(format!( + "header.root: expected {:#x}, got {:#x}", + expected_root, root_addr + )); + } + + let top_addr = (*header).top as u64; + let expected_top = opt_vaddr(expected.top); + if top_addr != expected_top { + errors.push(format!( + "header.top: expected {:#x}, got {:#x}", + expected_top, top_addr + )); + } + + let next_addr = (*header).next as u64; + if next_addr != 0 { + errors.push(format!("header.next: expected 0x0, got {:#x}", next_addr)); + } + } + + // Check each node. + for i in 0..n { + let offset = size_of::() + i * size_of::(); + if offset + size_of::() > data.len() { + errors.push(format!("N{}: out of bounds", i)); + continue; + } + let ptr = unsafe { data.as_ptr().add(offset) as *const TreeNode }; + let exp = &expected.nodes[i]; + let label = format!("N{}", i); + + unsafe { + let parent_addr = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).parent)) as u64; + let expected_parent = opt_vaddr(exp.parent); + if parent_addr != expected_parent { + errors.push(format!( + "{}.parent: expected {:#x}, got {:#x}", + label, expected_parent, parent_addr + )); + } + + let left_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_L])) as u64; + let expected_left = opt_vaddr(exp.left); + if left_addr != expected_left { + errors.push(format!( + "{}.L: expected {:#x}, got {:#x}", + label, expected_left, left_addr + )); + } + + let right_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_R])) as u64; + let expected_right = opt_vaddr(exp.right); + if right_addr != expected_right { + errors.push(format!( + "{}.R: expected {:#x}, got {:#x}", + label, expected_right, right_addr + )); + } + + let key = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).key)); + if key != exp.key { + errors.push(format!("{}.key: expected {}, got {}", label, exp.key, key)); + } + + let value = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).value)); + if value != exp.value { + errors.push(format!( + "{}.value: expected {}, got {}", + label, exp.value, value + )); + } + + let color = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).color)) as u8; + if color != exp.color { + let color_name = |c: u8| if c == 0 { "B" } else { "R" }; + errors.push(format!( + "{}.color: expected {}, got {}", + label, + color_name(exp.color), + color_name(color) + )); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors.join("; ")) + } +} + +// --------------------------------------------------------------------------- +// Helpers: tree test setup and runners +// --------------------------------------------------------------------------- + +fn insert_tree_setup( + lang: ProgramLanguage, + desc: &TreeDesc, + insert_key: u16, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(lang); + let (system_program_pubkey, _) = mollusk_svm::program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, tree_account) = build_tree_account(desc, &setup.program_id); + + let insn_data = InsertInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Insert as u8, + }, + key: insert_key, + value: TEST_VALUE, + }; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + unsafe { as_bytes(&insn_data) }, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account), + ]; + + (setup, instruction, accounts) +} + +/// Run an insert and assert success with full tree state check. +fn run_success( + lang: ProgramLanguage, + desc: &TreeDesc, + insert_key: u16, + expected: &ExpectedTree, +) -> CaseResult { + let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => { + let tree_data = &result.resulting_accounts[AccountIndex::Tree as usize] + .1 + .data; + match assert_tree_account(tree_data, expected) { + Ok(()) => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + Err(e) => CaseResult { + cu: result.compute_units_consumed, + error: Some(e), + }, + } + } + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Success, got {:?}", other)), + }, + } +} + +/// Run an insert and check for KEY_EXISTS error. +fn run_dup_error(lang: ProgramLanguage, desc: &TreeDesc, insert_key: u16) -> CaseResult { + let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::KEY_EXISTS, + ) +} + +// --------------------------------------------------------------------------- +// Shorthand constructors +// --------------------------------------------------------------------------- + +const B: u8 = Color::Black as u8; +const R: u8 = Color::Red as u8; + +fn node( + key: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +) -> NodeDesc { + NodeDesc { + key, + value: key, // Use key as value for pre-existing nodes. + color, + parent, + left, + right, + } +} + +fn expected( + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +) -> ExpectedNode { + ExpectedNode { + key, + value, + color, + parent, + left, + right, + } +} + +// --------------------------------------------------------------------------- +// Test case enum +// --------------------------------------------------------------------------- + #[derive(Clone, Copy)] pub(super) enum InsertCase { - InstructionDataLenShort, - InstructionDataLenLong, - InsertSkipAlloc, - InsertAllocHappyPath, - NAccountsInsertAllocation, - SystemProgramDuplicate, - SystemProgramDataLen, - RentDuplicate, - RentAddressChunk0, - RentAddressChunk1, - RentAddressChunk2, - RentAddressChunk3, + // Input validation. + InputDataShort, + InputDataLong, + // Allocation checks. + AllocNAccounts, + AllocSysprogDuplicate, + AllocSysprogDataLen, + AllocRentDuplicate, + AllocRentAddrChunk0, + AllocRentAddrChunk1, + AllocRentAddrChunk2, + AllocRentAddrChunk3, + // Allocation happy path (CPI overhead). + AllocHappyPath, + // Search — expect KEY_EXISTS error. + SearchDupRoot, + SearchDupLeft, + SearchDupRight, + // Insert to empty tree. + EmptyTree, + // Case 1: parent is black. + Case1Left, + Case1Right, + // Case 4: parent is root and red. + Case4Left, + Case4Right, + // Case 2+3: red uncle, propagate to root. + Case23LeftLeft, + Case23LeftRight, + Case23RightLeft, + Case23RightRight, + // Case 2+1: red uncle, propagate to black ancestor. + Case21Left, + Case21Right, + // Case 6: single rotation (outer child). + Case6LeftNull, + Case6RightNull, + Case6LeftBlack, + Case6RightBlack, + // Case 5+6: double rotation (inner child). + Case56LeftNull, + Case56RightNull, + Case56LeftBlack, + Case56RightBlack, + // Case 6: non-null great-grandparent. + Case6GgpLeftLeft, + Case6GgpLeftRight, + Case6GgpRightRight, + Case6GgpRightLeft, + // Case 2+6: non-null new_child in rotation. + Case26Left, + Case26Right, + // Case 2+5+6: non-null new_child in rotations. + Case256Left, + Case256Right, } impl InsertCase { - pub(super) const CASES: &'static [Self] = &[ - Self::InstructionDataLenShort, - Self::InstructionDataLenLong, - Self::InsertSkipAlloc, - Self::InsertAllocHappyPath, - ]; + pub(super) const INPUT_CASES: &'static [Self] = &[Self::InputDataShort, Self::InputDataLong]; pub(super) const ALLOC_CHECK_CASES: &'static [Self] = &[ - Self::NAccountsInsertAllocation, - Self::SystemProgramDuplicate, - Self::SystemProgramDataLen, - Self::RentDuplicate, - Self::RentAddressChunk0, - Self::RentAddressChunk1, - Self::RentAddressChunk2, - Self::RentAddressChunk3, + Self::AllocNAccounts, + Self::AllocSysprogDuplicate, + Self::AllocSysprogDataLen, + Self::AllocRentDuplicate, + Self::AllocRentAddrChunk0, + Self::AllocRentAddrChunk1, + Self::AllocRentAddrChunk2, + Self::AllocRentAddrChunk3, + ]; + + pub(super) const ALLOC_CASES: &'static [Self] = &[Self::AllocHappyPath]; + + pub(super) const SEARCH_CASES: &'static [Self] = &[ + Self::SearchDupRoot, + Self::SearchDupLeft, + Self::SearchDupRight, + ]; + + pub(super) const TREE_CASES: &'static [Self] = &[ + Self::EmptyTree, + Self::Case1Left, + Self::Case1Right, + Self::Case4Left, + Self::Case4Right, + Self::Case23LeftLeft, + Self::Case23LeftRight, + Self::Case23RightLeft, + Self::Case23RightRight, + Self::Case21Left, + Self::Case21Right, + Self::Case6LeftNull, + Self::Case6RightNull, + Self::Case6LeftBlack, + Self::Case6RightBlack, + Self::Case56LeftNull, + Self::Case56RightNull, + Self::Case56LeftBlack, + Self::Case56RightBlack, + Self::Case6GgpLeftLeft, + Self::Case6GgpLeftRight, + Self::Case6GgpRightRight, + Self::Case6GgpRightLeft, + Self::Case26Left, + Self::Case26Right, + Self::Case256Left, + Self::Case256Right, ]; } impl TestCase for InsertCase { fn name(&self) -> &'static str { match self { - Self::InstructionDataLenShort => "Instruction data too short", - Self::InstructionDataLenLong => "Instruction data too long", - Self::InsertSkipAlloc => "Insert skip alloc", - Self::InsertAllocHappyPath => "Insert alloc happy path", - Self::NAccountsInsertAllocation => "Wrong N accounts for allocation", - Self::SystemProgramDuplicate => "System program is duplicate", - Self::SystemProgramDataLen => "System program wrong data length", - Self::RentDuplicate => "Rent sysvar is duplicate", - Self::RentAddressChunk0 => "Rent address mismatch chunk 0", - Self::RentAddressChunk1 => "Rent address mismatch chunk 1", - Self::RentAddressChunk2 => "Rent address mismatch chunk 2", - Self::RentAddressChunk3 => "Rent address mismatch chunk 3", + Self::InputDataShort => "Instruction data too short", + Self::InputDataLong => "Instruction data too long", + Self::AllocNAccounts => "Wrong N accounts for allocation", + Self::AllocSysprogDuplicate => "System program is duplicate", + Self::AllocSysprogDataLen => "System program wrong data length", + Self::AllocRentDuplicate => "Rent sysvar is duplicate", + Self::AllocRentAddrChunk0 => "Rent address mismatch chunk 0", + Self::AllocRentAddrChunk1 => "Rent address mismatch chunk 1", + Self::AllocRentAddrChunk2 => "Rent address mismatch chunk 2", + Self::AllocRentAddrChunk3 => "Rent address mismatch chunk 3", + Self::AllocHappyPath => "Insert alloc happy path", + Self::SearchDupRoot => "Dup at root", + Self::SearchDupLeft => "Dup in left", + Self::SearchDupRight => "Dup in right", + Self::EmptyTree => "Empty tree", + Self::Case1Left => "Case 1: left child", + Self::Case1Right => "Case 1: right child", + Self::Case4Left => "Case 4: left child", + Self::Case4Right => "Case 4: right child", + Self::Case23LeftLeft => "Case 2+3: left-left", + Self::Case23LeftRight => "Case 2+3: left-right", + Self::Case23RightLeft => "Case 2+3: right-left", + Self::Case23RightRight => "Case 2+3: right-right", + Self::Case21Left => "Case 2+1: left", + Self::Case21Right => "Case 2+1: right", + Self::Case6LeftNull => "Case 6: left-left null uncle", + Self::Case6RightNull => "Case 6: right-right null uncle", + Self::Case6LeftBlack => "Case 6: left-left black uncle", + Self::Case6RightBlack => "Case 6: right-right black uncle", + Self::Case56LeftNull => "Case 5+6: left-right null uncle", + Self::Case56RightNull => "Case 5+6: right-left null uncle", + Self::Case56LeftBlack => "Case 5+6: left-right black uncle", + Self::Case56RightBlack => "Case 5+6: right-left black uncle", + Self::Case6GgpLeftLeft => "Case 6: GGP non-null, LL GP-left", + Self::Case6GgpLeftRight => "Case 6: GGP non-null, LL GP-right", + Self::Case6GgpRightRight => "Case 6: GGP non-null, RR GP-right", + Self::Case6GgpRightLeft => "Case 6: GGP non-null, RR GP-left", + Self::Case26Left => "Case 2+6: non-null new_child dir_l", + Self::Case26Right => "Case 2+6: non-null new_child dir_r", + Self::Case256Left => "Case 2+5+6: non-null new_child dir_l", + Self::Case256Right => "Case 2+5+6: non-null new_child dir_r", } } fn fixed_costs(&self) -> u64 { match self { - Self::InsertAllocHappyPath => fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM, + Self::AllocHappyPath => fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM, _ => 0, } } fn run(&self, lang: ProgramLanguage) -> CaseResult { match self { - Self::InstructionDataLenShort => { + // ----- Input validation ----- + Self::InputDataShort => { let (setup, mut instruction, accounts) = insert_skip_alloc_setup(lang); // Correct discriminator but wrong length (1 byte instead of 5). instruction.data = vec![TreeInstruction::Insert as u8]; @@ -201,7 +660,7 @@ impl TestCase for InsertCase { error_codes::error::INSTRUCTION_DATA_LEN, ) } - Self::InstructionDataLenLong => { + Self::InputDataLong => { let (setup, mut instruction, accounts) = insert_skip_alloc_setup(lang); // Correct discriminator but wrong length (6 bytes instead of 5). instruction.data = vec![TreeInstruction::Insert as u8, 0, 0, 0, 0, 0]; @@ -212,21 +671,9 @@ impl TestCase for InsertCase { error_codes::error::INSTRUCTION_DATA_LEN, ) } - Self::InsertSkipAlloc => { - let (setup, instruction, accounts) = insert_skip_alloc_setup(lang); - let result = setup.mollusk.process_instruction(&instruction, &accounts); - match &result.program_result { - MolluskResult::Success => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Success, got {:?}", other)), - }, - } - } - Self::NAccountsInsertAllocation => { + + // ----- Allocation checks ----- + Self::AllocNAccounts => { // Use insert_setup (top=null triggers allocation) but strip CPI accounts. let (setup, mut instruction, mut accounts) = insert_setup(lang); instruction.accounts.truncate(2); @@ -238,7 +685,7 @@ impl TestCase for InsertCase { error_codes::error::N_ACCOUNTS_INSERT_ALLOCATION, ) } - Self::SystemProgramDuplicate => { + Self::AllocSysprogDuplicate => { let (setup, mut instruction, mut accounts) = insert_setup(lang); instruction.accounts[AccountIndex::SystemProgram as usize] = instruction.accounts[AccountIndex::User as usize].clone(); @@ -251,7 +698,7 @@ impl TestCase for InsertCase { error_codes::error::SYSTEM_PROGRAM_DUPLICATE, ) } - Self::SystemProgramDataLen => { + Self::AllocSysprogDataLen => { let (setup, instruction, mut accounts) = insert_setup(lang); accounts[AccountIndex::SystemProgram as usize].1.data = vec![]; check_error( @@ -261,7 +708,7 @@ impl TestCase for InsertCase { error_codes::error::SYSTEM_PROGRAM_DATA_LEN, ) } - Self::RentDuplicate => { + Self::AllocRentDuplicate => { let (setup, mut instruction, mut accounts) = insert_setup(lang); instruction.accounts[AccountIndex::RentSysvar as usize] = instruction.accounts[AccountIndex::User as usize].clone(); @@ -274,31 +721,33 @@ impl TestCase for InsertCase { error_codes::error::RENT_DUPLICATE, ) } - Self::RentAddressChunk0 => insert_alloc_address_mismatch( + Self::AllocRentAddrChunk0 => insert_alloc_address_mismatch( lang, AccountIndex::RentSysvar as usize, 0, error_codes::error::RENT_ADDRESS, ), - Self::RentAddressChunk1 => insert_alloc_address_mismatch( + Self::AllocRentAddrChunk1 => insert_alloc_address_mismatch( lang, AccountIndex::RentSysvar as usize, 1, error_codes::error::RENT_ADDRESS, ), - Self::RentAddressChunk2 => insert_alloc_address_mismatch( + Self::AllocRentAddrChunk2 => insert_alloc_address_mismatch( lang, AccountIndex::RentSysvar as usize, 2, error_codes::error::RENT_ADDRESS, ), - Self::RentAddressChunk3 => insert_alloc_address_mismatch( + Self::AllocRentAddrChunk3 => insert_alloc_address_mismatch( lang, AccountIndex::RentSysvar as usize, 3, error_codes::error::RENT_ADDRESS, ), - Self::InsertAllocHappyPath => { + + // ----- Allocation happy path ----- + Self::AllocHappyPath => { let (setup, instruction, accounts) = insert_setup(lang); let result = setup.mollusk.process_instruction(&instruction, &accounts); match &result.program_result { @@ -376,6 +825,692 @@ impl TestCase for InsertCase { }, } } + + // ----- Search: duplicate key errors ----- + + // Root with key 10, insert 10. + Self::SearchDupRoot => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + run_dup_error(lang, &desc, 10) + } + // Root 10, left child 5, insert 5. + Self::SearchDupLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + run_dup_error(lang, &desc, 5) + } + // Root 10, right child 15, insert 15. + Self::SearchDupRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + run_dup_error(lang, &desc, 15) + } + + // ----- Insert to empty tree ----- + Self::EmptyTree => { + let desc = TreeDesc { + root: None, + nodes: &[], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![expected(42, TEST_VALUE, R, None, None, None)], + }; + run_success(lang, &desc, 42, &exp) + } + + // ----- Case 1: parent is black ----- + + // B(10) root, insert 5 → left child. + Self::Case1Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, Some(1), None), + expected(5, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 5, &exp) + } + // B(10) root, insert 15 → right child. + Self::Case1Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, None, Some(1)), + expected(15, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 15, &exp) + } + + // ----- Case 4: parent is root and red ----- + + // R(10) root, insert 5 → left child, parent recolored B. + Self::Case4Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, R, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, Some(1), None), + expected(5, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 5, &exp) + } + // R(10) root, insert 15 → right child, parent recolored B. + Self::Case4Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[node(10, R, None, None, None)], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, B, None, None, Some(1)), + expected(15, TEST_VALUE, R, Some(0), None, None), + ], + }; + run_success(lang, &desc, 15, &exp) + } + + // ----- Case 2+3: red uncle, propagate to root ----- + // Before: B(10) root, R(5) left, R(15) right. + // After recolor: R(10), B(5), B(15), inserted node red. + Self::Case23LeftLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), Some(3), None), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + Self::Case23LeftRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, Some(3)), + expected(15, 15, B, Some(0), None, None), + expected(7, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 7, &exp) + } + Self::Case23RightLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, Some(0), Some(3), None), + expected(12, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 12, &exp) + } + Self::Case23RightRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(10, 10, R, None, Some(1), Some(2)), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, Some(0), None, Some(3)), + expected(20, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 2+1: red uncle, propagate to black ancestor ----- + + // Before: B(20) root, B(10) left of root, R(5) left of 10, R(15) right of 10. + // After: B(20), R(10), B(5), B(15), R(1) inserted. + Self::Case21Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), None), + node(10, B, Some(0), Some(2), Some(3)), + node(5, R, Some(1), None, None), + node(15, R, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(1), None), + expected(10, 10, R, Some(0), Some(2), Some(3)), + expected(5, 5, B, Some(1), Some(4), None), + expected(15, 15, B, Some(1), None, None), + expected(1, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Mirror: B(2) root, B(10) right of root, R(5) left of 10, R(15) right of 10. + Self::Case21Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(2, B, None, None, Some(1)), + node(10, B, Some(0), Some(2), Some(3)), + node(5, R, Some(1), None, None), + node(15, R, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(2, 2, B, None, None, Some(1)), + expected(10, 10, R, Some(0), Some(2), Some(3)), + expected(5, 5, B, Some(1), None, None), + expected(15, 15, B, Some(1), None, Some(4)), + expected(20, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 6: single rotation (outer child) ----- + + // Left-left, null uncle: B(10) root, R(5) left, insert 1. + // After: B(5) new root, R(1) left, R(10) right. + Self::Case6LeftNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, None), + expected(5, 5, B, None, Some(2), Some(0)), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Right-right, null uncle: B(10) root, R(15) right, insert 20. + // After: B(15) new root, R(10) left, R(20) right. + Self::Case6RightNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, None), + expected(15, 15, B, None, Some(0), Some(2)), + expected(20, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + // Left-left, black uncle: B(10) root, R(5) left, B(15) right, insert 1. + // After: B(5) new root, R(1) left, R(10) right with B(15) as 10's right. + Self::Case6LeftBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(10, 10, R, Some(1), None, Some(2)), + expected(5, 5, B, None, Some(3), Some(0)), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(1), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Right-right, black uncle: B(10) root, B(5) left, R(15) right, insert 20. + // After: B(15) new root, R(10) left with B(5) as 10's left, R(20) right. + Self::Case6RightBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), Some(1), None), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, B, None, Some(0), Some(3)), + expected(20, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 20, &exp) + } + + // ----- Case 5+6: double rotation (inner child) ----- + + // Left-right, null uncle: B(10) root, R(5) left, insert 7. + // After: B(7) new root, R(5) left, R(10) right. + Self::Case56LeftNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), None, None), + expected(5, 5, R, Some(2), None, None), + expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + ], + }; + run_success(lang, &desc, 7, &exp) + } + // Right-left, null uncle: B(10) root, R(15) right, insert 12. + // After: B(12) new root, R(10) left, R(15) right. + Self::Case56RightNull => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(10, 10, R, Some(2), None, None), + expected(15, 15, R, Some(2), None, None), + expected(12, TEST_VALUE, B, None, Some(0), Some(1)), + ], + }; + run_success(lang, &desc, 12, &exp) + } + // Left-right, black uncle: B(10) root, R(5) left, B(15) right, insert 7. + // After: B(7) new root, R(5) left, R(10) right with B(15) as 10's right. + Self::Case56LeftBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), None, Some(2)), + expected(5, 5, R, Some(3), None, None), + expected(15, 15, B, Some(0), None, None), + expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + ], + }; + run_success(lang, &desc, 7, &exp) + } + // Right-left, black uncle: B(10) root, B(5) left, R(15) right, insert 12. + // After: B(12) new root, R(10) left with B(5) as 10's left, R(15) right. + Self::Case56RightBlack => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), Some(1), None), + expected(5, 5, B, Some(0), None, None), + expected(15, 15, R, Some(3), None, None), + expected(12, TEST_VALUE, B, None, Some(0), Some(2)), + ], + }; + run_success(lang, &desc, 12, &exp) + } + + // ----- Case 6: non-null great-grandparent ----- + + // LL, GP is left child of GGP. Insert 1. + // B(20) root, B(10) left with R(5) left, B(25) right. + // Case 6 dir_l rotates GP=B(10) right under GGP=B(20). + // GGP.child[L] = parent (GP was left child). + Self::Case6GgpLeftLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, B, Some(0), Some(2), None), + node(5, R, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(2), Some(3)), + expected(10, 10, R, Some(2), None, None), + expected(5, 5, B, Some(0), Some(4), Some(1)), + expected(25, 25, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // LL, GP is right child of GGP. Insert 10. + // B(5) root, B(3) left, B(20) right with R(15) left. + // Case 6 dir_l rotates GP=B(20) right under GGP=B(5). + // GGP.child[R] = parent (GP was right child). + Self::Case6GgpLeftRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(20, B, Some(0), Some(3), None), + node(15, R, Some(2), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(5, 5, B, None, Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(20, 20, R, Some(3), None, None), + expected(15, 15, B, Some(0), Some(4), Some(2)), + expected(10, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 10, &exp) + } + // RR, GP is right child of GGP. Insert 25. + // B(5) root, B(3) left, B(15) right with R(20) right. + // Case 6 dir_r rotates GP=B(15) left under GGP=B(5). + // GGP.child[R] = parent (GP was right child). + Self::Case6GgpRightRight => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(5, 5, B, None, Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(15, 15, R, Some(3), None, None), + expected(20, 20, B, Some(0), Some(2), Some(4)), + expected(25, TEST_VALUE, R, Some(3), None, None), + ], + }; + run_success(lang, &desc, 25, &exp) + } + // RR, GP is left child of GGP. Insert 17. + // B(20) root, B(10) left with R(15) right, B(25) right. + // Case 6 dir_r rotates GP=B(10) left under GGP=B(20). + // GGP.child[L] = parent (GP was left child). + Self::Case6GgpRightLeft => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, B, Some(0), None, Some(2)), + node(15, R, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(0), + top: None, + nodes: vec![ + expected(20, 20, B, None, Some(2), Some(3)), + expected(10, 10, R, Some(2), None, None), + expected(15, 15, B, Some(0), Some(1), Some(4)), + expected(25, 25, B, Some(0), None, None), + expected(17, TEST_VALUE, R, Some(2), None, None), + ], + }; + run_success(lang, &desc, 17, &exp) + } + + // ----- Case 2+6: non-null new_child in rotation ----- + + // Dir_l: insert 1 into 7-node tree. + // Case 2 recolors at bottom, then case 6 dir_l rotates with + // new_child = B(15) non-null. + Self::Case26Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(3)), + node(10, R, Some(0), Some(2), Some(6)), + node(5, B, Some(1), Some(4), Some(5)), + node(25, B, Some(0), None, None), + node(3, R, Some(2), None, None), + node(7, R, Some(2), None, None), + node(15, B, Some(1), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(1), + top: None, + nodes: vec![ + expected(20, 20, R, Some(1), Some(6), Some(3)), + expected(10, 10, B, None, Some(2), Some(0)), + expected(5, 5, R, Some(1), Some(4), Some(5)), + expected(25, 25, B, Some(0), None, None), + expected(3, 3, B, Some(2), Some(7), None), + expected(7, 7, B, Some(2), None, None), + expected(15, 15, B, Some(0), None, None), + expected(1, TEST_VALUE, R, Some(4), None, None), + ], + }; + run_success(lang, &desc, 1, &exp) + } + // Dir_r: insert 30 into 7-node tree. + // Case 2 recolors at bottom, then case 6 dir_r rotates with + // new_child = B(10) non-null. + Self::Case26Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(5, B, None, Some(1), Some(2)), + node(3, B, Some(0), None, None), + node(15, R, Some(0), Some(3), Some(4)), + node(10, B, Some(2), None, None), + node(20, B, Some(2), Some(5), Some(6)), + node(17, R, Some(4), None, None), + node(25, R, Some(4), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(2), + top: None, + nodes: vec![ + expected(5, 5, R, Some(2), Some(1), Some(3)), + expected(3, 3, B, Some(0), None, None), + expected(15, 15, B, None, Some(0), Some(4)), + expected(10, 10, B, Some(0), None, None), + expected(20, 20, R, Some(2), Some(5), Some(6)), + expected(17, 17, B, Some(4), None, None), + expected(25, 25, B, Some(4), None, Some(7)), + expected(30, TEST_VALUE, R, Some(6), None, None), + ], + }; + run_success(lang, &desc, 30, &exp) + } + + // ----- Case 2+5+6: non-null new_child in rotations ----- + + // Dir_l: insert 11 into 7-node tree. + // Case 2 recolors at bottom, then case 5 dir_l rotates with + // new_child = B(12) non-null, then case 6 dir_l rotates with + // new_child = B(17) non-null. + Self::Case256Left => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(20, B, None, Some(1), Some(4)), + node(10, R, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(15, B, Some(1), Some(5), Some(6)), + node(25, B, Some(0), None, None), + node(12, R, Some(3), None, None), + node(17, R, Some(3), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(20, 20, R, Some(3), Some(6), Some(4)), + expected(10, 10, R, Some(3), Some(2), Some(5)), + expected(5, 5, B, Some(1), None, None), + expected(15, 15, B, None, Some(1), Some(0)), + expected(25, 25, B, Some(0), None, None), + expected(12, 12, B, Some(1), Some(7), None), + expected(17, 17, B, Some(0), None, None), + expected(11, TEST_VALUE, R, Some(5), None, None), + ], + }; + run_success(lang, &desc, 11, &exp) + } + // Dir_r: insert 18 into 7-node tree. + // Case 2 recolors at bottom, then case 5 dir_r rotates with + // new_child = B(17) non-null, then case 6 dir_r rotates with + // new_child = B(12) non-null. + Self::Case256Right => { + let desc = TreeDesc { + root: Some(0), + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(4)), + node(15, B, Some(2), Some(5), Some(6)), + node(25, B, Some(2), None, None), + node(12, R, Some(3), None, None), + node(17, R, Some(3), None, None), + ], + }; + let exp = ExpectedTree { + root: Some(3), + top: None, + nodes: vec![ + expected(10, 10, R, Some(3), Some(1), Some(5)), + expected(5, 5, B, Some(0), None, None), + expected(20, 20, R, Some(3), Some(6), Some(4)), + expected(15, 15, B, None, Some(0), Some(2)), + expected(25, 25, B, Some(2), None, None), + expected(12, 12, B, Some(0), None, None), + expected(17, 17, B, Some(2), None, Some(7)), + expected(18, TEST_VALUE, R, Some(6), None, None), + ], + }; + run_success(lang, &desc, 18, &exp) + } } } } diff --git a/examples/tree/src/tests/insert_tree.rs b/examples/tree/src/tests/insert_tree.rs deleted file mode 100644 index 324cf84b..00000000 --- a/examples/tree/src/tests/insert_tree.rs +++ /dev/null @@ -1,1154 +0,0 @@ -use super::*; -use solana_sdk::instruction::AccountMeta; -use tree_interface::{ - input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, - StackNode, TreeHeader, TreeNode, -}; - -const TEST_VALUE: u16 = 1; - -// --------------------------------------------------------------------------- -// Helpers: tree description types -// --------------------------------------------------------------------------- - -struct NodeDesc { - key: u16, - value: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -} - -struct TreeDesc<'a> { - root: Option, - nodes: &'a [NodeDesc], -} - -/// Compute the virtual address of node slot `i` in the tree account. -fn node_vaddr(i: usize) -> u64 { - MM_INPUT_START - + input_buffer::TREE_DATA_OFF as u64 - + size_of::() as u64 - + (i as u64) * (size_of::() as u64) -} - -/// Convert an optional node index to a virtual address (0 for None). -fn opt_vaddr(idx: Option) -> u64 { - match idx { - Some(i) => node_vaddr(i), - None => 0, - } -} - -// --------------------------------------------------------------------------- -// Helper: build tree account data -// --------------------------------------------------------------------------- - -/// Build tree account data with pre-existing nodes and one free StackNode. -/// -/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] | free_slot -/// -/// - `header.root` → virtual address of `nodes[root]`, or null. -/// - `header.top` → virtual address of the free slot (index = nodes.len()). -/// - `header.next` → 0 (unused in skip-alloc path). -fn build_tree_account(desc: &TreeDesc, program_id: &Pubkey) -> (Pubkey, Account) { - let n = desc.nodes.len(); - // N existing nodes + 1 free slot. - let data_len = size_of::() + (n + 1) * size_of::(); - let mut data = vec![0u8; data_len]; - - // Write header. - let header = data.as_mut_ptr() as *mut TreeHeader; - unsafe { - (*header).root = opt_vaddr(desc.root) as *mut TreeNode; - (*header).top = node_vaddr(n) as *mut StackNode; - (*header).next = core::ptr::null_mut(); - } - - // Write existing nodes. - for (i, node) in desc.nodes.iter().enumerate() { - let offset = size_of::() + i * size_of::(); - let ptr = unsafe { data.as_mut_ptr().add(offset) as *mut TreeNode }; - unsafe { - (*ptr).parent = opt_vaddr(node.parent) as *mut TreeNode; - (*ptr).child[tree::DIR_L] = opt_vaddr(node.left) as *mut TreeNode; - (*ptr).child[tree::DIR_R] = opt_vaddr(node.right) as *mut TreeNode; - (*ptr).key = node.key; - (*ptr).value = node.value; - (*ptr).color = core::mem::transmute(node.color); - } - } - - // Free slot is already zeroed (StackNode.next = null). - - let pubkey = Pubkey::new_unique(); - let mut account = Account::new(0, data_len, program_id); - account.data = data; - (pubkey, account) -} - -// --------------------------------------------------------------------------- -// Helper: assert tree account (full state) -// --------------------------------------------------------------------------- - -struct ExpectedNode { - key: u16, - value: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -} - -struct ExpectedTree { - root: Option, - top: Option, - nodes: Vec, -} - -/// Assert every field of the tree account data against expected state. -/// Returns Ok(()) on match, Err(description) on mismatch. -fn assert_tree_account(data: &[u8], expected: &ExpectedTree) -> Result<(), String> { - let mut errors = Vec::new(); - let n = expected.nodes.len(); - - // Check data length. - let expected_len = size_of::() + n * size_of::(); - if data.len() != expected_len { - errors.push(format!( - "data len: expected {}, got {}", - expected_len, - data.len() - )); - } - - // Check header. - let header = data.as_ptr() as *const TreeHeader; - unsafe { - let root_addr = (*header).root as u64; - let expected_root = opt_vaddr(expected.root); - if root_addr != expected_root { - errors.push(format!( - "header.root: expected {:#x}, got {:#x}", - expected_root, root_addr - )); - } - - let top_addr = (*header).top as u64; - let expected_top = opt_vaddr(expected.top); - if top_addr != expected_top { - errors.push(format!( - "header.top: expected {:#x}, got {:#x}", - expected_top, top_addr - )); - } - - let next_addr = (*header).next as u64; - if next_addr != 0 { - errors.push(format!("header.next: expected 0x0, got {:#x}", next_addr)); - } - } - - // Check each node. - for i in 0..n { - let offset = size_of::() + i * size_of::(); - if offset + size_of::() > data.len() { - errors.push(format!("N{}: out of bounds", i)); - continue; - } - let ptr = unsafe { data.as_ptr().add(offset) as *const TreeNode }; - let exp = &expected.nodes[i]; - let label = format!("N{}", i); - - unsafe { - let parent_addr = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).parent)) as u64; - let expected_parent = opt_vaddr(exp.parent); - if parent_addr != expected_parent { - errors.push(format!( - "{}.parent: expected {:#x}, got {:#x}", - label, expected_parent, parent_addr - )); - } - - let left_addr = - core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_L])) as u64; - let expected_left = opt_vaddr(exp.left); - if left_addr != expected_left { - errors.push(format!( - "{}.L: expected {:#x}, got {:#x}", - label, expected_left, left_addr - )); - } - - let right_addr = - core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_R])) as u64; - let expected_right = opt_vaddr(exp.right); - if right_addr != expected_right { - errors.push(format!( - "{}.R: expected {:#x}, got {:#x}", - label, expected_right, right_addr - )); - } - - let key = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).key)); - if key != exp.key { - errors.push(format!("{}.key: expected {}, got {}", label, exp.key, key)); - } - - let value = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).value)); - if value != exp.value { - errors.push(format!( - "{}.value: expected {}, got {}", - label, exp.value, value - )); - } - - let color = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).color)) as u8; - if color != exp.color { - let color_name = |c: u8| if c == 0 { "B" } else { "R" }; - errors.push(format!( - "{}.color: expected {}, got {}", - label, - color_name(exp.color), - color_name(color) - )); - } - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors.join("; ")) - } -} - -// --------------------------------------------------------------------------- -// Helper: setup -// --------------------------------------------------------------------------- - -fn insert_tree_setup( - lang: ProgramLanguage, - desc: &TreeDesc, - insert_key: u16, -) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let setup = setup_test(lang); - let (system_program_pubkey, _) = mollusk_svm::program::keyed_account_for_system_program(); - - let user_pubkey = Pubkey::new_unique(); - let (tree_pubkey, tree_account) = build_tree_account(desc, &setup.program_id); - - let insn_data = InsertInstruction { - header: InstructionHeader { - discriminator: TreeInstruction::Insert as u8, - }, - key: insert_key, - value: TEST_VALUE, - }; - - let instruction = Instruction::new_with_bytes( - setup.program_id, - unsafe { as_bytes(&insn_data) }, - vec![ - AccountMeta::new(user_pubkey, true), - AccountMeta::new(tree_pubkey, false), - ], - ); - - let accounts = vec![ - ( - user_pubkey, - Account::new(USER_LAMPORTS, 0, &system_program_pubkey), - ), - (tree_pubkey, tree_account), - ]; - - (setup, instruction, accounts) -} - -/// Run an insert and assert success with full tree state check. -fn run_success( - lang: ProgramLanguage, - desc: &TreeDesc, - insert_key: u16, - expected: &ExpectedTree, -) -> CaseResult { - let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); - let result = setup.mollusk.process_instruction(&instruction, &accounts); - match &result.program_result { - MolluskResult::Success => { - let tree_data = &result.resulting_accounts[AccountIndex::Tree as usize].1.data; - match assert_tree_account(tree_data, expected) { - Ok(()) => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - Err(e) => CaseResult { - cu: result.compute_units_consumed, - error: Some(e), - }, - } - } - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Success, got {:?}", other)), - }, - } -} - -/// Run an insert and check for KEY_EXISTS error. -fn run_dup_error(lang: ProgramLanguage, desc: &TreeDesc, insert_key: u16) -> CaseResult { - let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); - check_error( - &setup, - &instruction, - &accounts, - error_codes::error::KEY_EXISTS, - ) -} - -// --------------------------------------------------------------------------- -// Shorthand constructors -// --------------------------------------------------------------------------- - -const B: u8 = Color::Black as u8; -const R: u8 = Color::Red as u8; - -fn node(key: u16, color: u8, parent: Option, left: Option, right: Option) -> NodeDesc { - NodeDesc { - key, - value: key, // Use key as value for pre-existing nodes. - color, - parent, - left, - right, - } -} - -fn expected(key: u16, value: u16, color: u8, parent: Option, left: Option, right: Option) -> ExpectedNode { - ExpectedNode { - key, - value, - color, - parent, - left, - right, - } -} - -// --------------------------------------------------------------------------- -// Test case enum -// --------------------------------------------------------------------------- - -#[derive(Clone, Copy)] -pub(super) enum InsertTreeCase { - // Search — expect KEY_EXISTS error. - DupAtRoot, - DupInLeft, - DupInRight, - // Insert to empty tree. - EmptyTree, - // Case 1: parent is black. - Case1Left, - Case1Right, - // Case 4: parent is root and red. - Case4Left, - Case4Right, - // Case 2+3: red uncle, propagate to root. - Case23LeftLeft, - Case23LeftRight, - Case23RightLeft, - Case23RightRight, - // Case 2+1: red uncle, propagate to black ancestor. - Case21Left, - Case21Right, - // Case 6: single rotation (outer child). - Case6LeftNull, - Case6RightNull, - Case6LeftBlack, - Case6RightBlack, - // Case 5+6: double rotation (inner child). - Case56LeftNull, - Case56RightNull, - Case56LeftBlack, - Case56RightBlack, - // Case 6: non-null great-grandparent. - Case6GgpLeftLeft, - Case6GgpLeftRight, - Case6GgpRightRight, - Case6GgpRightLeft, - // Case 2+6: non-null new_child in rotation. - Case26Left, - Case26Right, - // Case 2+5+6: non-null new_child in rotations. - Case256Left, - Case256Right, -} - -impl InsertTreeCase { - pub(super) const SEARCH_CASES: &'static [Self] = &[ - Self::DupAtRoot, - Self::DupInLeft, - Self::DupInRight, - ]; - - pub(super) const TREE_CASES: &'static [Self] = &[ - Self::EmptyTree, - Self::Case1Left, - Self::Case1Right, - Self::Case4Left, - Self::Case4Right, - Self::Case23LeftLeft, - Self::Case23LeftRight, - Self::Case23RightLeft, - Self::Case23RightRight, - Self::Case21Left, - Self::Case21Right, - Self::Case6LeftNull, - Self::Case6RightNull, - Self::Case6LeftBlack, - Self::Case6RightBlack, - Self::Case56LeftNull, - Self::Case56RightNull, - Self::Case56LeftBlack, - Self::Case56RightBlack, - Self::Case6GgpLeftLeft, - Self::Case6GgpLeftRight, - Self::Case6GgpRightRight, - Self::Case6GgpRightLeft, - Self::Case26Left, - Self::Case26Right, - Self::Case256Left, - Self::Case256Right, - ]; -} - -impl TestCase for InsertTreeCase { - fn name(&self) -> &'static str { - match self { - Self::DupAtRoot => "Dup at root", - Self::DupInLeft => "Dup in left", - Self::DupInRight => "Dup in right", - Self::EmptyTree => "Empty tree", - Self::Case1Left => "Case 1: left child", - Self::Case1Right => "Case 1: right child", - Self::Case4Left => "Case 4: left child", - Self::Case4Right => "Case 4: right child", - Self::Case23LeftLeft => "Case 2+3: left-left", - Self::Case23LeftRight => "Case 2+3: left-right", - Self::Case23RightLeft => "Case 2+3: right-left", - Self::Case23RightRight => "Case 2+3: right-right", - Self::Case21Left => "Case 2+1: left", - Self::Case21Right => "Case 2+1: right", - Self::Case6LeftNull => "Case 6: left-left null uncle", - Self::Case6RightNull => "Case 6: right-right null uncle", - Self::Case6LeftBlack => "Case 6: left-left black uncle", - Self::Case6RightBlack => "Case 6: right-right black uncle", - Self::Case56LeftNull => "Case 5+6: left-right null uncle", - Self::Case56RightNull => "Case 5+6: right-left null uncle", - Self::Case56LeftBlack => "Case 5+6: left-right black uncle", - Self::Case56RightBlack => "Case 5+6: right-left black uncle", - Self::Case6GgpLeftLeft => "Case 6: GGP non-null, LL GP-left", - Self::Case6GgpLeftRight => "Case 6: GGP non-null, LL GP-right", - Self::Case6GgpRightRight => "Case 6: GGP non-null, RR GP-right", - Self::Case6GgpRightLeft => "Case 6: GGP non-null, RR GP-left", - Self::Case26Left => "Case 2+6: non-null new_child dir_l", - Self::Case26Right => "Case 2+6: non-null new_child dir_r", - Self::Case256Left => "Case 2+5+6: non-null new_child dir_l", - Self::Case256Right => "Case 2+5+6: non-null new_child dir_r", - } - } - - fn run(&self, lang: ProgramLanguage) -> CaseResult { - match self { - // ----- Search: duplicate key errors ----- - - // Root with key 10, insert 10. - Self::DupAtRoot => { - let desc = TreeDesc { - root: Some(0), - nodes: &[node(10, B, None, None, None)], - }; - run_dup_error(lang, &desc, 10) - } - // Root 10, left child 5, insert 5. - Self::DupInLeft => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), None), - node(5, R, Some(0), None, None), - ], - }; - run_dup_error(lang, &desc, 5) - } - // Root 10, right child 15, insert 15. - Self::DupInRight => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, None, Some(1)), - node(15, R, Some(0), None, None), - ], - }; - run_dup_error(lang, &desc, 15) - } - - // ----- Insert to empty tree ----- - - Self::EmptyTree => { - let desc = TreeDesc { - root: None, - nodes: &[], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![expected(42, TEST_VALUE, R, None, None, None)], - }; - run_success(lang, &desc, 42, &exp) - } - - // ----- Case 1: parent is black ----- - - // B(10) root, insert 5 → left child. - Self::Case1Left => { - let desc = TreeDesc { - root: Some(0), - nodes: &[node(10, B, None, None, None)], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, B, None, Some(1), None), - expected(5, TEST_VALUE, R, Some(0), None, None), - ], - }; - run_success(lang, &desc, 5, &exp) - } - // B(10) root, insert 15 → right child. - Self::Case1Right => { - let desc = TreeDesc { - root: Some(0), - nodes: &[node(10, B, None, None, None)], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, B, None, None, Some(1)), - expected(15, TEST_VALUE, R, Some(0), None, None), - ], - }; - run_success(lang, &desc, 15, &exp) - } - - // ----- Case 4: parent is root and red ----- - - // R(10) root, insert 5 → left child, parent recolored B. - Self::Case4Left => { - let desc = TreeDesc { - root: Some(0), - nodes: &[node(10, R, None, None, None)], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, B, None, Some(1), None), - expected(5, TEST_VALUE, R, Some(0), None, None), - ], - }; - run_success(lang, &desc, 5, &exp) - } - // R(10) root, insert 15 → right child, parent recolored B. - Self::Case4Right => { - let desc = TreeDesc { - root: Some(0), - nodes: &[node(10, R, None, None, None)], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, B, None, None, Some(1)), - expected(15, TEST_VALUE, R, Some(0), None, None), - ], - }; - run_success(lang, &desc, 15, &exp) - } - - // ----- Case 2+3: red uncle, propagate to root ----- - // Before: B(10) root, R(5) left, R(15) right. - // After recolor: R(10), B(5), B(15), inserted node red. - - Self::Case23LeftLeft => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), Some(3), None), - expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - Self::Case23LeftRight => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, Some(3)), - expected(15, 15, B, Some(0), None, None), - expected(7, TEST_VALUE, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 7, &exp) - } - Self::Case23RightLeft => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, Some(0), Some(3), None), - expected(12, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 12, &exp) - } - Self::Case23RightRight => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, Some(0), None, Some(3)), - expected(20, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 20, &exp) - } - - // ----- Case 2+1: red uncle, propagate to black ancestor ----- - - // Before: B(20) root, B(10) left of root, R(5) left of 10, R(15) right of 10. - // After: B(20), R(10), B(5), B(15), R(1) inserted. - Self::Case21Left => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(20, B, None, Some(1), None), - node(10, B, Some(0), Some(2), Some(3)), - node(5, R, Some(1), None, None), - node(15, R, Some(1), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(20, 20, B, None, Some(1), None), - expected(10, 10, R, Some(0), Some(2), Some(3)), - expected(5, 5, B, Some(1), Some(4), None), - expected(15, 15, B, Some(1), None, None), - expected(1, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // Mirror: B(2) root, B(10) right of root, R(5) left of 10, R(15) right of 10. - Self::Case21Right => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(2, B, None, None, Some(1)), - node(10, B, Some(0), Some(2), Some(3)), - node(5, R, Some(1), None, None), - node(15, R, Some(1), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(2, 2, B, None, None, Some(1)), - expected(10, 10, R, Some(0), Some(2), Some(3)), - expected(5, 5, B, Some(1), None, None), - expected(15, 15, B, Some(1), None, Some(4)), - expected(20, TEST_VALUE, R, Some(3), None, None), - ], - }; - run_success(lang, &desc, 20, &exp) - } - - // ----- Case 6: single rotation (outer child) ----- - - // Left-left, null uncle: B(10) root, R(5) left, insert 1. - // After: B(5) new root, R(1) left, R(10) right. - Self::Case6LeftNull => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), None), - node(5, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(1), - top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, None), - expected(5, 5, B, None, Some(2), Some(0)), - expected(1, TEST_VALUE, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // Right-right, null uncle: B(10) root, R(15) right, insert 20. - // After: B(15) new root, R(10) left, R(20) right. - Self::Case6RightNull => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, None, Some(1)), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(1), - top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, None), - expected(15, 15, B, None, Some(0), Some(2)), - expected(20, TEST_VALUE, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 20, &exp) - } - // Left-left, black uncle: B(10) root, R(5) left, B(15) right, insert 1. - // After: B(5) new root, R(1) left, R(10) right with B(15) as 10's right. - Self::Case6LeftBlack => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, B, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(1), - top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, Some(2)), - expected(5, 5, B, None, Some(3), Some(0)), - expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // Right-right, black uncle: B(10) root, B(5) left, R(15) right, insert 20. - // After: B(15) new root, R(10) left with B(5) as 10's left, R(20) right. - Self::Case6RightBlack => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(2), - top: None, - nodes: vec![ - expected(10, 10, R, Some(2), Some(1), None), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, None, Some(0), Some(3)), - expected(20, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 20, &exp) - } - - // ----- Case 5+6: double rotation (inner child) ----- - - // Left-right, null uncle: B(10) root, R(5) left, insert 7. - // After: B(7) new root, R(5) left, R(10) right. - Self::Case56LeftNull => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), None), - node(5, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(2), - top: None, - nodes: vec![ - expected(10, 10, R, Some(2), None, None), - expected(5, 5, R, Some(2), None, None), - expected(7, TEST_VALUE, B, None, Some(1), Some(0)), - ], - }; - run_success(lang, &desc, 7, &exp) - } - // Right-left, null uncle: B(10) root, R(15) right, insert 12. - // After: B(12) new root, R(10) left, R(15) right. - Self::Case56RightNull => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, None, Some(1)), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(2), - top: None, - nodes: vec![ - expected(10, 10, R, Some(2), None, None), - expected(15, 15, R, Some(2), None, None), - expected(12, TEST_VALUE, B, None, Some(0), Some(1)), - ], - }; - run_success(lang, &desc, 12, &exp) - } - // Left-right, black uncle: B(10) root, R(5) left, B(15) right, insert 7. - // After: B(7) new root, R(5) left, R(10) right with B(15) as 10's right. - Self::Case56LeftBlack => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, B, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(3), - top: None, - nodes: vec![ - expected(10, 10, R, Some(3), None, Some(2)), - expected(5, 5, R, Some(3), None, None), - expected(15, 15, B, Some(0), None, None), - expected(7, TEST_VALUE, B, None, Some(1), Some(0)), - ], - }; - run_success(lang, &desc, 7, &exp) - } - // Right-left, black uncle: B(10) root, B(5) left, R(15) right, insert 12. - // After: B(12) new root, R(10) left with B(5) as 10's left, R(15) right. - Self::Case56RightBlack => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(3), - top: None, - nodes: vec![ - expected(10, 10, R, Some(3), Some(1), None), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, R, Some(3), None, None), - expected(12, TEST_VALUE, B, None, Some(0), Some(2)), - ], - }; - run_success(lang, &desc, 12, &exp) - } - - // ----- Case 6: non-null great-grandparent ----- - - // LL, GP is left child of GGP. Insert 1. - // B(20) root, B(10) left with R(5) left, B(25) right. - // Case 6 dir_l rotates GP=B(10) right under GGP=B(20). - // GGP.child[L] = parent (GP was left child). - Self::Case6GgpLeftLeft => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(20, B, None, Some(1), Some(3)), - node(10, B, Some(0), Some(2), None), - node(5, R, Some(1), None, None), - node(25, B, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(20, 20, B, None, Some(2), Some(3)), - expected(10, 10, R, Some(2), None, None), - expected(5, 5, B, Some(0), Some(4), Some(1)), - expected(25, 25, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // LL, GP is right child of GGP. Insert 10. - // B(5) root, B(3) left, B(20) right with R(15) left. - // Case 6 dir_l rotates GP=B(20) right under GGP=B(5). - // GGP.child[R] = parent (GP was right child). - Self::Case6GgpLeftRight => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(5, B, None, Some(1), Some(2)), - node(3, B, Some(0), None, None), - node(20, B, Some(0), Some(3), None), - node(15, R, Some(2), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(5, 5, B, None, Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(20, 20, R, Some(3), None, None), - expected(15, 15, B, Some(0), Some(4), Some(2)), - expected(10, TEST_VALUE, R, Some(3), None, None), - ], - }; - run_success(lang, &desc, 10, &exp) - } - // RR, GP is right child of GGP. Insert 25. - // B(5) root, B(3) left, B(15) right with R(20) right. - // Case 6 dir_r rotates GP=B(15) left under GGP=B(5). - // GGP.child[R] = parent (GP was right child). - Self::Case6GgpRightRight => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(5, B, None, Some(1), Some(2)), - node(3, B, Some(0), None, None), - node(15, B, Some(0), None, Some(3)), - node(20, R, Some(2), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(5, 5, B, None, Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(15, 15, R, Some(3), None, None), - expected(20, 20, B, Some(0), Some(2), Some(4)), - expected(25, TEST_VALUE, R, Some(3), None, None), - ], - }; - run_success(lang, &desc, 25, &exp) - } - // RR, GP is left child of GGP. Insert 17. - // B(20) root, B(10) left with R(15) right, B(25) right. - // Case 6 dir_r rotates GP=B(10) left under GGP=B(20). - // GGP.child[L] = parent (GP was left child). - Self::Case6GgpRightLeft => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(20, B, None, Some(1), Some(3)), - node(10, B, Some(0), None, Some(2)), - node(15, R, Some(1), None, None), - node(25, B, Some(0), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(0), - top: None, - nodes: vec![ - expected(20, 20, B, None, Some(2), Some(3)), - expected(10, 10, R, Some(2), None, None), - expected(15, 15, B, Some(0), Some(1), Some(4)), - expected(25, 25, B, Some(0), None, None), - expected(17, TEST_VALUE, R, Some(2), None, None), - ], - }; - run_success(lang, &desc, 17, &exp) - } - - // ----- Case 2+6: non-null new_child in rotation ----- - - // Dir_l: insert 1 into 7-node tree. - // Case 2 recolors at bottom, then case 6 dir_l rotates with - // new_child = B(15) non-null. - Self::Case26Left => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(20, B, None, Some(1), Some(3)), - node(10, R, Some(0), Some(2), Some(6)), - node(5, B, Some(1), Some(4), Some(5)), - node(25, B, Some(0), None, None), - node(3, R, Some(2), None, None), - node(7, R, Some(2), None, None), - node(15, B, Some(1), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(1), - top: None, - nodes: vec![ - expected(20, 20, R, Some(1), Some(6), Some(3)), - expected(10, 10, B, None, Some(2), Some(0)), - expected(5, 5, R, Some(1), Some(4), Some(5)), - expected(25, 25, B, Some(0), None, None), - expected(3, 3, B, Some(2), Some(7), None), - expected(7, 7, B, Some(2), None, None), - expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(4), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // Dir_r: insert 30 into 7-node tree. - // Case 2 recolors at bottom, then case 6 dir_r rotates with - // new_child = B(10) non-null. - Self::Case26Right => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(5, B, None, Some(1), Some(2)), - node(3, B, Some(0), None, None), - node(15, R, Some(0), Some(3), Some(4)), - node(10, B, Some(2), None, None), - node(20, B, Some(2), Some(5), Some(6)), - node(17, R, Some(4), None, None), - node(25, R, Some(4), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(2), - top: None, - nodes: vec![ - expected(5, 5, R, Some(2), Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(15, 15, B, None, Some(0), Some(4)), - expected(10, 10, B, Some(0), None, None), - expected(20, 20, R, Some(2), Some(5), Some(6)), - expected(17, 17, B, Some(4), None, None), - expected(25, 25, B, Some(4), None, Some(7)), - expected(30, TEST_VALUE, R, Some(6), None, None), - ], - }; - run_success(lang, &desc, 30, &exp) - } - - // ----- Case 2+5+6: non-null new_child in rotations ----- - - // Dir_l: insert 11 into 7-node tree. - // Case 2 recolors at bottom, then case 5 dir_l rotates with - // new_child = B(12) non-null, then case 6 dir_l rotates with - // new_child = B(17) non-null. - Self::Case256Left => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(20, B, None, Some(1), Some(4)), - node(10, R, Some(0), Some(2), Some(3)), - node(5, B, Some(1), None, None), - node(15, B, Some(1), Some(5), Some(6)), - node(25, B, Some(0), None, None), - node(12, R, Some(3), None, None), - node(17, R, Some(3), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(3), - top: None, - nodes: vec![ - expected(20, 20, R, Some(3), Some(6), Some(4)), - expected(10, 10, R, Some(3), Some(2), Some(5)), - expected(5, 5, B, Some(1), None, None), - expected(15, 15, B, None, Some(1), Some(0)), - expected(25, 25, B, Some(0), None, None), - expected(12, 12, B, Some(1), Some(7), None), - expected(17, 17, B, Some(0), None, None), - expected(11, TEST_VALUE, R, Some(5), None, None), - ], - }; - run_success(lang, &desc, 11, &exp) - } - // Dir_r: insert 18 into 7-node tree. - // Case 2 recolors at bottom, then case 5 dir_r rotates with - // new_child = B(17) non-null, then case 6 dir_r rotates with - // new_child = B(12) non-null. - Self::Case256Right => { - let desc = TreeDesc { - root: Some(0), - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), - node(20, R, Some(0), Some(3), Some(4)), - node(15, B, Some(2), Some(5), Some(6)), - node(25, B, Some(2), None, None), - node(12, R, Some(3), None, None), - node(17, R, Some(3), None, None), - ], - }; - let exp = ExpectedTree { - root: Some(3), - top: None, - nodes: vec![ - expected(10, 10, R, Some(3), Some(1), Some(5)), - expected(5, 5, B, Some(0), None, None), - expected(20, 20, R, Some(3), Some(6), Some(4)), - expected(15, 15, B, None, Some(0), Some(2)), - expected(25, 25, B, Some(2), None, None), - expected(12, 12, B, Some(0), None, None), - expected(17, 17, B, Some(2), None, Some(7)), - expected(18, TEST_VALUE, R, Some(6), None, None), - ], - }; - run_success(lang, &desc, 18, &exp) - } - } - } -} From f617922fcf998dfa00405bcca3215b1f49a7a7d7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:35:06 -0700 Subject: [PATCH 207/263] Update test listings --- docs/src/examples/tree.md | 3 +- examples/tree/src/tests/insert.rs | 71 +++++++++++++++---------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index d28edf32..5e6dcfe8 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -165,7 +165,7 @@ not available in Rust, since the compiler enforces ::: details Benchmarking - + ::: @@ -189,6 +189,7 @@ not available in Rust, since the compiler enforces + ::: diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 2b0e67c2..dfd70823 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -8,9 +8,6 @@ use tree_interface::{ InstructionHeader, StackNode, TreeHeader, TreeNode, }; -const TEST_KEY: u16 = 42; -const TEST_VALUE: u16 = 1; - // --------------------------------------------------------------------------- // Helpers: allocation setup // --------------------------------------------------------------------------- @@ -20,8 +17,8 @@ fn insert_instruction_data() -> InsertInstruction { header: InstructionHeader { discriminator: TreeInstruction::Insert as u8, }, - key: TEST_KEY, - value: TEST_VALUE, + key: 42, + value: 1, } } @@ -368,7 +365,7 @@ fn insert_tree_setup( discriminator: TreeInstruction::Insert as u8, }, key: insert_key, - value: TEST_VALUE, + value: 1, }; let instruction = Instruction::new_with_bytes( @@ -796,11 +793,11 @@ impl TestCase for InsertCase { }; let key = node.key; let value = node.value; - if key != TEST_KEY { - errors.push(format!("key: expected {}, got {}", TEST_KEY, key)); + if key != 42 { + errors.push(format!("key: expected 42, got {}", key)); } - if value != TEST_VALUE { - errors.push(format!("value: expected {}, got {}", TEST_VALUE, value)); + if value != 1 { + errors.push(format!("value: expected 1, got {}", value)); } let config = Config { panic: false, @@ -868,7 +865,7 @@ impl TestCase for InsertCase { let exp = ExpectedTree { root: Some(0), top: None, - nodes: vec![expected(42, TEST_VALUE, R, None, None, None)], + nodes: vec![expected(42, 1, R, None, None, None)], }; run_success(lang, &desc, 42, &exp) } @@ -886,7 +883,7 @@ impl TestCase for InsertCase { top: None, nodes: vec![ expected(10, 10, B, None, Some(1), None), - expected(5, TEST_VALUE, R, Some(0), None, None), + expected(5, 1, R, Some(0), None, None), ], }; run_success(lang, &desc, 5, &exp) @@ -902,7 +899,7 @@ impl TestCase for InsertCase { top: None, nodes: vec![ expected(10, 10, B, None, None, Some(1)), - expected(15, TEST_VALUE, R, Some(0), None, None), + expected(15, 1, R, Some(0), None, None), ], }; run_success(lang, &desc, 15, &exp) @@ -921,7 +918,7 @@ impl TestCase for InsertCase { top: None, nodes: vec![ expected(10, 10, B, None, Some(1), None), - expected(5, TEST_VALUE, R, Some(0), None, None), + expected(5, 1, R, Some(0), None, None), ], }; run_success(lang, &desc, 5, &exp) @@ -937,7 +934,7 @@ impl TestCase for InsertCase { top: None, nodes: vec![ expected(10, 10, B, None, None, Some(1)), - expected(15, TEST_VALUE, R, Some(0), None, None), + expected(15, 1, R, Some(0), None, None), ], }; run_success(lang, &desc, 15, &exp) @@ -962,7 +959,7 @@ impl TestCase for InsertCase { expected(10, 10, R, None, Some(1), Some(2)), expected(5, 5, B, Some(0), Some(3), None), expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(1), None, None), + expected(1, 1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -983,7 +980,7 @@ impl TestCase for InsertCase { expected(10, 10, R, None, Some(1), Some(2)), expected(5, 5, B, Some(0), None, Some(3)), expected(15, 15, B, Some(0), None, None), - expected(7, TEST_VALUE, R, Some(1), None, None), + expected(7, 1, R, Some(1), None, None), ], }; run_success(lang, &desc, 7, &exp) @@ -1004,7 +1001,7 @@ impl TestCase for InsertCase { expected(10, 10, R, None, Some(1), Some(2)), expected(5, 5, B, Some(0), None, None), expected(15, 15, B, Some(0), Some(3), None), - expected(12, TEST_VALUE, R, Some(2), None, None), + expected(12, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 12, &exp) @@ -1025,7 +1022,7 @@ impl TestCase for InsertCase { expected(10, 10, R, None, Some(1), Some(2)), expected(5, 5, B, Some(0), None, None), expected(15, 15, B, Some(0), None, Some(3)), - expected(20, TEST_VALUE, R, Some(2), None, None), + expected(20, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 20, &exp) @@ -1053,7 +1050,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(0), Some(2), Some(3)), expected(5, 5, B, Some(1), Some(4), None), expected(15, 15, B, Some(1), None, None), - expected(1, TEST_VALUE, R, Some(2), None, None), + expected(1, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1077,7 +1074,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(0), Some(2), Some(3)), expected(5, 5, B, Some(1), None, None), expected(15, 15, B, Some(1), None, Some(4)), - expected(20, TEST_VALUE, R, Some(3), None, None), + expected(20, 1, R, Some(3), None, None), ], }; run_success(lang, &desc, 20, &exp) @@ -1101,7 +1098,7 @@ impl TestCase for InsertCase { nodes: vec![ expected(10, 10, R, Some(1), None, None), expected(5, 5, B, None, Some(2), Some(0)), - expected(1, TEST_VALUE, R, Some(1), None, None), + expected(1, 1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1122,7 +1119,7 @@ impl TestCase for InsertCase { nodes: vec![ expected(10, 10, R, Some(1), None, None), expected(15, 15, B, None, Some(0), Some(2)), - expected(20, TEST_VALUE, R, Some(1), None, None), + expected(20, 1, R, Some(1), None, None), ], }; run_success(lang, &desc, 20, &exp) @@ -1145,7 +1142,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(1), None, Some(2)), expected(5, 5, B, None, Some(3), Some(0)), expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(1), None, None), + expected(1, 1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1168,7 +1165,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(2), Some(1), None), expected(5, 5, B, Some(0), None, None), expected(15, 15, B, None, Some(0), Some(3)), - expected(20, TEST_VALUE, R, Some(2), None, None), + expected(20, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 20, &exp) @@ -1192,7 +1189,7 @@ impl TestCase for InsertCase { nodes: vec![ expected(10, 10, R, Some(2), None, None), expected(5, 5, R, Some(2), None, None), - expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + expected(7, 1, B, None, Some(1), Some(0)), ], }; run_success(lang, &desc, 7, &exp) @@ -1213,7 +1210,7 @@ impl TestCase for InsertCase { nodes: vec![ expected(10, 10, R, Some(2), None, None), expected(15, 15, R, Some(2), None, None), - expected(12, TEST_VALUE, B, None, Some(0), Some(1)), + expected(12, 1, B, None, Some(0), Some(1)), ], }; run_success(lang, &desc, 12, &exp) @@ -1236,7 +1233,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(3), None, Some(2)), expected(5, 5, R, Some(3), None, None), expected(15, 15, B, Some(0), None, None), - expected(7, TEST_VALUE, B, None, Some(1), Some(0)), + expected(7, 1, B, None, Some(1), Some(0)), ], }; run_success(lang, &desc, 7, &exp) @@ -1259,7 +1256,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(3), Some(1), None), expected(5, 5, B, Some(0), None, None), expected(15, 15, R, Some(3), None, None), - expected(12, TEST_VALUE, B, None, Some(0), Some(2)), + expected(12, 1, B, None, Some(0), Some(2)), ], }; run_success(lang, &desc, 12, &exp) @@ -1289,7 +1286,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(2), None, None), expected(5, 5, B, Some(0), Some(4), Some(1)), expected(25, 25, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(2), None, None), + expected(1, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1316,7 +1313,7 @@ impl TestCase for InsertCase { expected(3, 3, B, Some(0), None, None), expected(20, 20, R, Some(3), None, None), expected(15, 15, B, Some(0), Some(4), Some(2)), - expected(10, TEST_VALUE, R, Some(3), None, None), + expected(10, 1, R, Some(3), None, None), ], }; run_success(lang, &desc, 10, &exp) @@ -1343,7 +1340,7 @@ impl TestCase for InsertCase { expected(3, 3, B, Some(0), None, None), expected(15, 15, R, Some(3), None, None), expected(20, 20, B, Some(0), Some(2), Some(4)), - expected(25, TEST_VALUE, R, Some(3), None, None), + expected(25, 1, R, Some(3), None, None), ], }; run_success(lang, &desc, 25, &exp) @@ -1370,7 +1367,7 @@ impl TestCase for InsertCase { expected(10, 10, R, Some(2), None, None), expected(15, 15, B, Some(0), Some(1), Some(4)), expected(25, 25, B, Some(0), None, None), - expected(17, TEST_VALUE, R, Some(2), None, None), + expected(17, 1, R, Some(2), None, None), ], }; run_success(lang, &desc, 17, &exp) @@ -1405,7 +1402,7 @@ impl TestCase for InsertCase { expected(3, 3, B, Some(2), Some(7), None), expected(7, 7, B, Some(2), None, None), expected(15, 15, B, Some(0), None, None), - expected(1, TEST_VALUE, R, Some(4), None, None), + expected(1, 1, R, Some(4), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1437,7 +1434,7 @@ impl TestCase for InsertCase { expected(20, 20, R, Some(2), Some(5), Some(6)), expected(17, 17, B, Some(4), None, None), expected(25, 25, B, Some(4), None, Some(7)), - expected(30, TEST_VALUE, R, Some(6), None, None), + expected(30, 1, R, Some(6), None, None), ], }; run_success(lang, &desc, 30, &exp) @@ -1473,7 +1470,7 @@ impl TestCase for InsertCase { expected(25, 25, B, Some(0), None, None), expected(12, 12, B, Some(1), Some(7), None), expected(17, 17, B, Some(0), None, None), - expected(11, TEST_VALUE, R, Some(5), None, None), + expected(11, 1, R, Some(5), None, None), ], }; run_success(lang, &desc, 11, &exp) @@ -1506,7 +1503,7 @@ impl TestCase for InsertCase { expected(25, 25, B, Some(2), None, None), expected(12, 12, B, Some(0), None, None), expected(17, 17, B, Some(2), None, Some(7)), - expected(18, TEST_VALUE, R, Some(6), None, None), + expected(18, 1, R, Some(6), None, None), ], }; run_success(lang, &desc, 18, &exp) From 3452c18748a1a3b6742b79d3ff0732f98e8cde85 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:43:33 -0700 Subject: [PATCH 208/263] Add more input check cases --- docs/src/examples/tree.md | 2 +- .../tests/insert_input_checks/result.txt | 23 ++++++++- examples/tree/src/tests/insert.rs | 49 ++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 5e6dcfe8..43403da0 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -165,7 +165,7 @@ not available in Rust, since the compiler enforces ::: details Benchmarking - + ::: diff --git a/examples/tree/artifacts/tests/insert_input_checks/result.txt b/examples/tree/artifacts/tests/insert_input_checks/result.txt index fe6bb963..4130a17c 100644 --- a/examples/tree/artifacts/tests/insert_input_checks/result.txt +++ b/examples/tree/artifacts/tests/insert_input_checks/result.txt @@ -2,6 +2,9 @@ |-----------|-----------|------------|----------|------------| | Instruction data too short | 7 | 9 | +2 | +28.6% | | Instruction data too long | 7 | 9 | +2 | +28.6% | +| Too few accounts | 8 | 10 | +2 | +25.0% | +| User has nonzero data length | 10 | 12 | +2 | +20.0% | +| Tree account is duplicate | 12 | 14 | +2 | +16.7% | test tests::test_insert_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units @@ -14,4 +17,22 @@ test tests::test_insert_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 \ No newline at end of file diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index dfd70823..b2fbd5b2 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -482,6 +482,9 @@ pub(super) enum InsertCase { // Input validation. InputDataShort, InputDataLong, + InputNAccounts, + InputUserDataLen, + InputTreeDuplicate, // Allocation checks. AllocNAccounts, AllocSysprogDuplicate, @@ -537,7 +540,13 @@ pub(super) enum InsertCase { } impl InsertCase { - pub(super) const INPUT_CASES: &'static [Self] = &[Self::InputDataShort, Self::InputDataLong]; + pub(super) const INPUT_CASES: &'static [Self] = &[ + Self::InputDataShort, + Self::InputDataLong, + Self::InputNAccounts, + Self::InputUserDataLen, + Self::InputTreeDuplicate, + ]; pub(super) const ALLOC_CHECK_CASES: &'static [Self] = &[ Self::AllocNAccounts, @@ -594,6 +603,9 @@ impl TestCase for InsertCase { match self { Self::InputDataShort => "Instruction data too short", Self::InputDataLong => "Instruction data too long", + Self::InputNAccounts => "Too few accounts", + Self::InputUserDataLen => "User has nonzero data length", + Self::InputTreeDuplicate => "Tree account is duplicate", Self::AllocNAccounts => "Wrong N accounts for allocation", Self::AllocSysprogDuplicate => "System program is duplicate", Self::AllocSysprogDataLen => "System program wrong data length", @@ -668,6 +680,41 @@ impl TestCase for InsertCase { error_codes::error::INSTRUCTION_DATA_LEN, ) } + Self::InputNAccounts => { + let (setup, mut instruction, mut accounts) = insert_skip_alloc_setup(lang); + // Remove tree account (1 account instead of 2). + instruction.accounts.pop(); + accounts.pop(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS, + ) + } + Self::InputUserDataLen => { + let (setup, instruction, mut accounts) = insert_skip_alloc_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::USER_DATA_LEN, + ) + } + Self::InputTreeDuplicate => { + let (setup, mut instruction, mut accounts) = insert_skip_alloc_setup(lang); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::TREE_DUPLICATE, + ) + } // ----- Allocation checks ----- Self::AllocNAccounts => { From 75245f91c6905f76e778a2c0c855e3f974a2b7e7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:57:58 -0700 Subject: [PATCH 209/263] Rebuild, list --- docs/src/examples/tree.md | 2 +- .../artifacts/tests/insert_alloc/result.txt | 13 ++- examples/tree/src/tests/insert.rs | 81 ++++++++++++++++++- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 43403da0..1deb7367 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -189,7 +189,7 @@ not available in Rust, since the compiler enforces - + ::: diff --git a/examples/tree/artifacts/tests/insert_alloc/result.txt b/examples/tree/artifacts/tests/insert_alloc/result.txt index e485c24c..1512f72f 100644 --- a/examples/tree/artifacts/tests/insert_alloc/result.txt +++ b/examples/tree/artifacts/tests/insert_alloc/result.txt @@ -1,6 +1,7 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| | Insert alloc happy path | 1096 | 101 | 129 | +28 | +27.7% | +| Alloc exceeds max data length | 1096 | 1398904 | 1398904 | +0 | +0.0% | test tests::test_insert_alloc ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] @@ -11,4 +12,14 @@ test tests::test_insert_alloc ... ok [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success [ ... DEBUG ... ] Program DASMAC... consumed 1225 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 43131 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: Failed to reallocate account data +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] +[ ... DEBUG ... ] Program 11111111111111111111111111111111 success +[ ... DEBUG ... ] Program DASMAC... consumed 43160 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: Failed to reallocate account data \ No newline at end of file diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index b2fbd5b2..329b94c0 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -128,6 +128,61 @@ fn insert_alloc_address_mismatch( check_error(&setup, &instruction, &accounts, expected_error) } +/// Set up an insert where the tree account is already at +/// `MAX_PERMITTED_DATA_LENGTH` so that allocating one more `TreeNode` +/// exceeds the absolute account size limit. +fn insert_max_data_setup( + program_language: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + const MAX_PERMITTED_DATA_LENGTH: usize = 10 * 1024 * 1024; + + let mut setup = setup_test_with_rent(program_language); + let (system_program_pubkey, system_program_account) = + program::keyed_account_for_system_program(); + let (rent_sysvar_pubkey, rent_sysvar_account) = + setup.mollusk.sysvars.keyed_account_for_rent_sysvar(); + + let user_pubkey = Pubkey::new_unique(); + let tree_pubkey = Pubkey::new_unique(); + + let insn_data = insert_instruction_data(); + let instruction = Instruction::new_with_bytes( + setup.program_id, + unsafe { as_bytes(&insn_data) }, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + AccountMeta::new_readonly(system_program_pubkey, false), + AccountMeta::new_readonly(rent_sysvar_pubkey, false), + ], + ); + + // Tree account already at MAX_PERMITTED_DATA_LENGTH. + let rent = Rent::from_bytes(&rent_sysvar_account.data).unwrap(); + let tree_lamports = rent.try_minimum_balance(MAX_PERMITTED_DATA_LENGTH).unwrap(); + let mut tree_account = + Account::new(tree_lamports, MAX_PERMITTED_DATA_LENGTH, &setup.program_id); + // top = null → forces allocation path (no free nodes to recycle). + // next → points right after current data (where the new node would go). + let next_ptr = + MM_INPUT_START + input_buffer::TREE_DATA_OFF as u64 + MAX_PERMITTED_DATA_LENGTH as u64; + let next_off = tree::HEADER_NEXT_OFF as usize; + tree_account.data[next_off..next_off + size_of::<*mut TreeNode>()] + .copy_from_slice(&next_ptr.to_le_bytes()); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account), + (system_program_pubkey, system_program_account), + (rent_sysvar_pubkey, rent_sysvar_account), + ]; + + (setup, instruction, accounts) +} + // --------------------------------------------------------------------------- // Helpers: tree description types // --------------------------------------------------------------------------- @@ -496,6 +551,8 @@ pub(super) enum InsertCase { AllocRentAddrChunk3, // Allocation happy path (CPI overhead). AllocHappyPath, + // Allocation exceeds max permitted data length. + AllocMaxDataLen, // Search — expect KEY_EXISTS error. SearchDupRoot, SearchDupLeft, @@ -559,7 +616,7 @@ impl InsertCase { Self::AllocRentAddrChunk3, ]; - pub(super) const ALLOC_CASES: &'static [Self] = &[Self::AllocHappyPath]; + pub(super) const ALLOC_CASES: &'static [Self] = &[Self::AllocHappyPath, Self::AllocMaxDataLen]; pub(super) const SEARCH_CASES: &'static [Self] = &[ Self::SearchDupRoot, @@ -615,6 +672,7 @@ impl TestCase for InsertCase { Self::AllocRentAddrChunk2 => "Rent address mismatch chunk 2", Self::AllocRentAddrChunk3 => "Rent address mismatch chunk 3", Self::AllocHappyPath => "Insert alloc happy path", + Self::AllocMaxDataLen => "Alloc exceeds max data length", Self::SearchDupRoot => "Dup at root", Self::SearchDupLeft => "Dup in left", Self::SearchDupRight => "Dup in right", @@ -650,7 +708,9 @@ impl TestCase for InsertCase { fn fixed_costs(&self) -> u64 { match self { - Self::AllocHappyPath => fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM, + Self::AllocHappyPath | Self::AllocMaxDataLen => { + fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM + } _ => 0, } } @@ -870,6 +930,23 @@ impl TestCase for InsertCase { } } + // ----- Allocation: max data length ----- + Self::AllocMaxDataLen => { + let (setup, instruction, accounts) = insert_max_data_setup(lang); + let result = setup.mollusk.process_instruction(&instruction, &accounts); + let expected = ProgramError::InvalidRealloc; + match &result.program_result { + MolluskResult::Failure(err) if *err == expected => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), + }, + } + } + // ----- Search: duplicate key errors ----- // Root with key 10, insert 10. From 0039fb020f234e40d8c4b8e0423895a7920aff9a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:52:44 -0700 Subject: [PATCH 210/263] Clean up tests --- .../snippets/interface/instructions.txt | 6 +- .../tests/entrypoint_branching/test.txt | 2 +- .../tests/initialize_create_account/test.txt | 2 +- .../tests/initialize_input_checks/test.txt | 2 +- .../tests/initialize_pda_checks/result.txt | 8 +- .../tests/initialize_pda_checks/test.txt | 2 +- .../artifacts/tests/insert_alloc/test.txt | 2 +- .../tests/insert_alloc_checks/test.txt | 2 +- .../tests/insert_input_checks/test.txt | 2 +- .../artifacts/tests/insert_search/test.txt | 2 +- .../artifacts/tests/insert_to_tree/test.txt | 2 +- .../artifacts/tests/multi_insert/result.txt | 115 +++ .../artifacts/tests/multi_insert/test.txt | 5 + examples/tree/interface/src/common.rs | 6 +- examples/tree/specs/test-framework-cleanup.md | 274 ++++++ examples/tree/src/tests.rs | 79 +- examples/tree/src/tests/entrypoint.rs | 2 - examples/tree/src/tests/init.rs | 77 +- examples/tree/src/tests/insert.rs | 869 ++++++++++++------ 19 files changed, 1081 insertions(+), 378 deletions(-) create mode 100644 examples/tree/artifacts/tests/multi_insert/result.txt create mode 100644 examples/tree/artifacts/tests/multi_insert/test.txt create mode 100644 examples/tree/specs/test-framework-cleanup.md diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index 9baf5c58..1a125235 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -26,10 +26,8 @@ pub struct InsertInstruction { #[repr(C, packed)] /// Value in r0. -struct Return { - /// If a value is retrieved from the tree, it's encoded in high bits. - maybe_value: u16, - /// Nonzero iff error. +struct RemoveReturn { + value: u16, status: u16, } diff --git a/examples/tree/artifacts/tests/entrypoint_branching/test.txt b/examples/tree/artifacts/tests/entrypoint_branching/test.txt index cfd0f52a..6c056146 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/test.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/test.txt @@ -1,4 +1,4 @@ #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); + print_comparison_table(entrypoint::EntrypointCase::CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/test.txt b/examples/tree/artifacts/tests/initialize_create_account/test.txt index aa2dd6c3..966c88b0 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/test.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); + print_comparison_table(init::InitCase::CPI_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/test.txt b/examples/tree/artifacts/tests/initialize_input_checks/test.txt index 24226cfc..d179220a 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); + print_comparison_table(init::InitCase::CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index 49588334..c306b324 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,9 +1,9 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 1 | 1500 | 44 | 52 | +8 | +18.2% | -| PDA mismatch chunk 2 | 1500 | 47 | 55 | +8 | +17.0% | -| PDA mismatch chunk 3 | 1500 | 50 | 58 | +8 | +16.0% | -| PDA mismatch chunk 4 | 1500 | 53 | 61 | +8 | +15.1% | +| PDA mismatch chunk 0 | 1500 | 44 | 52 | +8 | +18.2% | +| PDA mismatch chunk 1 | 1500 | 47 | 55 | +8 | +17.0% | +| PDA mismatch chunk 2 | 1500 | 50 | 58 | +8 | +16.0% | +| PDA mismatch chunk 3 | 1500 | 53 | 61 | +8 | +15.1% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt index 0f682d5d..5bd90196 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/test.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); + print_comparison_table(init::InitCase::PDA_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc/test.txt b/examples/tree/artifacts/tests/insert_alloc/test.txt index 7565fb2a..272fa7a1 100644 --- a/examples/tree/artifacts/tests/insert_alloc/test.txt +++ b/examples/tree/artifacts/tests/insert_alloc/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_alloc() { - print_comparison_table(insert::InsertCase::ALLOC_CASES, false, false); + print_comparison_table(insert::InsertCase::ALLOC_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc_checks/test.txt b/examples/tree/artifacts/tests/insert_alloc_checks/test.txt index cd77af95..a65656e6 100644 --- a/examples/tree/artifacts/tests/insert_alloc_checks/test.txt +++ b/examples/tree/artifacts/tests/insert_alloc_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_alloc_checks() { - print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES, false, false); + print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_input_checks/test.txt b/examples/tree/artifacts/tests/insert_input_checks/test.txt index b127bee7..58e622ae 100644 --- a/examples/tree/artifacts/tests/insert_input_checks/test.txt +++ b/examples/tree/artifacts/tests/insert_input_checks/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_input_checks() { - print_comparison_table(insert::InsertCase::INPUT_CASES, false, false); + print_comparison_table(insert::InsertCase::INPUT_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/test.txt b/examples/tree/artifacts/tests/insert_search/test.txt index d25d7800..7edbdf49 100644 --- a/examples/tree/artifacts/tests/insert_search/test.txt +++ b/examples/tree/artifacts/tests/insert_search/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_search() { - print_comparison_table(insert::InsertCase::SEARCH_CASES, false, false); + print_comparison_table(insert::InsertCase::SEARCH_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/test.txt b/examples/tree/artifacts/tests/insert_to_tree/test.txt index 9b42b922..c6455408 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/test.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/test.txt @@ -1,4 +1,4 @@ #[test] fn test_insert_to_tree() { - print_comparison_table(insert::InsertCase::TREE_CASES, false, false); + print_comparison_table(insert::InsertCase::TREE_CASES); } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt new file mode 100644 index 00000000..f3522de1 --- /dev/null +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -0,0 +1,115 @@ +test tests::test_multi_insert ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/multi_insert/test.txt b/examples/tree/artifacts/tests/multi_insert/test.txt new file mode 100644 index 00000000..642b47f2 --- /dev/null +++ b/examples/tree/artifacts/tests/multi_insert/test.txt @@ -0,0 +1,5 @@ +#[test] +fn test_multi_insert() { + insert::test_multi_insert(ProgramLanguage::Assembly); + insert::test_multi_insert(ProgramLanguage::Rust); +} \ No newline at end of file diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 96dd9d48..b3ba10b4 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -265,10 +265,8 @@ pub struct InsertInstruction { #[repr(C, packed)] /// Value in r0. -struct Return { - /// If a value is retrieved from the tree, it's encoded in high bits. - maybe_value: u16, - /// Nonzero iff error. +struct RemoveReturn { + value: u16, status: u16, } diff --git a/examples/tree/specs/test-framework-cleanup.md b/examples/tree/specs/test-framework-cleanup.md new file mode 100644 index 00000000..89358b8d --- /dev/null +++ b/examples/tree/specs/test-framework-cleanup.md @@ -0,0 +1,274 @@ +# Test framework cleanup specification + +## Scope + +Recommendations for reducing duplication, improving consistency, +and simplifying the test harness across `tests.rs`, `init.rs`, +`insert.rs`, and `entrypoint.rs`. + +## 1. Unify error-checking helpers + +### Problem + +Three distinct error-match patterns are copy-pasted throughout the +test modules: + +- **`check_error`** (shared) handles `ProgramError::Custom(code)`. +- **Inline match for stdlib errors** (`InvalidRealloc`, + `NotEnoughAccountKeys`, `Custom(1)`) is duplicated in + `AllocMaxDataLen`, `UserInsufficientLamports`, and + `SystemProgramAddress`. +- **Success-with-validation** is duplicated in `AllocHappyPath` + and `CreateAccountHappyPath`. + +### Proposal + +Generalize `check_error` into `check_result` that accepts a +`ProgramError` directly: + +```rust +fn check_result( + setup: &TestSetup, + instruction: &Instruction, + accounts: &[(Pubkey, Account)], + expected: ProgramError, +) -> CaseResult { ... } +``` + +The existing `check_error` becomes a thin wrapper: + +```rust +fn check_error(..., code: error_codes::error) -> CaseResult { + check_result(..., ProgramError::Custom(code.into())) +} +``` + +This eliminates the inline match blocks in `AllocMaxDataLen`, +`UserInsufficientLamports`, and `SystemProgramAddress`. + +## 2. Merge `NodeDesc` and `ExpectedNode` + +### Problem + +`NodeDesc` and `ExpectedNode` are structurally identical. The only +behavioral difference is that `node()` sets `value = key` while +`expected()` takes an explicit value. Two types for the same shape +adds noise. + +### Proposal + +Single type `NodeSpec` with one constructor and a builder method: + +```rust +struct NodeSpec { + key: u16, + value: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +} + +fn node(key, color, parent, left, right) -> NodeSpec { + NodeSpec { key, value: key, color, parent, left, right } +} +``` + +For expected nodes where value differs from key (the inserted node), +use a builder: + +```rust +impl NodeSpec { + fn val(mut self, v: u16) -> Self { self.value = v; self } +} +``` + +Usage: + +```rust +// Pre-existing node: value = key (default). +node(10, B, None, Some(1), None) +// Inserted node: value = 1. +node(42, R, Some(0), None, None).val(1) +``` + +`TreeDesc` and `ExpectedTree` merge into a single `TreeSpec` with +an optional `top` field (`TreeDesc` never sets it explicitly — +`build_tree_account` computes it; `ExpectedTree` specifies it for +assertion). Making `top` `Option>` or always +computing it from context keeps one type. + +## 3. Reduce `fixed_costs` match verbosity + +### Problem + +`InitCase::fixed_costs()` enumerates all 17 zero-cost variants +explicitly. Adding a new input-check variant requires updating the +match arm. `InsertCase::fixed_costs()` uses `_ => 0` — simpler +and forward-compatible. + +### Proposal + +All `fixed_costs()` implementations should use `_ => 0` as the +default arm. Only list the non-zero cases explicitly. + +## 4. Fix `PdaMismatchChunk` display name indexing + +### Problem + +Variant names are `PdaMismatchChunk0..3` but display names are +"PDA mismatch chunk 1..4". The off-by-one makes the name not match +the variant. + +### Proposal + +Display as "PDA mismatch chunk 0..3" to match the variant names. + +## 5. Remove unused `allow_asm_failures` / `allow_rust_failures` + +### Problem + +Both parameters are always `false` in every call site. They add two +booleans to every `print_comparison_table` call that are never +exercised. + +### Proposal + +Remove both parameters. If per-case failure tolerance is ever +needed, add it as a `TestCase` trait method (`fn allow_failure`) +so the table function doesn't need configuration. + +## 6. Factor common setup into builders + +### Problem + +`insert_setup`, `insert_skip_alloc_setup`, `insert_max_data_setup`, +`init_setup`, and `pda_init_setup` share the same boilerplate: + +1. Create `TestSetup`. +1. Get system program and rent sysvar keyed accounts. +1. Create user and tree pubkeys. +1. Build instruction with account metas. +1. Assemble `(Pubkey, Account)` vec. + +Steps 2-5 are nearly identical across all five functions. The +differences are: + +- Whether rent is configured (SIMD-0194 threshold). +- Tree pubkey derivation (unique vs PDA). +- Which accounts are included (2 vs 4). +- Tree account initial state (empty, header-only, pre-built, max + data length). +- Instruction data (init discriminator vs insert struct). + +### Proposal + +Introduce a `SetupBuilder` that handles the common parts: + +```rust +struct SetupBuilder { + setup: TestSetup, + user: (Pubkey, Account), + tree: (Pubkey, Account), + system_program: Option<(Pubkey, Account)>, + rent_sysvar: Option<(Pubkey, Account)>, +} +``` + +Methods on the builder configure the tree account, account list, +and instruction, then finalize into the existing +`(TestSetup, Instruction, Vec<(Pubkey, Account)>)` tuple. Each +existing setup function becomes a few builder calls. + +Weigh this against the cost of added indirection — if the builder +doesn't clearly reduce total lines, keep the current explicit +functions but extract just the shared preamble (getting +system_program/rent keyed accounts) into a helper. + +## 7. Share imports via parent module + +### Problem + +Each test module imports `mollusk_svm::program`, `AccountMeta`, +`Rent`, `Check`, `Config` independently. These are used by both +`init.rs` and `insert.rs`. + +### Proposal + +Re-export the common types from `tests.rs` so that `use super::*` +covers them: + +```rust +// tests.rs +use mollusk_svm::program; +use mollusk_svm::result::{Check, Config}; +use pinocchio::sysvars::rent::Rent; +use solana_sdk::instruction::AccountMeta; +``` + +The child modules already use `use super::*` and would pick these +up without additional imports. + +## 8. Unify address-mismatch helpers + +### Problem + +`run_address_mismatch` (init) and `insert_alloc_address_mismatch` +(insert) do the same bit-flip logic with different setup functions +and word sizes. The core pattern — flip a byte in a pubkey chunk +to trigger a mismatch — is identical. + +### Proposal + +Extract the bit-flip operation into a shared helper in `tests.rs`: + +```rust +fn flip_account_address( + instruction: &mut Instruction, + accounts: &mut [(Pubkey, Account)], + account_index: usize, + chunk_index: usize, + chunk_size: usize, +) { + let flip_index = (chunk_index * chunk_size) + chunk_size - 1; + accounts[account_index].0.as_mut()[flip_index] ^= 1; + instruction.accounts[account_index].pubkey = + accounts[account_index].0; +} +``` + +The module-specific helpers become: call setup, call +`flip_account_address`, call `check_error`. + +## 9. Implement multi-insert integration tests + +### Problem + +The insert-tests spec (section "Multi-insert integration tests") +describes five sequential-insert test sequences. These are not yet +implemented. + +### Proposal + +Implement them as specified, using the existing `build_tree_account` +and `assert_tree_account` infrastructure. Each test processes +multiple insert instructions in sequence, feeding resulting account +state forward. + +## Priority + +Recommendations ordered by impact-to-effort ratio: + +1. **Fix PDA mismatch display names** — trivial, correctness. +1. **Remove `allow_*_failures` params** — trivial, noise + reduction. +1. **Unify `check_error` → `check_result`** — small change, + removes three inline match blocks. +1. **Default `_ => 0` for `fixed_costs`** — one-line fix. +1. **Share imports via parent** — small, removes duplicate + imports. +1. **Merge `NodeDesc`/`ExpectedNode`** — moderate, cleaner API. +1. **Extract address-flip helper** — moderate, deduplicates. +1. **Factor setup builders** — larger refactor, weigh benefit. +1. **Multi-insert integration tests** — new feature, already + specced. diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index d501f76e..b78a661a 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -2,9 +2,11 @@ mod entrypoint; mod init; mod insert; -use mollusk_svm::result::ProgramResult as MolluskResult; +use mollusk_svm::program; +use mollusk_svm::result::{Check, Config, ProgramResult as MolluskResult}; +use pinocchio::sysvars::rent::Rent; use solana_sdk::account::Account; -use solana_sdk::instruction::Instruction; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::program_error::ProgramError; use solana_sdk::pubkey::Pubkey; use test_utils::{setup_test, ProgramLanguage, TestSetup}; @@ -53,14 +55,13 @@ struct CaseResult { error: Option, } -fn check_error( +fn check_result( setup: &TestSetup, instruction: &Instruction, accounts: &[(Pubkey, Account)], - expected_error: error_codes::error, + expected: ProgramError, ) -> CaseResult { let result = setup.mollusk.process_instruction(instruction, accounts); - let expected = ProgramError::Custom(expected_error.into()); match &result.program_result { MolluskResult::Failure(err) if *err == expected => CaseResult { cu: result.compute_units_consumed, @@ -73,6 +74,32 @@ fn check_error( } } +fn flip_account_address( + instruction: &mut Instruction, + accounts: &mut [(Pubkey, Account)], + account_index: usize, + chunk_index: usize, + chunk_size: usize, +) { + let flip_index = (chunk_index * chunk_size) + chunk_size - 1; + accounts[account_index].0.as_mut()[flip_index] ^= 1; + instruction.accounts[account_index].pubkey = accounts[account_index].0; +} + +fn check_error( + setup: &TestSetup, + instruction: &Instruction, + accounts: &[(Pubkey, Account)], + expected_error: error_codes::error, +) -> CaseResult { + check_result( + setup, + instruction, + accounts, + ProgramError::Custom(expected_error.into()), + ) +} + trait TestCase: Copy { fn name(&self) -> &'static str; fn run(&self, lang: ProgramLanguage) -> CaseResult; @@ -83,11 +110,7 @@ trait TestCase: Copy { } } -fn print_comparison_table( - cases: &[T], - allow_asm_failures: bool, - allow_rust_failures: bool, -) { +fn print_comparison_table(cases: &[T]) { let mut failures = Vec::new(); let has_fixed_costs = cases.iter().any(|c| c.fixed_costs() > 0); @@ -140,18 +163,10 @@ fn print_comparison_table( } if let Some(err) = &asm.error { - if allow_asm_failures { - println!(" (ASM) {}: {}", case.name(), err); - } else { - failures.push(format!(" ASM {}: {}", case.name(), err)); - } + failures.push(format!(" ASM {}: {}", case.name(), err)); } if let Some(err) = &rs.error { - if allow_rust_failures { - println!(" (Rust) {}: {}", case.name(), err); - } else { - failures.push(format!(" Rust {}: {}", case.name(), err)); - } + failures.push(format!(" Rust {}: {}", case.name(), err)); } } @@ -164,45 +179,51 @@ fn print_comparison_table( #[test] fn test_entrypoint_branching() { - print_comparison_table(entrypoint::EntrypointCase::CASES, false, false); + print_comparison_table(entrypoint::EntrypointCase::CASES); } #[test] fn test_insert_input_checks() { - print_comparison_table(insert::InsertCase::INPUT_CASES, false, false); + print_comparison_table(insert::InsertCase::INPUT_CASES); } #[test] fn test_insert_alloc_checks() { - print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES, false, false); + print_comparison_table(insert::InsertCase::ALLOC_CHECK_CASES); } #[test] fn test_insert_alloc() { - print_comparison_table(insert::InsertCase::ALLOC_CASES, false, false); + print_comparison_table(insert::InsertCase::ALLOC_CASES); } #[test] fn test_initialize_input_checks() { - print_comparison_table(init::InitCase::CASES, false, false); + print_comparison_table(init::InitCase::CASES); } #[test] fn test_initialize_pda_checks() { - print_comparison_table(init::InitCase::PDA_CASES, false, false); + print_comparison_table(init::InitCase::PDA_CASES); } #[test] fn test_initialize_create_account() { - print_comparison_table(init::InitCase::CPI_CASES, false, false); + print_comparison_table(init::InitCase::CPI_CASES); } #[test] fn test_insert_search() { - print_comparison_table(insert::InsertCase::SEARCH_CASES, false, false); + print_comparison_table(insert::InsertCase::SEARCH_CASES); } #[test] fn test_insert_to_tree() { - print_comparison_table(insert::InsertCase::TREE_CASES, false, false); + print_comparison_table(insert::InsertCase::TREE_CASES); +} + +#[test] +fn test_multi_insert() { + insert::test_multi_insert(ProgramLanguage::Assembly); + insert::test_multi_insert(ProgramLanguage::Rust); } diff --git a/examples/tree/src/tests/entrypoint.rs b/examples/tree/src/tests/entrypoint.rs index 4c047be2..dcfc3304 100644 --- a/examples/tree/src/tests/entrypoint.rs +++ b/examples/tree/src/tests/entrypoint.rs @@ -1,6 +1,4 @@ use super::*; -use mollusk_svm::program; -use solana_sdk::instruction::AccountMeta; #[derive(Clone, Copy)] pub(super) enum EntrypointCase { diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index f68785d5..98b9233e 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -1,8 +1,4 @@ use super::*; -use mollusk_svm::program; -use mollusk_svm::result::{Check, Config}; -use pinocchio::sysvars::rent::Rent; -use solana_sdk::instruction::AccountMeta; use tree_interface::{input_buffer, tree, Instruction as TreeInstruction, TreeHeader}; fn init_setup( @@ -80,16 +76,12 @@ fn pda_init_setup( fn run_address_mismatch( lang: ProgramLanguage, account_index: usize, - word_index: usize, - word_size: usize, + chunk_index: usize, + chunk_size: usize, expected_error: error_codes::error, ) -> CaseResult { let (setup, mut instruction, mut accounts) = pda_init_setup(lang); - - let flip_index = (word_index * word_size) + (word_size - 1); - accounts[account_index].0.as_mut()[flip_index] ^= 1; - instruction.accounts[account_index].pubkey = accounts[account_index].0; - + flip_account_address(&mut instruction, &mut accounts, account_index, chunk_index, chunk_size); check_error(&setup, &instruction, &accounts, expected_error) } @@ -176,10 +168,10 @@ impl TestCase for InitCase { Self::RentAddressWord5 => "Rent address mismatch word 5", Self::RentAddressWord6 => "Rent address mismatch word 6", Self::RentAddressWord7 => "Rent address mismatch word 7", - Self::PdaMismatchChunk0 => "PDA mismatch chunk 1", - Self::PdaMismatchChunk1 => "PDA mismatch chunk 2", - Self::PdaMismatchChunk2 => "PDA mismatch chunk 3", - Self::PdaMismatchChunk3 => "PDA mismatch chunk 4", + Self::PdaMismatchChunk0 => "PDA mismatch chunk 0", + Self::PdaMismatchChunk1 => "PDA mismatch chunk 1", + Self::PdaMismatchChunk2 => "PDA mismatch chunk 2", + Self::PdaMismatchChunk3 => "PDA mismatch chunk 3", Self::UserInsufficientLamports => "User has insufficient Lamports", Self::SystemProgramAddress => "System Program is wrong address", Self::CreateAccountHappyPath => "CreateAccount happy path", @@ -188,24 +180,6 @@ impl TestCase for InitCase { fn fixed_costs(&self) -> u64 { match self { - // Input checks - no syscalls. - Self::InstructionData - | Self::NAccountsTooFew - | Self::NAccountsTooMany - | Self::UserDataLen - | Self::TreeDuplicate - | Self::TreeDataLen - | Self::SystemProgramDuplicate - | Self::SystemProgramDataLen - | Self::RentDuplicate - | Self::RentAddressWord0 - | Self::RentAddressWord1 - | Self::RentAddressWord2 - | Self::RentAddressWord3 - | Self::RentAddressWord4 - | Self::RentAddressWord5 - | Self::RentAddressWord6 - | Self::RentAddressWord7 => 0, // PDA checks - sol_try_find_program_address only. Self::PdaMismatchChunk0 | Self::PdaMismatchChunk1 @@ -221,6 +195,7 @@ impl TestCase for InitCase { + fixed_costs::CPI_BASE + fixed_costs::SYSTEM_PROGRAM } + _ => 0, } } @@ -419,37 +394,25 @@ impl TestCase for InitCase { Self::UserInsufficientLamports => { let (setup, instruction, mut accounts) = pda_init_setup(lang); accounts[AccountIndex::User as usize].1.lamports = 0; - let result = setup.mollusk.process_instruction(&instruction, &accounts); // SystemError::ResultWithNegativeLamports. - let expected = ProgramError::Custom(1); - match &result.program_result { - MolluskResult::Failure(err) if *err == expected => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), - }, - } + check_result( + &setup, + &instruction, + &accounts, + ProgramError::Custom(1), + ) } Self::SystemProgramAddress => { let (setup, mut instruction, mut accounts) = pda_init_setup(lang); let fake_pubkey = Pubkey::new_unique(); accounts[AccountIndex::SystemProgram as usize].0 = fake_pubkey; instruction.accounts[AccountIndex::SystemProgram as usize].pubkey = fake_pubkey; - let result = setup.mollusk.process_instruction(&instruction, &accounts); - let expected = ProgramError::NotEnoughAccountKeys; - match &result.program_result { - MolluskResult::Failure(err) if *err == expected => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), - }, - } + check_result( + &setup, + &instruction, + &accounts, + ProgramError::NotEnoughAccountKeys, + ) } Self::CreateAccountHappyPath => { let (setup, instruction, accounts) = pda_init_setup(lang); diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 329b94c0..549b48ce 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -1,10 +1,6 @@ use super::*; -use mollusk_svm::program; -use mollusk_svm::result::{Check, Config}; -use pinocchio::sysvars::rent::Rent; -use solana_sdk::instruction::AccountMeta; use tree_interface::{ - cpi, input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, + input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, StackNode, TreeHeader, TreeNode, }; @@ -121,10 +117,13 @@ fn insert_alloc_address_mismatch( expected_error: error_codes::error, ) -> CaseResult { let (setup, mut instruction, mut accounts) = insert_setup(lang); - // Flip the last byte of the 8-byte chunk to trigger a mismatch. - let flip_index = (chunk_index * size_of::()) + size_of::() - 1; - accounts[account_index].0.as_mut()[flip_index] ^= 1; - instruction.accounts[account_index].pubkey = accounts[account_index].0; + flip_account_address( + &mut instruction, + &mut accounts, + account_index, + chunk_index, + size_of::(), + ); check_error(&setup, &instruction, &accounts, expected_error) } @@ -187,7 +186,7 @@ fn insert_max_data_setup( // Helpers: tree description types // --------------------------------------------------------------------------- -struct NodeDesc { +struct NodeSpec { key: u16, value: u16, color: u8, @@ -196,9 +195,17 @@ struct NodeDesc { right: Option, } -struct TreeDesc<'a> { +impl NodeSpec { + fn val(mut self, v: u16) -> Self { + self.value = v; + self + } +} + +struct TreeSpec<'a> { root: Option, - nodes: &'a [NodeDesc], + top: Option, + nodes: &'a [NodeSpec], } /// Compute the virtual address of node slot `i` in the tree account. @@ -228,7 +235,7 @@ fn opt_vaddr(idx: Option) -> u64 { /// - `header.root` → virtual address of `nodes[root]`, or null. /// - `header.top` → virtual address of the free slot (index = nodes.len()). /// - `header.next` → 0 (unused in skip-alloc path). -fn build_tree_account(desc: &TreeDesc, program_id: &Pubkey) -> (Pubkey, Account) { +fn build_tree_account(desc: &TreeSpec, program_id: &Pubkey) -> (Pubkey, Account) { let n = desc.nodes.len(); // N existing nodes + 1 free slot. let data_len = size_of::() + (n + 1) * size_of::(); @@ -268,33 +275,18 @@ fn build_tree_account(desc: &TreeDesc, program_id: &Pubkey) -> (Pubkey, Account) // Helper: assert tree account (full state) // --------------------------------------------------------------------------- -struct ExpectedNode { - key: u16, - value: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -} - -struct ExpectedTree { - root: Option, - top: Option, - nodes: Vec, -} - /// Assert every field of the tree account data against expected state. /// Returns Ok(()) on match, Err(description) on mismatch. -fn assert_tree_account(data: &[u8], expected: &ExpectedTree) -> Result<(), String> { +fn assert_tree_account(data: &[u8], expected: &TreeSpec) -> Result<(), String> { let mut errors = Vec::new(); let n = expected.nodes.len(); - // Check data length. - let expected_len = size_of::() + n * size_of::(); - if data.len() != expected_len { + // Check data length (at least enough for the expected nodes). + let min_len = size_of::() + n * size_of::(); + if data.len() < min_len { errors.push(format!( - "data len: expected {}, got {}", - expected_len, + "data len: expected at least {}, got {}", + min_len, data.len() )); } @@ -406,7 +398,7 @@ fn assert_tree_account(data: &[u8], expected: &ExpectedTree) -> Result<(), Strin fn insert_tree_setup( lang: ProgramLanguage, - desc: &TreeDesc, + desc: &TreeSpec, insert_key: u16, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { let setup = setup_test(lang); @@ -446,9 +438,9 @@ fn insert_tree_setup( /// Run an insert and assert success with full tree state check. fn run_success( lang: ProgramLanguage, - desc: &TreeDesc, + desc: &TreeSpec, insert_key: u16, - expected: &ExpectedTree, + expected: &TreeSpec, ) -> CaseResult { let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); let result = setup.mollusk.process_instruction(&instruction, &accounts); @@ -476,7 +468,7 @@ fn run_success( } /// Run an insert and check for KEY_EXISTS error. -fn run_dup_error(lang: ProgramLanguage, desc: &TreeDesc, insert_key: u16) -> CaseResult { +fn run_dup_error(lang: ProgramLanguage, desc: &TreeSpec, insert_key: u16) -> CaseResult { let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); check_error( &setup, @@ -499,28 +491,10 @@ fn node( parent: Option, left: Option, right: Option, -) -> NodeDesc { - NodeDesc { +) -> NodeSpec { + NodeSpec { key, - value: key, // Use key as value for pre-existing nodes. - color, - parent, - left, - right, - } -} - -fn expected( - key: u16, - value: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -) -> ExpectedNode { - ExpectedNode { - key, - value, + value: key, color, parent, left, @@ -933,34 +907,30 @@ impl TestCase for InsertCase { // ----- Allocation: max data length ----- Self::AllocMaxDataLen => { let (setup, instruction, accounts) = insert_max_data_setup(lang); - let result = setup.mollusk.process_instruction(&instruction, &accounts); - let expected = ProgramError::InvalidRealloc; - match &result.program_result { - MolluskResult::Failure(err) if *err == expected => CaseResult { - cu: result.compute_units_consumed, - error: None, - }, - other => CaseResult { - cu: result.compute_units_consumed, - error: Some(format!("expected Failure({:?}), got {:?}", expected, other)), - }, - } + check_result( + &setup, + &instruction, + &accounts, + ProgramError::InvalidRealloc, + ) } // ----- Search: duplicate key errors ----- // Root with key 10, insert 10. Self::SearchDupRoot => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[node(10, B, None, None, None)], }; run_dup_error(lang, &desc, 10) } // Root 10, left child 5, insert 5. Self::SearchDupLeft => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), None), node(5, R, Some(0), None, None), @@ -970,8 +940,9 @@ impl TestCase for InsertCase { } // Root 10, right child 15, insert 15. Self::SearchDupRight => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, None, Some(1)), node(15, R, Some(0), None, None), @@ -982,14 +953,15 @@ impl TestCase for InsertCase { // ----- Insert to empty tree ----- Self::EmptyTree => { - let desc = TreeDesc { + let desc = TreeSpec { root: None, + top: None, nodes: &[], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![expected(42, 1, R, None, None, None)], + nodes: &[node(42, R, None, None, None).val(1)], }; run_success(lang, &desc, 42, &exp) } @@ -998,32 +970,34 @@ impl TestCase for InsertCase { // B(10) root, insert 5 → left child. Self::Case1Left => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[node(10, B, None, None, None)], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, B, None, Some(1), None), - expected(5, 1, R, Some(0), None, None), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None).val(1), ], }; run_success(lang, &desc, 5, &exp) } // B(10) root, insert 15 → right child. Self::Case1Right => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[node(10, B, None, None, None)], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, B, None, None, Some(1)), - expected(15, 1, R, Some(0), None, None), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None).val(1), ], }; run_success(lang, &desc, 15, &exp) @@ -1033,32 +1007,34 @@ impl TestCase for InsertCase { // R(10) root, insert 5 → left child, parent recolored B. Self::Case4Left => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[node(10, R, None, None, None)], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, B, None, Some(1), None), - expected(5, 1, R, Some(0), None, None), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None).val(1), ], }; run_success(lang, &desc, 5, &exp) } // R(10) root, insert 15 → right child, parent recolored B. Self::Case4Right => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[node(10, R, None, None, None)], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, B, None, None, Some(1)), - expected(15, 1, R, Some(0), None, None), + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None).val(1), ], }; run_success(lang, &desc, 15, &exp) @@ -1068,85 +1044,89 @@ impl TestCase for InsertCase { // Before: B(10) root, R(5) left, R(15) right. // After recolor: R(10), B(5), B(15), inserted node red. Self::Case23LeftLeft => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), Some(3), None), - expected(15, 15, B, Some(0), None, None), - expected(1, 1, R, Some(1), None, None), + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), Some(3), None), + node(15, B, Some(0), None, None), + node(1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) } Self::Case23LeftRight => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, Some(3)), - expected(15, 15, B, Some(0), None, None), - expected(7, 1, R, Some(1), None, None), + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), None, Some(3)), + node(15, B, Some(0), None, None), + node(7, R, Some(1), None, None).val(1), ], }; run_success(lang, &desc, 7, &exp) } Self::Case23RightLeft => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, Some(0), Some(3), None), - expected(12, 1, R, Some(2), None, None), + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), Some(3), None), + node(12, R, Some(2), None, None).val(1), ], }; run_success(lang, &desc, 12, &exp) } Self::Case23RightRight => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(10, 10, R, None, Some(1), Some(2)), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, Some(0), None, Some(3)), - expected(20, 1, R, Some(2), None, None), + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None).val(1), ], }; run_success(lang, &desc, 20, &exp) @@ -1157,8 +1137,9 @@ impl TestCase for InsertCase { // Before: B(20) root, B(10) left of root, R(5) left of 10, R(15) right of 10. // After: B(20), R(10), B(5), B(15), R(1) inserted. Self::Case21Left => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(20, B, None, Some(1), None), node(10, B, Some(0), Some(2), Some(3)), @@ -1166,23 +1147,24 @@ impl TestCase for InsertCase { node(15, R, Some(1), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(20, 20, B, None, Some(1), None), - expected(10, 10, R, Some(0), Some(2), Some(3)), - expected(5, 5, B, Some(1), Some(4), None), - expected(15, 15, B, Some(1), None, None), - expected(1, 1, R, Some(2), None, None), + nodes: &[ + node(20, B, None, Some(1), None), + node(10, R, Some(0), Some(2), Some(3)), + node(5, B, Some(1), Some(4), None), + node(15, B, Some(1), None, None), + node(1, R, Some(2), None, None), ], }; run_success(lang, &desc, 1, &exp) } // Mirror: B(2) root, B(10) right of root, R(5) left of 10, R(15) right of 10. Self::Case21Right => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(2, B, None, None, Some(1)), node(10, B, Some(0), Some(2), Some(3)), @@ -1190,15 +1172,15 @@ impl TestCase for InsertCase { node(15, R, Some(1), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(2, 2, B, None, None, Some(1)), - expected(10, 10, R, Some(0), Some(2), Some(3)), - expected(5, 5, B, Some(1), None, None), - expected(15, 15, B, Some(1), None, Some(4)), - expected(20, 1, R, Some(3), None, None), + nodes: &[ + node(2, B, None, None, Some(1)), + node(10, R, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(15, B, Some(1), None, Some(4)), + node(20, R, Some(3), None, None).val(1), ], }; run_success(lang, &desc, 20, &exp) @@ -1209,20 +1191,21 @@ impl TestCase for InsertCase { // Left-left, null uncle: B(10) root, R(5) left, insert 1. // After: B(5) new root, R(1) left, R(10) right. Self::Case6LeftNull => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), None), node(5, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(1), top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, None), - expected(5, 5, B, None, Some(2), Some(0)), - expected(1, 1, R, Some(1), None, None), + nodes: &[ + node(10, R, Some(1), None, None), + node(5, B, None, Some(2), Some(0)), + node(1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1230,20 +1213,21 @@ impl TestCase for InsertCase { // Right-right, null uncle: B(10) root, R(15) right, insert 20. // After: B(15) new root, R(10) left, R(20) right. Self::Case6RightNull => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, None, Some(1)), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(1), top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, None), - expected(15, 15, B, None, Some(0), Some(2)), - expected(20, 1, R, Some(1), None, None), + nodes: &[ + node(10, R, Some(1), None, None), + node(15, B, None, Some(0), Some(2)), + node(20, R, Some(1), None, None).val(1), ], }; run_success(lang, &desc, 20, &exp) @@ -1251,22 +1235,23 @@ impl TestCase for InsertCase { // Left-left, black uncle: B(10) root, R(5) left, B(15) right, insert 1. // After: B(5) new root, R(1) left, R(10) right with B(15) as 10's right. Self::Case6LeftBlack => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, B, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(1), top: None, - nodes: vec![ - expected(10, 10, R, Some(1), None, Some(2)), - expected(5, 5, B, None, Some(3), Some(0)), - expected(15, 15, B, Some(0), None, None), - expected(1, 1, R, Some(1), None, None), + nodes: &[ + node(10, R, Some(1), None, Some(2)), + node(5, B, None, Some(3), Some(0)), + node(15, B, Some(0), None, None), + node(1, R, Some(1), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1274,22 +1259,23 @@ impl TestCase for InsertCase { // Right-right, black uncle: B(10) root, B(5) left, R(15) right, insert 20. // After: B(15) new root, R(10) left with B(5) as 10's left, R(20) right. Self::Case6RightBlack => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, B, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(2), top: None, - nodes: vec![ - expected(10, 10, R, Some(2), Some(1), None), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, B, None, Some(0), Some(3)), - expected(20, 1, R, Some(2), None, None), + nodes: &[ + node(10, R, Some(2), Some(1), None), + node(5, B, Some(0), None, None), + node(15, B, None, Some(0), Some(3)), + node(20, R, Some(2), None, None).val(1), ], }; run_success(lang, &desc, 20, &exp) @@ -1300,20 +1286,21 @@ impl TestCase for InsertCase { // Left-right, null uncle: B(10) root, R(5) left, insert 7. // After: B(7) new root, R(5) left, R(10) right. Self::Case56LeftNull => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), None), node(5, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(2), top: None, - nodes: vec![ - expected(10, 10, R, Some(2), None, None), - expected(5, 5, R, Some(2), None, None), - expected(7, 1, B, None, Some(1), Some(0)), + nodes: &[ + node(10, R, Some(2), None, None), + node(5, R, Some(2), None, None), + node(7, B, None, Some(1), Some(0)).val(1), ], }; run_success(lang, &desc, 7, &exp) @@ -1321,20 +1308,21 @@ impl TestCase for InsertCase { // Right-left, null uncle: B(10) root, R(15) right, insert 12. // After: B(12) new root, R(10) left, R(15) right. Self::Case56RightNull => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, None, Some(1)), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(2), top: None, - nodes: vec![ - expected(10, 10, R, Some(2), None, None), - expected(15, 15, R, Some(2), None, None), - expected(12, 1, B, None, Some(0), Some(1)), + nodes: &[ + node(10, R, Some(2), None, None), + node(15, R, Some(2), None, None), + node(12, B, None, Some(0), Some(1)).val(1), ], }; run_success(lang, &desc, 12, &exp) @@ -1342,22 +1330,23 @@ impl TestCase for InsertCase { // Left-right, black uncle: B(10) root, R(5) left, B(15) right, insert 7. // After: B(7) new root, R(5) left, R(10) right with B(15) as 10's right. Self::Case56LeftBlack => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, R, Some(0), None, None), node(15, B, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(3), top: None, - nodes: vec![ - expected(10, 10, R, Some(3), None, Some(2)), - expected(5, 5, R, Some(3), None, None), - expected(15, 15, B, Some(0), None, None), - expected(7, 1, B, None, Some(1), Some(0)), + nodes: &[ + node(10, R, Some(3), None, Some(2)), + node(5, R, Some(3), None, None), + node(15, B, Some(0), None, None), + node(7, B, None, Some(1), Some(0)).val(1), ], }; run_success(lang, &desc, 7, &exp) @@ -1365,22 +1354,23 @@ impl TestCase for InsertCase { // Right-left, black uncle: B(10) root, B(5) left, R(15) right, insert 12. // After: B(12) new root, R(10) left with B(5) as 10's left, R(15) right. Self::Case56RightBlack => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, B, Some(0), None, None), node(15, R, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(3), top: None, - nodes: vec![ - expected(10, 10, R, Some(3), Some(1), None), - expected(5, 5, B, Some(0), None, None), - expected(15, 15, R, Some(3), None, None), - expected(12, 1, B, None, Some(0), Some(2)), + nodes: &[ + node(10, R, Some(3), Some(1), None), + node(5, B, Some(0), None, None), + node(15, R, Some(3), None, None), + node(12, B, None, Some(0), Some(2)).val(1), ], }; run_success(lang, &desc, 12, &exp) @@ -1393,8 +1383,9 @@ impl TestCase for InsertCase { // Case 6 dir_l rotates GP=B(10) right under GGP=B(20). // GGP.child[L] = parent (GP was left child). Self::Case6GgpLeftLeft => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(20, B, None, Some(1), Some(3)), node(10, B, Some(0), Some(2), None), @@ -1402,15 +1393,15 @@ impl TestCase for InsertCase { node(25, B, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(20, 20, B, None, Some(2), Some(3)), - expected(10, 10, R, Some(2), None, None), - expected(5, 5, B, Some(0), Some(4), Some(1)), - expected(25, 25, B, Some(0), None, None), - expected(1, 1, R, Some(2), None, None), + nodes: &[ + node(20, B, None, Some(2), Some(3)), + node(10, R, Some(2), None, None), + node(5, B, Some(0), Some(4), Some(1)), + node(25, B, Some(0), None, None), + node(1, R, Some(2), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1420,8 +1411,9 @@ impl TestCase for InsertCase { // Case 6 dir_l rotates GP=B(20) right under GGP=B(5). // GGP.child[R] = parent (GP was right child). Self::Case6GgpLeftRight => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(5, B, None, Some(1), Some(2)), node(3, B, Some(0), None, None), @@ -1429,15 +1421,15 @@ impl TestCase for InsertCase { node(15, R, Some(2), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(5, 5, B, None, Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(20, 20, R, Some(3), None, None), - expected(15, 15, B, Some(0), Some(4), Some(2)), - expected(10, 1, R, Some(3), None, None), + nodes: &[ + node(5, B, None, Some(1), Some(3)), + node(3, B, Some(0), None, None), + node(20, R, Some(3), None, None), + node(15, B, Some(0), Some(4), Some(2)), + node(10, R, Some(3), None, None).val(1), ], }; run_success(lang, &desc, 10, &exp) @@ -1447,8 +1439,9 @@ impl TestCase for InsertCase { // Case 6 dir_r rotates GP=B(15) left under GGP=B(5). // GGP.child[R] = parent (GP was right child). Self::Case6GgpRightRight => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(5, B, None, Some(1), Some(2)), node(3, B, Some(0), None, None), @@ -1456,15 +1449,15 @@ impl TestCase for InsertCase { node(20, R, Some(2), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(5, 5, B, None, Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(15, 15, R, Some(3), None, None), - expected(20, 20, B, Some(0), Some(2), Some(4)), - expected(25, 1, R, Some(3), None, None), + nodes: &[ + node(5, B, None, Some(1), Some(3)), + node(3, B, Some(0), None, None), + node(15, R, Some(3), None, None), + node(20, B, Some(0), Some(2), Some(4)), + node(25, R, Some(3), None, None).val(1), ], }; run_success(lang, &desc, 25, &exp) @@ -1474,8 +1467,9 @@ impl TestCase for InsertCase { // Case 6 dir_r rotates GP=B(10) left under GGP=B(20). // GGP.child[L] = parent (GP was left child). Self::Case6GgpRightLeft => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(20, B, None, Some(1), Some(3)), node(10, B, Some(0), None, Some(2)), @@ -1483,15 +1477,15 @@ impl TestCase for InsertCase { node(25, B, Some(0), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(0), top: None, - nodes: vec![ - expected(20, 20, B, None, Some(2), Some(3)), - expected(10, 10, R, Some(2), None, None), - expected(15, 15, B, Some(0), Some(1), Some(4)), - expected(25, 25, B, Some(0), None, None), - expected(17, 1, R, Some(2), None, None), + nodes: &[ + node(20, B, None, Some(2), Some(3)), + node(10, R, Some(2), None, None), + node(15, B, Some(0), Some(1), Some(4)), + node(25, B, Some(0), None, None), + node(17, R, Some(2), None, None).val(1), ], }; run_success(lang, &desc, 17, &exp) @@ -1503,8 +1497,9 @@ impl TestCase for InsertCase { // Case 2 recolors at bottom, then case 6 dir_l rotates with // new_child = B(15) non-null. Self::Case26Left => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(20, B, None, Some(1), Some(3)), node(10, R, Some(0), Some(2), Some(6)), @@ -1515,18 +1510,18 @@ impl TestCase for InsertCase { node(15, B, Some(1), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(1), top: None, - nodes: vec![ - expected(20, 20, R, Some(1), Some(6), Some(3)), - expected(10, 10, B, None, Some(2), Some(0)), - expected(5, 5, R, Some(1), Some(4), Some(5)), - expected(25, 25, B, Some(0), None, None), - expected(3, 3, B, Some(2), Some(7), None), - expected(7, 7, B, Some(2), None, None), - expected(15, 15, B, Some(0), None, None), - expected(1, 1, R, Some(4), None, None), + nodes: &[ + node(20, R, Some(1), Some(6), Some(3)), + node(10, B, None, Some(2), Some(0)), + node(5, R, Some(1), Some(4), Some(5)), + node(25, B, Some(0), None, None), + node(3, B, Some(2), Some(7), None), + node(7, B, Some(2), None, None), + node(15, B, Some(0), None, None), + node(1, R, Some(4), None, None), ], }; run_success(lang, &desc, 1, &exp) @@ -1535,8 +1530,9 @@ impl TestCase for InsertCase { // Case 2 recolors at bottom, then case 6 dir_r rotates with // new_child = B(10) non-null. Self::Case26Right => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(5, B, None, Some(1), Some(2)), node(3, B, Some(0), None, None), @@ -1547,18 +1543,18 @@ impl TestCase for InsertCase { node(25, R, Some(4), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(2), top: None, - nodes: vec![ - expected(5, 5, R, Some(2), Some(1), Some(3)), - expected(3, 3, B, Some(0), None, None), - expected(15, 15, B, None, Some(0), Some(4)), - expected(10, 10, B, Some(0), None, None), - expected(20, 20, R, Some(2), Some(5), Some(6)), - expected(17, 17, B, Some(4), None, None), - expected(25, 25, B, Some(4), None, Some(7)), - expected(30, 1, R, Some(6), None, None), + nodes: &[ + node(5, R, Some(2), Some(1), Some(3)), + node(3, B, Some(0), None, None), + node(15, B, None, Some(0), Some(4)), + node(10, B, Some(0), None, None), + node(20, R, Some(2), Some(5), Some(6)), + node(17, B, Some(4), None, None), + node(25, B, Some(4), None, Some(7)), + node(30, R, Some(6), None, None).val(1), ], }; run_success(lang, &desc, 30, &exp) @@ -1571,8 +1567,9 @@ impl TestCase for InsertCase { // new_child = B(12) non-null, then case 6 dir_l rotates with // new_child = B(17) non-null. Self::Case256Left => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(20, B, None, Some(1), Some(4)), node(10, R, Some(0), Some(2), Some(3)), @@ -1583,18 +1580,18 @@ impl TestCase for InsertCase { node(17, R, Some(3), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(3), top: None, - nodes: vec![ - expected(20, 20, R, Some(3), Some(6), Some(4)), - expected(10, 10, R, Some(3), Some(2), Some(5)), - expected(5, 5, B, Some(1), None, None), - expected(15, 15, B, None, Some(1), Some(0)), - expected(25, 25, B, Some(0), None, None), - expected(12, 12, B, Some(1), Some(7), None), - expected(17, 17, B, Some(0), None, None), - expected(11, 1, R, Some(5), None, None), + nodes: &[ + node(20, R, Some(3), Some(6), Some(4)), + node(10, R, Some(3), Some(2), Some(5)), + node(5, B, Some(1), None, None), + node(15, B, None, Some(1), Some(0)), + node(25, B, Some(0), None, None), + node(12, B, Some(1), Some(7), None), + node(17, B, Some(0), None, None), + node(11, R, Some(5), None, None).val(1), ], }; run_success(lang, &desc, 11, &exp) @@ -1604,8 +1601,9 @@ impl TestCase for InsertCase { // new_child = B(17) non-null, then case 6 dir_r rotates with // new_child = B(12) non-null. Self::Case256Right => { - let desc = TreeDesc { + let desc = TreeSpec { root: Some(0), + top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), node(5, B, Some(0), None, None), @@ -1616,18 +1614,18 @@ impl TestCase for InsertCase { node(17, R, Some(3), None, None), ], }; - let exp = ExpectedTree { + let exp = TreeSpec { root: Some(3), top: None, - nodes: vec![ - expected(10, 10, R, Some(3), Some(1), Some(5)), - expected(5, 5, B, Some(0), None, None), - expected(20, 20, R, Some(3), Some(6), Some(4)), - expected(15, 15, B, None, Some(0), Some(2)), - expected(25, 25, B, Some(2), None, None), - expected(12, 12, B, Some(0), None, None), - expected(17, 17, B, Some(2), None, Some(7)), - expected(18, 1, R, Some(6), None, None), + nodes: &[ + node(10, R, Some(3), Some(1), Some(5)), + node(5, B, Some(0), None, None), + node(20, R, Some(3), Some(6), Some(4)), + node(15, B, None, Some(0), Some(2)), + node(25, B, Some(2), None, None), + node(12, B, Some(0), None, None), + node(17, B, Some(2), None, Some(7)), + node(18, R, Some(6), None, None).val(1), ], }; run_success(lang, &desc, 18, &exp) @@ -1635,3 +1633,336 @@ impl TestCase for InsertCase { } } } + +// --------------------------------------------------------------------------- +// Multi-insert integration tests +// --------------------------------------------------------------------------- + +/// Build an empty tree account with `n` pre-allocated free slots. +fn build_empty_tree(n: usize, program_id: &Pubkey) -> (Pubkey, Account) { + let data_len = size_of::() + n * size_of::(); + let mut data = vec![0u8; data_len]; + + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = core::ptr::null_mut(); + (*header).top = if n > 0 { + node_vaddr(0) as *mut StackNode + } else { + core::ptr::null_mut() + }; + (*header).next = core::ptr::null_mut(); + } + + // Link free slots into a singly-linked list. + for i in 0..n { + let offset = size_of::() + i * size_of::(); + let slot = unsafe { data.as_mut_ptr().add(offset) as *mut StackNode }; + unsafe { + (*slot).next = if i + 1 < n { + node_vaddr(i + 1) as *mut StackNode + } else { + core::ptr::null_mut() + }; + } + } + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} + +struct MultiInsertStep<'a> { + key: u16, + expected: TreeSpec<'a>, +} + +fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) { + let setup = setup_test(lang); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, mut tree_account) = + build_empty_tree(steps.len(), &setup.program_id); + + for (i, step) in steps.iter().enumerate() { + let insn_data = InsertInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Insert as u8, + }, + key: step.key, + value: 1, + }; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + unsafe { as_bytes(&insn_data) }, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account.clone()), + ]; + + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Success => { + tree_account = + result.resulting_accounts[AccountIndex::Tree as usize].1.clone(); + if let Err(e) = assert_tree_account(&tree_account.data, &step.expected) { + panic!( + "step {} (key={}): {}", + i, step.key, e + ); + } + } + other => panic!( + "step {} (key={}): expected Success, got {:?}", + i, step.key, other + ), + } + } +} + +pub(super) fn test_multi_insert(lang: ProgramLanguage) { + // 3-node balanced: 10, 5, 15. + run_multi_insert(lang, &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + ]); + + // Left-skew: 10, 5, 1 → right rotation. + run_multi_insert(lang, &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 1, + expected: TreeSpec { + root: Some(1), + top: None, + nodes: &[ + node(10, R, Some(1), None, None).val(1), + node(5, B, None, Some(2), Some(0)).val(1), + node(1, R, Some(1), None, None).val(1), + ], + }, + }, + ]); + + // Right-skew: 10, 15, 20 → left rotation. + run_multi_insert(lang, &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, None, Some(1)).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 20, + expected: TreeSpec { + root: Some(1), + top: None, + nodes: &[ + node(10, R, Some(1), None, None).val(1), + node(15, B, None, Some(0), Some(2)).val(1), + node(20, R, Some(1), None, None).val(1), + ], + }, + }, + ]); + + // Zigzag: 10, 5, 7 → double rotation. + run_multi_insert(lang, &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 7, + expected: TreeSpec { + root: Some(2), + top: None, + nodes: &[ + node(10, R, Some(2), None, None).val(1), + node(5, R, Some(2), None, None).val(1), + node(7, B, None, Some(1), Some(0)).val(1), + ], + }, + }, + ]); + + // 7-node full: 10, 5, 15, 3, 7, 12, 20. + run_multi_insert(lang, &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 3, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 7, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 12, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + ], + }, + }, + MultiInsertStep { + key: 20, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, + }, + ]); +} From ecb98922441e88091baf9a39ce3c38b584c91ad6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:59:43 -0700 Subject: [PATCH 211/263] Include multi-insert --- docs/src/examples/tree.md | 2 + .../artifacts/tests/multi_insert/result.txt | 55 +++++---- .../artifacts/tests/multi_insert/test.txt | 3 +- examples/tree/src/tests.rs | 3 +- examples/tree/src/tests/insert.rs | 106 ++++++++++++++---- 5 files changed, 121 insertions(+), 48 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 1deb7367..d64445b7 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -294,6 +294,8 @@ not available in Rust, since the compiler enforces + + ::: diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index f3522de1..4efa3d42 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,3 +1,10 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| 3-node balanced (10,5,15) | 100 | 127 | +27 | +27.0% | +| Left-skew rotation (10,5,1) | 125 | 163 | +38 | +30.4% | +| Right-skew rotation (10,15,20) | 126 | 153 | +27 | +21.4% | +| Zigzag double rotation (10,5,7) | 134 | 167 | +33 | +24.6% | +| 7-node full tree (10,5,15,3,7,12,20) | 284 | 375 | +91 | +32.0% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -9,13 +16,13 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -24,16 +31,16 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units @@ -42,28 +49,25 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -72,25 +76,28 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/multi_insert/test.txt b/examples/tree/artifacts/tests/multi_insert/test.txt index 642b47f2..ac4468c9 100644 --- a/examples/tree/artifacts/tests/multi_insert/test.txt +++ b/examples/tree/artifacts/tests/multi_insert/test.txt @@ -1,5 +1,4 @@ #[test] fn test_multi_insert() { - insert::test_multi_insert(ProgramLanguage::Assembly); - insert::test_multi_insert(ProgramLanguage::Rust); + print_comparison_table(insert::MultiInsertCase::CASES); } \ No newline at end of file diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index b78a661a..97c9e78b 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -224,6 +224,5 @@ fn test_insert_to_tree() { #[test] fn test_multi_insert() { - insert::test_multi_insert(ProgramLanguage::Assembly); - insert::test_multi_insert(ProgramLanguage::Rust); + print_comparison_table(insert::MultiInsertCase::CASES); } diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 549b48ce..9ec83be6 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -1678,7 +1678,7 @@ struct MultiInsertStep<'a> { expected: TreeSpec<'a>, } -fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) { +fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) -> CaseResult { let setup = setup_test(lang); let (system_program_pubkey, _) = program::keyed_account_for_system_program(); @@ -1686,6 +1686,8 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) { let (tree_pubkey, mut tree_account) = build_empty_tree(steps.len(), &setup.program_id); + let mut total_cu = 0u64; + for (i, step) in steps.iter().enumerate() { let insn_data = InsertInstruction { header: InstructionHeader { @@ -1713,27 +1715,87 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) { ]; let result = setup.mollusk.process_instruction(&instruction, &accounts); + total_cu += result.compute_units_consumed; match &result.program_result { MolluskResult::Success => { tree_account = result.resulting_accounts[AccountIndex::Tree as usize].1.clone(); if let Err(e) = assert_tree_account(&tree_account.data, &step.expected) { - panic!( - "step {} (key={}): {}", - i, step.key, e - ); + return CaseResult { + cu: total_cu, + error: Some(format!("step {} (key={}): {}", i, step.key, e)), + }; } } - other => panic!( - "step {} (key={}): expected Success, got {:?}", - i, step.key, other - ), + other => { + return CaseResult { + cu: total_cu, + error: Some(format!( + "step {} (key={}): expected Success, got {:?}", + i, step.key, other + )), + }; + } + } + } + + CaseResult { + cu: total_cu, + error: None, + } +} + +// --------------------------------------------------------------------------- +// Multi-insert case enum +// --------------------------------------------------------------------------- + +#[derive(Clone, Copy)] +pub(super) enum MultiInsertCase { + /// 10, 5, 15 — case 2+3 recolor only. + Balanced3, + /// 10, 5, 1 — case 5+6 right rotation. + LeftSkew, + /// 10, 15, 20 — case 5+6 left rotation. + RightSkew, + /// 10, 5, 7 — case 4+5+6 double rotation. + Zigzag, + /// 10, 5, 15, 3, 7, 12, 20 — full 7-node tree. + Full7, +} + +impl MultiInsertCase { + pub(super) const CASES: &'static [Self] = &[ + Self::Balanced3, + Self::LeftSkew, + Self::RightSkew, + Self::Zigzag, + Self::Full7, + ]; +} + +impl TestCase for MultiInsertCase { + fn name(&self) -> &'static str { + match self { + Self::Balanced3 => "3-node balanced (10,5,15)", + Self::LeftSkew => "Left-skew rotation (10,5,1)", + Self::RightSkew => "Right-skew rotation (10,15,20)", + Self::Zigzag => "Zigzag double rotation (10,5,7)", + Self::Full7 => "7-node full tree (10,5,15,3,7,12,20)", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + Self::Balanced3 => run_balanced_3(lang), + Self::LeftSkew => run_left_skew(lang), + Self::RightSkew => run_right_skew(lang), + Self::Zigzag => run_zigzag(lang), + Self::Full7 => run_full_7(lang), } } } -pub(super) fn test_multi_insert(lang: ProgramLanguage) { - // 3-node balanced: 10, 5, 15. +fn run_balanced_3(lang: ProgramLanguage) -> CaseResult { run_multi_insert(lang, &[ MultiInsertStep { key: 10, @@ -1766,9 +1828,10 @@ pub(super) fn test_multi_insert(lang: ProgramLanguage) { ], }, }, - ]); + ]) +} - // Left-skew: 10, 5, 1 → right rotation. +fn run_left_skew(lang: ProgramLanguage) -> CaseResult { run_multi_insert(lang, &[ MultiInsertStep { key: 10, @@ -1801,9 +1864,10 @@ pub(super) fn test_multi_insert(lang: ProgramLanguage) { ], }, }, - ]); + ]) +} - // Right-skew: 10, 15, 20 → left rotation. +fn run_right_skew(lang: ProgramLanguage) -> CaseResult { run_multi_insert(lang, &[ MultiInsertStep { key: 10, @@ -1836,9 +1900,10 @@ pub(super) fn test_multi_insert(lang: ProgramLanguage) { ], }, }, - ]); + ]) +} - // Zigzag: 10, 5, 7 → double rotation. +fn run_zigzag(lang: ProgramLanguage) -> CaseResult { run_multi_insert(lang, &[ MultiInsertStep { key: 10, @@ -1871,9 +1936,10 @@ pub(super) fn test_multi_insert(lang: ProgramLanguage) { ], }, }, - ]); + ]) +} - // 7-node full: 10, 5, 15, 3, 7, 12, 20. +fn run_full_7(lang: ProgramLanguage) -> CaseResult { run_multi_insert(lang, &[ MultiInsertStep { key: 10, @@ -1964,5 +2030,5 @@ pub(super) fn test_multi_insert(lang: ProgramLanguage) { ], }, }, - ]); + ]) } From 26b87bacabcb5b79bfdc26c29c4a27827cd8c2d2 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:12:40 -0700 Subject: [PATCH 212/263] Add remove insn scaffolding --- examples/tree/interface/src/common.rs | 18 ++++++++++++++++-- examples/tree/macros/src/lib.rs | 7 +++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index b3ba10b4..31bb7813 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,4 +1,5 @@ use core::mem::size_of; +use error_codes::error; use macros::{array_fields, constant_group, error_codes}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, @@ -237,13 +238,14 @@ pub struct StackNode { // ANCHOR_END: tree-defs-common // ANCHOR: instructions - #[repr(u8)] pub enum Instruction { /// Initialize the tree. Initialize, /// Insert key-value pair. Insert, + /// Remove key-value pair. + Remove, } #[repr(C, packed)] @@ -263,9 +265,15 @@ pub struct InsertInstruction { pub value: u16, } +#[repr(C, packed)] +pub struct RemoveInstruction { + pub header: InstructionHeader, + pub key: u16, +} + #[repr(C, packed)] /// Value in r0. -struct RemoveReturn { +pub struct RemoveReturn { value: u16, status: u16, } @@ -280,10 +288,16 @@ constant_group! { DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, /// Insert instruction discriminator. DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, + /// Remove instruction discriminator. + DISCRIMINATOR_REMOVE: u8 = Instruction::Remove as u8, /// Key field in insert instruction. offset!(INSERT_KEY, InsertInstruction.key), /// Value field in insert instruction. offset!(INSERT_VALUE, InsertInstruction.value), + /// Key field in remove instruction. + offset!(REMOVE_KEY, RemoveInstruction.key), + /// Status value for successful remove (first non-error code). + REMOVE_STATUS_OK: u16 = error::N_CODES as u16, } } diff --git a/examples/tree/macros/src/lib.rs b/examples/tree/macros/src/lib.rs index 59f14964..016ad7c1 100644 --- a/examples/tree/macros/src/lib.rs +++ b/examples/tree/macros/src/lib.rs @@ -97,6 +97,8 @@ pub fn error_codes(input: TokenStream) -> TokenStream { let header = asm_header("Error codes."); let body = asm_lines.join("\n"); + let n_codes = input.entries.len() as u32; + let expanded = quote! { pub mod error_codes { #[repr(u32)] @@ -105,6 +107,11 @@ pub fn error_codes(input: TokenStream) -> TokenStream { #(#variant_defs),* } + impl error { + /// Total number of error codes. + pub const N_CODES: u32 = #n_codes; + } + impl From for u32 { fn from(e: error) -> u32 { e as u32 From 12f85ea3ca6c90cf969b754451081929dde15881 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:16:50 -0700 Subject: [PATCH 213/263] Update likely branches --- .../tree/artifacts/tests/insert_search/result.txt | 12 ++++++------ examples/tree/src/program.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/tree/artifacts/tests/insert_search/result.txt b/examples/tree/artifacts/tests/insert_search/result.txt index 36d2d1ba..36b92e46 100644 --- a/examples/tree/artifacts/tests/insert_search/result.txt +++ b/examples/tree/artifacts/tests/insert_search/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Dup at root | 26 | 33 | +7 | +26.9% | -| Dup in left | 32 | 44 | +12 | +37.5% | -| Dup in right | 33 | 42 | +9 | +27.3% | +| Dup at root | 26 | 32 | +6 | +23.1% | +| Dup in left | 32 | 43 | +11 | +34.4% | +| Dup in right | 33 | 41 | +8 | +24.2% | test tests::test_insert_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 3ea72cd6..703c645a 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -307,9 +307,9 @@ unsafe fn insert( } parent = cursor; let cursor_key = (*cursor).key; - if key > cursor_key { + if likely(key > cursor_key) { cursor = (*cursor).child[tree::DIR_R]; - } else if key < cursor_key { + } else if likely(key < cursor_key) { cursor = (*cursor).child[tree::DIR_L]; } else { return error::KEY_EXISTS.into(); From c4a209f21b485c386621e919f3cf6520ed8f12ce Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:39:59 -0700 Subject: [PATCH 214/263] Optimize more --- docs/src/examples/tree.md | 20 - examples/tree/artifacts/dumps/asm.txt | 343 ++++---- examples/tree/artifacts/dumps/rs.txt | 807 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 255 +++--- .../tree/artifacts/snippets/asm/constants.txt | 4 + .../snippets/asm/insert-fixup-child-dir.txt | 10 - .../artifacts/snippets/asm/insert-search.txt | 29 +- .../artifacts/snippets/asm/insert-to-tree.txt | 11 - .../snippets/interface/instructions.txt | 17 +- .../snippets/rs/insert-fixup-child-dir.txt | 3 - .../artifacts/snippets/rs/insert-search.txt | 32 +- .../artifacts/snippets/rs/insert-to-tree.txt | 8 - .../artifacts/tests/insert_alloc/result.txt | 4 +- .../artifacts/tests/insert_search/result.txt | 16 +- .../artifacts/tests/insert_to_tree/result.txt | 160 ++-- .../artifacts/tests/multi_insert/result.txt | 76 +- examples/tree/src/program.rs | 45 +- examples/tree/src/tree/tree.s | 50 +- 18 files changed, 941 insertions(+), 949 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt delete mode 100644 examples/tree/artifacts/snippets/asm/insert-to-tree.txt delete mode 100644 examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt delete mode 100644 examples/tree/artifacts/snippets/rs/insert-to-tree.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index d64445b7..8c5f2a72 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -220,26 +220,6 @@ not available in Rust, since the compiler enforces -::: details Insert to tree - -::: code-group - -<<< ../../../examples/tree/artifacts/snippets/asm/insert-to-tree.txt{asm} [Assembly] - -<<< ../../../examples/tree/artifacts/snippets/rs/insert-to-tree.txt{rs} [Rust] - -::: - -::: details Child direction - -::: code-group - -<<< ../../../examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt{asm} [Assembly] - -<<< ../../../examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt{rs} [Rust] - -::: - ::: details Case 1 ::: code-group diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 0b49a871..47f1921d 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3392 (bytes into file) + Start of section headers 3400 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xd40 +There are 7 section headers, starting at offset 0xd48 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000ab8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000ba0 000ba0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000c40 000c40 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000ca0 000ca0 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000ce0 000ce0 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000d10 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000ac0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000ba8 000ba8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000c48 000c48 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000ca8 000ca8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000ce8 000ce8 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000d18 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ab8 0x000ab8 R E 0x1000 - LOAD 0x000c40 0x0000000000000c40 0x0000000000000c40 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000ba0 0x0000000000000ba0 0x0000000000000ba0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ac0 0x000ac0 R E 0x1000 + LOAD 0x000c48 0x0000000000000c48 0x0000000000000c48 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000ba8 0x0000000000000ba8 0x0000000000000ba8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xba0 contains 10 entries +Dynamic section at offset 0xba8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xce0 + 0x0000000000000011 (REL) 0xce8 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xc40 + 0x0000000000000006 (SYMTAB) 0xc48 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xca0 + 0x0000000000000005 (STRTAB) 0xca8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xce0 contains 3 entries +Relocation section '.rel.dyn' at offset 0xce8 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 39 01 01 00 00 00 if r9 != 0x1 goto +0x139 - 37 55 08 3a 01 04 00 00 00 if r8 != 0x4 goto +0x13a + 36 55 09 3a 01 01 00 00 00 if r9 != 0x1 goto +0x13a + 37 55 08 3b 01 04 00 00 00 if r8 != 0x4 goto +0x13b 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 4a 01 00 00 00 00 if r9 != 0x0 goto +0x14a + 39 55 09 4b 01 00 00 00 00 if r9 != 0x0 goto +0x14b 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 46 01 ff 00 00 00 if r9 != 0xff goto +0x146 + 41 55 09 47 01 ff 00 00 00 if r9 != 0xff goto +0x147 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 42 01 00 00 00 00 if r9 != 0x0 goto +0x142 + 43 55 09 43 01 00 00 00 00 if r9 != 0x0 goto +0x143 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 3e 01 ff 00 00 00 if r9 != 0xff goto +0x13e + 45 55 09 3f 01 ff 00 00 00 if r9 != 0xff goto +0x13f 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 3a 01 0e 00 00 00 if r9 != 0xe goto +0x13a + 47 55 09 3b 01 0e 00 00 00 if r9 != 0xe goto +0x13b 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 36 01 ff 00 00 00 if r9 != 0xff goto +0x136 + 49 55 09 37 01 ff 00 00 00 if r9 != 0xff goto +0x137 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 + 53 5d 89 31 01 00 00 00 00 if r9 != r8 goto +0x131 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 2c 01 00 00 00 00 if r9 != r8 goto +0x12c + 57 5d 89 2d 01 00 00 00 00 if r9 != r8 goto +0x12d 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 + 61 5d 89 29 01 00 00 00 00 if r9 != r8 goto +0x129 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 25 01 00 00 00 00 if r9 != r8 goto +0x125 + 64 5d 89 26 01 00 00 00 00 if r9 != r8 goto +0x126 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 18 01 00 00 00 00 if r9 != r8 goto +0x118 + 75 5d 89 19 01 00 00 00 00 if r9 != r8 goto +0x119 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 15 01 00 00 00 00 if r9 != r8 goto +0x115 + 78 5d 89 16 01 00 00 00 00 if r9 != r8 goto +0x116 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 12 01 00 00 00 00 if r9 != r8 goto +0x112 + 81 5d 89 13 01 00 00 00 00 if r9 != r8 goto +0x113 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 0f 01 00 00 00 00 if r9 != r8 goto +0x10f + 84 5d 89 10 01 00 00 00 00 if r9 != r8 goto +0x110 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 cc 00 05 00 00 00 if r9 != 0x5 goto +0xcc - 146 a5 08 cd 00 02 00 00 00 if r8 < 0x2 goto +0xcd + 145 55 09 cd 00 05 00 00 00 if r9 != 0x5 goto +0xcd + 146 a5 08 ce 00 02 00 00 00 if r8 < 0x2 goto +0xce 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 dd 00 00 00 00 00 if r9 != 0x0 goto +0xdd + 148 55 09 de 00 00 00 00 00 if r9 != 0x0 goto +0xde 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 d9 00 ff 00 00 00 if r9 != 0xff goto +0xd9 + 150 55 09 da 00 ff 00 00 00 if r9 != 0xff goto +0xda 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 c8 00 04 00 00 00 if r8 != 0x4 goto +0xc8 + 153 55 08 c9 00 04 00 00 00 if r8 != 0x4 goto +0xc9 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 ca 00 ff 00 00 00 if r8 != 0xff goto +0xca + 161 55 08 cb 00 ff 00 00 00 if r8 != 0xff goto +0xcb 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 c6 00 0e 00 00 00 if r8 != 0xe goto +0xc6 + 163 55 08 c7 00 0e 00 00 00 if r8 != 0xe goto +0xc7 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 c2 00 ff 00 00 00 if r8 != 0xff goto +0xc2 + 165 55 08 c3 00 ff 00 00 00 if r8 != 0xff goto +0xc3 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 bc 00 00 00 00 00 if r8 != r4 goto +0xbc + 169 5d 48 bd 00 00 00 00 00 if r8 != r4 goto +0xbd 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 b8 00 00 00 00 00 if r8 != r4 goto +0xb8 + 173 5d 48 b9 00 00 00 00 00 if r8 != r4 goto +0xb9 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 b4 00 00 00 00 00 if r8 != r4 goto +0xb4 + 177 5d 48 b5 00 00 00 00 00 if r8 != r4 goto +0xb5 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 b1 00 00 00 00 00 if r8 != r4 goto +0xb1 + 180 5d 48 b2 00 00 00 00 00 if r8 != r4 goto +0xb2 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -290,134 +290,135 @@ Disassembly of section .text 238 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) 239 b7 02 00 00 00 00 00 00 r2 = 0x0 240 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) - 241 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa + 241 15 03 06 00 00 00 00 00 if r3 == 0x0 goto +0x6 242 bf 32 00 00 00 00 00 00 r2 = r3 243 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) - 244 ad 54 03 00 00 00 00 00 if r4 < r5 goto +0x3 - 245 2d 54 04 00 00 00 00 00 if r4 > r5 goto +0x4 + 244 ad 54 07 00 00 00 00 00 if r4 < r5 goto +0x7 + 245 2d 54 0c 00 00 00 00 00 if r4 > r5 goto +0xc 246 b7 00 00 00 0e 00 00 00 r0 = 0xe 247 95 00 00 00 00 00 00 00 exit - 248 79 33 08 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x8) - 249 05 00 f7 ff 00 00 00 00 goto -0x9 - 250 79 33 10 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x10) - 251 05 00 f5 ff 00 00 00 00 goto -0xb - 252 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 - 253 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 - 254 55 02 02 00 00 00 00 00 if r2 != 0x0 goto +0x2 - 255 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 - 256 95 00 00 00 00 00 00 00 exit - 257 69 25 18 00 00 00 00 00 r5 = *(u16 *)(r2 + 0x18) - 258 2d 54 02 00 00 00 00 00 if r4 > r5 goto +0x2 - 259 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 - 260 05 00 01 00 00 00 00 00 goto +0x1 - 261 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 - 262 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) - 263 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 - 264 95 00 00 00 00 00 00 00 exit - 265 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) - 266 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 - 267 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 268 95 00 00 00 00 00 00 00 exit - 269 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) - 270 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 - 271 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) - 272 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 273 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 274 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 - 275 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) - 276 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 277 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) - 278 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 - 279 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 280 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 281 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 - 282 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 283 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 284 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 - 285 bf 29 00 00 00 00 00 00 r9 = r2 - 286 bf 62 00 00 00 00 00 00 r2 = r6 - 287 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 288 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) - 289 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 - 290 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 291 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 292 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 - 293 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 294 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 295 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 296 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 297 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 298 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 299 05 00 03 00 00 00 00 00 goto +0x3 - 300 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 301 05 00 01 00 00 00 00 00 goto +0x1 - 302 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 303 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 304 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 305 95 00 00 00 00 00 00 00 exit - 306 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) - 307 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 308 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 309 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f - 310 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) - 311 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 312 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) - 313 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 - 314 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 315 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 316 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 - 317 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 318 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 319 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 - 320 bf 29 00 00 00 00 00 00 r9 = r2 - 321 bf 62 00 00 00 00 00 00 r2 = r6 - 322 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 323 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 324 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 - 325 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 326 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 327 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 - 328 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 329 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 330 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 331 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 332 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 333 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 334 05 00 03 00 00 00 00 00 goto +0x3 - 335 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 336 05 00 01 00 00 00 00 00 goto +0x1 - 337 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 338 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 339 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 340 95 00 00 00 00 00 00 00 exit - 341 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 342 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 - 343 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 344 bf 39 00 00 00 00 00 00 r9 = r3 - 345 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) - 346 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 - 347 95 00 00 00 00 00 00 00 exit - 348 b7 00 00 00 09 00 00 00 r0 = 0x9 - 349 95 00 00 00 00 00 00 00 exit - 350 b7 00 00 00 0c 00 00 00 r0 = 0xc - 351 95 00 00 00 00 00 00 00 exit - 352 b7 00 00 00 01 00 00 00 r0 = 0x1 - 353 95 00 00 00 00 00 00 00 exit - 354 b7 00 00 00 0d 00 00 00 r0 = 0xd - 355 95 00 00 00 00 00 00 00 exit - 356 b7 00 00 00 0a 00 00 00 r0 = 0xa - 357 95 00 00 00 00 00 00 00 exit - 358 b7 00 00 00 08 00 00 00 r0 = 0x8 - 359 95 00 00 00 00 00 00 00 exit - 360 b7 00 00 00 07 00 00 00 r0 = 0x7 - 361 95 00 00 00 00 00 00 00 exit - 362 b7 00 00 00 04 00 00 00 r0 = 0x4 - 363 95 00 00 00 00 00 00 00 exit - 364 b7 00 00 00 06 00 00 00 r0 = 0x6 - 365 95 00 00 00 00 00 00 00 exit - 366 b7 00 00 00 03 00 00 00 r0 = 0x3 - 367 95 00 00 00 00 00 00 00 exit - 368 b7 00 00 00 05 00 00 00 r0 = 0x5 - 369 95 00 00 00 00 00 00 00 exit - 370 b7 00 00 00 02 00 00 00 r0 = 0x2 - 371 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 248 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 249 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 250 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 + 251 95 00 00 00 00 00 00 00 exit + 252 79 23 08 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x8) + 253 55 03 f4 ff 00 00 00 00 if r3 != 0x0 goto -0xc + 254 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 255 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 256 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 + 257 05 00 05 00 00 00 00 00 goto +0x5 + 258 79 23 10 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x10) + 259 55 03 ee ff 00 00 00 00 if r3 != 0x0 goto -0x12 + 260 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 261 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 262 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 + 263 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 264 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 + 265 95 00 00 00 00 00 00 00 exit + 266 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) + 267 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 + 268 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 269 95 00 00 00 00 00 00 00 exit + 270 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) + 271 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 + 272 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) + 273 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 274 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 275 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 + 276 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) + 277 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 278 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) + 279 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 + 280 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 281 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 282 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 + 283 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 284 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 285 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 + 286 bf 29 00 00 00 00 00 00 r9 = r2 + 287 bf 62 00 00 00 00 00 00 r2 = r6 + 288 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 289 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 290 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 + 291 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 292 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 293 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 + 294 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 295 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 296 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 297 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 298 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 299 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 300 05 00 03 00 00 00 00 00 goto +0x3 + 301 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 302 05 00 01 00 00 00 00 00 goto +0x1 + 303 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 304 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 305 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 306 95 00 00 00 00 00 00 00 exit + 307 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 308 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 309 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 310 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f + 311 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 312 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 313 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 314 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 315 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 316 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 317 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 318 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 319 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 320 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 321 bf 29 00 00 00 00 00 00 r9 = r2 + 322 bf 62 00 00 00 00 00 00 r2 = r6 + 323 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 324 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 325 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 326 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 327 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 328 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 329 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 330 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 331 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 332 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 333 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 334 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 335 05 00 03 00 00 00 00 00 goto +0x3 + 336 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 337 05 00 01 00 00 00 00 00 goto +0x1 + 338 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 339 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 340 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 341 95 00 00 00 00 00 00 00 exit + 342 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 343 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 344 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 345 bf 39 00 00 00 00 00 00 r9 = r3 + 346 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 347 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 + 348 95 00 00 00 00 00 00 00 exit + 349 b7 00 00 00 09 00 00 00 r0 = 0x9 + 350 95 00 00 00 00 00 00 00 exit + 351 b7 00 00 00 0c 00 00 00 r0 = 0xc + 352 95 00 00 00 00 00 00 00 exit + 353 b7 00 00 00 01 00 00 00 r0 = 0x1 + 354 95 00 00 00 00 00 00 00 exit + 355 b7 00 00 00 0d 00 00 00 r0 = 0xd + 356 95 00 00 00 00 00 00 00 exit + 357 b7 00 00 00 0a 00 00 00 r0 = 0xa + 358 95 00 00 00 00 00 00 00 exit + 359 b7 00 00 00 08 00 00 00 r0 = 0x8 + 360 95 00 00 00 00 00 00 00 exit + 361 b7 00 00 00 07 00 00 00 r0 = 0x7 + 362 95 00 00 00 00 00 00 00 exit + 363 b7 00 00 00 04 00 00 00 r0 = 0x4 + 364 95 00 00 00 00 00 00 00 exit + 365 b7 00 00 00 06 00 00 00 r0 = 0x6 + 366 95 00 00 00 00 00 00 00 exit + 367 b7 00 00 00 03 00 00 00 r0 = 0x3 + 368 95 00 00 00 00 00 00 00 exit + 369 b7 00 00 00 05 00 00 00 r0 = 0x5 + 370 95 00 00 00 00 00 00 00 exit + 371 b7 00 00 00 02 00 00 00 r0 = 0x2 + 372 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 7bbfc638..c034496b 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 5840 (bytes into file) + Start of section headers 5800 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x16d0 +There are 8 section headers, starting at offset 0x16a8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000cc0 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000de0 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000de8 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000de8 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000de8 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001160 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00119e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000c98 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000db8 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000dc0 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000dc0 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000dc0 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001138 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 001176 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000cc0 0x000cc0 E 0x8 - LOAD 0x000de0 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000de8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000de8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000c98 0x000c98 E 0x8 + LOAD 0x000db8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000dc0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000dc0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3264 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3224 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -108,407 +108,402 @@ Disassembly of section .text 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 f2 00 01 00 00 00 jne r5, 0x1, +0xf2 - 28 55 03 7c 01 05 00 00 00 jne r3, 0x5, +0x17c - 30 a5 04 7d 01 02 00 00 00 jlt r4, 0x2, +0x17d + 20 55 05 eb 00 01 00 00 00 jne r5, 0x1, +0xeb + 28 55 03 75 01 05 00 00 00 jne r3, 0x5, +0x175 + 30 a5 04 76 01 02 00 00 00 jlt r4, 0x2, +0x176 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 7d 01 00 00 00 00 jne r3, 0x0, +0x17d + 40 55 03 76 01 00 00 00 00 jne r3, 0x0, +0x176 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 7d 01 ff 00 00 00 jne r3, 0xff, +0x17d + 50 55 03 76 01 ff 00 00 00 jne r3, 0xff, +0x176 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 70 15 03 43 00 00 00 00 00 jeq r3, 0x0, +0x43 + 70 15 03 3c 00 00 00 00 00 jeq r3, 0x0, +0x3c 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 98 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - a0 15 04 a9 00 00 00 00 00 jeq r4, 0x0, +0xa9 + a0 15 04 a2 00 00 00 00 00 jeq r4, 0x0, +0xa2 a8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] - b0 05 00 04 00 00 00 00 00 ja +0x4 - b8 bf 25 00 00 00 00 00 00 mov64 r5, r2 - c0 0f 45 00 00 00 00 00 00 add64 r5, r4 - c8 9c 54 00 00 00 00 00 00 ldxdw r4, [r5 + 0x0] - d0 15 04 09 00 00 00 00 00 jeq r4, 0x0, +0x9 - d8 bf 42 00 00 00 00 00 00 mov64 r2, r4 - e0 b7 04 00 00 10 00 00 00 mov64 r4, 0x10 - e8 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] - f0 bf 10 00 00 00 00 00 00 mov64 r0, r1 - f8 2d 50 f7 ff 00 00 00 00 jgt r0, r5, -0x9 - 100 b7 04 00 00 08 00 00 00 mov64 r4, 0x8 - 108 ad 50 f5 ff 00 00 00 00 jlt r0, r5, -0xb - 110 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - 118 05 00 b8 00 00 00 00 00 ja +0xb8 - 120 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 128 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 130 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 138 3c 25 18 00 00 00 00 00 ldxh w5, [r2 + 0x18] - 140 b4 01 00 00 01 00 00 00 mov32 w1, 0x1 - 148 2d 54 01 00 00 00 00 00 jgt r4, r5, +0x1 - 150 b4 01 00 00 00 00 00 00 mov32 w1, 0x0 - 158 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 - 160 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 168 0f 14 00 00 00 00 00 00 add64 r4, r1 - 170 9f 34 08 00 00 00 00 00 stxdw [r4 + 0x8], r3 - 178 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 180 05 00 06 00 00 00 00 00 ja +0x6 - 188 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 190 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 198 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 1a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 1a8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 1b0 15 02 a5 00 00 00 00 00 jeq r2, 0x0, +0xa5 - 1b8 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] - 1c0 15 01 a3 00 00 00 00 00 jeq r1, 0x0, +0xa3 - 1c8 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] - 1d0 15 01 a0 00 00 00 00 00 jeq r1, 0x0, +0xa0 - 1d8 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] - 1e0 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 - 1e8 15 04 85 00 00 00 00 00 jeq r4, 0x0, +0x85 - 1f0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] - 1f8 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf - 200 05 00 82 00 00 00 00 00 ja +0x82 - 208 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] - 210 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 - 218 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] - 220 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 - 228 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] - 230 1d 43 a3 00 00 00 00 00 jeq r3, r4, +0xa3 - 238 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 240 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 248 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 - 250 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 258 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 260 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 268 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 270 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 - 278 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 280 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e - 288 05 00 85 00 00 00 00 00 ja +0x85 - 290 55 04 3b 01 04 00 00 00 jne r4, 0x4, +0x13b - 298 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 2a0 bf 35 00 00 00 00 00 00 mov64 r5, r3 - 2a8 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 2b0 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - 2b8 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 2c0 0f 54 00 00 00 00 00 00 add64 r4, r5 - 2c8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2d0 55 05 2f 01 ff 00 00 00 jne r5, 0xff, +0x12f - 2d8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2e0 55 05 2f 01 0e 00 00 00 jne r5, 0xe, +0x12f - 2e8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2f0 55 05 31 01 ff 00 00 00 jne r5, 0xff, +0x131 - 2f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 300 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 308 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 310 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] - 318 5d 57 78 00 00 00 00 00 jne r7, r5, +0x78 - 320 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 328 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 330 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] - 338 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 - 340 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 348 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 350 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] - 358 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 - 360 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 368 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 370 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 378 5d 52 6c 00 00 00 00 00 jne r2, r5, +0x6c - 380 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 388 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 390 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 - 398 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 - 3a0 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 3a8 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 3b0 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 - 3b8 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 3c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 3c8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 - 3d0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 - 3d8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 - 3e0 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 3e8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3f0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 - 3f8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 - 400 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + b0 bf 42 00 00 00 00 00 00 mov64 r2, r4 + b8 3c 24 18 00 00 00 00 00 ldxh w4, [r2 + 0x18] + c0 bf 15 00 00 00 00 00 00 mov64 r5, r1 + c8 bd 45 03 00 00 00 00 00 jle r5, r4, +0x3 + d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] + d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 + e0 05 00 05 00 00 00 00 00 ja +0x5 + e8 3d 45 6d 01 00 00 00 00 jge r5, r4, +0x16d + f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] + f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa + 100 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 + 108 05 00 01 00 00 00 00 00 ja +0x1 + 110 b7 01 00 00 10 00 00 00 mov64 r1, 0x10 + 118 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 120 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 128 0f 14 00 00 00 00 00 00 add64 r4, r1 + 130 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 138 9f 34 00 00 00 00 00 00 stxdw [r4 + 0x0], r3 + 140 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 148 05 00 06 00 00 00 00 00 ja +0x6 + 150 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 158 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 160 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 168 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 170 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 178 15 02 a5 00 00 00 00 00 jeq r2, 0x0, +0xa5 + 180 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 188 15 01 a3 00 00 00 00 00 jeq r1, 0x0, +0xa3 + 190 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] + 198 15 01 a0 00 00 00 00 00 jeq r1, 0x0, +0xa0 + 1a0 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] + 1a8 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 + 1b0 15 04 85 00 00 00 00 00 jeq r4, 0x0, +0x85 + 1b8 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 1c0 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf + 1c8 05 00 82 00 00 00 00 00 ja +0x82 + 1d0 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] + 1d8 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 + 1e0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 1e8 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 + 1f0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] + 1f8 1d 43 a3 00 00 00 00 00 jeq r3, r4, +0xa3 + 200 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 208 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 210 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 218 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 220 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 228 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 230 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 238 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 + 240 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 248 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e + 250 05 00 85 00 00 00 00 00 ja +0x85 + 258 55 04 3b 01 04 00 00 00 jne r4, 0x4, +0x13b + 260 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 268 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 270 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 278 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 280 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 288 0f 54 00 00 00 00 00 00 add64 r4, r5 + 290 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 298 55 05 2f 01 ff 00 00 00 jne r5, 0xff, +0x12f + 2a0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2a8 55 05 2f 01 0e 00 00 00 jne r5, 0xe, +0x12f + 2b0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2b8 55 05 31 01 ff 00 00 00 jne r5, 0xff, +0x131 + 2c0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 2c8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 2d0 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 2d8 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 2e0 5d 57 78 00 00 00 00 00 jne r7, r5, +0x78 + 2e8 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 2f0 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 2f8 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 300 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 + 308 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 310 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 318 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 320 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 + 328 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 330 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 338 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 340 5d 52 6c 00 00 00 00 00 jne r2, r5, +0x6c + 348 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 350 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 358 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 + 360 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 368 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 370 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 378 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 380 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 388 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 390 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 + 398 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 + 3a0 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 3a8 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3b0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3b8 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 + 3c0 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 + 3c8 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 3d0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 3d8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 3e0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 3e8 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 + 3f0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 3f8 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 400 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 408 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 410 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 418 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 420 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 - 428 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 430 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 438 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 - 440 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 448 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 450 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 - 458 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 460 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 468 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 470 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 478 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 480 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 - 488 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 490 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 498 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 4a0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 4a8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 4b0 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 - 4b8 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 4c0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 - 4c8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 - 4d0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d8 07 02 00 00 30 01 00 00 add64 r2, 0x130 - 4e0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 - 4e8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4f0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 - 4f8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 - 500 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 508 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 - 510 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 - 518 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc - 520 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 - 528 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 - 530 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 - 538 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 540 07 03 00 00 10 00 00 00 add64 r3, 0x10 - 548 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 550 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 558 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 560 07 04 00 00 48 00 00 00 add64 r4, 0x48 - 568 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 570 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 578 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 580 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 588 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 590 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 598 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 5a0 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 - 5a8 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] - 5b0 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 5b8 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 5c0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - 5c8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 5d0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] - 5d8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 5e0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - 5e8 55 04 57 ff 00 00 00 00 jne r4, 0x0, -0xa9 - 5f0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 - 5f8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 600 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 - 608 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 610 05 00 19 00 00 00 00 00 ja +0x19 - 618 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] - 620 1d 43 18 00 00 00 00 00 jeq r3, r4, +0x18 - 628 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 630 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 638 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 640 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 648 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 650 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 658 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 660 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 - 668 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 670 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 - 678 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] - 680 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 - 688 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 - 690 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 - 698 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 - 6a0 0f 32 00 00 00 00 00 00 add64 r2, r3 - 6a8 07 02 00 00 08 00 00 00 add64 r2, 0x8 - 6b0 bf 26 00 00 00 00 00 00 mov64 r6, r2 - 6b8 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 - 6c0 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 6c8 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 6d0 05 00 01 00 00 00 00 00 ja +0x1 - 6d8 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 6e0 9d 00 00 00 00 00 00 00 return - 6e8 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 6f0 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 - 6f8 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 700 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 708 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 710 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 - 718 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 720 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 - 728 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 730 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 738 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 740 55 03 e1 ff 00 00 00 00 jne r3, 0x0, -0x1f - 748 05 00 e1 ff 00 00 00 00 ja -0x1f - 750 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 758 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 - 760 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 768 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 770 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 778 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 - 780 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 788 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 - 790 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 798 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 - 7a0 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 7a8 55 03 56 ff 00 00 00 00 jne r3, 0x0, -0xaa - 7b0 05 00 56 ff 00 00 00 00 ja -0xaa - 7b8 55 05 9c 00 00 00 00 00 jne r5, 0x0, +0x9c - 7c0 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 7c8 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 7d0 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 7d8 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 7e0 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 7e8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7f0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 7f8 55 02 96 00 00 00 00 00 jne r2, 0x0, +0x96 - 800 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 808 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 810 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 818 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 820 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 828 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 830 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 838 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 840 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 848 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 850 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f - 858 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 860 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 868 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 870 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 - 878 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 880 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 888 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 890 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 - 898 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 8a0 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 8a8 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a - 8b0 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 8b8 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 8c0 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 8c8 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 8d0 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 8d8 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 8e0 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 8e8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 8f0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 8f8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 900 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 908 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 910 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f - 918 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 920 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 928 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c - 930 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 938 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 940 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 - 948 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 950 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 958 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 - 960 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 968 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 970 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 978 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 980 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - 988 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 990 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - 998 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 9a0 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - 9a8 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 9b0 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - 9b8 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 9c0 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - 9c8 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - 9d0 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - 9d8 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 9e0 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 9e8 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 9f0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 9f8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - a00 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - a08 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a10 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - a18 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - a20 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a28 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - a30 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - a38 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a40 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - a48 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - a50 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - a58 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a60 07 01 00 00 30 00 00 00 add64 r1, 0x30 - a68 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - a70 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a78 07 01 00 00 60 00 00 00 add64 r1, 0x60 - a80 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - a88 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a90 07 01 00 00 50 00 00 00 add64 r1, 0x50 - a98 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - aa0 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - aa8 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - ab0 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - ab8 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - ac0 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - ac8 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - ad0 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - ad8 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - ae0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - ae8 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - af0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - af8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - b00 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - b08 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b10 07 01 00 00 10 00 00 00 add64 r1, 0x10 - b18 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - b20 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b28 07 01 00 00 48 00 00 00 add64 r1, 0x48 - b30 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - b38 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b40 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - b48 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - b50 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - b58 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - b60 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b68 07 01 00 00 0f 00 00 00 add64 r1, 0xf - b70 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - b78 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - b80 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b88 07 01 00 00 20 01 00 00 add64 r1, 0x120 - b90 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - b98 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - ba0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ba8 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - bb0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - bb8 07 02 00 00 68 00 00 00 add64 r2, 0x68 - bc0 bf a4 00 00 00 00 00 00 mov64 r4, r10 - bc8 07 04 00 00 30 01 00 00 add64 r4, 0x130 - bd0 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - bd8 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - be0 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - be8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - bf0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - bf8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - c00 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - c08 05 00 5a ff 00 00 00 00 ja -0xa6 - c10 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - c18 05 00 58 ff 00 00 00 00 ja -0xa8 - c20 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - c28 05 00 56 ff 00 00 00 00 ja -0xaa - c30 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c38 05 00 54 ff 00 00 00 00 ja -0xac - c40 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - c48 05 00 52 ff 00 00 00 00 ja -0xae - c50 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - c58 05 00 50 ff 00 00 00 00 ja -0xb0 - c60 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - c68 05 00 4e ff 00 00 00 00 ja -0xb2 - c70 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - c78 05 00 4c ff 00 00 00 00 ja -0xb4 - c80 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - c88 05 00 4a ff 00 00 00 00 ja -0xb6 - c90 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - c98 05 00 48 ff 00 00 00 00 ja -0xb8 - ca0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - ca8 05 00 46 ff 00 00 00 00 ja -0xba - cb0 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - cb8 05 00 44 ff 00 00 00 00 ja -0xbc \ No newline at end of file + 410 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 418 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 420 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 428 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 430 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 438 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 440 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 448 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 + 450 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 458 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 460 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 468 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 470 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 478 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 + 480 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 488 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 + 490 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 + 498 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4a0 07 02 00 00 30 01 00 00 add64 r2, 0x130 + 4a8 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 4b0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4b8 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 + 4c0 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4c8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4d0 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 + 4d8 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 + 4e0 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc + 4e8 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 + 4f0 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 + 4f8 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 500 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 508 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 510 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 518 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 520 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 528 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 530 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 538 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 540 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 548 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 550 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 558 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 560 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 568 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 570 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] + 578 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 580 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 588 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 590 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 598 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5a0 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5a8 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + 5b0 55 04 5e ff 00 00 00 00 jne r4, 0x0, -0xa2 + 5b8 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5c0 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 5c8 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 + 5d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 5d8 05 00 19 00 00 00 00 00 ja +0x19 + 5e0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] + 5e8 1d 43 18 00 00 00 00 00 jeq r3, r4, +0x18 + 5f0 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 5f8 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 600 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 608 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 610 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 618 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 620 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 628 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 + 630 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 638 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 + 640 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] + 648 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 + 650 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 + 658 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 + 660 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 + 668 0f 32 00 00 00 00 00 00 add64 r2, r3 + 670 07 02 00 00 08 00 00 00 add64 r2, 0x8 + 678 bf 26 00 00 00 00 00 00 mov64 r6, r2 + 680 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + 688 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 690 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 698 05 00 01 00 00 00 00 00 ja +0x1 + 6a0 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 6a8 9d 00 00 00 00 00 00 00 return + 6b0 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 6b8 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 + 6c0 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 6c8 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 6d0 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 6d8 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 + 6e0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 6e8 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 + 6f0 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 6f8 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 700 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 708 55 03 e1 ff 00 00 00 00 jne r3, 0x0, -0x1f + 710 05 00 e1 ff 00 00 00 00 ja -0x1f + 718 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 720 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 + 728 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 730 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 738 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 740 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 + 748 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 750 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 + 758 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 760 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 768 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 770 55 03 56 ff 00 00 00 00 jne r3, 0x0, -0xaa + 778 05 00 56 ff 00 00 00 00 ja -0xaa + 780 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e + 788 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 790 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 798 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 7a0 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 7a8 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 7b0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7b8 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 7c0 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 + 7c8 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 7d0 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 7d8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 7e0 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 7e8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 7f0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 800 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 808 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 810 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 818 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f + 820 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 828 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 830 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 838 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 + 840 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 848 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 850 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 858 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 + 860 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 868 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 870 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a + 878 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 880 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 888 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 890 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 898 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 8a0 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 8a8 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 8b0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 8b8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 8c0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 8c8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 8d0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 8d8 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 + 8e0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 8e8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 8f0 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 8f8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 900 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 908 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b + 910 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 918 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 920 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 + 928 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 930 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 938 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 940 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 948 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + 950 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 958 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + 960 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 968 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + 970 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 978 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + 980 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 988 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + 990 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + 998 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + 9a0 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 9a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 9b0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 9b8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 9c0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 9c8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 9d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 9d8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 9e0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 9e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 9f0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 9f8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + a00 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a08 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + a10 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + a18 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + a20 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a28 07 01 00 00 30 00 00 00 add64 r1, 0x30 + a30 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + a38 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a40 07 01 00 00 60 00 00 00 add64 r1, 0x60 + a48 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + a50 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a58 07 01 00 00 50 00 00 00 add64 r1, 0x50 + a60 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + a68 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + a70 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + a78 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + a80 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + a88 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + a90 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + a98 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + aa0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + aa8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + ab0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + ab8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + ac0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + ac8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + ad0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + ad8 07 01 00 00 10 00 00 00 add64 r1, 0x10 + ae0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + ae8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + af0 07 01 00 00 48 00 00 00 add64 r1, 0x48 + af8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + b00 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b08 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + b10 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + b18 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + b20 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + b28 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b30 07 01 00 00 0f 00 00 00 add64 r1, 0xf + b38 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + b40 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + b48 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b50 07 01 00 00 20 01 00 00 add64 r1, 0x120 + b58 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + b60 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + b68 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b70 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + b78 bf a2 00 00 00 00 00 00 mov64 r2, r10 + b80 07 02 00 00 68 00 00 00 add64 r2, 0x68 + b88 bf a4 00 00 00 00 00 00 mov64 r4, r10 + b90 07 04 00 00 30 01 00 00 add64 r4, 0x130 + b98 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + ba0 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + ba8 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + bb0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + bb8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + bc0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + bc8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + bd0 05 00 5a ff 00 00 00 00 ja -0xa6 + bd8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + be0 05 00 58 ff 00 00 00 00 ja -0xa8 + be8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + bf0 05 00 56 ff 00 00 00 00 ja -0xaa + bf8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + c00 05 00 54 ff 00 00 00 00 ja -0xac + c08 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + c10 05 00 52 ff 00 00 00 00 ja -0xae + c18 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + c20 05 00 50 ff 00 00 00 00 ja -0xb0 + c28 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + c30 05 00 4e ff 00 00 00 00 ja -0xb2 + c38 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + c40 05 00 4c ff 00 00 00 00 ja -0xb4 + c48 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + c50 05 00 4a ff 00 00 00 00 ja -0xb6 + c58 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + c60 05 00 48 ff 00 00 00 00 ja -0xb8 + c68 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + c70 05 00 46 ff 00 00 00 00 ja -0xba + c78 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + c80 05 00 44 ff 00 00 00 00 ja -0xbc + c88 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + c90 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 69fda107..0c9b1aab 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -5,112 +5,105 @@ entrypoint: ldxdw r4, [r1+0] ldxdw r3, [r2-8] ldxb r5, [r2+0] - jne r5, 1, jmp_07b0 - jne r3, 5, jmp_0c08 - jlt r4, 2, jmp_0c18 + jne r5, 1, jmp_0778 + jne r3, 5, jmp_0bd0 + jlt r4, 2, jmp_0be0 ldxdw r3, [r1+88] - jne r3, 0, jmp_0c28 + jne r3, 0, jmp_0bf0 ldxb r3, [r1+10344] - jne r3, 255, jmp_0c38 + jne r3, 255, jmp_0c00 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] - jeq r3, 0, jmp_0298 + jeq r3, 0, jmp_0260 ldxdw r4, [r3+0] stxdw [r1+10440], r4 ldxw r1, [r2+1] stxw [r3+24], r1 ldxdw r4, [r6+0] - jeq r4, 0, jmp_05f8 + jeq r4, 0, jmp_05c0 jmp_00a8: ldxh r1, [r2+1] - ja jmp_00d8 -jmp_00b8: - mov64 r5, r2 - add64 r5, r4 - ldxdw r4, [r5+0] - jeq r4, 0, jmp_0120 - -jmp_00d8: +jmp_00b0: mov64 r2, r4 - mov64 r4, 16 - ldxh r5, [r2+24] - mov64 r0, r1 - jgt r0, r5, jmp_00b8 - mov64 r4, 8 - jlt r0, r5, jmp_00b8 - mov64 r0, 14 - ja jmp_06d8 + ldxh r4, [r2+24] + mov64 r5, r1 + jle r5, r4, jmp_00e8 + ldxdw r4, [r2+16] + jne r4, 0, jmp_00b0 + ja jmp_0110 -jmp_0120: - stxdw [r3+0], r2 - stb [r3+28], 1 - mov64 r4, r1 - ldxh r5, [r2+24] - mov32 r1, 1 - jgt r4, r5, jmp_0158 - mov32 r1, 0 +jmp_00e8: + jge r5, r4, jmp_0c50 + ldxdw r4, [r2+8] + jne r4, 0, jmp_00b0 + mov64 r1, 8 + ja jmp_0118 + +jmp_0110: + mov64 r1, 16 -jmp_0158: - lsh64 r1, 3 +jmp_0118: + stxdw [r3+0], r2 mov64 r4, r2 add64 r4, r1 - stxdw [r4+8], r3 + stb [r3+28], 1 + stxdw [r4+0], r3 mov64 r0, 0 - ja jmp_01b8 + ja jmp_0180 -jmp_0188: +jmp_0150: stb [r2+28], 0 stb [r4+28], 0 stb [r1+28], 1 ldxdw r2, [r1+0] mov64 r3, r1 - jeq r2, 0, jmp_06d8 + jeq r2, 0, jmp_06a0 -jmp_01b8: +jmp_0180: ldxb r1, [r2+28] - jeq r1, 0, jmp_06d8 + jeq r1, 0, jmp_06a0 ldxdw r1, [r2+0] - jeq r1, 0, jmp_06d0 + jeq r1, 0, jmp_0698 ldxdw r4, [r1+8] - jeq r2, r4, jmp_0208 - jeq r4, 0, jmp_0620 + jeq r2, r4, jmp_01d0 + jeq r4, 0, jmp_05e8 ldxb r5, [r4+28] - jne r5, 0, jmp_0188 - ja jmp_0620 + jne r5, 0, jmp_0150 + ja jmp_05e8 -jmp_0208: +jmp_01d0: ldxdw r4, [r1+16] - jeq r4, 0, jmp_0228 + jeq r4, 0, jmp_01f0 ldxb r5, [r4+28] - jne r5, 0, jmp_0188 + jne r5, 0, jmp_0150 -jmp_0228: +jmp_01f0: ldxdw r4, [r2+16] - jeq r3, r4, jmp_0748 + jeq r3, r4, jmp_0710 mov64 r3, r4 mov64 r4, r2 stxdw [r1+8], r3 ldxdw r2, [r1+0] - jeq r3, 0, jmp_0268 + jeq r3, 0, jmp_0230 -jmp_0260: +jmp_0228: stxdw [r3+0], r1 -jmp_0268: +jmp_0230: stxdw [r4+0], r2 stxdw [r4+16], r1 stxdw [r1+0], r4 - jne r2, 0, jmp_0680 + jne r2, 0, jmp_0648 -jmp_0288: +jmp_0250: stxdw [r6+0], r4 - ja jmp_06b8 + ja jmp_0680 -jmp_0298: - jne r4, 4, jmp_0c68 +jmp_0260: + jne r4, 4, jmp_0c30 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -118,28 +111,28 @@ jmp_0298: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0c48 + jne r5, 255, jmp_0c10 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0c58 + jne r5, 14, jmp_0c20 ldxb r5, [r4+31032] - jne r5, 255, jmp_0c78 + jne r5, 255, jmp_0c40 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 ldxdw r7, [r4+31040] - jne r7, r5, jmp_06d8 + jne r7, r5, jmp_06a0 mov32 r5, 1288277025 hor64 r5, 2146519613 ldxdw r7, [r4+31048] - jne r7, r5, jmp_06d8 + jne r7, r5, jmp_06a0 mov32 r5, 149871192 hor64 r5, 1157472667 ldxdw r7, [r4+31056] - jne r7, r5, jmp_06d8 + jne r7, r5, jmp_06a0 mov64 r7, r2 ldxdw r2, [r4+31064] mov32 r5, -1965433885 - jne r2, r5, jmp_06d8 + jne r2, r5, jmp_06a0 ldxdw r2, [r4+31120] lmul64 r2, 29 stxdw [r10+308], r2 @@ -219,62 +212,62 @@ jmp_0298: ldxdw r4, [r6+0] jne r4, 0, jmp_00a8 -jmp_05f8: +jmp_05c0: stdw [r3+0], 0 stb [r3+28], 1 stxdw [r6+0], r3 -jmp_0610: +jmp_05d8: mov64 r0, 0 - ja jmp_06d8 + ja jmp_06a0 -jmp_0620: +jmp_05e8: ldxdw r4, [r2+8] - jeq r3, r4, jmp_06e0 + jeq r3, r4, jmp_06a8 mov64 r3, r4 mov64 r4, r2 stxdw [r1+16], r3 ldxdw r2, [r1+0] - jeq r3, 0, jmp_0660 + jeq r3, 0, jmp_0628 -jmp_0658: +jmp_0620: stxdw [r3+0], r1 -jmp_0660: +jmp_0628: stxdw [r4+0], r2 stxdw [r4+8], r1 stxdw [r1+0], r4 - jeq r2, 0, jmp_0288 + jeq r2, 0, jmp_0250 -jmp_0680: +jmp_0648: ldxdw r5, [r2+16] mov32 r3, 1 - jeq r1, r5, jmp_06a0 + jeq r1, r5, jmp_0668 mov32 r3, 0 -jmp_06a0: +jmp_0668: lsh64 r3, 3 add64 r2, r3 stxdw [r2+8], r4 -jmp_06b8: +jmp_0680: stb [r4+28], 0 stb [r1+28], 1 - ja jmp_06d8 + ja jmp_06a0 -jmp_06d0: +jmp_0698: stb [r2+28], 0 -jmp_06d8: +jmp_06a0: exit -jmp_06e0: +jmp_06a8: ldxdw r3, [r4+16] stxdw [r2+8], r3 - jeq r3, 0, jmp_0700 + jeq r3, 0, jmp_06c8 stxdw [r3+0], r2 -jmp_0700: +jmp_06c8: stxdw [r4+0], r1 stxdw [r4+16], r2 stxdw [r2+0], r4 @@ -282,16 +275,16 @@ jmp_0700: ldxdw r3, [r4+8] stxdw [r1+16], r3 ldxdw r2, [r1+0] - jne r3, 0, jmp_0658 - ja jmp_0660 + jne r3, 0, jmp_0620 + ja jmp_0628 -jmp_0748: +jmp_0710: ldxdw r3, [r4+8] stxdw [r2+16], r3 - jeq r3, 0, jmp_0768 + jeq r3, 0, jmp_0730 stxdw [r3+0], r2 -jmp_0768: +jmp_0730: stxdw [r4+0], r1 stxdw [r4+8], r2 stxdw [r2+0], r4 @@ -299,41 +292,41 @@ jmp_0768: ldxdw r3, [r4+16] stxdw [r1+8], r3 ldxdw r2, [r1+0] - jne r3, 0, jmp_0260 - ja jmp_0268 + jne r3, 0, jmp_0228 + ja jmp_0230 -jmp_07b0: - jne r5, 0, jmp_0c88 - jne r3, 1, jmp_0c08 - jne r4, 4, jmp_0c18 +jmp_0778: + jne r5, 0, jmp_0c60 + jne r3, 1, jmp_0bd0 + jne r4, 4, jmp_0be0 ldxdw r2, [r1+88] - jne r2, 0, jmp_0c28 + jne r2, 0, jmp_0bf0 ldxb r2, [r1+10344] - jne r2, 255, jmp_0c38 + jne r2, 255, jmp_0c00 ldxdw r2, [r1+10424] - jne r2, 0, jmp_0c98 + jne r2, 0, jmp_0c70 ldxb r2, [r1+20680] - jne r2, 255, jmp_0c48 + jne r2, 255, jmp_0c10 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0c58 + jne r2, 14, jmp_0c20 ldxb r2, [r1+31032] - jne r2, 255, jmp_0c78 + jne r2, 255, jmp_0c40 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_06d8 + jne r3, r2, jmp_06a0 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_06d8 + jne r3, r2, jmp_06a0 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_06d8 + jne r3, r2, jmp_06a0 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_06d8 + jne r2, r3, jmp_06a0 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 @@ -347,16 +340,16 @@ jmp_07b0: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_06d8 + jne r1, r2, jmp_06a0 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_06d8 + jne r1, r2, jmp_06a0 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_06d8 + jne r1, r2, jmp_06a0 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_06d8 + jne r1, r2, jmp_06a0 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -441,44 +434,48 @@ jmp_07b0: mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - ja jmp_0610 + ja jmp_05d8 -jmp_0c08: +jmp_0bd0: mov64 r0, 12 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c18: +jmp_0be0: mov64 r0, 1 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c28: +jmp_0bf0: mov64 r0, 2 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c38: +jmp_0c00: mov64 r0, 5 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c48: +jmp_0c10: mov64 r0, 6 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c58: +jmp_0c20: mov64 r0, 4 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c68: +jmp_0c30: mov64 r0, 13 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c78: +jmp_0c40: mov64 r0, 7 - ja jmp_06d8 + ja jmp_06a0 + +jmp_0c50: + mov64 r0, 14 + ja jmp_06a0 -jmp_0c88: +jmp_0c60: mov64 r0, 11 - ja jmp_06d8 + ja jmp_06a0 -jmp_0c98: +jmp_0c70: mov64 r0, 3 - ja jmp_06d8 + ja jmp_06a0 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 922b7635..1dd4d54f 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -118,8 +118,12 @@ # Initialize instruction discriminator. .equ INSN_DISCRIMINATOR_INITIALIZE, 0 .equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. +.equ INSN_DISCRIMINATOR_REMOVE, 2 # Remove instruction discriminator. .equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. +.equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. +# Status value for successful remove (first non-error code). +.equ INSN_REMOVE_STATUS_OK, 14 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt deleted file mode 100644 index 5e842679..00000000 --- a/examples/tree/artifacts/snippets/asm/insert-fixup-child-dir.txt +++ /dev/null @@ -1,10 +0,0 @@ -insert_get_child_dir: - # Get child direction, set at parent. - # --------------------------------------------------------------------- - ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; - jgt r4, r5, insert_get_child_dir_branch_r -insert_get_child_dir_branch_l: - stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; - ja insert_fixup_main -insert_get_child_dir_branch_r: - stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index d8ac2c5b..79fe38a9 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -2,18 +2,37 @@ insert_search: # r9 ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; mov64 r2, NULL # r2 = parent = null; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; + jeq r3, NULL, insert_root insert_search_loop: - jeq r3, NULL, insert_to_tree mov64 r2, r3 # r2 = parent = cursor; ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit + +insert_root: + # Root is null: new node becomes root. + # --------------------------------------------------------------------- + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = null; + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; + exit + insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[L]; - ja insert_search_loop + ldxdw r3, [r2 + TREE_NODE_CHILD_L_OFF] # r3 = parent.child[L]; + jne r3, NULL, insert_search_loop + # Null child: insert node as left child of parent. + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; + ja insert_fixup_main + insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[R]; - ja insert_search_loop \ No newline at end of file + ldxdw r3, [r2 + TREE_NODE_CHILD_R_OFF] # r3 = parent.child[R]; + jne r3, NULL, insert_search_loop + # Null child: insert node as right child of parent. + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; + stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt b/examples/tree/artifacts/snippets/asm/insert-to-tree.txt deleted file mode 100644 index f5005262..00000000 --- a/examples/tree/artifacts/snippets/asm/insert-to-tree.txt +++ /dev/null @@ -1,11 +0,0 @@ -insert_to_tree: - # Flag new node as red and store parent pointer. - # --------------------------------------------------------------------- - stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; - - # Handle case of new node at root. - # --------------------------------------------------------------------- - jne r2, NULL, insert_get_child_dir - stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; - exit # Parent is null, new node at root. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index 1a125235..13f11429 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -1,10 +1,11 @@ - #[repr(u8)] pub enum Instruction { /// Initialize the tree. Initialize, /// Insert key-value pair. Insert, + /// Remove key-value pair. + Remove, } #[repr(C, packed)] @@ -24,9 +25,15 @@ pub struct InsertInstruction { pub value: u16, } +#[repr(C, packed)] +pub struct RemoveInstruction { + pub header: InstructionHeader, + pub key: u16, +} + #[repr(C, packed)] /// Value in r0. -struct RemoveReturn { +pub struct RemoveReturn { value: u16, status: u16, } @@ -41,9 +48,15 @@ constant_group! { DISCRIMINATOR_INITIALIZE: u8 = Instruction::Initialize as u8, /// Insert instruction discriminator. DISCRIMINATOR_INSERT: u8 = Instruction::Insert as u8, + /// Remove instruction discriminator. + DISCRIMINATOR_REMOVE: u8 = Instruction::Remove as u8, /// Key field in insert instruction. offset!(INSERT_KEY, InsertInstruction.key), /// Value field in insert instruction. offset!(INSERT_VALUE, InsertInstruction.value), + /// Key field in remove instruction. + offset!(REMOVE_KEY, RemoveInstruction.key), + /// Status value for successful remove (first non-error code). + REMOVE_STATUS_OK: u16 = error::N_CODES as u16, } } diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt deleted file mode 100644 index f2fe2dcf..00000000 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-child-dir.txt +++ /dev/null @@ -1,3 +0,0 @@ - // Get child direction, set at parent. - let child_dir = (key > (*parent).key) as usize; - (*parent).child[child_dir] = node; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index d30bc010..2a4f15ec 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -1,16 +1,34 @@ let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; + + // Root is null: new node becomes root. + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*tree_header).root = node; + return SUCCESS; + } + loop { - if cursor.is_null() { - break; - } parent = cursor; let cursor_key = (*cursor).key; - if key > cursor_key { - cursor = (*cursor).child[tree::DIR_R]; - } else if key < cursor_key { - cursor = (*cursor).child[tree::DIR_L]; + if likely(key > cursor_key) { + cursor = (*parent).child[tree::DIR_R]; + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*parent).child[tree::DIR_R] = node; + break; + } + } else if likely(key < cursor_key) { + cursor = (*parent).child[tree::DIR_L]; + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*parent).child[tree::DIR_L] = node; + break; + } } else { return error::KEY_EXISTS.into(); } diff --git a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt b/examples/tree/artifacts/snippets/rs/insert-to-tree.txt deleted file mode 100644 index 1b058bf8..00000000 --- a/examples/tree/artifacts/snippets/rs/insert-to-tree.txt +++ /dev/null @@ -1,8 +0,0 @@ - (*node).color = Color::Red; - (*node).parent = parent; - - // New node at root. - if parent.is_null() { - (*tree_header).root = node; - return SUCCESS; - } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_alloc/result.txt b/examples/tree/artifacts/tests/insert_alloc/result.txt index 1512f72f..caac00fe 100644 --- a/examples/tree/artifacts/tests/insert_alloc/result.txt +++ b/examples/tree/artifacts/tests/insert_alloc/result.txt @@ -1,12 +1,12 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| Insert alloc happy path | 1096 | 101 | 129 | +28 | +27.7% | +| Insert alloc happy path | 1096 | 100 | 129 | +29 | +29.0% | | Alloc exceeds max data length | 1096 | 1398904 | 1398904 | +0 | +0.0% | test tests::test_insert_alloc ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 1197 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1196 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] diff --git a/examples/tree/artifacts/tests/insert_search/result.txt b/examples/tree/artifacts/tests/insert_search/result.txt index 36b92e46..dd5a1650 100644 --- a/examples/tree/artifacts/tests/insert_search/result.txt +++ b/examples/tree/artifacts/tests/insert_search/result.txt @@ -1,24 +1,24 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Dup at root | 26 | 32 | +6 | +23.1% | -| Dup in left | 32 | 43 | +11 | +34.4% | -| Dup in right | 33 | 41 | +8 | +24.2% | +| Dup at root | 26 | 30 | +4 | +15.4% | +| Dup in left | 31 | 37 | +6 | +19.4% | +| Dup in right | 32 | 36 | +4 | +12.5% | test tests::test_insert_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index abe93663..f5787975 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,192 +1,192 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Empty tree | 25 | 27 | +2 | +8.0% | -| Case 1: left child | 36 | 50 | +14 | +38.9% | -| Case 1: right child | 36 | 47 | +11 | +30.6% | -| Case 4: left child | 39 | 53 | +14 | +35.9% | -| Case 4: right child | 39 | 50 | +11 | +28.2% | -| Case 2+3: left-left | 56 | 75 | +19 | +33.9% | -| Case 2+3: left-right | 56 | 72 | +16 | +28.6% | -| Case 2+3: right-left | 57 | 72 | +15 | +26.3% | -| Case 2+3: right-right | 57 | 69 | +12 | +21.1% | -| Case 2+1: left | 64 | 88 | +24 | +37.5% | -| Case 2+1: right | 66 | 80 | +14 | +21.2% | -| Case 6: left-left null uncle | 61 | 83 | +22 | +36.1% | -| Case 6: right-right null uncle | 62 | 76 | +14 | +22.6% | -| Case 6: left-left black uncle | 63 | 85 | +22 | +34.9% | -| Case 6: right-right black uncle | 64 | 79 | +15 | +23.4% | -| Case 5+6: left-right null uncle | 70 | 87 | +17 | +24.3% | -| Case 5+6: right-left null uncle | 71 | 86 | +15 | +21.1% | -| Case 5+6: left-right black uncle | 72 | 89 | +17 | +23.6% | -| Case 5+6: right-left black uncle | 73 | 89 | +16 | +21.9% | -| Case 6: GGP non-null, LL GP-left | 70 | 101 | +31 | +44.3% | -| Case 6: GGP non-null, LL GP-right | 71 | 98 | +27 | +38.0% | -| Case 6: GGP non-null, RR GP-right | 72 | 92 | +20 | +27.8% | -| Case 6: GGP non-null, RR GP-left | 71 | 95 | +24 | +33.8% | -| Case 2+6: non-null new_child dir_l | 92 | 124 | +32 | +34.8% | -| Case 2+6: non-null new_child dir_r | 95 | 113 | +18 | +18.9% | -| Case 2+5+6: non-null new_child dir_l | 103 | 129 | +26 | +25.2% | -| Case 2+5+6: non-null new_child dir_r | 104 | 122 | +18 | +17.3% | +| Empty tree | 24 | 27 | +3 | +12.5% | +| Case 1: left child | 32 | 41 | +9 | +28.1% | +| Case 1: right child | 32 | 40 | +8 | +25.0% | +| Case 4: left child | 35 | 44 | +9 | +25.7% | +| Case 4: right child | 35 | 43 | +8 | +22.9% | +| Case 2+3: left-left | 51 | 62 | +11 | +21.6% | +| Case 2+3: left-right | 51 | 61 | +10 | +19.6% | +| Case 2+3: right-left | 52 | 60 | +8 | +15.4% | +| Case 2+3: right-right | 52 | 59 | +7 | +13.5% | +| Case 2+1: left | 58 | 71 | +13 | +22.4% | +| Case 2+1: right | 60 | 67 | +7 | +11.7% | +| Case 6: left-left null uncle | 56 | 70 | +14 | +25.0% | +| Case 6: right-right null uncle | 57 | 66 | +9 | +15.8% | +| Case 6: left-left black uncle | 58 | 72 | +14 | +24.1% | +| Case 6: right-right black uncle | 59 | 69 | +10 | +16.9% | +| Case 5+6: left-right null uncle | 65 | 76 | +11 | +16.9% | +| Case 5+6: right-left null uncle | 66 | 74 | +8 | +12.1% | +| Case 5+6: left-right black uncle | 67 | 78 | +11 | +16.4% | +| Case 5+6: right-left black uncle | 68 | 77 | +9 | +13.2% | +| Case 6: GGP non-null, LL GP-left | 64 | 84 | +20 | +31.2% | +| Case 6: GGP non-null, LL GP-right | 65 | 82 | +17 | +26.2% | +| Case 6: GGP non-null, RR GP-right | 66 | 79 | +13 | +19.7% | +| Case 6: GGP non-null, RR GP-left | 65 | 81 | +16 | +24.6% | +| Case 2+6: non-null new_child dir_l | 85 | 103 | +18 | +21.2% | +| Case 2+6: non-null new_child dir_r | 88 | 97 | +9 | +10.2% | +| Case 2+5+6: non-null new_child dir_l | 96 | 109 | +13 | +13.5% | +| Case 2+5+6: non-null new_child dir_r | 97 | 105 | +8 | +8.2% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 79 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 86 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 89 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 89 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 101 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 92 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 79 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 81 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 92 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 124 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 113 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 96 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 129 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 104 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 122 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index 4efa3d42..8522fefc 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,122 +1,122 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| 3-node balanced (10,5,15) | 100 | 127 | +27 | +27.0% | -| Left-skew rotation (10,5,1) | 125 | 163 | +38 | +30.4% | -| Right-skew rotation (10,15,20) | 126 | 153 | +27 | +21.4% | -| Zigzag double rotation (10,5,7) | 134 | 167 | +33 | +24.6% | -| 7-node full tree (10,5,15,3,7,12,20) | 284 | 375 | +91 | +32.0% | +| 3-node balanced (10,5,15) | 91 | 111 | +20 | +22.0% | +| Left-skew rotation (10,5,1) | 115 | 141 | +26 | +22.6% | +| Right-skew rotation (10,15,20) | 116 | 136 | +20 | +17.2% | +| Zigzag double rotation (10,5,7) | 124 | 147 | +23 | +18.5% | +| 7-node full tree (10,5,15,3,7,12,20) | 255 | 313 | +58 | +22.7% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 46 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 703c645a..60526cc4 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -301,39 +301,40 @@ unsafe fn insert( let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; + + // Root is null: new node becomes root. + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*tree_header).root = node; + return SUCCESS; + } + loop { - if cursor.is_null() { - break; - } parent = cursor; let cursor_key = (*cursor).key; if likely(key > cursor_key) { - cursor = (*cursor).child[tree::DIR_R]; + cursor = (*parent).child[tree::DIR_R]; + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*parent).child[tree::DIR_R] = node; + break; + } } else if likely(key < cursor_key) { - cursor = (*cursor).child[tree::DIR_L]; + cursor = (*parent).child[tree::DIR_L]; + if cursor.is_null() { + (*node).color = Color::Red; + (*node).parent = parent; + (*parent).child[tree::DIR_L] = node; + break; + } } else { return error::KEY_EXISTS.into(); } } // ANCHOR_END: insert-search - // ANCHOR: insert-to-tree - (*node).color = Color::Red; - (*node).parent = parent; - - // New node at root. - if parent.is_null() { - (*tree_header).root = node; - return SUCCESS; - } - // ANCHOR_END: insert-to-tree - - // ANCHOR: insert-fixup-child-dir - // Get child direction, set at parent. - let child_dir = (key > (*parent).key) as usize; - (*parent).child[child_dir] = node; - // ANCHOR_END: insert-fixup-child-dir - // ANCHOR: insert-fixup-case-1 // Main insert fixup. loop { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d47f721d..9aa0d08a 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -119,8 +119,12 @@ # Initialize instruction discriminator. .equ INSN_DISCRIMINATOR_INITIALIZE, 0 .equ INSN_DISCRIMINATOR_INSERT, 1 # Insert instruction discriminator. +.equ INSN_DISCRIMINATOR_REMOVE, 2 # Remove instruction discriminator. .equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. +.equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. +# Status value for successful remove (first non-error code). +.equ INSN_REMOVE_STATUS_OK, 14 # Init stack frame layout. # ------------------------ @@ -666,49 +670,41 @@ insert_search: # r9 ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; mov64 r2, NULL # r2 = parent = null; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; + jeq r3, NULL, insert_root insert_search_loop: - jeq r3, NULL, insert_to_tree mov64 r2, r3 # r2 = parent = cursor; ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key; jlt r4, r5, insert_search_branch_l jgt r4, r5, insert_search_branch_r mov64 r0, E_KEY_EXISTS # Error if key already exists. exit -insert_search_branch_l: - ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = cursor.child[L]; - ja insert_search_loop -insert_search_branch_r: - ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = cursor.child[R]; - ja insert_search_loop -# ANCHOR_END: insert-search -# ANCHOR: insert-to-tree -insert_to_tree: - # Flag new node as red and store parent pointer. +insert_root: + # Root is null: new node becomes root. # --------------------------------------------------------------------- stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; - stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; - - # Handle case of new node at root. - # --------------------------------------------------------------------- - jne r2, NULL, insert_get_child_dir + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = null; stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; - exit # Parent is null, new node at root. -# ANCHOR_END: insert-to-tree + exit -# ANCHOR: insert-fixup-child-dir -insert_get_child_dir: - # Get child direction, set at parent. - # --------------------------------------------------------------------- - ldxh r5, [r2 + TREE_NODE_KEY_OFF] # r5 = parent.key; - jgt r4, r5, insert_get_child_dir_branch_r -insert_get_child_dir_branch_l: +insert_search_branch_l: + ldxdw r3, [r2 + TREE_NODE_CHILD_L_OFF] # r3 = parent.child[L]; + jne r3, NULL, insert_search_loop + # Null child: insert node as left child of parent. + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; ja insert_fixup_main -insert_get_child_dir_branch_r: + +insert_search_branch_r: + ldxdw r3, [r2 + TREE_NODE_CHILD_R_OFF] # r3 = parent.child[R]; + jne r3, NULL, insert_search_loop + # Null child: insert node as right child of parent. + stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; stxdw [r2 + TREE_NODE_CHILD_R_OFF], r9 # parent.child[R] = node; -# ANCHOR_END: insert-fixup-child-dir +# ANCHOR_END: insert-search # ANCHOR: insert-fixup-case-1 insert_fixup_main: From 9ecadf3be70c23ad61ecd631bbf7afb8afd97cf9 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:03:21 -0700 Subject: [PATCH 215/263] Inline ja loop --- examples/tree/artifacts/dumps/asm.txt | 302 +++++++++--------- .../artifacts/snippets/asm/insert-search.txt | 5 +- .../tests/entrypoint_branching/result.txt | 1 + .../artifacts/tests/insert_to_tree/result.txt | 52 +-- .../artifacts/tests/multi_insert/result.txt | 22 +- examples/tree/src/tree/tree.s | 5 +- 6 files changed, 198 insertions(+), 189 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 47f1921d..9a66c373 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3400 (bytes into file) + Start of section headers 3416 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xd48 +There are 7 section headers, starting at offset 0xd58 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000ac0 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000ba8 000ba8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000c48 000c48 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000ca8 000ca8 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000ce8 000ce8 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000d18 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000ad0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000bb8 000bb8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000c58 000c58 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000cb8 000cb8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000cf8 000cf8 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000d28 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ac0 0x000ac0 R E 0x1000 - LOAD 0x000c48 0x0000000000000c48 0x0000000000000c48 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000ba8 0x0000000000000ba8 0x0000000000000ba8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ad0 0x000ad0 R E 0x1000 + LOAD 0x000c58 0x0000000000000c58 0x0000000000000c58 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000bb8 0x0000000000000bb8 0x0000000000000bb8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xba8 contains 10 entries +Dynamic section at offset 0xbb8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xce8 + 0x0000000000000011 (REL) 0xcf8 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xc48 + 0x0000000000000006 (SYMTAB) 0xc58 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xca8 + 0x0000000000000005 (STRTAB) 0xcb8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xce8 contains 3 entries +Relocation section '.rel.dyn' at offset 0xcf8 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 3a 01 01 00 00 00 if r9 != 0x1 goto +0x13a - 37 55 08 3b 01 04 00 00 00 if r8 != 0x4 goto +0x13b + 36 55 09 3c 01 01 00 00 00 if r9 != 0x1 goto +0x13c + 37 55 08 3d 01 04 00 00 00 if r8 != 0x4 goto +0x13d 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 4b 01 00 00 00 00 if r9 != 0x0 goto +0x14b + 39 55 09 4d 01 00 00 00 00 if r9 != 0x0 goto +0x14d 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 47 01 ff 00 00 00 if r9 != 0xff goto +0x147 + 41 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 43 01 00 00 00 00 if r9 != 0x0 goto +0x143 + 43 55 09 45 01 00 00 00 00 if r9 != 0x0 goto +0x145 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 3f 01 ff 00 00 00 if r9 != 0xff goto +0x13f + 45 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 3b 01 0e 00 00 00 if r9 != 0xe goto +0x13b + 47 55 09 3d 01 0e 00 00 00 if r9 != 0xe goto +0x13d 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 37 01 ff 00 00 00 if r9 != 0xff goto +0x137 + 49 55 09 39 01 ff 00 00 00 if r9 != 0xff goto +0x139 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 31 01 00 00 00 00 if r9 != r8 goto +0x131 + 53 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 2d 01 00 00 00 00 if r9 != r8 goto +0x12d + 57 5d 89 2f 01 00 00 00 00 if r9 != r8 goto +0x12f 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 29 01 00 00 00 00 if r9 != r8 goto +0x129 + 61 5d 89 2b 01 00 00 00 00 if r9 != r8 goto +0x12b 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 26 01 00 00 00 00 if r9 != r8 goto +0x126 + 64 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 19 01 00 00 00 00 if r9 != r8 goto +0x119 + 75 5d 89 1b 01 00 00 00 00 if r9 != r8 goto +0x11b 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 16 01 00 00 00 00 if r9 != r8 goto +0x116 + 78 5d 89 18 01 00 00 00 00 if r9 != r8 goto +0x118 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 13 01 00 00 00 00 if r9 != r8 goto +0x113 + 81 5d 89 15 01 00 00 00 00 if r9 != r8 goto +0x115 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 10 01 00 00 00 00 if r9 != r8 goto +0x110 + 84 5d 89 12 01 00 00 00 00 if r9 != r8 goto +0x112 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 cd 00 05 00 00 00 if r9 != 0x5 goto +0xcd - 146 a5 08 ce 00 02 00 00 00 if r8 < 0x2 goto +0xce + 145 55 09 cf 00 05 00 00 00 if r9 != 0x5 goto +0xcf + 146 a5 08 d0 00 02 00 00 00 if r8 < 0x2 goto +0xd0 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 de 00 00 00 00 00 if r9 != 0x0 goto +0xde + 148 55 09 e0 00 00 00 00 00 if r9 != 0x0 goto +0xe0 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 da 00 ff 00 00 00 if r9 != 0xff goto +0xda + 150 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 c9 00 04 00 00 00 if r8 != 0x4 goto +0xc9 + 153 55 08 cb 00 04 00 00 00 if r8 != 0x4 goto +0xcb 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 cb 00 ff 00 00 00 if r8 != 0xff goto +0xcb + 161 55 08 cd 00 ff 00 00 00 if r8 != 0xff goto +0xcd 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 c7 00 0e 00 00 00 if r8 != 0xe goto +0xc7 + 163 55 08 c9 00 0e 00 00 00 if r8 != 0xe goto +0xc9 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 c3 00 ff 00 00 00 if r8 != 0xff goto +0xc3 + 165 55 08 c5 00 ff 00 00 00 if r8 != 0xff goto +0xc5 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 bd 00 00 00 00 00 if r8 != r4 goto +0xbd + 169 5d 48 bf 00 00 00 00 00 if r8 != r4 goto +0xbf 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 b9 00 00 00 00 00 if r8 != r4 goto +0xb9 + 173 5d 48 bb 00 00 00 00 00 if r8 != r4 goto +0xbb 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 b5 00 00 00 00 00 if r8 != r4 goto +0xb5 + 177 5d 48 b7 00 00 00 00 00 if r8 != r4 goto +0xb7 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 b2 00 00 00 00 00 if r8 != r4 goto +0xb2 + 180 5d 48 b4 00 00 00 00 00 if r8 != r4 goto +0xb4 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -294,7 +294,7 @@ Disassembly of section .text 242 bf 32 00 00 00 00 00 00 r2 = r3 243 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) 244 ad 54 07 00 00 00 00 00 if r4 < r5 goto +0x7 - 245 2d 54 0c 00 00 00 00 00 if r4 > r5 goto +0xc + 245 2d 54 0e 00 00 00 00 00 if r4 > r5 goto +0xe 246 b7 00 00 00 0e 00 00 00 r0 = 0xe 247 95 00 00 00 00 00 00 00 exit 248 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 @@ -306,119 +306,121 @@ Disassembly of section .text 254 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 255 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 256 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 - 257 05 00 05 00 00 00 00 00 goto +0x5 - 258 79 23 10 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x10) - 259 55 03 ee ff 00 00 00 00 if r3 != 0x0 goto -0x12 - 260 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 - 261 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 - 262 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 - 263 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) - 264 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 - 265 95 00 00 00 00 00 00 00 exit - 266 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) - 267 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 - 268 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 269 95 00 00 00 00 00 00 00 exit - 270 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) - 271 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 - 272 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) - 273 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 274 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 275 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 - 276 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) - 277 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 278 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) - 279 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 - 280 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 281 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 282 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 - 283 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 284 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 285 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 - 286 bf 29 00 00 00 00 00 00 r9 = r2 - 287 bf 62 00 00 00 00 00 00 r2 = r6 - 288 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 289 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) - 290 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 - 291 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 292 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 293 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 - 294 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 295 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 296 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 297 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 298 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 299 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 300 05 00 03 00 00 00 00 00 goto +0x3 - 301 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 302 05 00 01 00 00 00 00 00 goto +0x1 - 303 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 304 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 305 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 306 95 00 00 00 00 00 00 00 exit - 307 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) - 308 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 309 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 310 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f - 311 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) - 312 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 313 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) - 314 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 - 315 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 316 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 317 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 - 318 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 319 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 320 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 - 321 bf 29 00 00 00 00 00 00 r9 = r2 - 322 bf 62 00 00 00 00 00 00 r2 = r6 - 323 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 324 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 325 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 - 326 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 327 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 328 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 - 329 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 330 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 331 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 332 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 333 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 334 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 335 05 00 03 00 00 00 00 00 goto +0x3 - 336 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 337 05 00 01 00 00 00 00 00 goto +0x1 - 338 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 339 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 340 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 341 95 00 00 00 00 00 00 00 exit - 342 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 343 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 - 344 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 345 bf 39 00 00 00 00 00 00 r9 = r3 - 346 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) - 347 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 - 348 95 00 00 00 00 00 00 00 exit - 349 b7 00 00 00 09 00 00 00 r0 = 0x9 + 257 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 258 55 06 09 00 00 00 00 00 if r6 != 0x0 goto +0x9 + 259 95 00 00 00 00 00 00 00 exit + 260 79 23 10 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x10) + 261 55 03 ec ff 00 00 00 00 if r3 != 0x0 goto -0x14 + 262 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 263 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 264 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 + 265 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 266 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 + 267 95 00 00 00 00 00 00 00 exit + 268 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) + 269 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 + 270 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 271 95 00 00 00 00 00 00 00 exit + 272 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) + 273 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 + 274 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) + 275 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 276 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 277 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 + 278 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) + 279 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 280 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) + 281 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 + 282 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 283 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 284 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 + 285 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 286 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 287 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 + 288 bf 29 00 00 00 00 00 00 r9 = r2 + 289 bf 62 00 00 00 00 00 00 r2 = r6 + 290 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 291 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 292 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 + 293 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 294 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 295 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 + 296 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 297 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 298 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 299 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 300 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 301 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 302 05 00 03 00 00 00 00 00 goto +0x3 + 303 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 304 05 00 01 00 00 00 00 00 goto +0x1 + 305 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 306 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 307 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 308 95 00 00 00 00 00 00 00 exit + 309 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 310 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 311 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 312 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f + 313 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 314 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 315 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 316 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 317 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 318 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 319 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 320 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 321 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 322 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 323 bf 29 00 00 00 00 00 00 r9 = r2 + 324 bf 62 00 00 00 00 00 00 r2 = r6 + 325 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 326 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 327 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 328 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 329 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 330 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 331 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 332 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 333 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 334 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 335 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 336 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 337 05 00 03 00 00 00 00 00 goto +0x3 + 338 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 339 05 00 01 00 00 00 00 00 goto +0x1 + 340 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 341 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 342 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 343 95 00 00 00 00 00 00 00 exit + 344 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 345 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 346 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 347 bf 39 00 00 00 00 00 00 r9 = r3 + 348 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 349 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 350 95 00 00 00 00 00 00 00 exit - 351 b7 00 00 00 0c 00 00 00 r0 = 0xc + 351 b7 00 00 00 09 00 00 00 r0 = 0x9 352 95 00 00 00 00 00 00 00 exit - 353 b7 00 00 00 01 00 00 00 r0 = 0x1 + 353 b7 00 00 00 0c 00 00 00 r0 = 0xc 354 95 00 00 00 00 00 00 00 exit - 355 b7 00 00 00 0d 00 00 00 r0 = 0xd + 355 b7 00 00 00 01 00 00 00 r0 = 0x1 356 95 00 00 00 00 00 00 00 exit - 357 b7 00 00 00 0a 00 00 00 r0 = 0xa + 357 b7 00 00 00 0d 00 00 00 r0 = 0xd 358 95 00 00 00 00 00 00 00 exit - 359 b7 00 00 00 08 00 00 00 r0 = 0x8 + 359 b7 00 00 00 0a 00 00 00 r0 = 0xa 360 95 00 00 00 00 00 00 00 exit - 361 b7 00 00 00 07 00 00 00 r0 = 0x7 + 361 b7 00 00 00 08 00 00 00 r0 = 0x8 362 95 00 00 00 00 00 00 00 exit - 363 b7 00 00 00 04 00 00 00 r0 = 0x4 + 363 b7 00 00 00 07 00 00 00 r0 = 0x7 364 95 00 00 00 00 00 00 00 exit - 365 b7 00 00 00 06 00 00 00 r0 = 0x6 + 365 b7 00 00 00 04 00 00 00 r0 = 0x4 366 95 00 00 00 00 00 00 00 exit - 367 b7 00 00 00 03 00 00 00 r0 = 0x3 + 367 b7 00 00 00 06 00 00 00 r0 = 0x6 368 95 00 00 00 00 00 00 00 exit - 369 b7 00 00 00 05 00 00 00 r0 = 0x5 + 369 b7 00 00 00 03 00 00 00 r0 = 0x3 370 95 00 00 00 00 00 00 00 exit - 371 b7 00 00 00 02 00 00 00 r0 = 0x2 - 372 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 371 b7 00 00 00 05 00 00 00 r0 = 0x5 + 372 95 00 00 00 00 00 00 00 exit + 373 b7 00 00 00 02 00 00 00 r0 = 0x2 + 374 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index 79fe38a9..6b43d467 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -27,7 +27,10 @@ insert_search_branch_l: stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; - ja insert_fixup_main + # Inline case 1: if parent is black, tree is valid. + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + jne r6, TREE_COLOR_B, insert_fixup_check_case_4 + exit insert_search_branch_r: ldxdw r3, [r2 + TREE_NODE_CHILD_R_OFF] # r3 = parent.child[R]; diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 02744479..5d06cfda 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -2,6 +2,7 @@ |-----------|-----------|------------|----------|------------| | Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | test tests::test_entrypoint_branching ... ok + Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index f5787975..8d4ffb0d 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,31 +1,31 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | Empty tree | 24 | 27 | +3 | +12.5% | -| Case 1: left child | 32 | 41 | +9 | +28.1% | +| Case 1: left child | 31 | 41 | +10 | +32.3% | | Case 1: right child | 32 | 40 | +8 | +25.0% | -| Case 4: left child | 35 | 44 | +9 | +25.7% | +| Case 4: left child | 34 | 44 | +10 | +29.4% | | Case 4: right child | 35 | 43 | +8 | +22.9% | -| Case 2+3: left-left | 51 | 62 | +11 | +21.6% | +| Case 2+3: left-left | 50 | 62 | +12 | +24.0% | | Case 2+3: left-right | 51 | 61 | +10 | +19.6% | -| Case 2+3: right-left | 52 | 60 | +8 | +15.4% | +| Case 2+3: right-left | 51 | 60 | +9 | +17.6% | | Case 2+3: right-right | 52 | 59 | +7 | +13.5% | -| Case 2+1: left | 58 | 71 | +13 | +22.4% | +| Case 2+1: left | 57 | 71 | +14 | +24.6% | | Case 2+1: right | 60 | 67 | +7 | +11.7% | -| Case 6: left-left null uncle | 56 | 70 | +14 | +25.0% | +| Case 6: left-left null uncle | 55 | 70 | +15 | +27.3% | | Case 6: right-right null uncle | 57 | 66 | +9 | +15.8% | -| Case 6: left-left black uncle | 58 | 72 | +14 | +24.1% | +| Case 6: left-left black uncle | 57 | 72 | +15 | +26.3% | | Case 6: right-right black uncle | 59 | 69 | +10 | +16.9% | | Case 5+6: left-right null uncle | 65 | 76 | +11 | +16.9% | -| Case 5+6: right-left null uncle | 66 | 74 | +8 | +12.1% | +| Case 5+6: right-left null uncle | 65 | 74 | +9 | +13.8% | | Case 5+6: left-right black uncle | 67 | 78 | +11 | +16.4% | -| Case 5+6: right-left black uncle | 68 | 77 | +9 | +13.2% | -| Case 6: GGP non-null, LL GP-left | 64 | 84 | +20 | +31.2% | -| Case 6: GGP non-null, LL GP-right | 65 | 82 | +17 | +26.2% | +| Case 5+6: right-left black uncle | 67 | 77 | +10 | +14.9% | +| Case 6: GGP non-null, LL GP-left | 63 | 84 | +21 | +33.3% | +| Case 6: GGP non-null, LL GP-right | 64 | 82 | +18 | +28.1% | | Case 6: GGP non-null, RR GP-right | 66 | 79 | +13 | +19.7% | | Case 6: GGP non-null, RR GP-left | 65 | 81 | +16 | +24.6% | -| Case 2+6: non-null new_child dir_l | 85 | 103 | +18 | +21.2% | +| Case 2+6: non-null new_child dir_l | 84 | 103 | +19 | +22.6% | | Case 2+6: non-null new_child dir_r | 88 | 97 | +9 | +10.2% | -| Case 2+5+6: non-null new_child dir_l | 96 | 109 | +13 | +13.5% | +| Case 2+5+6: non-null new_child dir_l | 95 | 109 | +14 | +14.7% | | Case 2+5+6: non-null new_child dir_r | 97 | 105 | +8 | +8.2% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] @@ -35,7 +35,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units @@ -47,7 +47,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units @@ -59,7 +59,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units @@ -71,7 +71,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units @@ -83,7 +83,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units @@ -95,7 +95,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units @@ -107,7 +107,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units @@ -125,7 +125,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units @@ -137,19 +137,19 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units @@ -167,7 +167,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 81 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 85 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units @@ -179,7 +179,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 96 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index 8522fefc..bdc3235c 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,16 +1,16 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| 3-node balanced (10,5,15) | 91 | 111 | +20 | +22.0% | -| Left-skew rotation (10,5,1) | 115 | 141 | +26 | +22.6% | +| 3-node balanced (10,5,15) | 90 | 111 | +21 | +23.3% | +| Left-skew rotation (10,5,1) | 113 | 141 | +28 | +24.8% | | Right-skew rotation (10,15,20) | 116 | 136 | +20 | +17.2% | -| Zigzag double rotation (10,5,7) | 124 | 147 | +23 | +18.5% | -| 7-node full tree (10,5,15,3,7,12,20) | 255 | 313 | +58 | +22.7% | +| Zigzag double rotation (10,5,7) | 123 | 147 | +24 | +19.5% | +| 7-node full tree (10,5,15,3,7,12,20) | 252 | 313 | +61 | +24.2% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units @@ -28,10 +28,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -64,7 +64,7 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units @@ -82,19 +82,19 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 9aa0d08a..9a3f2376 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -695,7 +695,10 @@ insert_search_branch_l: stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = parent; stxdw [r2 + TREE_NODE_CHILD_L_OFF], r9 # parent.child[L] = node; - ja insert_fixup_main + # Inline case 1: if parent is black, tree is valid. + ldxb r6, [r2 + TREE_NODE_COLOR_OFF] # r6 = parent.color; + jne r6, TREE_COLOR_B, insert_fixup_check_case_4 + exit insert_search_branch_r: ldxdw r3, [r2 + TREE_NODE_CHILD_R_OFF] # r3 = parent.child[R]; From 3487c9c3925717fab352980f7a8f325bbc734f08 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:08:41 -0700 Subject: [PATCH 216/263] Eliminate ja --- examples/tree/artifacts/dumps/asm.txt | 220 +++++++++--------- .../asm/insert-fixup-case-5-6-dir-l.txt | 11 +- .../asm/insert-fixup-case-5-6-dir-r.txt | 11 +- .../tests/entrypoint_branching/result.txt | 1 - .../artifacts/tests/insert_to_tree/result.txt | 16 +- examples/tree/src/tree/tree.s | 22 +- 6 files changed, 154 insertions(+), 127 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 9a66c373..2cfedfb2 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3416 (bytes into file) + Start of section headers 3480 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xd58 +There are 7 section headers, starting at offset 0xd98 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000ad0 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000bb8 000bb8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000c58 000c58 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000cb8 000cb8 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000cf8 000cf8 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000d28 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000b10 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000bf8 000bf8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000c98 000c98 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000cf8 000cf8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000d38 000d38 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000d68 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000ad0 0x000ad0 R E 0x1000 - LOAD 0x000c58 0x0000000000000c58 0x0000000000000c58 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000bb8 0x0000000000000bb8 0x0000000000000bb8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000b10 0x000b10 R E 0x1000 + LOAD 0x000c98 0x0000000000000c98 0x0000000000000c98 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000bf8 0x0000000000000bf8 0x0000000000000bf8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xbb8 contains 10 entries +Dynamic section at offset 0xbf8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xcf8 + 0x0000000000000011 (REL) 0xd38 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xc58 + 0x0000000000000006 (SYMTAB) 0xc98 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xcb8 + 0x0000000000000005 (STRTAB) 0xcf8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xcf8 contains 3 entries +Relocation section '.rel.dyn' at offset 0xd38 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -91,32 +91,32 @@ Disassembly of section .text 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 34 b7 00 00 00 0b 00 00 00 r0 = 0xb 35 95 00 00 00 00 00 00 00 exit - 36 55 09 3c 01 01 00 00 00 if r9 != 0x1 goto +0x13c - 37 55 08 3d 01 04 00 00 00 if r8 != 0x4 goto +0x13d + 36 55 09 44 01 01 00 00 00 if r9 != 0x1 goto +0x144 + 37 55 08 45 01 04 00 00 00 if r8 != 0x4 goto +0x145 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 4d 01 00 00 00 00 if r9 != 0x0 goto +0x14d + 39 55 09 55 01 00 00 00 00 if r9 != 0x0 goto +0x155 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 + 41 55 09 51 01 ff 00 00 00 if r9 != 0xff goto +0x151 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 45 01 00 00 00 00 if r9 != 0x0 goto +0x145 + 43 55 09 4d 01 00 00 00 00 if r9 != 0x0 goto +0x14d 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 + 45 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 3d 01 0e 00 00 00 if r9 != 0xe goto +0x13d + 47 55 09 45 01 0e 00 00 00 if r9 != 0xe goto +0x145 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 39 01 ff 00 00 00 if r9 != 0xff goto +0x139 + 49 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 + 53 5d 89 3b 01 00 00 00 00 if r9 != r8 goto +0x13b 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 2f 01 00 00 00 00 if r9 != r8 goto +0x12f + 57 5d 89 37 01 00 00 00 00 if r9 != r8 goto +0x137 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 2b 01 00 00 00 00 if r9 != r8 goto +0x12b + 61 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 + 64 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 65 b7 02 00 00 00 00 00 00 r2 = 0x0 66 bf 13 00 00 00 00 00 00 r3 = r1 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -127,16 +127,16 @@ Disassembly of section .text 72 85 10 00 00 ff ff ff ff call -0x1 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 1b 01 00 00 00 00 if r9 != r8 goto +0x11b + 75 5d 89 23 01 00 00 00 00 if r9 != r8 goto +0x123 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 18 01 00 00 00 00 if r9 != r8 goto +0x118 + 78 5d 89 20 01 00 00 00 00 if r9 != r8 goto +0x120 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 15 01 00 00 00 00 if r9 != r8 goto +0x115 + 81 5d 89 1d 01 00 00 00 00 if r9 != r8 goto +0x11d 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 12 01 00 00 00 00 if r9 != r8 goto +0x112 + 84 5d 89 1a 01 00 00 00 00 if r9 != r8 goto +0x11a 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -197,15 +197,15 @@ Disassembly of section .text 142 07 07 00 00 18 00 00 00 r7 += 0x18 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 144 95 00 00 00 00 00 00 00 exit - 145 55 09 cf 00 05 00 00 00 if r9 != 0x5 goto +0xcf - 146 a5 08 d0 00 02 00 00 00 if r8 < 0x2 goto +0xd0 + 145 55 09 d7 00 05 00 00 00 if r9 != 0x5 goto +0xd7 + 146 a5 08 d8 00 02 00 00 00 if r8 < 0x2 goto +0xd8 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 e0 00 00 00 00 00 if r9 != 0x0 goto +0xe0 + 148 55 09 e8 00 00 00 00 00 if r9 != 0x0 goto +0xe8 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 dc 00 ff 00 00 00 if r9 != 0xff goto +0xdc + 150 55 09 e4 00 ff 00 00 00 if r9 != 0xff goto +0xe4 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 cb 00 04 00 00 00 if r8 != 0x4 goto +0xcb + 153 55 08 d3 00 04 00 00 00 if r8 != 0x4 goto +0xd3 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 156 bf 97 00 00 00 00 00 00 r7 = r9 @@ -213,23 +213,23 @@ Disassembly of section .text 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 159 0f 19 00 00 00 00 00 00 r9 += r1 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 cd 00 ff 00 00 00 if r8 != 0xff goto +0xcd + 161 55 08 d5 00 ff 00 00 00 if r8 != 0xff goto +0xd5 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 c9 00 0e 00 00 00 if r8 != 0xe goto +0xc9 + 163 55 08 d1 00 0e 00 00 00 if r8 != 0xe goto +0xd1 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 c5 00 ff 00 00 00 if r8 != 0xff goto +0xc5 + 165 55 08 cd 00 ff 00 00 00 if r8 != 0xff goto +0xcd 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 bf 00 00 00 00 00 if r8 != r4 goto +0xbf + 169 5d 48 c7 00 00 00 00 00 if r8 != r4 goto +0xc7 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 bb 00 00 00 00 00 if r8 != r4 goto +0xbb + 173 5d 48 c3 00 00 00 00 00 if r8 != r4 goto +0xc3 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 b7 00 00 00 00 00 if r8 != r4 goto +0xb7 + 177 5d 48 bf 00 00 00 00 00 if r8 != r4 goto +0xbf 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 b4 00 00 00 00 00 if r8 != r4 goto +0xb4 + 180 5d 48 bc 00 00 00 00 00 if r8 != r4 goto +0xbc 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -322,11 +322,11 @@ Disassembly of section .text 270 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 271 95 00 00 00 00 00 00 00 exit 272 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) - 273 2d 45 23 00 00 00 00 00 if r5 > r4 goto +0x23 + 273 2d 45 27 00 00 00 00 00 if r5 > r4 goto +0x27 274 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) 275 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 276 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 277 55 08 42 00 00 00 00 00 if r8 != 0x0 goto +0x42 + 277 55 08 4a 00 00 00 00 00 if r8 != 0x0 goto +0x4a 278 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) 279 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa 280 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) @@ -347,80 +347,88 @@ Disassembly of section .text 295 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 296 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 297 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 298 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 + 298 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa 299 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 300 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 + 300 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 301 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 302 05 00 03 00 00 00 00 00 goto +0x3 - 303 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 304 05 00 01 00 00 00 00 00 goto +0x1 - 305 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 302 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 303 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 304 95 00 00 00 00 00 00 00 exit + 305 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 306 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 307 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 308 95 00 00 00 00 00 00 00 exit - 309 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) - 310 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 311 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 312 55 08 1f 00 00 00 00 00 if r8 != 0x0 goto +0x1f - 313 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) - 314 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 315 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) - 316 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 - 317 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 318 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 319 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 - 320 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 321 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 322 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 - 323 bf 29 00 00 00 00 00 00 r9 = r2 - 324 bf 62 00 00 00 00 00 00 r2 = r6 - 325 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 326 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 327 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 - 328 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 329 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 330 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 - 331 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 332 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 333 15 04 06 00 00 00 00 00 if r4 == 0x0 goto +0x6 - 334 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 335 5d 83 02 00 00 00 00 00 if r3 != r8 goto +0x2 - 336 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 337 05 00 03 00 00 00 00 00 goto +0x3 - 338 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 339 05 00 01 00 00 00 00 00 goto +0x1 - 340 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 309 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 310 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 311 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 312 95 00 00 00 00 00 00 00 exit + 313 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 314 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 315 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 316 55 08 23 00 00 00 00 00 if r8 != 0x0 goto +0x23 + 317 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 318 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 319 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 320 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 321 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 322 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 323 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 324 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 325 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 326 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 327 bf 29 00 00 00 00 00 00 r9 = r2 + 328 bf 62 00 00 00 00 00 00 r2 = r6 + 329 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 330 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 331 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 332 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 333 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 334 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 335 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 336 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 337 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa + 338 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 339 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 + 340 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 341 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 342 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 343 95 00 00 00 00 00 00 00 exit - 344 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 345 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 344 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 345 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 346 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 347 bf 39 00 00 00 00 00 00 r9 = r3 - 348 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) - 349 55 02 ab ff 00 00 00 00 if r2 != 0x0 goto -0x55 - 350 95 00 00 00 00 00 00 00 exit - 351 b7 00 00 00 09 00 00 00 r0 = 0x9 - 352 95 00 00 00 00 00 00 00 exit - 353 b7 00 00 00 0c 00 00 00 r0 = 0xc - 354 95 00 00 00 00 00 00 00 exit - 355 b7 00 00 00 01 00 00 00 r0 = 0x1 - 356 95 00 00 00 00 00 00 00 exit - 357 b7 00 00 00 0d 00 00 00 r0 = 0xd + 347 95 00 00 00 00 00 00 00 exit + 348 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 349 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 350 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 351 95 00 00 00 00 00 00 00 exit + 352 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 353 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 354 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 355 bf 39 00 00 00 00 00 00 r9 = r3 + 356 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 357 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d 358 95 00 00 00 00 00 00 00 exit - 359 b7 00 00 00 0a 00 00 00 r0 = 0xa + 359 b7 00 00 00 09 00 00 00 r0 = 0x9 360 95 00 00 00 00 00 00 00 exit - 361 b7 00 00 00 08 00 00 00 r0 = 0x8 + 361 b7 00 00 00 0c 00 00 00 r0 = 0xc 362 95 00 00 00 00 00 00 00 exit - 363 b7 00 00 00 07 00 00 00 r0 = 0x7 + 363 b7 00 00 00 01 00 00 00 r0 = 0x1 364 95 00 00 00 00 00 00 00 exit - 365 b7 00 00 00 04 00 00 00 r0 = 0x4 + 365 b7 00 00 00 0d 00 00 00 r0 = 0xd 366 95 00 00 00 00 00 00 00 exit - 367 b7 00 00 00 06 00 00 00 r0 = 0x6 + 367 b7 00 00 00 0a 00 00 00 r0 = 0xa 368 95 00 00 00 00 00 00 00 exit - 369 b7 00 00 00 03 00 00 00 r0 = 0x3 + 369 b7 00 00 00 08 00 00 00 r0 = 0x8 370 95 00 00 00 00 00 00 00 exit - 371 b7 00 00 00 05 00 00 00 r0 = 0x5 + 371 b7 00 00 00 07 00 00 00 r0 = 0x7 372 95 00 00 00 00 00 00 00 exit - 373 b7 00 00 00 02 00 00 00 r0 = 0x2 - 374 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 373 b7 00 00 00 04 00 00 00 r0 = 0x4 + 374 95 00 00 00 00 00 00 00 exit + 375 b7 00 00 00 06 00 00 00 r0 = 0x6 + 376 95 00 00 00 00 00 00 00 exit + 377 b7 00 00 00 03 00 00 00 r0 = 0x3 + 378 95 00 00 00 00 00 00 00 exit + 379 b7 00 00 00 05 00 00 00 r0 = 0x5 + 380 95 00 00 00 00 00 00 00 exit + 381 b7 00 00 00 02 00 00 00 r0 = 0x2 + 382 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt index f7f5f861..c57fb729 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-l.txt @@ -40,14 +40,19 @@ insert_fixup_case_6_dir_l_skip: jeq r4, NULL, insert_fixup_case_6_dir_l_root ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; jne r3, r8, insert_fixup_case_6_dir_l_left + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_l_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_l_left: + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_l_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_l_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_l_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt index 86e9c014..5fa3a39e 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-5-6-dir-r.txt @@ -34,14 +34,19 @@ insert_fixup_case_6_dir_r_skip: jeq r4, NULL, insert_fixup_case_6_dir_r_root ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; jne r3, r8, insert_fixup_case_6_dir_r_left + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_r_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_r_left: + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_r_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_r_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_r_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 5d06cfda..02744479 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -2,7 +2,6 @@ |-----------|-----------|------------|----------|------------| | Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | test tests::test_entrypoint_branching ... ok - Blocking waiting for file lock on build directory [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 8d4ffb0d..90a9ed6d 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -19,10 +19,10 @@ | Case 5+6: right-left null uncle | 65 | 74 | +9 | +13.8% | | Case 5+6: left-right black uncle | 67 | 78 | +11 | +16.4% | | Case 5+6: right-left black uncle | 67 | 77 | +10 | +14.9% | -| Case 6: GGP non-null, LL GP-left | 63 | 84 | +21 | +33.3% | -| Case 6: GGP non-null, LL GP-right | 64 | 82 | +18 | +28.1% | -| Case 6: GGP non-null, RR GP-right | 66 | 79 | +13 | +19.7% | -| Case 6: GGP non-null, RR GP-left | 65 | 81 | +16 | +24.6% | +| Case 6: GGP non-null, LL GP-left | 62 | 84 | +22 | +35.5% | +| Case 6: GGP non-null, LL GP-right | 63 | 82 | +19 | +30.2% | +| Case 6: GGP non-null, RR GP-right | 65 | 79 | +14 | +21.5% | +| Case 6: GGP non-null, RR GP-left | 64 | 81 | +17 | +26.6% | | Case 2+6: non-null new_child dir_l | 84 | 103 | +19 | +22.6% | | Case 2+6: non-null new_child dir_r | 88 | 97 | +9 | +10.2% | | Case 2+5+6: non-null new_child dir_l | 95 | 109 | +14 | +14.7% | @@ -143,25 +143,25 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 79 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 81 of 1400000 compute units diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 9a3f2376..dcb7278d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -773,14 +773,19 @@ insert_fixup_case_6_dir_l_skip: jeq r4, NULL, insert_fixup_case_6_dir_l_root ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; jne r3, r8, insert_fixup_case_6_dir_l_left + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_l_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_l_left: + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_l_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_l_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_l_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit @@ -823,14 +828,19 @@ insert_fixup_case_6_dir_r_skip: jeq r4, NULL, insert_fixup_case_6_dir_r_root ldxdw r8, [r4 + TREE_NODE_CHILD_R_OFF] # r8 = great-grandparent.child[R]; jne r3, r8, insert_fixup_case_6_dir_r_left + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_R_OFF], r2 # great-grandparent.child[R] = parent; - ja insert_fixup_case_6_dir_r_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_r_left: + # Inline color + exit to eliminate `ja` (saves 1 CU). stxdw [r4 + TREE_NODE_CHILD_L_OFF], r2 # great-grandparent.child[L] = parent; - ja insert_fixup_case_6_dir_r_color + stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; + exit insert_fixup_case_6_dir_r_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r2 # tree.root = parent; -insert_fixup_case_6_dir_r_color: stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r3 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # grandparent.color = red; exit From fc3b90c144f8a6001b0bcc2a0b853cd08a0d366b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:14:20 -0700 Subject: [PATCH 217/263] REbuild exmaples --- examples/tree/artifacts/dumps/rs.txt | 707 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 66 +- .../rs/insert-fixup-case-5-6-dir-l.txt | 7 +- .../rs/insert-fixup-case-5-6-dir-r.txt | 7 +- .../artifacts/tests/insert_to_tree/result.txt | 40 +- .../artifacts/tests/multi_insert/result.txt | 8 +- examples/tree/src/program.rs | 20 +- 7 files changed, 435 insertions(+), 420 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index c034496b..67630e49 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 5800 (bytes into file) + Start of section headers 5792 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x16a8 +There are 8 section headers, starting at offset 0x16a0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000c98 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000db8 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000dc0 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000dc0 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000dc0 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001138 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 001176 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000c90 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000db0 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000db8 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000db8 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000db8 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001130 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00116e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000c98 0x000c98 E 0x8 - LOAD 0x000db8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000dc0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000dc0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000c90 0x000c90 E 0x8 + LOAD 0x000db0 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000db8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000db8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3224 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3216 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -108,23 +108,23 @@ Disassembly of section .text 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 eb 00 01 00 00 00 jne r5, 0x1, +0xeb - 28 55 03 75 01 05 00 00 00 jne r3, 0x5, +0x175 - 30 a5 04 76 01 02 00 00 00 jlt r4, 0x2, +0x176 + 20 55 05 ea 00 01 00 00 00 jne r5, 0x1, +0xea + 28 55 03 74 01 05 00 00 00 jne r3, 0x5, +0x174 + 30 a5 04 75 01 02 00 00 00 jlt r4, 0x2, +0x175 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 76 01 00 00 00 00 jne r3, 0x0, +0x176 + 40 55 03 75 01 00 00 00 00 jne r3, 0x0, +0x175 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 76 01 ff 00 00 00 jne r3, 0xff, +0x176 + 50 55 03 75 01 ff 00 00 00 jne r3, 0xff, +0x175 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 70 15 03 3c 00 00 00 00 00 jeq r3, 0x0, +0x3c + 70 15 03 3f 00 00 00 00 00 jeq r3, 0x0, +0x3f 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 98 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - a0 15 04 a2 00 00 00 00 00 jeq r4, 0x0, +0xa2 + a0 15 04 a5 00 00 00 00 00 jeq r4, 0x0, +0xa5 a8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] b0 bf 42 00 00 00 00 00 00 mov64 r2, r4 b8 3c 24 18 00 00 00 00 00 ldxh w4, [r2 + 0x18] @@ -133,7 +133,7 @@ Disassembly of section .text d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 e0 05 00 05 00 00 00 00 00 ja +0x5 - e8 3d 45 6d 01 00 00 00 00 jge r5, r4, +0x16d + e8 3d 45 6c 01 00 00 00 00 jge r5, r4, +0x16c f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa 100 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 @@ -151,23 +151,23 @@ Disassembly of section .text 160 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 168 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] 170 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 178 15 02 a5 00 00 00 00 00 jeq r2, 0x0, +0xa5 + 178 15 02 a4 00 00 00 00 00 jeq r2, 0x0, +0xa4 180 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] - 188 15 01 a3 00 00 00 00 00 jeq r1, 0x0, +0xa3 + 188 15 01 a2 00 00 00 00 00 jeq r1, 0x0, +0xa2 190 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] - 198 15 01 a0 00 00 00 00 00 jeq r1, 0x0, +0xa0 + 198 15 01 9f 00 00 00 00 00 jeq r1, 0x0, +0x9f 1a0 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] 1a8 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 - 1b0 15 04 85 00 00 00 00 00 jeq r4, 0x0, +0x85 + 1b0 15 04 88 00 00 00 00 00 jeq r4, 0x0, +0x88 1b8 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] 1c0 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf - 1c8 05 00 82 00 00 00 00 00 ja +0x82 + 1c8 05 00 85 00 00 00 00 00 ja +0x85 1d0 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] 1d8 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 1e0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] 1e8 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 1f0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] - 1f8 1d 43 a3 00 00 00 00 00 jeq r3, r4, +0xa3 + 1f8 1d 43 a2 00 00 00 00 00 jeq r3, r4, +0xa2 200 bf 43 00 00 00 00 00 00 mov64 r3, r4 208 bf 24 00 00 00 00 00 00 mov64 r4, r2 210 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 @@ -177,333 +177,332 @@ Disassembly of section .text 230 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 238 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 240 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 248 55 02 7e 00 00 00 00 00 jne r2, 0x0, +0x7e - 250 05 00 85 00 00 00 00 00 ja +0x85 - 258 55 04 3b 01 04 00 00 00 jne r4, 0x4, +0x13b - 260 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 268 bf 35 00 00 00 00 00 00 mov64 r5, r3 - 270 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 278 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - 280 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 288 0f 54 00 00 00 00 00 00 add64 r4, r5 - 290 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 298 55 05 2f 01 ff 00 00 00 jne r5, 0xff, +0x12f - 2a0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2a8 55 05 2f 01 0e 00 00 00 jne r5, 0xe, +0x12f - 2b0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2b8 55 05 31 01 ff 00 00 00 jne r5, 0xff, +0x131 - 2c0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 2c8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 2d0 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 2d8 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] - 2e0 5d 57 78 00 00 00 00 00 jne r7, r5, +0x78 - 2e8 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 2f0 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 2f8 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] - 300 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 - 308 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 310 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 318 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] - 320 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 - 328 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 330 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 338 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 340 5d 52 6c 00 00 00 00 00 jne r2, r5, +0x6c - 348 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 350 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 358 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 - 360 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 - 368 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 370 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 378 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 - 380 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 388 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 390 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 - 398 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 - 3a0 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 - 3a8 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 3b0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3b8 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 - 3c0 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 - 3c8 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 - 3d0 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 3d8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 3e0 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 3e8 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 - 3f0 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 3f8 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 400 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 248 15 02 85 00 00 00 00 00 jeq r2, 0x0, +0x85 + 250 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] + 258 5d 31 81 00 00 00 00 00 jne r1, r3, +0x81 + 260 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 268 05 00 80 00 00 00 00 00 ja +0x80 + 270 55 04 37 01 04 00 00 00 jne r4, 0x4, +0x137 + 278 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 280 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 288 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 290 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 298 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 2a0 0f 54 00 00 00 00 00 00 add64 r4, r5 + 2a8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 2b0 55 05 2b 01 ff 00 00 00 jne r5, 0xff, +0x12b + 2b8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2c0 55 05 2b 01 0e 00 00 00 jne r5, 0xe, +0x12b + 2c8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2d0 55 05 2d 01 ff 00 00 00 jne r5, 0xff, +0x12d + 2d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 2e0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 2e8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 2f0 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 2f8 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 + 300 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 308 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 310 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 318 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 + 320 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 328 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 330 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 338 5d 57 6c 00 00 00 00 00 jne r7, r5, +0x6c + 340 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 348 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 350 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 358 5d 52 68 00 00 00 00 00 jne r2, r5, +0x68 + 360 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 368 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 370 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 + 378 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 380 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 388 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 390 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 398 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 3a0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 3a8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 + 3b0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 + 3b8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 3c0 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3c8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3d0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 + 3d8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 + 3e0 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 3e8 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 3f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 3f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 400 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 408 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 410 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 418 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 410 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 418 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 420 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 428 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 430 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 438 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 440 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 448 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 - 450 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 458 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 460 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 468 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 470 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 478 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 - 480 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 488 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 - 490 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 - 498 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4a0 07 02 00 00 30 01 00 00 add64 r2, 0x130 - 4a8 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 428 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 430 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 438 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 440 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 448 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 450 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 458 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 460 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 + 468 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 470 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 478 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 480 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 488 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 490 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 + 498 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 4a0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 + 4a8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 4b0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4b8 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 - 4c0 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4b8 07 02 00 00 30 01 00 00 add64 r2, 0x130 + 4c0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 4c8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d0 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 - 4d8 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 - 4e0 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc - 4e8 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 - 4f0 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 - 4f8 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 - 500 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 508 07 03 00 00 10 00 00 00 add64 r3, 0x10 - 510 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 518 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 520 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 528 07 04 00 00 48 00 00 00 add64 r4, 0x48 - 530 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 538 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 540 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 548 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 550 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 558 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 560 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 568 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 - 570 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] - 578 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 580 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 588 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - 590 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 598 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] - 5a0 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 5a8 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - 5b0 55 04 5e ff 00 00 00 00 jne r4, 0x0, -0xa2 - 5b8 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 - 5c0 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 5c8 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 - 5d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 5d8 05 00 19 00 00 00 00 00 ja +0x19 - 5e0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] - 5e8 1d 43 18 00 00 00 00 00 jeq r3, r4, +0x18 - 5f0 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 5f8 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 600 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 608 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 610 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 618 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 620 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 628 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 - 630 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 638 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 - 640 9c 25 10 00 00 00 00 00 ldxdw r5, [r2 + 0x10] - 648 b4 03 00 00 01 00 00 00 mov32 w3, 0x1 - 650 1d 51 01 00 00 00 00 00 jeq r1, r5, +0x1 - 658 b4 03 00 00 00 00 00 00 mov32 w3, 0x0 - 660 67 03 00 00 03 00 00 00 lsh64 r3, 0x3 - 668 0f 32 00 00 00 00 00 00 add64 r2, r3 - 670 07 02 00 00 08 00 00 00 add64 r2, 0x8 - 678 bf 26 00 00 00 00 00 00 mov64 r6, r2 - 680 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 - 688 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 690 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 698 05 00 01 00 00 00 00 00 ja +0x1 - 6a0 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 6a8 9d 00 00 00 00 00 00 00 return - 6b0 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 6b8 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 - 6c0 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 6c8 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 6d0 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 6d8 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 - 6e0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 6e8 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 - 6f0 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 6f8 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 700 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 708 55 03 e1 ff 00 00 00 00 jne r3, 0x0, -0x1f - 710 05 00 e1 ff 00 00 00 00 ja -0x1f - 718 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 720 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 - 728 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 730 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 738 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 740 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 - 748 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 750 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 - 758 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 760 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 - 768 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 770 55 03 56 ff 00 00 00 00 jne r3, 0x0, -0xaa - 778 05 00 56 ff 00 00 00 00 ja -0xaa - 780 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e - 788 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 790 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 798 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 7a0 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 7a8 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 7b0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7b8 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 7c0 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 - 7c8 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 7d0 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 7d8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 7e0 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 7e8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 7f0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 800 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 808 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 810 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 818 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f - 820 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 828 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 830 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 838 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 - 840 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 848 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 850 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 858 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 - 860 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 868 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 870 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a - 878 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 880 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 888 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 890 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 898 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 8a0 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 8a8 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 8b0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 8b8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 8c0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 8c8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 8d0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 8d8 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 - 8e0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 8e8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 8f0 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 8f8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 900 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 908 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b - 910 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 918 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 920 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 - 928 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 930 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 938 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 940 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 948 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - 950 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 958 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - 960 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 968 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - 970 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 978 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - 980 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 988 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - 990 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - 998 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - 9a0 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 9a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 9b0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 9b8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 9c0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 9c8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 9d0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 9d8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 9e0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 9e8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 9f0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 9f8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - a00 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a08 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - a10 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - a18 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - a20 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a28 07 01 00 00 30 00 00 00 add64 r1, 0x30 - a30 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - a38 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a40 07 01 00 00 60 00 00 00 add64 r1, 0x60 - a48 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - a50 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a58 07 01 00 00 50 00 00 00 add64 r1, 0x50 - a60 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - a68 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - a70 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - a78 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - a80 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - a88 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - a90 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - a98 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - aa0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - aa8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - ab0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - ab8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - ac0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - ac8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - ad0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ad8 07 01 00 00 10 00 00 00 add64 r1, 0x10 - ae0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - ae8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - af0 07 01 00 00 48 00 00 00 add64 r1, 0x48 - af8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - b00 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b08 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - b10 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - b18 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - b20 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - b28 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b30 07 01 00 00 0f 00 00 00 add64 r1, 0xf - b38 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - b40 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - b48 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b50 07 01 00 00 20 01 00 00 add64 r1, 0x120 - b58 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - b60 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - b68 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b70 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - b78 bf a2 00 00 00 00 00 00 mov64 r2, r10 - b80 07 02 00 00 68 00 00 00 add64 r2, 0x68 - b88 bf a4 00 00 00 00 00 00 mov64 r4, r10 - b90 07 04 00 00 30 01 00 00 add64 r4, 0x130 - b98 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - ba0 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - ba8 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - bb0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - bb8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - bc0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - bc8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - bd0 05 00 5a ff 00 00 00 00 ja -0xa6 - bd8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - be0 05 00 58 ff 00 00 00 00 ja -0xa8 - be8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - bf0 05 00 56 ff 00 00 00 00 ja -0xaa - bf8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c00 05 00 54 ff 00 00 00 00 ja -0xac - c08 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - c10 05 00 52 ff 00 00 00 00 ja -0xae - c18 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - c20 05 00 50 ff 00 00 00 00 ja -0xb0 - c28 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - c30 05 00 4e ff 00 00 00 00 ja -0xb2 - c38 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - c40 05 00 4c ff 00 00 00 00 ja -0xb4 - c48 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - c50 05 00 4a ff 00 00 00 00 ja -0xb6 - c58 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - c60 05 00 48 ff 00 00 00 00 ja -0xb8 - c68 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - c70 05 00 46 ff 00 00 00 00 ja -0xba - c78 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - c80 05 00 44 ff 00 00 00 00 ja -0xbc - c88 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - c90 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file + 4d0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 + 4d8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4e0 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 4e8 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 + 4f0 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 + 4f8 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc + 500 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 + 508 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 + 510 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 518 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 520 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 528 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 530 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 538 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 540 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 548 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 550 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 558 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 560 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 568 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 570 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 578 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 580 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 588 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] + 590 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 598 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 5a0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 5a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 5b0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5b8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5c0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + 5c8 55 04 5b ff 00 00 00 00 jne r4, 0x0, -0xa5 + 5d0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5d8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 5e0 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 + 5e8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 5f0 05 00 15 00 00 00 00 00 ja +0x15 + 5f8 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] + 600 1d 43 14 00 00 00 00 00 jeq r3, r4, +0x14 + 608 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 610 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 618 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 620 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 628 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 630 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 638 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 640 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 + 648 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 650 15 02 04 00 00 00 00 00 jeq r2, 0x0, +0x4 + 658 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] + 660 1d 31 7f ff 00 00 00 00 jeq r1, r3, -0x81 + 668 07 02 00 00 08 00 00 00 add64 r2, 0x8 + 670 bf 26 00 00 00 00 00 00 mov64 r6, r2 + 678 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + 680 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 688 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 690 05 00 01 00 00 00 00 00 ja +0x1 + 698 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 6a0 9d 00 00 00 00 00 00 00 return + 6a8 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 6b0 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 + 6b8 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 6c0 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 6c8 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 6d0 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 + 6d8 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 6e0 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 + 6e8 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 6f0 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 6f8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 700 55 03 e5 ff 00 00 00 00 jne r3, 0x0, -0x1b + 708 05 00 e5 ff 00 00 00 00 ja -0x1b + 710 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 718 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 + 720 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 728 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 730 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 738 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 + 740 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 748 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 + 750 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 758 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 760 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 768 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 + 770 05 00 57 ff 00 00 00 00 ja -0xa9 + 778 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e + 780 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 788 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 790 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 798 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 7a0 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 7a8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7b0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 7b8 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 + 7c0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 7c8 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 7d0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 7d8 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 7e0 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 7e8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 7f8 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 800 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 808 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 810 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f + 818 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 820 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 828 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 830 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 + 838 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 840 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 848 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 850 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 + 858 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 860 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 868 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a + 870 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 878 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 880 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 888 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 890 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 898 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 8a0 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 8a8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 8b0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 8b8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 8c0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 8c8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 8d0 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 + 8d8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 8e0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 8e8 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 8f0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 8f8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 900 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b + 908 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 910 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 918 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 + 920 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 928 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 930 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 938 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 940 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + 948 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 950 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + 958 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 960 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + 968 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 970 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + 978 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 980 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + 988 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + 990 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + 998 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 9a0 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 9a8 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 9b0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 9b8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 9c0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + 9c8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 9d0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 9d8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 9e0 bf 73 00 00 00 00 00 00 mov64 r3, r7 + 9e8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 9f0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 9f8 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a00 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + a08 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + a10 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + a18 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a20 07 01 00 00 30 00 00 00 add64 r1, 0x30 + a28 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + a30 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a38 07 01 00 00 60 00 00 00 add64 r1, 0x60 + a40 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + a48 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a50 07 01 00 00 50 00 00 00 add64 r1, 0x50 + a58 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + a60 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + a68 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + a70 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + a78 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + a80 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + a88 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + a90 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + a98 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + aa0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + aa8 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + ab0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + ab8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + ac0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + ac8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + ad0 07 01 00 00 10 00 00 00 add64 r1, 0x10 + ad8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + ae0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + ae8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + af0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + af8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b00 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + b08 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + b10 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + b18 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + b20 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b28 07 01 00 00 0f 00 00 00 add64 r1, 0xf + b30 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + b38 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + b40 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b48 07 01 00 00 20 01 00 00 add64 r1, 0x120 + b50 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + b58 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + b60 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b68 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + b70 bf a2 00 00 00 00 00 00 mov64 r2, r10 + b78 07 02 00 00 68 00 00 00 add64 r2, 0x68 + b80 bf a4 00 00 00 00 00 00 mov64 r4, r10 + b88 07 04 00 00 30 01 00 00 add64 r4, 0x130 + b90 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + b98 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + ba0 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + ba8 bf 71 00 00 00 00 00 00 mov64 r1, r7 + bb0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + bb8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + bc0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + bc8 05 00 5a ff 00 00 00 00 ja -0xa6 + bd0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + bd8 05 00 58 ff 00 00 00 00 ja -0xa8 + be0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + be8 05 00 56 ff 00 00 00 00 ja -0xaa + bf0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + bf8 05 00 54 ff 00 00 00 00 ja -0xac + c00 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + c08 05 00 52 ff 00 00 00 00 ja -0xae + c10 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + c18 05 00 50 ff 00 00 00 00 ja -0xb0 + c20 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + c28 05 00 4e ff 00 00 00 00 ja -0xb2 + c30 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + c38 05 00 4c ff 00 00 00 00 ja -0xb4 + c40 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + c48 05 00 4a ff 00 00 00 00 ja -0xb6 + c50 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + c58 05 00 48 ff 00 00 00 00 ja -0xb8 + c60 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + c68 05 00 46 ff 00 00 00 00 ja -0xba + c70 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + c78 05 00 44 ff 00 00 00 00 ja -0xbc + c80 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + c88 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 0c9b1aab..e24e2c9f 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -15,13 +15,13 @@ entrypoint: mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] - jeq r3, 0, jmp_0260 + jeq r3, 0, jmp_0270 ldxdw r4, [r3+0] stxdw [r1+10440], r4 ldxw r1, [r2+1] stxw [r3+24], r1 ldxdw r4, [r6+0] - jeq r4, 0, jmp_05c0 + jeq r4, 0, jmp_05d0 jmp_00a8: ldxh r1, [r2+1] @@ -66,13 +66,13 @@ jmp_0180: ldxb r1, [r2+28] jeq r1, 0, jmp_06a0 ldxdw r1, [r2+0] - jeq r1, 0, jmp_0698 + jeq r1, 0, jmp_0678 ldxdw r4, [r1+8] jeq r2, r4, jmp_01d0 - jeq r4, 0, jmp_05e8 + jeq r4, 0, jmp_05f8 ldxb r5, [r4+28] jne r5, 0, jmp_0150 - ja jmp_05e8 + ja jmp_05f8 jmp_01d0: ldxdw r4, [r1+16] @@ -96,13 +96,15 @@ jmp_0230: stxdw [r4+0], r2 stxdw [r4+16], r1 stxdw [r1+0], r4 - jne r2, 0, jmp_0648 - -jmp_0250: - stxdw [r6+0], r4 - ja jmp_0680 + jeq r2, 0, jmp_0688 + ldxdw r3, [r2+16] + jne r1, r3, jmp_0668 jmp_0260: + stxdw [r2+16], r4 + ja jmp_0690 + +jmp_0270: jne r4, 4, jmp_0c30 ldxdw r3, [r1+10424] mov64 r5, r3 @@ -212,51 +214,49 @@ jmp_0260: ldxdw r4, [r6+0] jne r4, 0, jmp_00a8 -jmp_05c0: +jmp_05d0: stdw [r3+0], 0 stb [r3+28], 1 stxdw [r6+0], r3 -jmp_05d8: +jmp_05e8: mov64 r0, 0 ja jmp_06a0 -jmp_05e8: +jmp_05f8: ldxdw r4, [r2+8] jeq r3, r4, jmp_06a8 mov64 r3, r4 mov64 r4, r2 stxdw [r1+16], r3 ldxdw r2, [r1+0] - jeq r3, 0, jmp_0628 + jeq r3, 0, jmp_0638 -jmp_0620: +jmp_0630: stxdw [r3+0], r1 -jmp_0628: +jmp_0638: stxdw [r4+0], r2 stxdw [r4+8], r1 stxdw [r1+0], r4 - jeq r2, 0, jmp_0250 - -jmp_0648: - ldxdw r5, [r2+16] - mov32 r3, 1 - jeq r1, r5, jmp_0668 - mov32 r3, 0 + jeq r2, 0, jmp_0688 + ldxdw r3, [r2+16] + jeq r1, r3, jmp_0260 jmp_0668: - lsh64 r3, 3 - add64 r2, r3 stxdw [r2+8], r4 + ja jmp_0690 -jmp_0680: - stb [r4+28], 0 - stb [r1+28], 1 +jmp_0678: + stb [r2+28], 0 ja jmp_06a0 -jmp_0698: - stb [r2+28], 0 +jmp_0688: + stxdw [r6+0], r4 + +jmp_0690: + stb [r4+28], 0 + stb [r1+28], 1 jmp_06a0: exit @@ -275,8 +275,8 @@ jmp_06c8: ldxdw r3, [r4+8] stxdw [r1+16], r3 ldxdw r2, [r1+0] - jne r3, 0, jmp_0620 - ja jmp_0628 + jne r3, 0, jmp_0630 + ja jmp_0638 jmp_0710: ldxdw r3, [r4+8] @@ -434,7 +434,7 @@ jmp_0778: mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - ja jmp_05d8 + ja jmp_05e8 jmp_0bd0: mov64 r0, 12 diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt index 8789e0aa..ec1c9701 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-l.txt @@ -54,8 +54,11 @@ (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; + if grandparent == (*great_grandparent).child[tree::DIR_R] { + (*great_grandparent).child[tree::DIR_R] = parent; + } else { + (*great_grandparent).child[tree::DIR_L] = parent; + } } else { (*tree_header).root = parent; } diff --git a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt index f5120efa..c976f321 100644 --- a/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt +++ b/examples/tree/artifacts/snippets/rs/insert-fixup-case-5-6-dir-r.txt @@ -52,8 +52,11 @@ (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; + if grandparent == (*great_grandparent).child[tree::DIR_R] { + (*great_grandparent).child[tree::DIR_R] = parent; + } else { + (*great_grandparent).child[tree::DIR_L] = parent; + } } else { (*tree_header).root = parent; } diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 90a9ed6d..625d1570 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -11,21 +11,21 @@ | Case 2+3: right-right | 52 | 59 | +7 | +13.5% | | Case 2+1: left | 57 | 71 | +14 | +24.6% | | Case 2+1: right | 60 | 67 | +7 | +11.7% | -| Case 6: left-left null uncle | 55 | 70 | +15 | +27.3% | +| Case 6: left-left null uncle | 55 | 69 | +14 | +25.5% | | Case 6: right-right null uncle | 57 | 66 | +9 | +15.8% | -| Case 6: left-left black uncle | 57 | 72 | +15 | +26.3% | +| Case 6: left-left black uncle | 57 | 71 | +14 | +24.6% | | Case 6: right-right black uncle | 59 | 69 | +10 | +16.9% | -| Case 5+6: left-right null uncle | 65 | 76 | +11 | +16.9% | +| Case 5+6: left-right null uncle | 65 | 75 | +10 | +15.4% | | Case 5+6: right-left null uncle | 65 | 74 | +9 | +13.8% | -| Case 5+6: left-right black uncle | 67 | 78 | +11 | +16.4% | +| Case 5+6: left-right black uncle | 67 | 77 | +10 | +14.9% | | Case 5+6: right-left black uncle | 67 | 77 | +10 | +14.9% | -| Case 6: GGP non-null, LL GP-left | 62 | 84 | +22 | +35.5% | -| Case 6: GGP non-null, LL GP-right | 63 | 82 | +19 | +30.2% | -| Case 6: GGP non-null, RR GP-right | 65 | 79 | +14 | +21.5% | -| Case 6: GGP non-null, RR GP-left | 64 | 81 | +17 | +26.6% | -| Case 2+6: non-null new_child dir_l | 84 | 103 | +19 | +22.6% | +| Case 6: GGP non-null, LL GP-left | 62 | 80 | +18 | +29.0% | +| Case 6: GGP non-null, LL GP-right | 63 | 80 | +17 | +27.0% | +| Case 6: GGP non-null, RR GP-right | 65 | 77 | +12 | +18.5% | +| Case 6: GGP non-null, RR GP-left | 64 | 77 | +13 | +20.3% | +| Case 2+6: non-null new_child dir_l | 84 | 102 | +18 | +21.4% | | Case 2+6: non-null new_child dir_r | 88 | 97 | +9 | +10.2% | -| Case 2+5+6: non-null new_child dir_l | 95 | 109 | +14 | +14.7% | +| Case 2+5+6: non-null new_child dir_l | 95 | 108 | +13 | +13.7% | | Case 2+5+6: non-null new_child dir_r | 97 | 105 | +8 | +8.2% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] @@ -98,7 +98,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units @@ -110,7 +110,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units @@ -122,7 +122,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units @@ -134,7 +134,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units @@ -146,31 +146,31 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 82 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 79 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 81 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units @@ -182,7 +182,7 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 109 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 108 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index bdc3235c..6d01d0b4 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,9 +1,9 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | 3-node balanced (10,5,15) | 90 | 111 | +21 | +23.3% | -| Left-skew rotation (10,5,1) | 113 | 141 | +28 | +24.8% | +| Left-skew rotation (10,5,1) | 113 | 140 | +27 | +23.9% | | Right-skew rotation (10,15,20) | 116 | 136 | +20 | +17.2% | -| Zigzag double rotation (10,5,7) | 123 | 147 | +24 | +19.5% | +| Zigzag double rotation (10,5,7) | 123 | 146 | +23 | +18.7% | | 7-node full tree (10,5,15,3,7,12,20) | 252 | 313 | +61 | +24.2% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] @@ -40,7 +40,7 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 70 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -76,7 +76,7 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 60526cc4..1c87dfd3 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -410,8 +410,11 @@ unsafe fn insert( (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; + if grandparent == (*great_grandparent).child[tree::DIR_R] { + (*great_grandparent).child[tree::DIR_R] = parent; + } else { + (*great_grandparent).child[tree::DIR_L] = parent; + } } else { (*tree_header).root = parent; } @@ -477,8 +480,11 @@ unsafe fn insert( (*grandparent).parent = parent; if !great_grandparent.is_null() { - let idx = (grandparent == (*great_grandparent).child[tree::DIR_R]) as usize; - (*great_grandparent).child[idx] = parent; + if grandparent == (*great_grandparent).child[tree::DIR_R] { + (*great_grandparent).child[tree::DIR_R] = parent; + } else { + (*great_grandparent).child[tree::DIR_L] = parent; + } } else { (*tree_header).root = parent; } @@ -701,7 +707,11 @@ unsafe fn rotate_subtree( (*subtree).parent = new_root; if !parent.is_null() { - (*parent).child[(subtree == (*parent).child[tree::DIR_R]) as usize] = new_root; + if subtree == (*parent).child[tree::DIR_R] { + (*parent).child[tree::DIR_R] = new_root; + } else { + (*parent).child[tree::DIR_L] = new_root; + } } else { (*tree).root = new_root; } From 35586cbc8d68a86f34245b23114c463b4df687d4 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:23:30 -0700 Subject: [PATCH 218/263] Inline optimization for RS --- examples/tree/artifacts/dumps/rs.txt | 769 +++++++++--------- examples/tree/artifacts/rs-disassembly.s | 235 +++--- .../artifacts/snippets/rs/insert-search.txt | 6 + .../artifacts/tests/insert_to_tree/result.txt | 104 +-- .../artifacts/tests/multi_insert/result.txt | 38 +- examples/tree/src/program.rs | 6 + 6 files changed, 587 insertions(+), 571 deletions(-) diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 67630e49..922b4abd 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 5792 (bytes into file) + Start of section headers 5816 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x16a0 +There are 8 section headers, starting at offset 0x16b8 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000c90 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000db0 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000db8 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000db8 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000db8 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001130 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00116e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000ca8 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000dc8 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000dd0 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000dd0 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000dd0 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001148 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 001186 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000c90 0x000c90 E 0x8 - LOAD 0x000db0 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000db8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000db8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000ca8 0x000ca8 E 0x8 + LOAD 0x000dc8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000dd0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000dd0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3216 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3240 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -108,23 +108,23 @@ Disassembly of section .text 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] - 20 55 05 ea 00 01 00 00 00 jne r5, 0x1, +0xea - 28 55 03 74 01 05 00 00 00 jne r3, 0x5, +0x174 - 30 a5 04 75 01 02 00 00 00 jlt r4, 0x2, +0x175 + 20 55 05 ed 00 01 00 00 00 jne r5, 0x1, +0xed + 28 55 03 77 01 05 00 00 00 jne r3, 0x5, +0x177 + 30 a5 04 78 01 02 00 00 00 jlt r4, 0x2, +0x178 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 75 01 00 00 00 00 jne r3, 0x0, +0x175 + 40 55 03 78 01 00 00 00 00 jne r3, 0x0, +0x178 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 75 01 ff 00 00 00 jne r3, 0xff, +0x175 + 50 55 03 78 01 ff 00 00 00 jne r3, 0xff, +0x178 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 70 15 03 3f 00 00 00 00 00 jeq r3, 0x0, +0x3f + 70 15 03 42 00 00 00 00 00 jeq r3, 0x0, +0x42 78 9c 34 00 00 00 00 00 00 ldxdw r4, [r3 + 0x0] 80 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 88 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] 90 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 98 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - a0 15 04 a5 00 00 00 00 00 jeq r4, 0x0, +0xa5 + a0 15 04 a8 00 00 00 00 00 jeq r4, 0x0, +0xa8 a8 3c 21 01 00 00 00 00 00 ldxh w1, [r2 + 0x1] b0 bf 42 00 00 00 00 00 00 mov64 r2, r4 b8 3c 24 18 00 00 00 00 00 ldxh w4, [r2 + 0x18] @@ -132,377 +132,380 @@ Disassembly of section .text c8 bd 45 03 00 00 00 00 00 jle r5, r4, +0x3 d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 - e0 05 00 05 00 00 00 00 00 ja +0x5 - e8 3d 45 6c 01 00 00 00 00 jge r5, r4, +0x16c + e0 05 00 09 00 00 00 00 00 ja +0x9 + e8 3d 45 6f 01 00 00 00 00 jge r5, r4, +0x16f f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa - 100 b7 01 00 00 08 00 00 00 mov64 r1, 0x8 - 108 05 00 01 00 00 00 00 00 ja +0x1 - 110 b7 01 00 00 10 00 00 00 mov64 r1, 0x10 - 118 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 120 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 128 0f 14 00 00 00 00 00 00 add64 r4, r1 - 130 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 138 9f 34 00 00 00 00 00 00 stxdw [r4 + 0x0], r3 - 140 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 148 05 00 06 00 00 00 00 00 ja +0x6 - 150 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 158 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 160 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 168 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 170 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 178 15 02 a4 00 00 00 00 00 jeq r2, 0x0, +0xa4 - 180 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] - 188 15 01 a2 00 00 00 00 00 jeq r1, 0x0, +0xa2 - 190 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] - 198 15 01 9f 00 00 00 00 00 jeq r1, 0x0, +0x9f - 1a0 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] - 1a8 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 - 1b0 15 04 88 00 00 00 00 00 jeq r4, 0x0, +0x88 - 1b8 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] - 1c0 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf - 1c8 05 00 85 00 00 00 00 00 ja +0x85 - 1d0 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] - 1d8 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 - 1e0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] - 1e8 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 - 1f0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] - 1f8 1d 43 a2 00 00 00 00 00 jeq r3, r4, +0xa2 - 200 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 208 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 210 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 - 218 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 220 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 228 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 230 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 238 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 - 240 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 248 15 02 85 00 00 00 00 00 jeq r2, 0x0, +0x85 - 250 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] - 258 5d 31 81 00 00 00 00 00 jne r1, r3, +0x81 - 260 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 268 05 00 80 00 00 00 00 00 ja +0x80 - 270 55 04 37 01 04 00 00 00 jne r4, 0x4, +0x137 - 278 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] - 280 bf 35 00 00 00 00 00 00 mov64 r5, r3 - 288 07 05 00 00 07 00 00 00 add64 r5, 0x7 - 290 57 05 00 00 f8 ff ff ff and64 r5, -0x8 - 298 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 2a0 0f 54 00 00 00 00 00 00 add64 r4, r5 - 2a8 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2b0 55 05 2b 01 ff 00 00 00 jne r5, 0xff, +0x12b - 2b8 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2c0 55 05 2b 01 0e 00 00 00 jne r5, 0xe, +0x12b - 2c8 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2d0 55 05 2d 01 ff 00 00 00 jne r5, 0xff, +0x12d - 2d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 2e0 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 - 2e8 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 - 2f0 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] - 2f8 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 - 300 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 - 308 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d - 310 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] - 318 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 - 320 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 - 328 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b - 330 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] - 338 5d 57 6c 00 00 00 00 00 jne r7, r5, +0x6c - 340 bf 27 00 00 00 00 00 00 mov64 r7, r2 - 348 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] - 350 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d - 358 5d 52 68 00 00 00 00 00 jne r2, r5, +0x68 - 360 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] - 368 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 370 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 - 378 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 - 380 bf 14 00 00 00 00 00 00 mov64 r4, r1 - 388 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 390 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 - 398 bf 12 00 00 00 00 00 00 mov64 r2, r1 - 3a0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 3a8 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 - 3b0 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 - 3b8 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 - 3c0 bf 15 00 00 00 00 00 00 mov64 r5, r1 - 3c8 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3d0 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 - 3d8 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 - 3e0 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 - 3e8 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 3f0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 3f8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 400 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 - 408 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 410 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 418 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 100 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 108 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 110 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 + 118 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 120 55 01 06 00 00 00 00 00 jne r1, 0x0, +0x6 + 128 05 00 9a 00 00 00 00 00 ja +0x9a + 130 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 138 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 140 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 + 148 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 150 15 01 95 00 00 00 00 00 jeq r1, 0x0, +0x95 + 158 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 160 05 00 06 00 00 00 00 00 ja +0x6 + 168 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 170 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 178 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 180 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 188 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 190 15 02 a4 00 00 00 00 00 jeq r2, 0x0, +0xa4 + 198 2c 21 1c 00 00 00 00 00 ldxb w1, [r2 + 0x1c] + 1a0 15 01 a2 00 00 00 00 00 jeq r1, 0x0, +0xa2 + 1a8 9c 21 00 00 00 00 00 00 ldxdw r1, [r2 + 0x0] + 1b0 15 01 9f 00 00 00 00 00 jeq r1, 0x0, +0x9f + 1b8 9c 14 08 00 00 00 00 00 ldxdw r4, [r1 + 0x8] + 1c0 1d 42 04 00 00 00 00 00 jeq r2, r4, +0x4 + 1c8 15 04 88 00 00 00 00 00 jeq r4, 0x0, +0x88 + 1d0 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 1d8 55 05 f1 ff 00 00 00 00 jne r5, 0x0, -0xf + 1e0 05 00 85 00 00 00 00 00 ja +0x85 + 1e8 9c 14 10 00 00 00 00 00 ldxdw r4, [r1 + 0x10] + 1f0 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 + 1f8 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + 200 55 05 ec ff 00 00 00 00 jne r5, 0x0, -0x14 + 208 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] + 210 1d 43 a2 00 00 00 00 00 jeq r3, r4, +0xa2 + 218 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 220 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 228 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 230 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 238 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 240 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 248 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 250 9f 14 10 00 00 00 00 00 stxdw [r4 + 0x10], r1 + 258 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 260 15 02 85 00 00 00 00 00 jeq r2, 0x0, +0x85 + 268 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] + 270 5d 31 81 00 00 00 00 00 jne r1, r3, +0x81 + 278 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 280 05 00 80 00 00 00 00 00 ja +0x80 + 288 55 04 37 01 04 00 00 00 jne r4, 0x4, +0x137 + 290 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] + 298 bf 35 00 00 00 00 00 00 mov64 r5, r3 + 2a0 07 05 00 00 07 00 00 00 add64 r5, 0x7 + 2a8 57 05 00 00 f8 ff ff ff and64 r5, -0x8 + 2b0 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 2b8 0f 54 00 00 00 00 00 00 add64 r4, r5 + 2c0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] + 2c8 55 05 2b 01 ff 00 00 00 jne r5, 0xff, +0x12b + 2d0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] + 2d8 55 05 2b 01 0e 00 00 00 jne r5, 0xe, +0x12b + 2e0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] + 2e8 55 05 2d 01 ff 00 00 00 jne r5, 0xff, +0x12d + 2f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 2f8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 + 300 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 + 308 9c 47 40 79 00 00 00 00 ldxdw r7, [r4 + 0x7940] + 310 5d 57 74 00 00 00 00 00 jne r7, r5, +0x74 + 318 b4 05 00 00 21 8c c9 4c mov32 w5, 0x4cc98c21 + 320 f7 05 00 00 3d 4a f1 7f hor64 r5, 0x7ff14a3d + 328 9c 47 48 79 00 00 00 00 ldxdw r7, [r4 + 0x7948] + 330 5d 57 70 00 00 00 00 00 jne r7, r5, +0x70 + 338 b4 05 00 00 58 da ee 08 mov32 w5, 0x8eeda58 + 340 f7 05 00 00 9b a1 fd 44 hor64 r5, 0x44fda19b + 348 9c 47 50 79 00 00 00 00 ldxdw r7, [r4 + 0x7950] + 350 5d 57 6c 00 00 00 00 00 jne r7, r5, +0x6c + 358 bf 27 00 00 00 00 00 00 mov64 r7, r2 + 360 9c 42 58 79 00 00 00 00 ldxdw r2, [r4 + 0x7958] + 368 b4 05 00 00 e3 db d9 8a mov32 w5, -0x7526241d + 370 5d 52 68 00 00 00 00 00 jne r2, r5, +0x68 + 378 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] + 380 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d + 388 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 + 390 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 398 bf 14 00 00 00 00 00 00 mov64 r4, r1 + 3a0 07 04 00 00 70 28 00 00 add64 r4, 0x2870 + 3a8 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 3b0 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 3b8 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 3c0 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 + 3c8 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 + 3d0 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 3d8 bf 15 00 00 00 00 00 00 mov64 r5, r1 + 3e0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 + 3e8 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 + 3f0 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 + 3f8 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 400 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 408 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 410 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + 418 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 420 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 428 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 430 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 428 07 03 00 00 30 00 00 00 add64 r3, 0x30 + 430 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 438 bf 13 00 00 00 00 00 00 mov64 r3, r1 - 440 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 448 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 450 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 458 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 460 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 - 468 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 470 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 478 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 480 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 488 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 490 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 - 498 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 4a0 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 - 4a8 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 - 4b0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4b8 07 02 00 00 30 01 00 00 add64 r2, 0x130 - 4c0 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 440 07 03 00 00 60 00 00 00 add64 r3, 0x60 + 448 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 450 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 458 07 03 00 00 50 00 00 00 add64 r3, 0x50 + 460 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 + 468 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + 470 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + 478 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 + 480 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + 488 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + 490 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + 498 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 4a0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + 4a8 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 + 4b0 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 4b8 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 + 4c0 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 4c8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d0 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 - 4d8 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4d0 07 02 00 00 30 01 00 00 add64 r2, 0x130 + 4d8 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 4e0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4e8 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 - 4f0 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 - 4f8 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc - 500 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 - 508 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 - 510 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 - 518 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 520 07 03 00 00 10 00 00 00 add64 r3, 0x10 - 528 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 530 07 02 00 00 68 00 00 00 add64 r2, 0x68 - 538 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 540 07 04 00 00 48 00 00 00 add64 r4, 0x48 - 548 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 550 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 558 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - 560 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 - 568 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - 570 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 578 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 580 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 - 588 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] - 590 bf 31 00 00 00 00 00 00 mov64 r1, r3 - 598 07 01 00 00 1d 00 00 00 add64 r1, 0x1d - 5a0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - 5a8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 5b0 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] - 5b8 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 - 5c0 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] - 5c8 55 04 5b ff 00 00 00 00 jne r4, 0x0, -0xa5 - 5d0 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 - 5d8 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 - 5e0 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 - 5e8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 5f0 05 00 15 00 00 00 00 00 ja +0x15 - 5f8 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] - 600 1d 43 14 00 00 00 00 00 jeq r3, r4, +0x14 - 608 bf 43 00 00 00 00 00 00 mov64 r3, r4 - 610 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 618 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 620 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 628 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 630 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 - 638 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - 640 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 - 648 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 - 650 15 02 04 00 00 00 00 00 jeq r2, 0x0, +0x4 - 658 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] - 660 1d 31 7f ff 00 00 00 00 jeq r1, r3, -0x81 - 668 07 02 00 00 08 00 00 00 add64 r2, 0x8 - 670 bf 26 00 00 00 00 00 00 mov64 r6, r2 - 678 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 - 680 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 - 688 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 - 690 05 00 01 00 00 00 00 00 ja +0x1 - 698 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 6a0 9d 00 00 00 00 00 00 00 return - 6a8 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 6b0 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 - 6b8 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 6c0 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 6c8 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 6d0 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 - 6d8 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 6e0 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 - 6e8 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 6f0 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 - 6f8 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 700 55 03 e5 ff 00 00 00 00 jne r3, 0x0, -0x1b - 708 05 00 e5 ff 00 00 00 00 ja -0x1b - 710 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] - 718 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 - 720 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 - 728 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - 730 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 - 738 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 - 740 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 - 748 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 - 750 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] - 758 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 - 760 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] - 768 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 - 770 05 00 57 ff 00 00 00 00 ja -0xa9 - 778 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e - 780 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 788 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 790 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 798 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 7a0 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 7a8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7b0 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 7b8 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 - 7c0 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 7c8 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 7d0 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 7d8 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 7e0 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 7e8 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 7f8 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 800 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 808 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 810 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f - 818 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 820 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 828 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 830 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 - 838 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 840 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 848 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 850 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 - 858 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 860 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 868 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a - 870 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 878 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 880 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 888 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 890 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 898 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 8a0 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 8a8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 8b0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 8b8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 8c0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 8c8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 8d0 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 - 8d8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 8e0 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 8e8 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 8f0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 8f8 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 900 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b - 908 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 910 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 918 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 - 920 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 928 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 930 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 938 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 940 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - 948 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 950 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - 958 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 960 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - 968 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 970 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - 978 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 980 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - 988 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - 990 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - 998 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 9a0 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 9a8 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 9b0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 9b8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 9c0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 9c8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 9d0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 9d8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + 4e8 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 + 4f0 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4f8 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 500 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 + 508 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 + 510 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc + 518 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 + 520 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 + 528 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 530 bf a3 00 00 00 00 00 00 mov64 r3, r10 + 538 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 540 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 548 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 550 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 558 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 560 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 568 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 570 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 578 b7 05 00 00 00 00 00 00 mov64 r5, 0x0 + 580 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 588 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 590 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 598 9f 18 b8 28 00 00 00 00 stxdw [r8 + 0x28b8], r1 + 5a0 9c 83 d0 28 00 00 00 00 ldxdw r3, [r8 + 0x28d0] + 5a8 bf 31 00 00 00 00 00 00 mov64 r1, r3 + 5b0 07 01 00 00 1d 00 00 00 add64 r1, 0x1d + 5b8 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 5c0 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 5c8 8c 21 01 00 00 00 00 00 ldxw w1, [r2 + 0x1] + 5d0 8f 13 18 00 00 00 00 00 stxw [r3 + 0x18], w1 + 5d8 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + 5e0 55 04 58 ff 00 00 00 00 jne r4, 0x0, -0xa8 + 5e8 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 5f0 27 03 1c 00 01 00 00 00 stb [r3 + 0x1c], 0x1 + 5f8 9f 36 00 00 00 00 00 00 stxdw [r6 + 0x0], r3 + 600 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 608 05 00 15 00 00 00 00 00 ja +0x15 + 610 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] + 618 1d 43 14 00 00 00 00 00 jeq r3, r4, +0x14 + 620 bf 43 00 00 00 00 00 00 mov64 r3, r4 + 628 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 630 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 638 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 640 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 648 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 650 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + 658 9f 14 08 00 00 00 00 00 stxdw [r4 + 0x8], r1 + 660 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + 668 15 02 04 00 00 00 00 00 jeq r2, 0x0, +0x4 + 670 9c 23 10 00 00 00 00 00 ldxdw r3, [r2 + 0x10] + 678 1d 31 7f ff 00 00 00 00 jeq r1, r3, -0x81 + 680 07 02 00 00 08 00 00 00 add64 r2, 0x8 + 688 bf 26 00 00 00 00 00 00 mov64 r6, r2 + 690 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + 698 27 04 1c 00 00 00 00 00 stb [r4 + 0x1c], 0x0 + 6a0 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + 6a8 05 00 01 00 00 00 00 00 ja +0x1 + 6b0 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 6b8 9d 00 00 00 00 00 00 00 return + 6c0 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 6c8 9f 32 08 00 00 00 00 00 stxdw [r2 + 0x8], r3 + 6d0 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 6d8 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 6e0 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 6e8 9f 24 10 00 00 00 00 00 stxdw [r4 + 0x10], r2 + 6f0 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 6f8 9f 41 10 00 00 00 00 00 stxdw [r1 + 0x10], r4 + 700 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 708 9f 31 10 00 00 00 00 00 stxdw [r1 + 0x10], r3 + 710 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 718 55 03 e5 ff 00 00 00 00 jne r3, 0x0, -0x1b + 720 05 00 e5 ff 00 00 00 00 ja -0x1b + 728 9c 43 08 00 00 00 00 00 ldxdw r3, [r4 + 0x8] + 730 9f 32 10 00 00 00 00 00 stxdw [r2 + 0x10], r3 + 738 15 03 01 00 00 00 00 00 jeq r3, 0x0, +0x1 + 740 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + 748 9f 14 00 00 00 00 00 00 stxdw [r4 + 0x0], r1 + 750 9f 24 08 00 00 00 00 00 stxdw [r4 + 0x8], r2 + 758 9f 42 00 00 00 00 00 00 stxdw [r2 + 0x0], r4 + 760 9f 41 08 00 00 00 00 00 stxdw [r1 + 0x8], r4 + 768 9c 43 10 00 00 00 00 00 ldxdw r3, [r4 + 0x10] + 770 9f 31 08 00 00 00 00 00 stxdw [r1 + 0x8], r3 + 778 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] + 780 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 + 788 05 00 57 ff 00 00 00 00 ja -0xa9 + 790 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e + 798 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 + 7a0 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a + 7a8 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] + 7b0 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a + 7b8 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] + 7c0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 7c8 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] + 7d0 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 + 7d8 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] + 7e0 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 + 7e8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] + 7f0 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 + 7f8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] + 800 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a + 808 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 810 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 + 818 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 + 820 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] + 828 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f + 830 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 + 838 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d + 840 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] + 848 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 + 850 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 + 858 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b + 860 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] + 868 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 + 870 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] + 878 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d + 880 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a + 888 bf 16 00 00 00 00 00 00 mov64 r6, r1 + 890 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 898 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 8a0 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 8a8 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 8b0 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 8b8 bf 17 00 00 00 00 00 00 mov64 r7, r1 + 8c0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 8c8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 8d0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 8d8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 8e0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 8e8 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 + 8f0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 8f8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] + 900 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e + 908 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 910 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] + 918 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b + 920 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + 928 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] + 930 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 + 938 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 940 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 948 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] + 950 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 958 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + 960 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 968 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + 970 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 978 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + 980 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 988 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + 990 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 998 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + 9a0 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + 9a8 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + 9b0 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + 9b8 bf 72 00 00 00 00 00 00 mov64 r2, r7 + 9c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 9c8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + 9d0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + 9d8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 9e0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 9e8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - 9f0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + 9e8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 9f0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 9f8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a00 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - a08 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - a10 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - a18 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a20 07 01 00 00 30 00 00 00 add64 r1, 0x30 - a28 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + a00 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + a08 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + a10 bf 73 00 00 00 00 00 00 mov64 r3, r7 + a18 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + a20 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + a28 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 a30 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a38 07 01 00 00 60 00 00 00 add64 r1, 0x60 - a40 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + a38 07 01 00 00 30 00 00 00 add64 r1, 0x30 + a40 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 a48 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a50 07 01 00 00 50 00 00 00 add64 r1, 0x50 - a58 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - a60 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - a68 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - a70 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - a78 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - a80 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - a88 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - a90 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - a98 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - aa0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - aa8 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - ab0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - ab8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - ac0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - ac8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ad0 07 01 00 00 10 00 00 00 add64 r1, 0x10 - ad8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + a50 07 01 00 00 60 00 00 00 add64 r1, 0x60 + a58 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + a60 bf 71 00 00 00 00 00 00 mov64 r1, r7 + a68 07 01 00 00 50 00 00 00 add64 r1, 0x50 + a70 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + a78 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + a80 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + a88 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + a90 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + a98 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + aa0 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + aa8 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + ab0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + ab8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + ac0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + ac8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + ad0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + ad8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 ae0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ae8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - af0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + ae8 07 01 00 00 10 00 00 00 add64 r1, 0x10 + af0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 af8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b00 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - b08 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - b10 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - b18 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - b20 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b28 07 01 00 00 0f 00 00 00 add64 r1, 0xf - b30 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - b38 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - b40 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b48 07 01 00 00 20 01 00 00 add64 r1, 0x120 - b50 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - b58 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - b60 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b68 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - b70 bf a2 00 00 00 00 00 00 mov64 r2, r10 - b78 07 02 00 00 68 00 00 00 add64 r2, 0x68 - b80 bf a4 00 00 00 00 00 00 mov64 r4, r10 - b88 07 04 00 00 30 01 00 00 add64 r4, 0x130 - b90 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - b98 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - ba0 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - ba8 bf 71 00 00 00 00 00 00 mov64 r1, r7 - bb0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - bb8 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - bc0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - bc8 05 00 5a ff 00 00 00 00 ja -0xa6 - bd0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - bd8 05 00 58 ff 00 00 00 00 ja -0xa8 - be0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - be8 05 00 56 ff 00 00 00 00 ja -0xaa - bf0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - bf8 05 00 54 ff 00 00 00 00 ja -0xac - c00 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - c08 05 00 52 ff 00 00 00 00 ja -0xae - c10 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - c18 05 00 50 ff 00 00 00 00 ja -0xb0 - c20 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - c28 05 00 4e ff 00 00 00 00 ja -0xb2 - c30 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - c38 05 00 4c ff 00 00 00 00 ja -0xb4 - c40 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - c48 05 00 4a ff 00 00 00 00 ja -0xb6 - c50 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - c58 05 00 48 ff 00 00 00 00 ja -0xb8 - c60 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - c68 05 00 46 ff 00 00 00 00 ja -0xba - c70 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - c78 05 00 44 ff 00 00 00 00 ja -0xbc - c80 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - c88 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file + b00 07 01 00 00 48 00 00 00 add64 r1, 0x48 + b08 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + b10 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b18 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + b20 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + b28 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + b30 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + b38 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b40 07 01 00 00 0f 00 00 00 add64 r1, 0xf + b48 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + b50 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + b58 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b60 07 01 00 00 20 01 00 00 add64 r1, 0x120 + b68 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + b70 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + b78 bf a1 00 00 00 00 00 00 mov64 r1, r10 + b80 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + b88 bf a2 00 00 00 00 00 00 mov64 r2, r10 + b90 07 02 00 00 68 00 00 00 add64 r2, 0x68 + b98 bf a4 00 00 00 00 00 00 mov64 r4, r10 + ba0 07 04 00 00 30 01 00 00 add64 r4, 0x130 + ba8 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + bb0 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + bb8 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + bc0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + bc8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + bd0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 + bd8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + be0 05 00 5a ff 00 00 00 00 ja -0xa6 + be8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + bf0 05 00 58 ff 00 00 00 00 ja -0xa8 + bf8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + c00 05 00 56 ff 00 00 00 00 ja -0xaa + c08 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + c10 05 00 54 ff 00 00 00 00 ja -0xac + c18 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + c20 05 00 52 ff 00 00 00 00 ja -0xae + c28 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + c30 05 00 50 ff 00 00 00 00 ja -0xb0 + c38 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + c40 05 00 4e ff 00 00 00 00 ja -0xb2 + c48 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + c50 05 00 4c ff 00 00 00 00 ja -0xb4 + c58 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + c60 05 00 4a ff 00 00 00 00 ja -0xb6 + c68 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + c70 05 00 48 ff 00 00 00 00 ja -0xb8 + c78 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + c80 05 00 46 ff 00 00 00 00 ja -0xba + c88 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + c90 05 00 44 ff 00 00 00 00 ja -0xbc + c98 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + ca0 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index e24e2c9f..5210c7da 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -5,23 +5,23 @@ entrypoint: ldxdw r4, [r1+0] ldxdw r3, [r2-8] ldxb r5, [r2+0] - jne r5, 1, jmp_0778 - jne r3, 5, jmp_0bd0 - jlt r4, 2, jmp_0be0 + jne r5, 1, jmp_0780 + jne r3, 5, jmp_0bd8 + jlt r4, 2, jmp_0be8 ldxdw r3, [r1+88] - jne r3, 0, jmp_0bf0 + jne r3, 0, jmp_0bf8 ldxb r3, [r1+10344] - jne r3, 255, jmp_0c00 + jne r3, 255, jmp_0c08 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] - jeq r3, 0, jmp_0270 + jeq r3, 0, jmp_0278 ldxdw r4, [r3+0] stxdw [r1+10440], r4 ldxw r1, [r2+1] stxw [r3+24], r1 ldxdw r4, [r6+0] - jeq r4, 0, jmp_05d0 + jeq r4, 0, jmp_05d8 jmp_00a8: ldxh r1, [r2+1] @@ -33,79 +33,80 @@ jmp_00b0: jle r5, r4, jmp_00e8 ldxdw r4, [r2+16] jne r4, 0, jmp_00b0 - ja jmp_0110 + ja jmp_0120 jmp_00e8: - jge r5, r4, jmp_0c50 + jge r5, r4, jmp_0c58 ldxdw r4, [r2+8] jne r4, 0, jmp_00b0 - mov64 r1, 8 - ja jmp_0118 - -jmp_0110: - mov64 r1, 16 + stxdw [r3+0], r2 + stb [r3+28], 1 + stxdw [r2+8], r3 + ja jmp_0138 -jmp_0118: +jmp_0120: stxdw [r3+0], r2 - mov64 r4, r2 - add64 r4, r1 stb [r3+28], 1 - stxdw [r4+0], r3 + stxdw [r2+16], r3 + +jmp_0138: + ldxb r1, [r2+28] + jeq r1, 0, jmp_05f0 mov64 r0, 0 - ja jmp_0180 + ja jmp_0188 -jmp_0150: +jmp_0158: stb [r2+28], 0 stb [r4+28], 0 stb [r1+28], 1 ldxdw r2, [r1+0] mov64 r3, r1 - jeq r2, 0, jmp_06a0 + jeq r2, 0, jmp_06a8 -jmp_0180: +jmp_0188: ldxb r1, [r2+28] - jeq r1, 0, jmp_06a0 + jeq r1, 0, jmp_06a8 ldxdw r1, [r2+0] - jeq r1, 0, jmp_0678 + jeq r1, 0, jmp_0680 ldxdw r4, [r1+8] - jeq r2, r4, jmp_01d0 - jeq r4, 0, jmp_05f8 + jeq r2, r4, jmp_01d8 + jeq r4, 0, jmp_0600 ldxb r5, [r4+28] - jne r5, 0, jmp_0150 - ja jmp_05f8 + jne r5, 0, jmp_0158 + ja jmp_0600 -jmp_01d0: +jmp_01d8: ldxdw r4, [r1+16] - jeq r4, 0, jmp_01f0 + jeq r4, 0, jmp_01f8 ldxb r5, [r4+28] - jne r5, 0, jmp_0150 + jne r5, 0, jmp_0158 -jmp_01f0: +jmp_01f8: ldxdw r4, [r2+16] - jeq r3, r4, jmp_0710 + jeq r3, r4, jmp_0718 mov64 r3, r4 mov64 r4, r2 stxdw [r1+8], r3 ldxdw r2, [r1+0] - jeq r3, 0, jmp_0230 + jeq r3, 0, jmp_0238 -jmp_0228: +jmp_0230: stxdw [r3+0], r1 -jmp_0230: +jmp_0238: stxdw [r4+0], r2 stxdw [r4+16], r1 stxdw [r1+0], r4 - jeq r2, 0, jmp_0688 + jeq r2, 0, jmp_0690 ldxdw r3, [r2+16] - jne r1, r3, jmp_0668 + jne r1, r3, jmp_0670 -jmp_0260: +jmp_0268: stxdw [r2+16], r4 - ja jmp_0690 + ja jmp_0698 -jmp_0270: - jne r4, 4, jmp_0c30 +jmp_0278: + jne r4, 4, jmp_0c38 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -113,28 +114,28 @@ jmp_0270: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0c10 + jne r5, 255, jmp_0c18 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0c20 + jne r5, 14, jmp_0c28 ldxb r5, [r4+31032] - jne r5, 255, jmp_0c40 + jne r5, 255, jmp_0c48 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 ldxdw r7, [r4+31040] - jne r7, r5, jmp_06a0 + jne r7, r5, jmp_06a8 mov32 r5, 1288277025 hor64 r5, 2146519613 ldxdw r7, [r4+31048] - jne r7, r5, jmp_06a0 + jne r7, r5, jmp_06a8 mov32 r5, 149871192 hor64 r5, 1157472667 ldxdw r7, [r4+31056] - jne r7, r5, jmp_06a0 + jne r7, r5, jmp_06a8 mov64 r7, r2 ldxdw r2, [r4+31064] mov32 r5, -1965433885 - jne r2, r5, jmp_06a0 + jne r2, r5, jmp_06a8 ldxdw r2, [r4+31120] lmul64 r2, 29 stxdw [r10+308], r2 @@ -214,60 +215,60 @@ jmp_0270: ldxdw r4, [r6+0] jne r4, 0, jmp_00a8 -jmp_05d0: +jmp_05d8: stdw [r3+0], 0 stb [r3+28], 1 stxdw [r6+0], r3 -jmp_05e8: +jmp_05f0: mov64 r0, 0 - ja jmp_06a0 + ja jmp_06a8 -jmp_05f8: +jmp_0600: ldxdw r4, [r2+8] - jeq r3, r4, jmp_06a8 + jeq r3, r4, jmp_06b0 mov64 r3, r4 mov64 r4, r2 stxdw [r1+16], r3 ldxdw r2, [r1+0] - jeq r3, 0, jmp_0638 + jeq r3, 0, jmp_0640 -jmp_0630: +jmp_0638: stxdw [r3+0], r1 -jmp_0638: +jmp_0640: stxdw [r4+0], r2 stxdw [r4+8], r1 stxdw [r1+0], r4 - jeq r2, 0, jmp_0688 + jeq r2, 0, jmp_0690 ldxdw r3, [r2+16] - jeq r1, r3, jmp_0260 + jeq r1, r3, jmp_0268 -jmp_0668: +jmp_0670: stxdw [r2+8], r4 - ja jmp_0690 + ja jmp_0698 -jmp_0678: +jmp_0680: stb [r2+28], 0 - ja jmp_06a0 + ja jmp_06a8 -jmp_0688: +jmp_0690: stxdw [r6+0], r4 -jmp_0690: +jmp_0698: stb [r4+28], 0 stb [r1+28], 1 -jmp_06a0: +jmp_06a8: exit -jmp_06a8: +jmp_06b0: ldxdw r3, [r4+16] stxdw [r2+8], r3 - jeq r3, 0, jmp_06c8 + jeq r3, 0, jmp_06d0 stxdw [r3+0], r2 -jmp_06c8: +jmp_06d0: stxdw [r4+0], r1 stxdw [r4+16], r2 stxdw [r2+0], r4 @@ -275,16 +276,16 @@ jmp_06c8: ldxdw r3, [r4+8] stxdw [r1+16], r3 ldxdw r2, [r1+0] - jne r3, 0, jmp_0630 - ja jmp_0638 + jne r3, 0, jmp_0638 + ja jmp_0640 -jmp_0710: +jmp_0718: ldxdw r3, [r4+8] stxdw [r2+16], r3 - jeq r3, 0, jmp_0730 + jeq r3, 0, jmp_0738 stxdw [r3+0], r2 -jmp_0730: +jmp_0738: stxdw [r4+0], r1 stxdw [r4+8], r2 stxdw [r2+0], r4 @@ -292,41 +293,41 @@ jmp_0730: ldxdw r3, [r4+16] stxdw [r1+8], r3 ldxdw r2, [r1+0] - jne r3, 0, jmp_0228 - ja jmp_0230 + jne r3, 0, jmp_0230 + ja jmp_0238 -jmp_0778: - jne r5, 0, jmp_0c60 - jne r3, 1, jmp_0bd0 - jne r4, 4, jmp_0be0 +jmp_0780: + jne r5, 0, jmp_0c68 + jne r3, 1, jmp_0bd8 + jne r4, 4, jmp_0be8 ldxdw r2, [r1+88] - jne r2, 0, jmp_0bf0 + jne r2, 0, jmp_0bf8 ldxb r2, [r1+10344] - jne r2, 255, jmp_0c00 + jne r2, 255, jmp_0c08 ldxdw r2, [r1+10424] - jne r2, 0, jmp_0c70 + jne r2, 0, jmp_0c78 ldxb r2, [r1+20680] - jne r2, 255, jmp_0c10 + jne r2, 255, jmp_0c18 ldxdw r2, [r1+20760] - jne r2, 14, jmp_0c20 + jne r2, 14, jmp_0c28 ldxb r2, [r1+31032] - jne r2, 255, jmp_0c40 + jne r2, 255, jmp_0c48 mov64 r0, 8 mov32 r2, 399877894 hor64 r2, 1364995097 ldxdw r3, [r1+31040] - jne r3, r2, jmp_06a0 + jne r3, r2, jmp_06a8 mov32 r2, 1288277025 hor64 r2, 2146519613 ldxdw r3, [r1+31048] - jne r3, r2, jmp_06a0 + jne r3, r2, jmp_06a8 mov32 r2, 149871192 hor64 r2, 1157472667 ldxdw r3, [r1+31056] - jne r3, r2, jmp_06a0 + jne r3, r2, jmp_06a8 ldxdw r2, [r1+31064] mov32 r3, -1965433885 - jne r2, r3, jmp_06a0 + jne r2, r3, jmp_06a8 mov64 r6, r1 add64 r6, 41401 mov64 r4, r10 @@ -340,16 +341,16 @@ jmp_0778: mov64 r0, 10 ldxdw r1, [r10+104] ldxdw r2, [r7+10352] - jne r1, r2, jmp_06a0 + jne r1, r2, jmp_06a8 ldxdw r1, [r10+112] ldxdw r2, [r7+10360] - jne r1, r2, jmp_06a0 + jne r1, r2, jmp_06a8 ldxdw r1, [r10+120] ldxdw r2, [r7+10368] - jne r1, r2, jmp_06a0 + jne r1, r2, jmp_06a8 ldxdw r1, [r10+128] ldxdw r2, [r7+10376] - jne r1, r2, jmp_06a0 + jne r1, r2, jmp_06a8 mov64 r1, r7 add64 r1, 10352 ldxdw r2, [r7+31120] @@ -434,48 +435,48 @@ jmp_0778: mov64 r1, r7 add64 r1, 10456 stxdw [r7+10448], r1 - ja jmp_05e8 + ja jmp_05f0 -jmp_0bd0: +jmp_0bd8: mov64 r0, 12 - ja jmp_06a0 + ja jmp_06a8 -jmp_0be0: +jmp_0be8: mov64 r0, 1 - ja jmp_06a0 + ja jmp_06a8 -jmp_0bf0: +jmp_0bf8: mov64 r0, 2 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c00: +jmp_0c08: mov64 r0, 5 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c10: +jmp_0c18: mov64 r0, 6 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c20: +jmp_0c28: mov64 r0, 4 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c30: +jmp_0c38: mov64 r0, 13 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c40: +jmp_0c48: mov64 r0, 7 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c50: +jmp_0c58: mov64 r0, 14 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c60: +jmp_0c68: mov64 r0, 11 - ja jmp_06a0 + ja jmp_06a8 -jmp_0c70: +jmp_0c78: mov64 r0, 3 - ja jmp_06a0 + ja jmp_06a8 diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index 2a4f15ec..4d6d7f98 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -19,6 +19,9 @@ (*node).color = Color::Red; (*node).parent = parent; (*parent).child[tree::DIR_R] = node; + if (*parent).color == Color::Black { + return SUCCESS; + } break; } } else if likely(key < cursor_key) { @@ -27,6 +30,9 @@ (*node).color = Color::Red; (*node).parent = parent; (*parent).child[tree::DIR_L] = node; + if (*parent).color == Color::Black { + return SUCCESS; + } break; } } else { diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index 625d1570..df758a7c 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,32 +1,32 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | Empty tree | 24 | 27 | +3 | +12.5% | -| Case 1: left child | 31 | 41 | +10 | +32.3% | -| Case 1: right child | 32 | 40 | +8 | +25.0% | -| Case 4: left child | 34 | 44 | +10 | +29.4% | -| Case 4: right child | 35 | 43 | +8 | +22.9% | -| Case 2+3: left-left | 50 | 62 | +12 | +24.0% | -| Case 2+3: left-right | 51 | 61 | +10 | +19.6% | -| Case 2+3: right-left | 51 | 60 | +9 | +17.6% | -| Case 2+3: right-right | 52 | 59 | +7 | +13.5% | -| Case 2+1: left | 57 | 71 | +14 | +24.6% | -| Case 2+1: right | 60 | 67 | +7 | +11.7% | -| Case 6: left-left null uncle | 55 | 69 | +14 | +25.5% | -| Case 6: right-right null uncle | 57 | 66 | +9 | +15.8% | -| Case 6: left-left black uncle | 57 | 71 | +14 | +24.6% | -| Case 6: right-right black uncle | 59 | 69 | +10 | +16.9% | -| Case 5+6: left-right null uncle | 65 | 75 | +10 | +15.4% | -| Case 5+6: right-left null uncle | 65 | 74 | +9 | +13.8% | -| Case 5+6: left-right black uncle | 67 | 77 | +10 | +14.9% | -| Case 5+6: right-left black uncle | 67 | 77 | +10 | +14.9% | -| Case 6: GGP non-null, LL GP-left | 62 | 80 | +18 | +29.0% | -| Case 6: GGP non-null, LL GP-right | 63 | 80 | +17 | +27.0% | -| Case 6: GGP non-null, RR GP-right | 65 | 77 | +12 | +18.5% | -| Case 6: GGP non-null, RR GP-left | 64 | 77 | +13 | +20.3% | -| Case 2+6: non-null new_child dir_l | 84 | 102 | +18 | +21.4% | -| Case 2+6: non-null new_child dir_r | 88 | 97 | +9 | +10.2% | -| Case 2+5+6: non-null new_child dir_l | 95 | 108 | +13 | +13.7% | -| Case 2+5+6: non-null new_child dir_r | 97 | 105 | +8 | +8.2% | +| Case 1: left child | 31 | 38 | +7 | +22.6% | +| Case 1: right child | 32 | 37 | +5 | +15.6% | +| Case 4: left child | 34 | 42 | +8 | +23.5% | +| Case 4: right child | 35 | 42 | +7 | +20.0% | +| Case 2+3: left-left | 50 | 60 | +10 | +20.0% | +| Case 2+3: left-right | 51 | 60 | +9 | +17.6% | +| Case 2+3: right-left | 51 | 58 | +7 | +13.7% | +| Case 2+3: right-right | 52 | 58 | +6 | +11.5% | +| Case 2+1: left | 57 | 69 | +12 | +21.1% | +| Case 2+1: right | 60 | 66 | +6 | +10.0% | +| Case 6: left-left null uncle | 55 | 67 | +12 | +21.8% | +| Case 6: right-right null uncle | 57 | 65 | +8 | +14.0% | +| Case 6: left-left black uncle | 57 | 69 | +12 | +21.1% | +| Case 6: right-right black uncle | 59 | 68 | +9 | +15.3% | +| Case 5+6: left-right null uncle | 65 | 74 | +9 | +13.8% | +| Case 5+6: right-left null uncle | 65 | 72 | +7 | +10.8% | +| Case 5+6: left-right black uncle | 67 | 76 | +9 | +13.4% | +| Case 5+6: right-left black uncle | 67 | 75 | +8 | +11.9% | +| Case 6: GGP non-null, LL GP-left | 62 | 78 | +16 | +25.8% | +| Case 6: GGP non-null, LL GP-right | 63 | 78 | +15 | +23.8% | +| Case 6: GGP non-null, RR GP-right | 65 | 76 | +11 | +16.9% | +| Case 6: GGP non-null, RR GP-left | 64 | 76 | +12 | +18.8% | +| Case 2+6: non-null new_child dir_l | 84 | 100 | +16 | +19.0% | +| Case 2+6: non-null new_child dir_r | 88 | 96 | +8 | +9.1% | +| Case 2+5+6: non-null new_child dir_l | 95 | 106 | +11 | +11.6% | +| Case 2+5+6: non-null new_child dir_r | 97 | 104 | +7 | +7.2% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -38,155 +38,155 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 71 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 80 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 77 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 102 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 100 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 96 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 108 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 106 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 105 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 104 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index 6d01d0b4..f07a976e 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,10 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| 3-node balanced (10,5,15) | 90 | 111 | +21 | +23.3% | -| Left-skew rotation (10,5,1) | 113 | 140 | +27 | +23.9% | -| Right-skew rotation (10,15,20) | 116 | 136 | +20 | +17.2% | -| Zigzag double rotation (10,5,7) | 123 | 146 | +23 | +18.7% | -| 7-node full tree (10,5,15,3,7,12,20) | 252 | 313 | +61 | +24.2% | +| 3-node balanced (10,5,15) | 90 | 106 | +16 | +17.8% | +| Left-skew rotation (10,5,1) | 113 | 136 | +23 | +20.4% | +| Right-skew rotation (10,15,20) | 116 | 134 | +18 | +15.5% | +| Zigzag double rotation (10,5,7) | 123 | 143 | +20 | +16.3% | +| 7-node full tree (10,5,15,3,7,12,20) | 252 | 297 | +45 | +17.9% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -19,10 +19,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -37,10 +37,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -55,10 +55,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -73,10 +73,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -103,20 +103,20 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 47 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 46 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 1c87dfd3..d9181bd4 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -319,6 +319,9 @@ unsafe fn insert( (*node).color = Color::Red; (*node).parent = parent; (*parent).child[tree::DIR_R] = node; + if (*parent).color == Color::Black { + return SUCCESS; + } break; } } else if likely(key < cursor_key) { @@ -327,6 +330,9 @@ unsafe fn insert( (*node).color = Color::Red; (*node).parent = parent; (*parent).child[tree::DIR_L] = node; + if (*parent).color == Color::Black { + return SUCCESS; + } break; } } else { From 23ecb3f49940b23648a7781ecde73f106016bc5a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:07:29 -0700 Subject: [PATCH 219/263] Add block comment --- examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt | 2 +- examples/tree/src/tree/tree.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt b/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt index 8a90b911..2fdee3c2 100644 --- a/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt +++ b/examples/tree/artifacts/snippets/asm/insert-fixup-case-2-3.txt @@ -2,7 +2,7 @@ insert_fixup_case_2: # r2 := parent # r3 := grandparent # r7 := uncle - # r9 := node + # Case 2/3. # r9 := node # --------------------------------------------------------------------- stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index dcb7278d..d9b12721 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -851,7 +851,7 @@ insert_fixup_case_2: # r2 := parent # r3 := grandparent # r7 := uncle - # r9 := node + # Case 2/3. # r9 := node # --------------------------------------------------------------------- stb [r2 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # uncle.color = black; From 44d21e283190a438490c73fadeddc498f32fbd44 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:23:59 -0700 Subject: [PATCH 220/263] Add remove spec --- examples/tree/specs/remove.md | 467 ++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 examples/tree/specs/remove.md diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md new file mode 100644 index 00000000..691e6942 --- /dev/null +++ b/examples/tree/specs/remove.md @@ -0,0 +1,467 @@ +# Remove instruction specification + +## Scope + +Implementation of the remove instruction for `tree.s` (assembly) +and `program.rs` (Rust). Covers input validation, BST search, node +deletion with in-order successor swap, red-black tree rebalancing, +node recycling to the free stack, and return value encoding. + +## Implementation phases + +The implementation proceeds incrementally: + +1. **Branching, input checks, error codes.** Add the + `KEY_DOES_NOT_EXIST` error code, entrypoint discriminator + branch, and input validation for both `tree.s` and `program.rs`. +1. **Search.** BST key lookup returning the found node or error. +1. **BST delete preparation and simple removal.** Successor swap, + simple cases 1-4. +1. **Rebalancing.** Simple case 4 fixup loop using + `rotate_subtree`. +1. **Node recycling and return value.** Free-stack push and + `RemoveReturn` encoding. + +Later phases may optimize rotations (inline, hardcoded branches) +once the baseline implementation is correct. + +## Interface changes + +### Error codes + +Add `KEY_DOES_NOT_EXIST` after `KEY_EXISTS` in the `error_codes!` +invocation in `interface/src/common.rs`: + +```rust +/// Key does not exist in tree during removal. +KEY_DOES_NOT_EXIST, +``` + +This increments `N_CODES` from 14 to 15. `REMOVE_STATUS_OK` +(defined as `error::N_CODES as u16`) automatically updates to 15. +Assembly constants are generated by the build script and do not +need manual updates. + +### Entrypoint + +Add remove discriminator branch in both implementations. In +`tree.s`: + +```asm +jeq r7, INSN_DISCRIMINATOR_INSERT, insert +jeq r7, INSN_DISCRIMINATOR_REMOVE, remove +jeq r7, INSN_DISCRIMINATOR_INITIALIZE, initialize +``` + +In `program.rs`, add a branch for `DISCRIMINATOR_REMOVE` in the +entrypoint function. + +## Input validation + +Identical to insert's general-instruction checks: + +- Instruction data length equals `SIZE_OF_REMOVE_INSTRUCTION` + (3 bytes). +- At least `N_ACCOUNTS_GENERAL` (2) accounts passed. +- User account has zero data length. +- Tree account is not a duplicate. + +Account layout: user followed by tree account (same as insert's +two-account path). + +## Algorithm + +### Overview + +1. Validate inputs. +1. Search for the key in the tree. +1. If not found, return `KEY_DOES_NOT_EXIST`. +1. Save `value = node.value` for the return. +1. If the node has two children, copy key/value from in-order + successor to node, then delete the successor instead. +1. Handle simple removal cases (no rebalancing). +1. Handle complex case: black leaf removal with rebalancing. +1. Recycle the removed node to the free stack. +1. Return `RemoveReturn { value, REMOVE_STATUS_OK }`. + +### Step 1 -- search + +Based on the insert search pattern but without inlined fixup +sections. The loop walks left/right with explicit branches and +returns either the matching node or an error. + +Assembly structure: + +```asm +remove_search: + ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root + jeq r3, NULL, e_key_does_not_exist + +remove_search_loop: + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = cursor.key + jeq r4, r5, remove_found # found + jgt r4, r5, remove_search_r + +remove_search_l: + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] + jne r3, NULL, remove_search_loop + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + +remove_search_r: + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] + jne r3, NULL, remove_search_loop + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + +remove_found: + # r3 = found node +``` + +Rust uses the existing `search()` function, which has the same +logic in compact form. + +### Step 2 -- BST delete preparation + +If `node` has two non-null children, find the in-order successor +(leftmost node in the right subtree) and copy its data: + +```text +successor = node.child[R] +while successor.child[L] != null: + successor = successor.child[L] +node.key = successor.key +node.value = successor.value +node = successor +``` + +After this step, `node` has at most one child. An in-order +successor has no left child; it may have a right child. + +If `node` originally had zero or one child, this step is skipped. + +### Step 3 -- removal + +Let `child` be the non-null child of `node` (or null if `node` is +a leaf), and `parent = node.parent`. + +**Simple case 1 -- one child** (`child != null`): + +In a valid red-black tree, a node with exactly one child must be +black, and the child must be red. Replace node with child and +recolor: + +```text +child.parent = parent +if parent != null: + parent.child[direction(node)] = child +else: + tree.root = child +child.color = Black +``` + +No rebalancing needed. + +**Simple case 2 -- root leaf** (`parent == null`, no children): + +```text +tree.root = null +``` + +No rebalancing needed. + +**Simple case 3 -- red leaf** (`node.color == Red`, +`parent != null`): + +```text +parent.child[direction(node)] = null +``` + +No rebalancing needed. + +**Simple case 4 -- black leaf** (`node.color == Black`, +`parent != null`): + +Detach the node, then rebalance. The direction must be computed +before detaching because `direction(node)` compares `node` against +`parent.child[DIR_R]`, which is cleared by the detach: + +```text +dir = direction(node) +parent.child[dir] = null +# Execute rebalancing with (parent, dir). +``` + +### Step 4 -- rebalancing (simple case 4 only) + +Entry: `parent` is the former parent of the removed node, `dir` is +the direction of the removed node relative to `parent`. + +Based on the Wikipedia red-black tree deletion algorithm. + +The first implementation uses the generic `rotate_subtree` helper +for all rotations. Inlining and direction-hardcoded branches can +be applied as later optimizations (see "Rotation inlining +optimizations" below). + +The verbatim reference algorithm (source of truth): + +```c +void remove(Tree* tree, Node* node) { + Node* parent = node->parent; + + Node* sibling; + Node* close_nephew; + Node* distant_nephew; + + Direction dir = direction(node); + + parent->child[dir] = NULL; + goto start_balance; + + do { + dir = direction(node); +start_balance: + sibling = parent->child[1 - dir]; + distant_nephew = sibling->child[1 - dir]; + close_nephew = sibling->child[dir]; + if (sibling->color == RED) { + // Case #3 + rotate_subtree(tree, parent, dir); + parent->color = RED; + sibling->color = BLACK; + sibling = close_nephew; + + distant_nephew = sibling->child[1 - dir]; + if (distant_nephew && distant_nephew->color == RED) { + goto case_6; + } + close_nephew = sibling->child[dir]; + if (close_nephew && close_nephew->color == RED) { + goto case_5; + } + + // Case #4 + sibling->color = RED; + parent->color = BLACK; + return; + } + + if (distant_nephew && distant_nephew->color == RED) { + goto case_6; + } + + if (close_nephew && close_nephew->color == RED) { + goto case_5; + } + + if (!parent) { + // Case #1 + return; + } + + if (parent->color == RED) { + // Case #4 + sibling->color = RED; + parent->color = BLACK; + return; + } + + // Case #2 + sibling->color = RED; + node = parent; + + } while (parent = node->parent); + +case_5: + + rotate_subtree(tree, sibling, 1 - dir); + sibling->color = RED; + close_nephew->color = BLACK; + distant_nephew = sibling; + sibling = close_nephew; + +case_6: + + rotate_subtree(tree, parent, dir); + sibling->color = parent->color; + parent->color = BLACK; + distant_nephew->color = BLACK; + return; +} +``` + +Notes on the algorithm structure: + +- The `goto start_balance` at entry skips the + `dir = direction(node)` recomputation because `dir` was already + set before detaching the node in step 3. +- The `if (!parent)` check (case 1) is unreachable in this + do-while structure: the first iteration enters via + `goto start_balance` with a non-null parent from step 3, and + subsequent iterations only enter when the while condition + `parent = node->parent` is non-null. It is included for + completeness with the Wikipedia source. +- Case 5 and case 6 are placed outside the loop. The `goto` + targets preserve `dir` from the current iteration. + +### Step 5 -- node recycling + +Null both child pointers (insert does not overwrite these fields +when reusing a node from the stack) and push onto the free stack: + +```text +node.child[L] = null +node.child[R] = null +(StackNode)node.next = tree_header.top +tree_header.top = (StackNode)node +``` + +`StackNode.next` occupies offset 0, which overlaps with +`TreeNode.parent`. Insert overwrites the parent field, so +rewriting it here is harmless. The key, value, and color fields +are also overwritten by insert, so they do not need clearing. + +### Return value + +On success, return `RemoveReturn` packed in `r0`: + +```text +r0 = (REMOVE_STATUS_OK << 16) | value +``` + +This matches the `RemoveReturn` struct layout (`value` at bits +0-15, `status` at bits 16-31). Error codes are returned as plain +`r0` values with zero upper bits, so there is no ambiguity. + +## Rust implementation notes + +- Add `remove()` with `#[inline(always)]` and the same parameter + signature as `insert()`. + +- Use the existing `search()` function for key lookup. + +- Use `rotate_subtree()` for rebalancing cases 3, 5, and 6. + +- Add a `direction()` helper: + + ```rust + #[inline(always)] + unsafe fn direction( + node: *const TreeNode, + ) -> usize { + (node == (*(*node).parent).child[tree::DIR_R]) as usize + } + ``` + +- The `goto case_5` / `goto case_6` exits from the rebalancing + loop do not map directly to Rust. Two options: + + - Break out of the loop with a flag or enum indicating which + case to execute, then handle case 5/6 after the loop. + - Inline case 5+6 at each goto site (four sites: two inside + the red-sibling block, two outside). + +## Assembly implementation notes + +The remove instruction label is added after the insert instruction +in `tree.s`. Input validation follows the same pattern as +`insert_input_checks`. + +The first implementation uses `rotate_subtree` with a runtime +`dir` register. The `goto`-based control flow maps directly to +assembly `ja` instructions. Later optimization passes may inline +rotations or introduce hardcoded dir_l/dir_r branches. + +## Rotation inlining optimizations + +When `rotate_subtree` is eventually inlined, several checks inside +the generic rotation can be eliminated based on red-black tree +invariants that hold at each call site. + +### Generic `rotate_subtree` checks + +The generic helper has two conditional branches: + +1. **`new_child` null check**: if `new_child` is non-null, + reparent it to `subtree`. +1. **`parent` null check**: if `subtree.parent` is null, update + `tree.root`; otherwise update the parent's child pointer (with + a direction comparison). + +### Case 3: `rotate(tree, parent, dir)` + +Sibling is red. In a valid red-black tree, a red node must have +two non-null black children. The deficit side (where the black +leaf was removed) requires equal black height through the sibling +subtree, which means both `close_nephew` and `distant_nephew` are +non-null. + +After rotation, `new_child = close_nephew`, which is the sibling's +child on the `dir` side. + +- **`new_child` null check: eliminate.** `close_nephew` is + guaranteed non-null (red sibling invariant). +- **`parent` null check: keep.** `parent` could be the tree root. + +### Case 5: `rotate(tree, sibling, 1 - dir)` + +Sibling is black and is `parent.child[1 - dir]`. Parent is +guaranteed non-null (case 1 / while-condition filters null +parents before reaching case 5). + +After rotation, `new_child = close_nephew.child[1 - dir]`. +`close_nephew` is red (that is the condition for entering case 5), +but its children may be null black leaves. + +- **`new_child` null check: keep.** `close_nephew`'s children may + be null. +- **`parent` null check: eliminate.** `sibling.parent = parent`, + which is non-null. Additionally, the direction of sibling + relative to parent is known (`1 - dir`), so the child pointer + update can be hardcoded to `parent.child[1 - dir] = new_root` + without a direction comparison. + +### Case 6: `rotate(tree, parent, dir)` + +Sibling is black, `distant_nephew` is red. `new_child` is +`sibling.child[dir]`, which may be null. + +- **`new_child` null check: keep.** `sibling.child[dir]` may be + null. +- **`parent` null check: depends on entry path.** + - **After case 3:** Parent was rotated in case 3, making it a + child of the old sibling (now grandparent). Parent's parent + is non-null. **Eliminate.** + - **Direct entry (no case 3):** Parent may be the tree root. + **Keep.** + - Splitting case 6 into post-case-3 and direct variants allows + the check to be eliminated at the first site. + +### Summary + +| Rotation | `new_child` null | `parent` null | Direction hardcode | +| -------- | ---------------- | --------------- | ------------------ | +| Case 3 | eliminate | keep | no | +| Case 5 | keep | eliminate | yes (`1 - dir`) | +| Case 6 | keep | keep or elim.\* | no | + +\*Can be eliminated when case 6 follows case 3. + +## Key invariants + +- `direction(node)` requires `node.parent` to be non-null. This + holds at every call site: simple case 4 guarantees a non-null + parent at entry, and the while condition filters null parents on + re-entry. +- A node with exactly one child must be black with a red child. + This follows from red-black tree properties (equal black height + on all paths). +- The in-order successor has no left child. It may have a right + child, which is handled by simple case 1 after the swap. +- After case 3 (red sibling rotation), the new sibling is + `close_nephew` from before the rotation. The algorithm + reassigns `sibling = close_nephew` before checking nephews. +- A red node must have two non-null black children. This guarantees + that both of a red sibling's children are non-null in case 3. From 4ea55eb86e1c9dc6f15cedce1e4774a34899db38 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:32:24 -0700 Subject: [PATCH 221/263] Beging remove impl --- .../tree/artifacts/snippets/asm/constants.txt | 4 ++- .../snippets/asm/entrypoint-branching.txt | 1 + .../snippets/asm/remove-input-checks.txt | 18 ++++++++++ .../snippets/rs/entrypoint-branching.txt | 2 ++ .../snippets/rs/remove-input-checks.txt | 20 +++++++++++ examples/tree/interface/src/asm.rs | 4 ++- examples/tree/interface/src/common.rs | 2 ++ examples/tree/interface/src/lib.rs | 4 +-- examples/tree/src/program.rs | 34 +++++++++++++++++-- examples/tree/src/tree/tree.s | 29 +++++++++++++++- 10 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/remove-input-checks.txt create mode 100644 examples/tree/artifacts/snippets/rs/remove-input-checks.txt diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 1dd4d54f..5e0c72b4 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -19,6 +19,7 @@ # Not enough accounts passed for insertion allocation. .equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 .equ E_KEY_EXISTS, 14 # Key already exists in tree during insertion. +.equ E_KEY_DOES_NOT_EXIST, 15 # Key does not exist in tree during removal. # Type sizes. # ----------- @@ -29,6 +30,7 @@ .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. .equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. +.equ SIZE_OF_REMOVE_INSTRUCTION, 3 # Size of RemoveInstruction. .equ SIZE_OF_TREE_NODE, 29 # Size of TreeNode. # Data layout constants. @@ -123,7 +125,7 @@ .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. .equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. # Status value for successful remove (first non-error code). -.equ INSN_REMOVE_STATUS_OK, 14 +.equ INSN_REMOVE_STATUS_OK, 15 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt index 6761dffc..c60e08e4 100644 --- a/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/asm/entrypoint-branching.txt @@ -10,6 +10,7 @@ entrypoint: # Jump to branch for given discriminator. # --------------------------------------------------------------------- jeq r7, INSN_DISCRIMINATOR_INSERT, insert + jeq r7, INSN_DISCRIMINATOR_REMOVE, remove jeq r7, INSN_DISCRIMINATOR_INITIALIZE, initialize # Error if invalid discriminator provided. mov64 r0, E_INSTRUCTION_DISCRIMINATOR diff --git a/examples/tree/artifacts/snippets/asm/remove-input-checks.txt b/examples/tree/artifacts/snippets/asm/remove-input-checks.txt new file mode 100644 index 00000000..d5296112 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-input-checks.txt @@ -0,0 +1,18 @@ +remove: + # Error if invalid instruction data length. + # --------------------------------------------------------------------- + jne r9, SIZE_OF_REMOVE_INSTRUCTION, e_instruction_data_len + + # Error if too few accounts. + # --------------------------------------------------------------------- + jlt r8, IB_N_ACCOUNTS_GENERAL, e_n_accounts + + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt index 4739d93d..44c0257d 100644 --- a/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt +++ b/examples/tree/artifacts/snippets/rs/entrypoint-branching.txt @@ -8,6 +8,8 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) - let instruction_discriminator = ldxb(instruction_data, instruction::DISCRIMINATOR_OFF); if likely(instruction_discriminator == instruction::DISCRIMINATOR_INSERT) { insert(input, instruction_data, instruction_data_len, n_accounts) + } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_REMOVE) { + remove(input, instruction_data, instruction_data_len, n_accounts) } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_INITIALIZE) { initialize(input, instruction_data, instruction_data_len, n_accounts) } else { diff --git a/examples/tree/artifacts/snippets/rs/remove-input-checks.txt b/examples/tree/artifacts/snippets/rs/remove-input-checks.txt new file mode 100644 index 00000000..104ce10c --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-input-checks.txt @@ -0,0 +1,20 @@ +#[inline(always)] +unsafe fn remove( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + check_instruction_data_len!(instruction_data_len, RemoveInstruction); + + // Error if too few accounts. + if_err!( + n_accounts < input_buffer::N_ACCOUNTS_GENERAL, + error::N_ACCOUNTS + ); + + // Error if user has data. + let _user = user_account!(input); + + // Error if tree is duplicate. + let _tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); \ No newline at end of file diff --git a/examples/tree/interface/src/asm.rs b/examples/tree/interface/src/asm.rs index 9a43b1da..a7b974af 100644 --- a/examples/tree/interface/src/asm.rs +++ b/examples/tree/interface/src/asm.rs @@ -5,7 +5,8 @@ use crate::bindings::{ }; use crate::common::{ cpi, CreateAccountInstructionData, Direction, GeneralInputBufferHeader, InitInputBuffer, - InitializeInstruction, InputBufferHeader, InsertInstruction, Instruction, TreeHeader, TreeNode, + InitializeInstruction, InputBufferHeader, InsertInstruction, Instruction, RemoveInstruction, + TreeHeader, TreeNode, }; use macros::{asm_constant_group, extend_constant_group, pubkey_chunk_group, sizes, stack_frame}; use pinocchio::{ @@ -24,6 +25,7 @@ sizes! { TreeHeader, InitializeInstruction, InsertInstruction, + RemoveInstruction, TreeNode, } diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 31bb7813..36d2913e 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -36,6 +36,8 @@ error_codes! { N_ACCOUNTS_INSERT_ALLOCATION, /// Key already exists in tree during insertion. KEY_EXISTS, + /// Key does not exist in tree during removal. + KEY_DOES_NOT_EXIST, } constant_group! { diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index abd3c41d..77215faf 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -11,6 +11,6 @@ pub use asm::*; pub use bindings::{SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds}; pub use common::{ cpi, error_codes, instruction, Color, CreateAccountInstructionData, Direction, - InitializeInstruction, InsertInstruction, Instruction, InstructionHeader, StackNode, - TransferInstructionData, TreeHeader, TreeNode, + InitializeInstruction, InsertInstruction, Instruction, InstructionHeader, RemoveInstruction, + StackNode, TransferInstructionData, TreeHeader, TreeNode, }; diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index d9181bd4..3a43e60f 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -9,9 +9,9 @@ use pinocchio::{ }; use tree_interface::{ cpi, data, error_codes::error, input_buffer, instruction, tree, Color, - CreateAccountInstructionData, InitializeInstruction, InsertInstruction, SolAccountInfo, - SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, TransferInstructionData, - TreeHeader, TreeNode, + CreateAccountInstructionData, InitializeInstruction, InsertInstruction, RemoveInstruction, + SolAccountInfo, SolAccountMeta, SolInstruction, SolSignerSeed, SolSignerSeeds, + TransferInstructionData, TreeHeader, TreeNode, }; #[cfg(target_os = "solana")] use { @@ -149,6 +149,8 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) - let instruction_discriminator = ldxb(instruction_data, instruction::DISCRIMINATOR_OFF); if likely(instruction_discriminator == instruction::DISCRIMINATOR_INSERT) { insert(input, instruction_data, instruction_data_len, n_accounts) + } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_REMOVE) { + remove(input, instruction_data, instruction_data_len, n_accounts) } else if likely(instruction_discriminator == instruction::DISCRIMINATOR_INITIALIZE) { initialize(input, instruction_data, instruction_data_len, n_accounts) } else { @@ -520,6 +522,32 @@ unsafe fn insert( } // ANCHOR_END: insert-fixup-case-2-3 +// ANCHOR: remove-input-checks +#[inline(always)] +unsafe fn remove( + input: *mut u8, + instruction_data: *mut u8, + instruction_data_len: u64, + n_accounts: u64, +) -> u64 { + check_instruction_data_len!(instruction_data_len, RemoveInstruction); + + // Error if too few accounts. + if_err!( + n_accounts < input_buffer::N_ACCOUNTS_GENERAL, + error::N_ACCOUNTS + ); + + // Error if user has data. + let _user = user_account!(input); + + // Error if tree is duplicate. + let _tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); + // ANCHOR_END: remove-input-checks + + error::KEY_DOES_NOT_EXIST.into() +} + // ANCHOR: initialize-input-checks #[inline(always)] unsafe fn initialize( diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index d9b12721..393f8165 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -20,6 +20,7 @@ # Not enough accounts passed for insertion allocation. .equ E_N_ACCOUNTS_INSERT_ALLOCATION, 13 .equ E_KEY_EXISTS, 14 # Key already exists in tree during insertion. +.equ E_KEY_DOES_NOT_EXIST, 15 # Key does not exist in tree during removal. # Type sizes. # ----------- @@ -30,6 +31,7 @@ .equ SIZE_OF_TREE_HEADER, 24 # Size of TreeHeader. .equ SIZE_OF_INITIALIZE_INSTRUCTION, 1 # Size of InitializeInstruction. .equ SIZE_OF_INSERT_INSTRUCTION, 5 # Size of InsertInstruction. +.equ SIZE_OF_REMOVE_INSTRUCTION, 3 # Size of RemoveInstruction. .equ SIZE_OF_TREE_NODE, 29 # Size of TreeNode. # Data layout constants. @@ -124,7 +126,7 @@ .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. .equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. # Status value for successful remove (first non-error code). -.equ INSN_REMOVE_STATUS_OK, 14 +.equ INSN_REMOVE_STATUS_OK, 15 # Init stack frame layout. # ------------------------ @@ -253,6 +255,7 @@ entrypoint: # Jump to branch for given discriminator. # --------------------------------------------------------------------- jeq r7, INSN_DISCRIMINATOR_INSERT, insert + jeq r7, INSN_DISCRIMINATOR_REMOVE, remove jeq r7, INSN_DISCRIMINATOR_INITIALIZE, initialize # Error if invalid discriminator provided. mov64 r0, E_INSTRUCTION_DISCRIMINATOR @@ -862,6 +865,30 @@ insert_fixup_case_2: exit # Case 3. # ANCHOR_END: insert-fixup-case-2-3 +# ANCHOR: remove-input-checks +remove: + # Error if invalid instruction data length. + # --------------------------------------------------------------------- + jne r9, SIZE_OF_REMOVE_INSTRUCTION, e_instruction_data_len + + # Error if too few accounts. + # --------------------------------------------------------------------- + jlt r8, IB_N_ACCOUNTS_GENERAL, e_n_accounts + + # Error if user has data. + # --------------------------------------------------------------------- + ldxdw r9, [r1 + IB_USER_DATA_LEN_OFF] + jne r9, DATA_LEN_ZERO, e_user_data_len + + # Error if tree is duplicate. + # --------------------------------------------------------------------- + ldxb r9, [r1 + IB_TREE_NON_DUP_MARKER_OFF] + jne r9, IB_NON_DUP_MARKER, e_tree_duplicate + # ANCHOR_END: remove-input-checks + + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From 11d45e3671f2fc2caabde279ba88a92989d78f18 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:18:59 -0700 Subject: [PATCH 222/263] Add testing spec --- .../snippets/interface/instructions.txt | 2 +- examples/tree/interface/src/common.rs | 2 +- examples/tree/specs/remove-tests.md | 758 ++++++++++++++++++ examples/tree/specs/remove.md | 6 +- 4 files changed, 763 insertions(+), 5 deletions(-) create mode 100644 examples/tree/specs/remove-tests.md diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index 13f11429..a81ac2ca 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -34,8 +34,8 @@ pub struct RemoveInstruction { #[repr(C, packed)] /// Value in r0. pub struct RemoveReturn { - value: u16, status: u16, + value: u16, } constant_group! { diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 36d2913e..655616da 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -276,8 +276,8 @@ pub struct RemoveInstruction { #[repr(C, packed)] /// Value in r0. pub struct RemoveReturn { - value: u16, status: u16, + value: u16, } constant_group! { diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md new file mode 100644 index 00000000..8f35f104 --- /dev/null +++ b/examples/tree/specs/remove-tests.md @@ -0,0 +1,758 @@ +# Remove-to-tree test specification + +## Scope + +Tests for the remove instruction: input validation, search, BST +deletion, red-black rebalancing, node recycling, and return value +encoding. Mirrors the structure of the insert test specification. + +## Shared test helpers + +The insert tests define helpers (`NodeSpec`, `TreeSpec`, +`build_tree_account`, `assert_tree_account`, `node()`, `B`, `R`, +`node_vaddr`, `opt_vaddr`, `build_empty_tree`) that are equally +useful for remove tests. These should be extracted into a shared +module (e.g. `tests/common.rs`) imported by both `tests/insert.rs` +and `tests/remove.rs`. + +Helpers that stay in `tests/insert.rs` (insert-specific): + +- `insert_instruction_data`, `insert_setup`, + `insert_skip_alloc_setup`, `insert_tree_setup`. +- `run_success`, `run_dup_error`. +- `InsertCase`, `MultiInsertCase`. + +New helpers in `tests/remove.rs` (remove-specific): + +- `remove_setup(lang, desc, remove_key)` -- build a pre-populated + tree account and a `RemoveInstruction` with the given key. Uses + two accounts (user + tree), no CPI accounts needed. +- `run_remove_success(lang, desc, remove_key, expected_value, expected_tree)` -- + execute the remove instruction, verify the + return code encodes the expected value, then assert full tree + state including the freed node slot. +- `run_remove_not_found(lang, desc, remove_key)` -- execute and + verify `KEY_DOES_NOT_EXIST` error. + +## Return value verification + +On success the program returns `RemoveReturn` packed in `r0`: + +```text +r0 = (value << 16) | REMOVE_STATUS_OK +``` + +The Solana runtime interprets any non-zero `r0` as +`ProgramError::Custom(r0)`. Tests must verify the result is +`ProgramError::Custom((value as u32) << 16 | REMOVE_STATUS_OK as u32)` where `REMOVE_STATUS_OK` equals `error::N_CODES` +(currently 15). This confirms both the value field (bits 16-31) +and the status field (bits 0-15) are encoded correctly. + +## Freed node verification + +When a node is removed it is cast to a `StackNode` and pushed onto +the free stack. The full-state assertion must verify: + +- **`header.top`** points to the freed node slot. +- **Freed node `child[L]`** is null (zeroed by remove). +- **Freed node `child[R]`** is null (zeroed by remove). +- **Freed node `parent`** (offset 0, overlaps `StackNode.next`) + equals the previous stack top (null if the stack was empty before + removal). + +The `key`, `value`, and `color` fields of the freed node are not +cleared by remove (insert overwrites them when the node is +recycled). Tests should still assert their values to confirm remove +does not clobber them unexpectedly -- they should retain whatever +values they had before removal. + +The existing `assert_tree_account` already checks every field of +every node in the buffer, so including the freed node slot in the +expected `TreeSpec.nodes` list is sufficient. No new assertion +helper is needed; the freed node is simply a `NodeSpec` with null +children and `parent` set to the old stack top index. + +## `build_tree_account` adjustment + +The insert helper always appends one extra free slot after the +existing nodes (for the node to be inserted). For remove tests, +the tree should contain only the existing nodes with no extra free +slot -- there is nothing to insert, and the removed node itself +becomes the new free slot. A `build_tree_account_no_free` variant +(or a flag) is needed: + +- `header.top = null` (no pre-existing free nodes). +- `header.next = null` (unused). +- Data length = `sizeof(TreeHeader) + N * sizeof(TreeNode)`. + +After removal, the freed node's slot is already within the +existing data. `header.top` will point to the freed node, and +`StackNode.next` will be null (stack was empty). + +If the tree already has free nodes on the stack before removal +(tested in multi-step scenarios), `header.top` is set to the +existing free node and the freed node's `StackNode.next` must +chain to it. + +## Input check tests + +Same checks as insert, using `RemoveInstruction` (discriminator 2, +3 bytes). Each test constructs a valid two-account remove setup, +mutates one property, and expects the corresponding error. + +| Case | Mutation | Expected error | +| ----------------- | ------------------------ | ---------------------- | +| Data too short | 1-byte instruction data | `INSTRUCTION_DATA_LEN` | +| Data too long | 4-byte instruction data | `INSTRUCTION_DATA_LEN` | +| Too few accounts | 1 account (user only) | `N_ACCOUNTS` | +| User has data | User account with 1 byte | `USER_DATA_LEN` | +| Tree is duplicate | Tree = copy of user | `TREE_DUPLICATE` | + +## Search error tests + +| Case | Tree setup | Key | Expected | +| -------------- | ------------------ | --- | -------------------- | +| Empty tree | Root is null | 10 | `KEY_DOES_NOT_EXIST` | +| Not found (L) | Root key=10 | 5 | `KEY_DOES_NOT_EXIST` | +| Not found (R) | Root key=10 | 15 | `KEY_DOES_NOT_EXIST` | +| Not found deep | Root 10, L=5, R=15 | 12 | `KEY_DOES_NOT_EXIST` | + +Search error tests must also verify the tree account data is +unchanged after the failed instruction. + +## Simple removal cases + +These cases do not trigger rebalancing. + +### Simple case 2: remove root leaf + +Single-node tree. Root becomes null, node is freed. + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 val=10 parent=-- L=-- R=-- + +After remove key=10 (returns value=10): + Header: root=-- top=N0 next=-- + N0: key=10 val=10 color=B parent=-- L=-- R=-- <- freed +``` + +`parent` (= `StackNode.next`) is null because the stack was empty. + +### Simple case 3: remove red leaf + +Red leaf with a black parent. Detach the leaf. + +Left child variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=-- R=-- + N1: key=5 color=R parent=-- L=-- R=-- <- freed +``` + +Right child variant (remove key=15): mirror with N1 as right +child of N0. + +### Simple case 1: node with one child + +A node with exactly one child must be black, and the child must +be red (RB invariant). Replace the node with its child and +recolor the child black. + +Right child variant (remove key=10): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=-- R=N1 + N1: R key=15 parent=N0 L=-- R=-- + +After: + Header: root=N1 top=N0 next=-- + N0: key=10 color=B parent=-- L=-- R=-- <- freed + N1: B key=15 parent=-- L=-- R=-- <- recolored B, new root +``` + +Left child variant (remove key=10, child is N1 at L): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- + +After: + Header: root=N1 top=N0 next=-- + N0: key=10 color=B parent=-- L=-- R=-- <- freed + N1: B key=5 parent=-- L=-- R=-- <- recolored B, new root +``` + +Non-root variant (remove key=15): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=N3 + N3: R key=20 parent=N2 L=-- R=-- + +After: + Header: root=N0 top=N2 next=-- + N0: B key=10 parent=-- L=N1 R=N3 + N1: B key=5 parent=N0 L=-- R=-- + N2: key=15 color=B parent=-- L=-- R=-- <- freed + N3: B key=20 parent=N0 L=-- R=-- <- recolored B +``` + +## Successor swap cases + +When the node to delete has two children, copy key/value from +the in-order successor (leftmost in right subtree), then delete +the successor instead. + +### Successor is immediate right child + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=15 parent=N0 L=-- R=-- + +After remove key=10 (returns value=10): + Header: root=N0 top=N2 next=-- + N0: B key=15 val=15 parent=-- L=N1 R=-- <- copied from successor + N1: B key=5 parent=N0 L=-- R=-- + N2: key=15 color=R parent=-- L=-- R=-- <- freed (was successor) +``` + +The successor (N2, key=15) is a red leaf -- simple case 3 after +the swap. + +### Successor with deep left descent + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=20 parent=N0 L=N3 R=N4 + N3: R key=15 parent=N2 L=-- R=-- + N4: R key=25 parent=N2 L=-- R=-- + +After remove key=10 (returns value=10): + Header: root=N0 top=N3 next=-- + N0: B key=15 val=15 parent=-- L=N1 R=N2 <- copied from successor + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=20 parent=N0 L=-- R=N4 + N3: key=15 color=R parent=-- L=-- R=-- <- freed (was successor) + N4: R key=25 parent=N2 L=-- R=-- +``` + +The successor (N3, key=15) is a red leaf -- simple case 3 after +the swap. + +### Successor with right child + +The successor has no left child but may have a right child. +This triggers simple case 1 (one-child node) after the swap. + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=N3 + N3: R key=20 parent=N2 L=-- R=-- + +After remove key=10 (returns value=10): + Header: root=N0 top=N2 next=-- + N0: B key=15 val=15 parent=-- L=N1 R=N3 <- copied from successor + N1: B key=5 parent=N0 L=-- R=-- + N2: key=15 color=B parent=-- L=-- R=-- <- freed (was successor) + N3: B key=20 parent=N0 L=-- R=-- <- recolored B +``` + +Successor N2 has one child (N3). Simple case 1: replace N2 with +N3, recolor N3 black. + +## Rebalancing cases + +Entry condition: a black leaf was removed from `parent.child[dir]`. +The rebalancing loop executes with `(parent, dir)`. + +Cases follow the Wikipedia algorithm numbering. Each case lists +both direction variants (dir_l where the removed node was a left +child, dir_r where it was a right child) unless noted otherwise. + +### Case 4: red parent, black sibling, black nephews + +Recolor sibling red and parent black. No rotation. + +Dir_l variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: R key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=-- R=N2 <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: R key=15 parent=N0 L=-- R=-- <- recolored R +``` + +Dir_r variant (remove key=15): mirror of above. + +### Case 6: black sibling, distant nephew red + +Single rotation at parent. Sibling takes parent's color, parent +and distant nephew become black. + +Dir_l variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=N3 + N3: R key=20 parent=N2 L=-- R=-- + +After: + Header: root=N2 top=N1 next=-- + N0: B key=10 parent=N2 L=-- R=-- <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=15 parent=-- L=N0 R=N3 <- new root + N3: B key=20 parent=N2 L=-- R=-- <- recolored B +``` + +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N3 R=-- + N2: B key=20 parent=N0 L=-- R=-- + N3: R key=3 parent=N1 L=-- R=-- + +After: + Header: root=N1 top=N2 next=-- + N0: B key=10 parent=N1 L=-- R=-- <- recolored B + N1: B key=5 parent=-- L=N3 R=N0 <- new root + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: B key=3 parent=N1 L=-- R=-- <- recolored B +``` + +### Case 6: non-null new_child in rotation + +The rotation transfers sibling's child on the `dir` side to +parent. When that child is non-null, it must be reparented. + +Dir_l variant (remove key=3): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N4 R=-- + N2: B key=20 parent=N0 L=N3 R=N5 + N3: R key=15 parent=N2 L=-- R=-- + N4: B key=3 parent=N1 L=-- R=-- + N5: R key=25 parent=N2 L=-- R=-- + +After remove key=5 (successor swap: N1 gets key=3 from N4, +then delete N4 which is a black leaf): + Header: root=N0 top=N4 next=-- + N0: B key=10 parent=N2 L=N1 R=N3 <- reparented + N1: B key=3 parent=N0 L=-- R=-- <- copied from successor + N2: B key=20 parent=-- L=N0 R=N5 <- new root + N3: B key=15 parent=N0 L=-- R=-- <- reparented, recolored B + N4: key=3 color=B parent=-- L=-- R=-- <- freed + N5: B key=25 parent=N2 L=-- R=-- <- recolored B +``` + +Wait -- this case is getting complex because it also involves a +successor swap. A cleaner test isolates the rotation by removing +a black leaf directly. Concrete before/after states for non-null +new_child cases will be determined during implementation when +exact tree shapes are constructed. + +### Case 5 + 6: close nephew red, distant nephew black + +Rotate sibling away from dir (case 5), then rotate parent toward +dir (case 6). + +Dir_l variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=20 parent=N0 L=N3 R=-- + N3: R key=15 parent=N2 L=-- R=-- + +After: + Header: root=N3 top=N1 next=-- + N0: B key=10 parent=N3 L=-- R=-- <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: R key=20 parent=N3 L=-- R=-- <- recolored R + N3: B key=15 parent=-- L=N0 R=N2 <- new root +``` + +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=N3 + N2: B key=20 parent=N0 L=-- R=-- + N3: R key=7 parent=N1 L=-- R=-- + +After: + Header: root=N3 top=N2 next=-- + N0: B key=10 parent=N3 L=-- R=-- <- recolored B + N1: R key=5 parent=N3 L=-- R=-- <- recolored R + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: B key=7 parent=-- L=N1 R=N0 <- new root +``` + +### Case 3 + case 4: red sibling, then recolor + +Red sibling is rotated, making the old close_nephew the new +sibling. If the new sibling has two black/null nephews, recolor +(case 4). + +Dir_l variant (remove key=3): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N4 R=-- + N2: R key=20 parent=N0 L=N3 R=N5 + N3: B key=15 parent=N2 L=-- R=-- + N4: B key=3 parent=N1 L=-- R=-- + +After remove key=5 (successor swap from N4, delete N4 as black +leaf, dir=L relative to N1): + Header: root=N2 top=N4 next=-- + N0: B key=10 parent=N2 L=N1 R=N3 <- reparented + N1: B key=3 parent=N0 L=-- R=-- <- swapped key/val + N2: B key=20 parent=-- L=N0 R=N5 <- recolored B, new root + N3: R key=15 parent=N0 L=-- R=-- <- recolored R (case 4) + N4: key=3 color=B parent=-- L=-- R=-- <- freed + N5: B key=25 parent=N2 L=-- R=-- +``` + +These trees are moderately complex. Exact before/after states +should be verified by hand or with a reference implementation +during test construction. The spec lists the required paths; the +implementation fills in precise node layouts. + +### Case 3 + case 6: red sibling, then distant nephew red + +After the case 3 rotation, the new sibling's distant nephew is +red. Jump directly to case 6. + +Dir_l and dir_r variants needed. + +### Case 3 + case 5 + case 6: red sibling, then double rotation + +After the case 3 rotation, the new sibling's close nephew is red +and distant nephew is black. Case 5 rotates, then case 6 rotates. + +Dir_l and dir_r variants needed. + +### Case 2: propagation + +Black sibling, both nephews black, black parent. Recolor sibling +red and propagate upward with `node = parent`. + +Dir_l variant (remove key=3): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N3 R=-- + N2: B key=15 parent=N0 L=-- R=-- + N3: B key=3 parent=N1 L=-- R=-- + +After remove key=5 (successor swap from N3, delete N3 as black +leaf): + Header: root=N0 top=N3 next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=3 parent=N0 L=-- R=-- <- swapped key/val + N2: R key=15 parent=N0 L=-- R=-- <- recolored R (case 2) + N3: key=3 color=B parent=-- L=-- R=-- <- freed +``` + +Wait -- after case 2 recolors sibling and propagates to N0 (the +root), the while condition `parent = node->parent` is null, so +the loop exits. But N0 is already black, so the tree is valid +with a shorter black height. The resulting tree has N2 as red, +which combined with case 2's recolor of the sibling means the +tree stays balanced. + +Exact states for case 2 propagation chains (case 2 → case 4, +case 2 → case 6, etc.) require larger trees and should be +verified during implementation. + +### Case 2 + case 4: propagate then red parent + +Case 2 propagates upward, reaching a red parent. Case 4 recolors +and terminates. + +### Case 2 + case 6: propagate then rotation + +Case 2 propagates upward, reaching a position where the distant +nephew is red. Case 6 rotates and terminates. + +## Case 6: parent null check variants + +Case 6 rotates parent. If parent is the tree root, the rotation +must update `tree.root`. If parent has a parent, the +great-grandparent's child pointer must be updated (left or right +depending on direction). + +| Variant | Parent position | Covers | +| --------------------- | ----------------------- | ------------------- | +| Parent is root | Parent has no parent | Root replacement | +| Parent is left child | Parent is GGP's L child | GGP.child[L] update | +| Parent is right child | Parent is GGP's R child | GGP.child[R] update | + +Each variant needs dir_l and dir_r sub-variants. + +### Case 3: parent null check + +Case 3 rotates parent. Same root vs. non-root variants as +case 6. + +## Test case summary + +### Input checks + +| # | Case | +| --- | ----------------- | +| 1 | Data too short | +| 2 | Data too long | +| 3 | Too few accounts | +| 4 | User has data | +| 5 | Tree is duplicate | + +### Search errors + +| # | Case | +| --- | ----------------- | +| 6 | Empty tree | +| 7 | Not found (left) | +| 8 | Not found (right) | +| 9 | Not found (deep) | + +### Simple removal + +| # | Case | Direction | +| --- | --------------------------------- | --------- | +| 10 | Root leaf (simple case 2) | -- | +| 11 | Red leaf (simple case 3) | L | +| 12 | Red leaf (simple case 3) | R | +| 13 | One child at root (simple case 1) | R child | +| 14 | One child at root (simple case 1) | L child | +| 15 | One child non-root (sc 1) | R child | + +### Successor swap + +| # | Case | +| --- | -------------------------- | +| 16 | Immediate right child | +| 17 | Deep left descent | +| 18 | Successor with right child | + +### Rebalancing (black leaf removal) + +| # | Path | Dir | +| --- | ----------------------------- | --- | +| 19 | Case 4 | L | +| 20 | Case 4 | R | +| 21 | Case 6 | L | +| 22 | Case 6 | R | +| 23 | Case 5 + 6 | L | +| 24 | Case 5 + 6 | R | +| 25 | Case 3 → 4 | L | +| 26 | Case 3 → 4 | R | +| 27 | Case 3 → 6 | L | +| 28 | Case 3 → 6 | R | +| 29 | Case 3 → 5 → 6 | L | +| 30 | Case 3 → 5 → 6 | R | +| 31 | Case 2 (propagate to root) | L | +| 32 | Case 2 (propagate to root) | R | +| 33 | Case 2 → 4 | -- | +| 34 | Case 2 → 6 | -- | +| 35 | Case 6 non-null new_child | L | +| 36 | Case 6 non-null new_child | R | +| 37 | Case 6 parent=root | L | +| 38 | Case 6 parent=root | R | +| 39 | Case 6 parent=GGP left child | L | +| 40 | Case 6 parent=GGP right child | R | +| 41 | Case 3 parent=root | L | +| 42 | Case 3 parent=root | R | + +### Multi-step integration + +| # | Case | +| --- | --------------------------------- | +| 43 | Insert 3, remove 1 (minimal) | +| 44 | Insert 7, remove all (full cycle) | +| 45 | Insert-remove-insert (recycling) | + +## Multi-step integration tests + +Sequential operations that verify insert and remove interact +correctly. These use `build_empty_tree` to pre-allocate free +slots, then chain insert and remove instructions, asserting full +tree state after each step. + +| Test | Sequence | Purpose | +| ---------- | ---------------------- | ---------------- | +| Minimal | Insert 10,5,15; rm 5 | Basic remove | +| Full cycle | Insert 7 nodes; rm all | All nodes freed | +| Recycle | Insert 3; rm 1; insert | Reuse from stack | + +The recycle test is critical: after removing a node, the free +stack must correctly provide it for the next insert. This +validates the `StackNode.next` chain and `header.top` updates +across both operations. + +## Coverage notes + +The test list above covers all paths through the Wikipedia +rebalancing algorithm, both direction variants, successor swap +edge cases, and the `rotate_subtree` null/non-null checks. As +optimizations are introduced (inlined rotations, hardcoded +direction branches), additional test cases may be needed to +ensure full branch coverage of the new code paths. Each +optimization should reference which existing tests cover it and +add new cases for any branches not yet exercised. + +## Reference algorithm + +The verbatim Wikipedia remove-rebalancing algorithm (source of +truth for case numbering and control flow): + +```c +void remove(Tree* tree, Node* node) { + Node* parent = node->parent; + + Node* sibling; + Node* close_nephew; + Node* distant_nephew; + + Direction dir = direction(node); + + parent->child[dir] = NULL; + goto start_balance; + + do { + dir = direction(node); +start_balance: + sibling = parent->child[1 - dir]; + distant_nephew = sibling->child[1 - dir]; + close_nephew = sibling->child[dir]; + if (sibling->color == RED) { + // Case #3 + rotate_subtree(tree, parent, dir); + parent->color = RED; + sibling->color = BLACK; + sibling = close_nephew; + + distant_nephew = sibling->child[1 - dir]; + if (distant_nephew + && distant_nephew->color == RED) { + goto case_6; + } + close_nephew = sibling->child[dir]; + if (close_nephew + && close_nephew->color == RED) { + goto case_5; + } + + // Case #4 + sibling->color = RED; + parent->color = BLACK; + return; + } + + if (distant_nephew + && distant_nephew->color == RED) { + goto case_6; + } + + if (close_nephew + && close_nephew->color == RED) { + goto case_5; + } + + if (!parent) { + // Case #1 + return; + } + + if (parent->color == RED) { + // Case #4 + sibling->color = RED; + parent->color = BLACK; + return; + } + + // Case #2 + sibling->color = RED; + node = parent; + + } while (parent = node->parent); + +case_5: + + rotate_subtree(tree, sibling, 1 - dir); + sibling->color = RED; + close_nephew->color = BLACK; + distant_nephew = sibling; + sibling = close_nephew; + +case_6: + + rotate_subtree(tree, parent, dir); + sibling->color = parent->color; + parent->color = BLACK; + distant_nephew->color = BLACK; + return; +} +``` + +The test cases map to paths through this algorithm: + +- **Case 2**: the `sibling->color = RED; node = parent` path, + loop continues. +- **Case 3**: `sibling->color == RED` branch, then falls through + to check nephews of the new sibling. +- **Case 4**: `parent->color == RED` recolor (both direct and + after case 3). +- **Case 5**: `close_nephew` is red, `goto case_5` from either + the case 3 block or the main block. +- **Case 6**: `distant_nephew` is red, `goto case_6` from either + the case 3 block or the main block. diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index 691e6942..c6650568 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -328,11 +328,11 @@ are also overwritten by insert, so they do not need clearing. On success, return `RemoveReturn` packed in `r0`: ```text -r0 = (REMOVE_STATUS_OK << 16) | value +r0 = (value << 16) | REMOVE_STATUS_OK ``` -This matches the `RemoveReturn` struct layout (`value` at bits -0-15, `status` at bits 16-31). Error codes are returned as plain +This matches the `RemoveReturn` struct layout (`status` at bits +0-15, `value` at bits 16-31). Error codes are returned as plain `r0` values with zero upper bits, so there is no ambiguity. ## Rust implementation notes From 9ec470e3b3e34b12c6131f7fb7d01e78272ec8d6 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:31:35 -0700 Subject: [PATCH 223/263] Bump sbpf version --- .github/workflows/build-examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-examples.yml b/.github/workflows/build-examples.yml index 4412db36..5a9b63f8 100644 --- a/.github/workflows/build-examples.yml +++ b/.github/workflows/build-examples.yml @@ -4,7 +4,7 @@ env: SBPF_ARCH_DISASSEMBLE: 'v2' SBPF_ARCH_DUMP: 'v4' SBPF_ARCH_TEST: 'v3' - SBPF_CLI_REVISION: 'eb67fc5' + SBPF_CLI_REVISION: 'c52805f' SOLANA_VERSION: 'v3.1.2' TOOLS_VERSION_DISASSEMBLE: 'v1.52' TOOLS_VERSION_DUMP: 'v1.51' From 0417f01da9183354cf45d346660cf7be661f18d7 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:32:03 -0700 Subject: [PATCH 224/263] Begin testing implementation --- examples/tree/src/tests.rs | 12 + examples/tree/src/tests/common.rs | 309 ++++++ examples/tree/src/tests/insert.rs | 271 +---- examples/tree/src/tests/remove.rs | 1685 +++++++++++++++++++++++++++++ 4 files changed, 2009 insertions(+), 268 deletions(-) create mode 100644 examples/tree/src/tests/common.rs create mode 100644 examples/tree/src/tests/remove.rs diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 97c9e78b..6bff9e22 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -1,6 +1,8 @@ +mod common; mod entrypoint; mod init; mod insert; +mod remove; use mollusk_svm::program; use mollusk_svm::result::{Check, Config, ProgramResult as MolluskResult}; @@ -226,3 +228,13 @@ fn test_insert_to_tree() { fn test_multi_insert() { print_comparison_table(insert::MultiInsertCase::CASES); } + +#[test] +fn test_remove_input_checks() { + print_comparison_table(remove::RemoveCase::INPUT_CASES); +} + +#[test] +fn test_remove_search() { + print_comparison_table(remove::RemoveCase::SEARCH_CASES); +} diff --git a/examples/tree/src/tests/common.rs b/examples/tree/src/tests/common.rs new file mode 100644 index 00000000..4e2a7ae6 --- /dev/null +++ b/examples/tree/src/tests/common.rs @@ -0,0 +1,309 @@ +use super::*; +use tree_interface::{input_buffer, tree, Color, StackNode, TreeHeader, TreeNode}; + +// --------------------------------------------------------------------------- +// Helpers: tree description types +// --------------------------------------------------------------------------- + +pub(super) struct NodeSpec { + pub key: u16, + pub value: u16, + pub color: u8, + pub parent: Option, + pub left: Option, + pub right: Option, +} + +impl NodeSpec { + pub fn val(mut self, v: u16) -> Self { + self.value = v; + self + } +} + +pub(super) struct TreeSpec<'a> { + pub root: Option, + pub top: Option, + pub nodes: &'a [NodeSpec], +} + +/// Compute the virtual address of node slot `i` in the tree account. +pub(super) fn node_vaddr(i: usize) -> u64 { + MM_INPUT_START + + input_buffer::TREE_DATA_OFF as u64 + + size_of::() as u64 + + (i as u64) * (size_of::() as u64) +} + +/// Convert an optional node index to a virtual address (0 for None). +pub(super) fn opt_vaddr(idx: Option) -> u64 { + match idx { + Some(i) => node_vaddr(i), + None => 0, + } +} + +// --------------------------------------------------------------------------- +// Helper: build tree account data +// --------------------------------------------------------------------------- + +/// Build tree account data with pre-existing nodes and one free StackNode. +/// +/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] | free_slot +/// +/// - `header.root` → virtual address of `nodes[root]`, or null. +/// - `header.top` → virtual address of the free slot (index = nodes.len()). +/// - `header.next` → 0 (unused in skip-alloc path). +pub(super) fn build_tree_account(desc: &TreeSpec, program_id: &Pubkey) -> (Pubkey, Account) { + let n = desc.nodes.len(); + // N existing nodes + 1 free slot. + let data_len = size_of::() + (n + 1) * size_of::(); + let mut data = vec![0u8; data_len]; + + // Write header. + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = opt_vaddr(desc.root) as *mut TreeNode; + (*header).top = node_vaddr(n) as *mut StackNode; + (*header).next = core::ptr::null_mut(); + } + + // Write existing nodes. + write_nodes(&mut data, desc.nodes); + + // Free slot is already zeroed (StackNode.next = null). + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} + +/// Build tree account data with pre-existing nodes and no free slot. +/// +/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] +/// +/// - `header.root` → virtual address of `nodes[root]`, or null. +/// - `header.top` → null (no pre-existing free nodes). +/// - `header.next` → null (unused). +pub(super) fn build_tree_account_no_free( + desc: &TreeSpec, + program_id: &Pubkey, +) -> (Pubkey, Account) { + let n = desc.nodes.len(); + let data_len = size_of::() + n * size_of::(); + let mut data = vec![0u8; data_len]; + + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = opt_vaddr(desc.root) as *mut TreeNode; + (*header).top = core::ptr::null_mut(); + (*header).next = core::ptr::null_mut(); + } + + write_nodes(&mut data, desc.nodes); + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} + +fn write_nodes(data: &mut [u8], nodes: &[NodeSpec]) { + for (i, node) in nodes.iter().enumerate() { + let offset = size_of::() + i * size_of::(); + let ptr = unsafe { data.as_mut_ptr().add(offset) as *mut TreeNode }; + unsafe { + (*ptr).parent = opt_vaddr(node.parent) as *mut TreeNode; + (*ptr).child[tree::DIR_L] = opt_vaddr(node.left) as *mut TreeNode; + (*ptr).child[tree::DIR_R] = opt_vaddr(node.right) as *mut TreeNode; + (*ptr).key = node.key; + (*ptr).value = node.value; + (*ptr).color = core::mem::transmute(node.color); + } + } +} + +// --------------------------------------------------------------------------- +// Helper: assert tree account (full state) +// --------------------------------------------------------------------------- + +/// Assert every field of the tree account data against expected state. +/// Returns Ok(()) on match, Err(description) on mismatch. +pub(super) fn assert_tree_account(data: &[u8], expected: &TreeSpec) -> Result<(), String> { + let mut errors = Vec::new(); + let n = expected.nodes.len(); + + // Check data length (at least enough for the expected nodes). + let min_len = size_of::() + n * size_of::(); + if data.len() < min_len { + errors.push(format!( + "data len: expected at least {}, got {}", + min_len, + data.len() + )); + } + + // Check header. + let header = data.as_ptr() as *const TreeHeader; + unsafe { + let root_addr = (*header).root as u64; + let expected_root = opt_vaddr(expected.root); + if root_addr != expected_root { + errors.push(format!( + "header.root: expected {:#x}, got {:#x}", + expected_root, root_addr + )); + } + + let top_addr = (*header).top as u64; + let expected_top = opt_vaddr(expected.top); + if top_addr != expected_top { + errors.push(format!( + "header.top: expected {:#x}, got {:#x}", + expected_top, top_addr + )); + } + + let next_addr = (*header).next as u64; + if next_addr != 0 { + errors.push(format!("header.next: expected 0x0, got {:#x}", next_addr)); + } + } + + // Check each node. + for i in 0..n { + let offset = size_of::() + i * size_of::(); + if offset + size_of::() > data.len() { + errors.push(format!("N{}: out of bounds", i)); + continue; + } + let ptr = unsafe { data.as_ptr().add(offset) as *const TreeNode }; + let exp = &expected.nodes[i]; + let label = format!("N{}", i); + + unsafe { + let parent_addr = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).parent)) as u64; + let expected_parent = opt_vaddr(exp.parent); + if parent_addr != expected_parent { + errors.push(format!( + "{}.parent: expected {:#x}, got {:#x}", + label, expected_parent, parent_addr + )); + } + + let left_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_L])) as u64; + let expected_left = opt_vaddr(exp.left); + if left_addr != expected_left { + errors.push(format!( + "{}.L: expected {:#x}, got {:#x}", + label, expected_left, left_addr + )); + } + + let right_addr = + core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_R])) as u64; + let expected_right = opt_vaddr(exp.right); + if right_addr != expected_right { + errors.push(format!( + "{}.R: expected {:#x}, got {:#x}", + label, expected_right, right_addr + )); + } + + let key = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).key)); + if key != exp.key { + errors.push(format!("{}.key: expected {}, got {}", label, exp.key, key)); + } + + let value = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).value)); + if value != exp.value { + errors.push(format!( + "{}.value: expected {}, got {}", + label, exp.value, value + )); + } + + let color = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).color)) as u8; + if color != exp.color { + let color_name = |c: u8| if c == 0 { "B" } else { "R" }; + errors.push(format!( + "{}.color: expected {}, got {}", + label, + color_name(exp.color), + color_name(color) + )); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors.join("; ")) + } +} + +// --------------------------------------------------------------------------- +// Shorthand constructors +// --------------------------------------------------------------------------- + +pub(super) const B: u8 = Color::Black as u8; +pub(super) const R: u8 = Color::Red as u8; + +pub(super) fn node( + key: u16, + color: u8, + parent: Option, + left: Option, + right: Option, +) -> NodeSpec { + NodeSpec { + key, + value: key, + color, + parent, + left, + right, + } +} + +// --------------------------------------------------------------------------- +// Helper: build empty tree with pre-allocated free slots +// --------------------------------------------------------------------------- + +/// Build an empty tree account with `n` pre-allocated free slots. +pub(super) fn build_empty_tree(n: usize, program_id: &Pubkey) -> (Pubkey, Account) { + let data_len = size_of::() + n * size_of::(); + let mut data = vec![0u8; data_len]; + + let header = data.as_mut_ptr() as *mut TreeHeader; + unsafe { + (*header).root = core::ptr::null_mut(); + (*header).top = if n > 0 { + node_vaddr(0) as *mut StackNode + } else { + core::ptr::null_mut() + }; + (*header).next = core::ptr::null_mut(); + } + + // Link free slots into a singly-linked list. + for i in 0..n { + let offset = size_of::() + i * size_of::(); + let slot = unsafe { data.as_mut_ptr().add(offset) as *mut StackNode }; + unsafe { + (*slot).next = if i + 1 < n { + node_vaddr(i + 1) as *mut StackNode + } else { + core::ptr::null_mut() + }; + } + } + + let pubkey = Pubkey::new_unique(); + let mut account = Account::new(0, data_len, program_id); + account.data = data; + (pubkey, account) +} diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 9ec83be6..ac4d4353 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -1,7 +1,8 @@ +use super::common::*; use super::*; use tree_interface::{ - input_buffer, tree, Color, InsertInstruction, Instruction as TreeInstruction, - InstructionHeader, StackNode, TreeHeader, TreeNode, + input_buffer, tree, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, + StackNode, TreeHeader, TreeNode, }; // --------------------------------------------------------------------------- @@ -182,215 +183,6 @@ fn insert_max_data_setup( (setup, instruction, accounts) } -// --------------------------------------------------------------------------- -// Helpers: tree description types -// --------------------------------------------------------------------------- - -struct NodeSpec { - key: u16, - value: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -} - -impl NodeSpec { - fn val(mut self, v: u16) -> Self { - self.value = v; - self - } -} - -struct TreeSpec<'a> { - root: Option, - top: Option, - nodes: &'a [NodeSpec], -} - -/// Compute the virtual address of node slot `i` in the tree account. -fn node_vaddr(i: usize) -> u64 { - MM_INPUT_START - + input_buffer::TREE_DATA_OFF as u64 - + size_of::() as u64 - + (i as u64) * (size_of::() as u64) -} - -/// Convert an optional node index to a virtual address (0 for None). -fn opt_vaddr(idx: Option) -> u64 { - match idx { - Some(i) => node_vaddr(i), - None => 0, - } -} - -// --------------------------------------------------------------------------- -// Helper: build tree account data -// --------------------------------------------------------------------------- - -/// Build tree account data with pre-existing nodes and one free StackNode. -/// -/// Memory layout: TreeHeader | node[0] | node[1] | ... | node[N-1] | free_slot -/// -/// - `header.root` → virtual address of `nodes[root]`, or null. -/// - `header.top` → virtual address of the free slot (index = nodes.len()). -/// - `header.next` → 0 (unused in skip-alloc path). -fn build_tree_account(desc: &TreeSpec, program_id: &Pubkey) -> (Pubkey, Account) { - let n = desc.nodes.len(); - // N existing nodes + 1 free slot. - let data_len = size_of::() + (n + 1) * size_of::(); - let mut data = vec![0u8; data_len]; - - // Write header. - let header = data.as_mut_ptr() as *mut TreeHeader; - unsafe { - (*header).root = opt_vaddr(desc.root) as *mut TreeNode; - (*header).top = node_vaddr(n) as *mut StackNode; - (*header).next = core::ptr::null_mut(); - } - - // Write existing nodes. - for (i, node) in desc.nodes.iter().enumerate() { - let offset = size_of::() + i * size_of::(); - let ptr = unsafe { data.as_mut_ptr().add(offset) as *mut TreeNode }; - unsafe { - (*ptr).parent = opt_vaddr(node.parent) as *mut TreeNode; - (*ptr).child[tree::DIR_L] = opt_vaddr(node.left) as *mut TreeNode; - (*ptr).child[tree::DIR_R] = opt_vaddr(node.right) as *mut TreeNode; - (*ptr).key = node.key; - (*ptr).value = node.value; - (*ptr).color = core::mem::transmute(node.color); - } - } - - // Free slot is already zeroed (StackNode.next = null). - - let pubkey = Pubkey::new_unique(); - let mut account = Account::new(0, data_len, program_id); - account.data = data; - (pubkey, account) -} - -// --------------------------------------------------------------------------- -// Helper: assert tree account (full state) -// --------------------------------------------------------------------------- - -/// Assert every field of the tree account data against expected state. -/// Returns Ok(()) on match, Err(description) on mismatch. -fn assert_tree_account(data: &[u8], expected: &TreeSpec) -> Result<(), String> { - let mut errors = Vec::new(); - let n = expected.nodes.len(); - - // Check data length (at least enough for the expected nodes). - let min_len = size_of::() + n * size_of::(); - if data.len() < min_len { - errors.push(format!( - "data len: expected at least {}, got {}", - min_len, - data.len() - )); - } - - // Check header. - let header = data.as_ptr() as *const TreeHeader; - unsafe { - let root_addr = (*header).root as u64; - let expected_root = opt_vaddr(expected.root); - if root_addr != expected_root { - errors.push(format!( - "header.root: expected {:#x}, got {:#x}", - expected_root, root_addr - )); - } - - let top_addr = (*header).top as u64; - let expected_top = opt_vaddr(expected.top); - if top_addr != expected_top { - errors.push(format!( - "header.top: expected {:#x}, got {:#x}", - expected_top, top_addr - )); - } - - let next_addr = (*header).next as u64; - if next_addr != 0 { - errors.push(format!("header.next: expected 0x0, got {:#x}", next_addr)); - } - } - - // Check each node. - for i in 0..n { - let offset = size_of::() + i * size_of::(); - if offset + size_of::() > data.len() { - errors.push(format!("N{}: out of bounds", i)); - continue; - } - let ptr = unsafe { data.as_ptr().add(offset) as *const TreeNode }; - let exp = &expected.nodes[i]; - let label = format!("N{}", i); - - unsafe { - let parent_addr = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).parent)) as u64; - let expected_parent = opt_vaddr(exp.parent); - if parent_addr != expected_parent { - errors.push(format!( - "{}.parent: expected {:#x}, got {:#x}", - label, expected_parent, parent_addr - )); - } - - let left_addr = - core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_L])) as u64; - let expected_left = opt_vaddr(exp.left); - if left_addr != expected_left { - errors.push(format!( - "{}.L: expected {:#x}, got {:#x}", - label, expected_left, left_addr - )); - } - - let right_addr = - core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).child[tree::DIR_R])) as u64; - let expected_right = opt_vaddr(exp.right); - if right_addr != expected_right { - errors.push(format!( - "{}.R: expected {:#x}, got {:#x}", - label, expected_right, right_addr - )); - } - - let key = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).key)); - if key != exp.key { - errors.push(format!("{}.key: expected {}, got {}", label, exp.key, key)); - } - - let value = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).value)); - if value != exp.value { - errors.push(format!( - "{}.value: expected {}, got {}", - label, exp.value, value - )); - } - - let color = core::ptr::read_unaligned(core::ptr::addr_of!((*ptr).color)) as u8; - if color != exp.color { - let color_name = |c: u8| if c == 0 { "B" } else { "R" }; - errors.push(format!( - "{}.color: expected {}, got {}", - label, - color_name(exp.color), - color_name(color) - )); - } - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors.join("; ")) - } -} // --------------------------------------------------------------------------- // Helpers: tree test setup and runners @@ -478,29 +270,6 @@ fn run_dup_error(lang: ProgramLanguage, desc: &TreeSpec, insert_key: u16) -> Cas ) } -// --------------------------------------------------------------------------- -// Shorthand constructors -// --------------------------------------------------------------------------- - -const B: u8 = Color::Black as u8; -const R: u8 = Color::Red as u8; - -fn node( - key: u16, - color: u8, - parent: Option, - left: Option, - right: Option, -) -> NodeSpec { - NodeSpec { - key, - value: key, - color, - parent, - left, - right, - } -} // --------------------------------------------------------------------------- // Test case enum @@ -1638,40 +1407,6 @@ impl TestCase for InsertCase { // Multi-insert integration tests // --------------------------------------------------------------------------- -/// Build an empty tree account with `n` pre-allocated free slots. -fn build_empty_tree(n: usize, program_id: &Pubkey) -> (Pubkey, Account) { - let data_len = size_of::() + n * size_of::(); - let mut data = vec![0u8; data_len]; - - let header = data.as_mut_ptr() as *mut TreeHeader; - unsafe { - (*header).root = core::ptr::null_mut(); - (*header).top = if n > 0 { - node_vaddr(0) as *mut StackNode - } else { - core::ptr::null_mut() - }; - (*header).next = core::ptr::null_mut(); - } - - // Link free slots into a singly-linked list. - for i in 0..n { - let offset = size_of::() + i * size_of::(); - let slot = unsafe { data.as_mut_ptr().add(offset) as *mut StackNode }; - unsafe { - (*slot).next = if i + 1 < n { - node_vaddr(i + 1) as *mut StackNode - } else { - core::ptr::null_mut() - }; - } - } - - let pubkey = Pubkey::new_unique(); - let mut account = Account::new(0, data_len, program_id); - account.data = data; - (pubkey, account) -} struct MultiInsertStep<'a> { key: u16, diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs new file mode 100644 index 00000000..77c608fa --- /dev/null +++ b/examples/tree/src/tests/remove.rs @@ -0,0 +1,1685 @@ +use super::common::*; +use super::*; +use tree_interface::{ + input_buffer, instruction, InsertInstruction, Instruction as TreeInstruction, + InstructionHeader, RemoveInstruction, StackNode, TreeHeader, TreeNode, +}; + +// --------------------------------------------------------------------------- +// Helpers: remove test setup +// --------------------------------------------------------------------------- + +fn remove_setup( + lang: ProgramLanguage, + desc: &TreeSpec, + remove_key: u16, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let setup = setup_test(lang); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, tree_account) = build_tree_account_no_free(desc, &setup.program_id); + + let insn_data = RemoveInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Remove as u8, + }, + key: remove_key, + }; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + unsafe { as_bytes(&insn_data) }, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account), + ]; + + (setup, instruction, accounts) +} + +/// A minimal two-account setup for input check tests. +fn remove_input_setup( + lang: ProgramLanguage, +) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[node(10, B, None, None, None)], + }; + remove_setup(lang, &desc, 10) +} + +// --------------------------------------------------------------------------- +// Helpers: remove runners +// --------------------------------------------------------------------------- + +/// Execute a remove and verify success with full tree state and return value. +/// +/// On success, the program returns `(value << 16) | REMOVE_STATUS_OK` encoded +/// as `ProgramError::Custom(...)`. +fn run_remove_success( + lang: ProgramLanguage, + desc: &TreeSpec, + remove_key: u16, + expected_value: u16, + expected: &TreeSpec, +) -> CaseResult { + let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); + let expected_r0 = + ((expected_value as u32) << 16) | instruction::REMOVE_STATUS_OK as u32; + let result = setup.mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + MolluskResult::Failure(err) if *err == ProgramError::Custom(expected_r0) => { + let tree_data = &result.resulting_accounts[AccountIndex::Tree as usize] + .1 + .data; + match assert_tree_account(tree_data, expected) { + Ok(()) => CaseResult { + cu: result.compute_units_consumed, + error: None, + }, + Err(e) => CaseResult { + cu: result.compute_units_consumed, + error: Some(e), + }, + } + } + other => CaseResult { + cu: result.compute_units_consumed, + error: Some(format!( + "expected Failure(Custom({:#x})), got {:?}", + expected_r0, other + )), + }, + } +} + +/// Execute a remove and verify KEY_DOES_NOT_EXIST error. +fn run_remove_not_found( + lang: ProgramLanguage, + desc: &TreeSpec, + remove_key: u16, +) -> CaseResult { + let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::KEY_DOES_NOT_EXIST, + ) +} + +// --------------------------------------------------------------------------- +// Helpers: multi-step operations +// --------------------------------------------------------------------------- + +enum MultiStep { + Insert { key: u16, value: u16 }, + Remove { key: u16, expected_value: u16 }, +} + +struct MultiStepCase<'a> { + step: MultiStep, + expected: TreeSpec<'a>, +} + +fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase]) -> CaseResult { + let setup = setup_test(lang); + let (system_program_pubkey, _) = program::keyed_account_for_system_program(); + + let user_pubkey = Pubkey::new_unique(); + let (tree_pubkey, mut tree_account) = build_empty_tree(n_slots, &setup.program_id); + + let mut total_cu = 0u64; + + for (i, step) in steps.iter().enumerate() { + let (insn_bytes, expected_result): (Vec, _) = match &step.step { + MultiStep::Insert { key, value } => { + let insn = InsertInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Insert as u8, + }, + key: *key, + value: *value, + }; + (unsafe { as_bytes(&insn) }.to_vec(), None) + } + MultiStep::Remove { key, expected_value } => { + let insn = RemoveInstruction { + header: InstructionHeader { + discriminator: TreeInstruction::Remove as u8, + }, + key: *key, + }; + let r0 = ((*expected_value as u32) << 16) + | instruction::REMOVE_STATUS_OK as u32; + (unsafe { as_bytes(&insn) }.to_vec(), Some(r0)) + } + }; + + let instruction = Instruction::new_with_bytes( + setup.program_id, + &insn_bytes, + vec![ + AccountMeta::new(user_pubkey, true), + AccountMeta::new(tree_pubkey, false), + ], + ); + + let accounts = vec![ + ( + user_pubkey, + Account::new(USER_LAMPORTS, 0, &system_program_pubkey), + ), + (tree_pubkey, tree_account.clone()), + ]; + + let result = setup.mollusk.process_instruction(&instruction, &accounts); + total_cu += result.compute_units_consumed; + + // Check program result. + let ok = match (&result.program_result, expected_result) { + (MolluskResult::Success, None) => true, + (MolluskResult::Failure(err), Some(r0)) + if *err == ProgramError::Custom(r0) => + { + true + } + _ => false, + }; + + if !ok { + let step_desc = match &step.step { + MultiStep::Insert { key, .. } => format!("insert key={}", key), + MultiStep::Remove { key, .. } => format!("remove key={}", key), + }; + return CaseResult { + cu: total_cu, + error: Some(format!( + "step {} ({}): expected {:?}, got {:?}", + i, step_desc, expected_result, result.program_result + )), + }; + } + + tree_account = result.resulting_accounts[AccountIndex::Tree as usize].1.clone(); + if let Err(e) = assert_tree_account(&tree_account.data, &step.expected) { + let step_desc = match &step.step { + MultiStep::Insert { key, .. } => format!("insert key={}", key), + MultiStep::Remove { key, .. } => format!("remove key={}", key), + }; + return CaseResult { + cu: total_cu, + error: Some(format!("step {} ({}): {}", i, step_desc, e)), + }; + } + } + + CaseResult { + cu: total_cu, + error: None, + } +} + +// --------------------------------------------------------------------------- +// Test case enum +// --------------------------------------------------------------------------- + +#[derive(Clone, Copy)] +pub(super) enum RemoveCase { + // Input validation (cases 1-5). + InputDataShort, + InputDataLong, + InputNAccounts, + InputUserDataLen, + InputTreeDuplicate, + // Search errors (cases 6-9). + SearchEmptyTree, + SearchNotFoundLeft, + SearchNotFoundRight, + SearchNotFoundDeep, + // Simple removal (cases 10-15). + SimpleRootLeaf, + SimpleRedLeafL, + SimpleRedLeafR, + SimpleOneChildRootR, + SimpleOneChildRootL, + SimpleOneChildNonRoot, + // Successor swap (cases 16-18). + SuccessorImmediate, + SuccessorDeep, + SuccessorWithChild, + // Rebalancing (cases 19-42). + Case4L, + Case4R, + Case6L, + Case6R, + Case56L, + Case56R, + Case3Then4L, + Case3Then4R, + Case3Then6L, + Case3Then6R, + Case3Then56L, + Case3Then56R, + Case2PropL, + Case2PropR, + Case2Then4, + Case2Then6, + Case6NewChildL, + Case6NewChildR, + Case6ParentRootL, + Case6ParentRootR, + Case6ParentGgpL, + Case6ParentGgpR, + Case3ParentRootL, + Case3ParentRootR, +} + +impl RemoveCase { + pub(super) const INPUT_CASES: &'static [Self] = &[ + Self::InputDataShort, + Self::InputDataLong, + Self::InputNAccounts, + Self::InputUserDataLen, + Self::InputTreeDuplicate, + ]; + + pub(super) const SEARCH_CASES: &'static [Self] = &[ + Self::SearchEmptyTree, + Self::SearchNotFoundLeft, + Self::SearchNotFoundRight, + Self::SearchNotFoundDeep, + ]; + + pub(super) const SIMPLE_CASES: &'static [Self] = &[ + Self::SimpleRootLeaf, + Self::SimpleRedLeafL, + Self::SimpleRedLeafR, + Self::SimpleOneChildRootR, + Self::SimpleOneChildRootL, + Self::SimpleOneChildNonRoot, + ]; + + pub(super) const SUCCESSOR_CASES: &'static [Self] = &[ + Self::SuccessorImmediate, + Self::SuccessorDeep, + Self::SuccessorWithChild, + ]; + + pub(super) const REBALANCE_CASES: &'static [Self] = &[ + Self::Case4L, + Self::Case4R, + Self::Case6L, + Self::Case6R, + Self::Case56L, + Self::Case56R, + Self::Case3Then4L, + Self::Case3Then4R, + Self::Case3Then6L, + Self::Case3Then6R, + Self::Case3Then56L, + Self::Case3Then56R, + Self::Case2PropL, + Self::Case2PropR, + Self::Case2Then4, + Self::Case2Then6, + Self::Case6NewChildL, + Self::Case6NewChildR, + Self::Case6ParentRootL, + Self::Case6ParentRootR, + Self::Case6ParentGgpL, + Self::Case6ParentGgpR, + Self::Case3ParentRootL, + Self::Case3ParentRootR, + ]; +} + +impl TestCase for RemoveCase { + fn name(&self) -> &'static str { + match self { + Self::InputDataShort => "Data too short", + Self::InputDataLong => "Data too long", + Self::InputNAccounts => "Too few accounts", + Self::InputUserDataLen => "User has data", + Self::InputTreeDuplicate => "Tree is duplicate", + Self::SearchEmptyTree => "Empty tree", + Self::SearchNotFoundLeft => "Not found (left)", + Self::SearchNotFoundRight => "Not found (right)", + Self::SearchNotFoundDeep => "Not found (deep)", + Self::SimpleRootLeaf => "Root leaf (sc 2)", + Self::SimpleRedLeafL => "Red leaf L (sc 3)", + Self::SimpleRedLeafR => "Red leaf R (sc 3)", + Self::SimpleOneChildRootR => "One child root R (sc 1)", + Self::SimpleOneChildRootL => "One child root L (sc 1)", + Self::SimpleOneChildNonRoot => "One child non-root (sc 1)", + Self::SuccessorImmediate => "Successor immediate R", + Self::SuccessorDeep => "Successor deep L descent", + Self::SuccessorWithChild => "Successor with R child", + Self::Case4L => "Case 4 dir_l", + Self::Case4R => "Case 4 dir_r", + Self::Case6L => "Case 6 dir_l", + Self::Case6R => "Case 6 dir_r", + Self::Case56L => "Case 5+6 dir_l", + Self::Case56R => "Case 5+6 dir_r", + Self::Case3Then4L => "Case 3->4 dir_l", + Self::Case3Then4R => "Case 3->4 dir_r", + Self::Case3Then6L => "Case 3->6 dir_l", + Self::Case3Then6R => "Case 3->6 dir_r", + Self::Case3Then56L => "Case 3->5->6 dir_l", + Self::Case3Then56R => "Case 3->5->6 dir_r", + Self::Case2PropL => "Case 2 propagate L", + Self::Case2PropR => "Case 2 propagate R", + Self::Case2Then4 => "Case 2->4", + Self::Case2Then6 => "Case 2->6", + Self::Case6NewChildL => "Case 6 new_child L", + Self::Case6NewChildR => "Case 6 new_child R", + Self::Case6ParentRootL => "Case 6 parent=root L", + Self::Case6ParentRootR => "Case 6 parent=root R", + Self::Case6ParentGgpL => "Case 6 parent=GGP L", + Self::Case6ParentGgpR => "Case 6 parent=GGP R", + Self::Case3ParentRootL => "Case 3 parent=root L", + Self::Case3ParentRootR => "Case 3 parent=root R", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + // ----- Input validation ----- + Self::InputDataShort => { + let (setup, mut instruction, accounts) = remove_input_setup(lang); + instruction.data = vec![TreeInstruction::Remove as u8]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA_LEN, + ) + } + Self::InputDataLong => { + let (setup, mut instruction, accounts) = remove_input_setup(lang); + instruction.data = vec![TreeInstruction::Remove as u8, 0, 0, 0]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::INSTRUCTION_DATA_LEN, + ) + } + Self::InputNAccounts => { + let (setup, mut instruction, mut accounts) = remove_input_setup(lang); + instruction.accounts.pop(); + accounts.pop(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::N_ACCOUNTS, + ) + } + Self::InputUserDataLen => { + let (setup, instruction, mut accounts) = remove_input_setup(lang); + accounts[AccountIndex::User as usize].1.data = vec![1u8; 1]; + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::USER_DATA_LEN, + ) + } + Self::InputTreeDuplicate => { + let (setup, mut instruction, mut accounts) = remove_input_setup(lang); + instruction.accounts[AccountIndex::Tree as usize] = + instruction.accounts[AccountIndex::User as usize].clone(); + accounts[AccountIndex::Tree as usize] = + accounts[AccountIndex::User as usize].clone(); + check_error( + &setup, + &instruction, + &accounts, + error_codes::error::TREE_DUPLICATE, + ) + } + + // ----- Search errors ----- + + Self::SearchEmptyTree => { + let desc = TreeSpec { + root: None, + top: None, + nodes: &[], + }; + run_remove_not_found(lang, &desc, 10) + } + Self::SearchNotFoundLeft => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[node(10, B, None, None, None)], + }; + run_remove_not_found(lang, &desc, 5) + } + Self::SearchNotFoundRight => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[node(10, B, None, None, None)], + }; + run_remove_not_found(lang, &desc, 15) + } + Self::SearchNotFoundDeep => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + run_remove_not_found(lang, &desc, 12) + } + + // ----- Simple removal ----- + + // Simple case 2: remove root leaf. + Self::SimpleRootLeaf => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[node(10, B, None, None, None)], + }; + let exp = TreeSpec { + root: None, + top: Some(0), + nodes: &[node(10, B, None, None, None)], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // Simple case 3: remove red leaf (left child). + Self::SimpleRedLeafL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, None), + node(5, R, None, None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Simple case 3: remove red leaf (right child). + Self::SimpleRedLeafR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, None), + node(15, R, None, None, None), + ], + }; + run_remove_success(lang, &desc, 15, 15, &exp) + } + + // Simple case 1: one child at root (right child). + Self::SimpleOneChildRootR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, None, Some(1)), + node(15, R, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(0), + nodes: &[ + node(10, B, None, None, None), + node(15, B, None, None, None), + ], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // Simple case 1: one child at root (left child). + Self::SimpleOneChildRootL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(0), + nodes: &[ + node(10, B, None, None, None), + node(5, B, None, None, None), + ], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // Simple case 1: one child non-root (right child). + Self::SimpleOneChildNonRoot => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), Some(3)), + node(5, B, Some(0), None, None), + node(15, B, None, None, None), + node(20, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 15, 15, &exp) + } + + // ----- Successor swap ----- + + // Successor is immediate right child. + Self::SuccessorImmediate => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(15, B, None, Some(1), None).val(15), + node(5, B, Some(0), None, None), + node(15, R, None, None, None), + ], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // Successor with deep left descent. + Self::SuccessorDeep => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, B, Some(0), Some(3), Some(4)), + node(15, R, Some(2), None, None), + node(25, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(15, B, None, Some(1), Some(2)).val(15), + node(5, B, Some(0), None, None), + node(20, B, Some(0), None, Some(4)), + node(15, R, None, None, None), + node(25, R, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // Successor with right child. + Self::SuccessorWithChild => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(15, B, None, Some(1), Some(3)).val(15), + node(5, B, Some(0), None, None), + node(15, B, None, None, None), + node(20, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 10, 10, &exp) + } + + // ----- Rebalancing ----- + + // Case 4 dir_l: red parent, black sibling, black nephews. + Self::Case4L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)), + node(5, B, None, None, None), + node(15, R, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 4 dir_r. + Self::Case4R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + node(15, B, None, None, None), + ], + }; + run_remove_success(lang, &desc, 15, 15, &exp) + } + + // Case 6 dir_l: black sibling, distant nephew red. + Self::Case6L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(2), None, None), + node(5, B, None, None, None), + node(15, B, None, Some(0), Some(3)), + node(20, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 6 dir_r. + Self::Case6R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), Some(3), None), + node(20, B, Some(0), None, None), + node(3, R, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(1), None, None), + node(5, B, None, Some(3), Some(0)), + node(20, B, None, None, None), + node(3, B, Some(1), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 5+6 dir_l. + Self::Case56L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, B, Some(0), Some(3), None), + node(15, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(3), + top: Some(1), + nodes: &[ + node(10, B, Some(3), None, None), + node(5, B, None, None, None), + node(20, R, Some(3), None, None), + node(15, B, None, Some(0), Some(2)), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 5+6 dir_r. + Self::Case56R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, Some(3)), + node(20, B, Some(0), None, None), + node(7, R, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(3), + top: Some(2), + nodes: &[ + node(10, B, Some(3), None, None), + node(5, R, Some(3), None, None), + node(20, B, None, None, None), + node(7, B, None, Some(1), Some(0)), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 3 -> 4 dir_l. + Self::Case3Then4L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(4)), + node(15, B, Some(2), None, None), + node(25, B, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(2), None, Some(3)), + node(5, B, None, None, None), + node(20, B, None, Some(0), Some(4)), + node(15, R, Some(0), None, None), + node(25, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 3 -> 4 dir_r. + Self::Case3Then4R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), Some(3), Some(4)), + node(20, B, Some(0), None, None), + node(3, B, Some(1), None, None), + node(7, B, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(1), Some(4), None), + node(5, B, None, Some(3), Some(0)), + node(20, B, None, None, None), + node(3, B, Some(1), None, None), + node(7, R, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 3 -> 6 dir_l. + Self::Case3Then6L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(5)), + node(15, B, Some(2), None, Some(4)), + node(17, R, Some(3), None, None), + node(25, B, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(3), None, None), + node(5, B, None, None, None), + node(20, B, None, Some(3), Some(5)), + node(15, B, Some(2), Some(0), Some(4)), + node(17, R, Some(3), None, None), + node(25, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 3 -> 6 dir_r. + Self::Case3Then6R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), Some(4), Some(3)), + node(20, B, Some(0), None, None), + node(7, B, Some(1), Some(5), None), + node(3, B, Some(1), None, None), + node(6, R, Some(3), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(3), None, None), + node(5, B, None, Some(4), Some(3)), + node(20, B, None, None, None), + node(7, B, Some(1), Some(5), Some(0)), + node(3, B, Some(1), None, None), + node(6, R, Some(3), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 3 -> 5 -> 6 dir_l. + Self::Case3Then56L => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(5)), + node(15, B, Some(2), Some(4), None), + node(13, R, Some(3), None, None), + node(25, B, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(4), None, None), + node(5, B, None, None, None), + node(20, B, None, Some(4), Some(5)), + node(15, R, Some(4), None, None), + node(13, B, Some(2), Some(0), Some(3)), + node(25, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 3 -> 5 -> 6 dir_r. + Self::Case3Then56R => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), Some(4), Some(3)), + node(20, B, Some(0), None, None), + node(7, B, Some(1), None, Some(5)), + node(3, B, Some(1), None, None), + node(8, R, Some(3), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(5), None, None), + node(5, B, None, Some(4), Some(5)), + node(20, B, None, None, None), + node(7, R, Some(5), None, None), + node(3, B, Some(1), None, None), + node(8, B, Some(1), Some(3), Some(0)), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 2: propagate to root (dir_l). + Self::Case2PropL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)), + node(5, B, None, None, None), + node(15, R, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 2: propagate to root (dir_r). + Self::Case2PropR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + node(15, B, None, None, None), + ], + }; + run_remove_success(lang, &desc, 15, 15, &exp) + } + + // Case 2 -> 4: propagate then red parent. + Self::Case2Then4 => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(20, B, None, Some(1), Some(4)), + node(10, R, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(15, B, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(20, B, None, Some(1), Some(4)), + node(10, B, Some(0), None, Some(3)), + node(5, B, None, None, None), + node(15, R, Some(1), None, None), + node(25, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 2 -> 6: propagate then distant nephew red. + Self::Case2Then6 => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(20, B, None, Some(1), Some(4)), + node(10, B, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(15, B, Some(1), None, None), + node(30, B, Some(0), None, Some(5)), + node(35, R, Some(4), None, None), + ], + }; + let exp = TreeSpec { + root: Some(4), + top: Some(2), + nodes: &[ + node(20, B, Some(4), Some(1), None), + node(10, B, Some(0), None, Some(3)), + node(5, B, None, None, None), + node(15, R, Some(1), None, None), + node(30, B, None, Some(0), Some(5)), + node(35, B, Some(4), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 6 with non-null new_child dir_l. + Self::Case6NewChildL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, B, Some(0), Some(3), Some(4)), + node(15, B, Some(2), None, None), + node(25, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(2), None, Some(3)), + node(5, B, None, None, None), + node(20, B, None, Some(0), Some(4)), + node(15, B, Some(0), None, None), + node(25, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 6 with non-null new_child dir_r. + Self::Case6NewChildR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), Some(3), Some(4)), + node(20, B, Some(0), None, None), + node(3, R, Some(1), None, None), + node(7, B, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(1), Some(4), None), + node(5, B, None, Some(3), Some(0)), + node(20, B, None, None, None), + node(3, B, Some(1), None, None), + node(7, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 6 parent=root dir_l (same tree as Case6L). + Self::Case6ParentRootL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), None, Some(3)), + node(20, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(2), None, None), + node(5, B, None, None, None), + node(15, B, None, Some(0), Some(3)), + node(20, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 6 parent=root dir_r. + Self::Case6ParentRootR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), Some(3), None), + node(20, B, Some(0), None, None), + node(3, R, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(1), None, None), + node(5, B, None, Some(3), Some(0)), + node(20, B, None, None, None), + node(3, B, Some(1), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + + // Case 6 parent=GGP left child dir_l. + Self::Case6ParentGgpL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(30, B, None, Some(1), Some(5)), + node(10, B, Some(0), Some(2), Some(3)), + node(5, B, Some(1), None, None), + node(20, B, Some(1), None, Some(4)), + node(25, R, Some(3), None, None), + node(35, B, Some(0), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(30, B, None, Some(3), Some(5)), + node(10, B, Some(3), None, None), + node(5, B, None, None, None), + node(20, B, Some(0), Some(1), Some(4)), + node(25, B, Some(3), None, None), + node(35, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 6 parent=GGP right child dir_r. + Self::Case6ParentGgpR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(5, B, None, Some(4), Some(1)), + node(20, B, Some(0), Some(2), Some(3)), + node(10, B, Some(1), Some(5), None), + node(25, B, Some(1), None, None), + node(3, B, Some(0), None, None), + node(7, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(5, B, None, Some(4), Some(2)), + node(20, B, Some(2), None, None), + node(10, B, Some(0), Some(5), Some(1)), + node(25, B, None, None, None), + node(3, B, Some(0), None, None), + node(7, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 25, 25, &exp) + } + + // Case 3 parent=root dir_l. + Self::Case3ParentRootL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(20, R, Some(0), Some(3), Some(4)), + node(15, B, Some(2), None, None), + node(25, B, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(2), + top: Some(1), + nodes: &[ + node(10, B, Some(2), None, Some(3)), + node(5, B, None, None, None), + node(20, B, None, Some(0), Some(4)), + node(15, R, Some(0), None, None), + node(25, B, Some(2), None, None), + ], + }; + run_remove_success(lang, &desc, 5, 5, &exp) + } + + // Case 3 parent=root dir_r. + Self::Case3ParentRootR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), Some(3), Some(4)), + node(20, B, Some(0), None, None), + node(3, B, Some(1), None, None), + node(7, B, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(1), + top: Some(2), + nodes: &[ + node(10, B, Some(1), Some(4), None), + node(5, B, None, Some(3), Some(0)), + node(20, B, None, None, None), + node(3, B, Some(1), None, None), + node(7, R, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 20, 20, &exp) + } + } + } +} + +// --------------------------------------------------------------------------- +// Multi-step integration tests +// --------------------------------------------------------------------------- + +#[derive(Clone, Copy)] +pub(super) enum MultiRemoveCase { + /// Insert 10,5,15; remove 5. + Minimal, + /// Insert 7 nodes; remove all. + FullCycle, + /// Insert 3; remove 1; insert 1. + Recycle, +} + +impl MultiRemoveCase { + pub(super) const CASES: &'static [Self] = &[ + Self::Minimal, + Self::FullCycle, + Self::Recycle, + ]; +} + +impl TestCase for MultiRemoveCase { + fn name(&self) -> &'static str { + match self { + Self::Minimal => "Insert 3, remove 1", + Self::FullCycle => "Insert 7, remove all", + Self::Recycle => "Insert-remove-insert (recycle)", + } + } + + fn run(&self, lang: ProgramLanguage) -> CaseResult { + match self { + Self::Minimal => run_multi_step(lang, 3, &[ + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 5, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)).val(1), + // Freed node: key/value/color retained, children nulled, + // parent (= StackNode.next) = null (stack was empty). + node(5, R, None, None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + ]), + + Self::FullCycle => run_multi_step(lang, 7, &[ + // Insert 10,5,15,3,7,12,20. + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 3, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 7, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 12, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 20, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, + }, + // Remove all: 3, 20, 7, 12, 5, 15, 10. + // Removing leaves first to simplify expected states. + MultiStepCase { + step: MultiStep::Remove { key: 3, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 20, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 7, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, None).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 12, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 5, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 15, expected_value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, None, None).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(1), None, None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + MultiStepCase { + step: MultiStep::Remove { key: 10, expected_value: 1 }, + expected: TreeSpec { + root: None, + top: Some(0), + nodes: &[ + node(10, B, Some(2), None, None).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(1), None, None).val(1), + node(3, R, Some(6), None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, + }, + ]), + + Self::Recycle => run_multi_step(lang, 3, &[ + // Insert 10,5,15. + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 10 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None)], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }, + }, + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 15 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }, + }, + // Remove 5: red leaf removal, N1 freed onto stack. + MultiStepCase { + step: MultiStep::Remove { key: 5, expected_value: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)), + node(5, R, None, None, None), + node(15, R, Some(0), None, None), + ], + }, + }, + // Insert 7: pops N1 from stack, reuses slot. + MultiStepCase { + step: MultiStep::Insert { key: 7, value: 7 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(7, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }, + }, + ]), + } + } +} From 7544e4572d42e0466832b138a08a4f1dd635b126 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:43:27 -0700 Subject: [PATCH 225/263] Add build/test skills --- .claude/commands/build-example.md | 21 +++++++++++++++++++++ .claude/commands/test-example.md | 16 ++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .claude/commands/build-example.md create mode 100644 .claude/commands/test-example.md diff --git a/.claude/commands/build-example.md b/.claude/commands/build-example.md new file mode 100644 index 00000000..d7d93ae8 --- /dev/null +++ b/.claude/commands/build-example.md @@ -0,0 +1,21 @@ +Run the full build-examples pipeline that builds, dumps, disassembles, +tests, and verifies artifacts. + +From the `examples/` directory, run: + +```sh +cargo run --bin build-examples -- --example $ARGUMENTS +``` + +If `$ARGUMENTS` is empty, run without the `--example` flag to build all +examples: + +```sh +cargo run --bin build-examples +``` + +This executes `examples/utils/build-examples/src/main.rs` which handles +building ELF files, generating dumps/disassembly, running tests, saving +test snippets, and verifying code snippets. + +Report the outcome. If the command fails, show the relevant error output. diff --git a/.claude/commands/test-example.md b/.claude/commands/test-example.md new file mode 100644 index 00000000..bd329b7b --- /dev/null +++ b/.claude/commands/test-example.md @@ -0,0 +1,16 @@ +Quick build and test cycle for a specific example program. + +Run the following commands sequentially from the example directory at +`examples/$ARGUMENTS`: + +```sh +cargo build-sbf --arch v3 --tools-version 1.51 +sbpf build +cargo test -- --test-threads 1 +``` + +If `$ARGUMENTS` is empty, infer the example name from the current +conversation context (e.g. recent file paths or discussion). If you still +cannot determine it, ask which example to test. + +Report the result of each step. If any step fails, stop and show the error. From 03cb70dad7ec3718710e76e89b28127a215ca65d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:05:06 -0700 Subject: [PATCH 226/263] Add hook --- .claude/settings.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..2cd35ba3 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Evaluate whether the interaction you just completed warrants self-improvement. If this was a substantive task (not a trivial question or explanation), check what was learned and take action:\n\n- Repeated instruction (corrected 2+ times): add it to CLAUDE.md.\n- Design decision: write or update a spec.\n- Repeatable workflow: propose a skill.\n- Must always happen: propose a hook.\n- Learned pattern: save to memory.\n\nIf nothing applies, do nothing.", + "timeout": 30 + } + ] + } + ] + } +} \ No newline at end of file From 59ddc68b40c9c7d3422c2111170508c726ecf35d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:30:16 -0700 Subject: [PATCH 227/263] Update specs --- examples/tree/specs/remove-tests.md | 326 +++++++++++++++++++++++----- examples/tree/specs/remove.md | 20 +- 2 files changed, 279 insertions(+), 67 deletions(-) diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index 8f35f104..854e87bb 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -36,17 +36,21 @@ New helpers in `tests/remove.rs` (remove-specific): ## Return value verification -On success the program returns `RemoveReturn` packed in `r0`: +The program returns `0` (`SUCCESS`) on a successful remove. The +SVM only persists account modifications when the program returns +zero; any non-zero `r0` is interpreted as +`ProgramError::Custom(r0)` and all account changes are reverted. -```text -r0 = (value << 16) | REMOVE_STATUS_OK -``` +Tests verify `MolluskResult::Success` (not a custom error code). + +### Removed value verification -The Solana runtime interprets any non-zero `r0` as -`ProgramError::Custom(r0)`. Tests must verify the result is -`ProgramError::Custom((value as u32) << 16 | REMOVE_STATUS_OK as u32)` where `REMOVE_STATUS_OK` equals `error::N_CODES` -(currently 15). This confirms both the value field (bits 16-31) -and the status field (bits 0-15) are encoded correctly. +Because the return code cannot carry the removed value (non-zero +would revert the tree mutation), tests verify the value by +inspecting the freed node on the stack. The freed node's `key`, +`value`, and `color` fields are not cleared by remove (see "Freed +node verification" below), so `assert_tree_account` confirms that +the freed node retains the correct value. ## Freed node verification @@ -62,15 +66,17 @@ the free stack. The full-state assertion must verify: The `key`, `value`, and `color` fields of the freed node are not cleared by remove (insert overwrites them when the node is -recycled). Tests should still assert their values to confirm remove -does not clobber them unexpectedly -- they should retain whatever -values they had before removal. - -The existing `assert_tree_account` already checks every field of -every node in the buffer, so including the freed node slot in the -expected `TreeSpec.nodes` list is sufficient. No new assertion -helper is needed; the freed node is simply a `NodeSpec` with null -children and `parent` set to the old stack top index. +recycled). Tests must assert these fields retain their pre-removal +values. In particular, the freed node's `value` field serves as +the primary mechanism for verifying which value was removed -- +since the return code is `0` (see "Return value verification" +above), the value cannot be communicated via `r0`. + +The existing `assert_tree_account` checks every field of every +node in the buffer, so including the freed node slot in the +expected `TreeSpec.nodes` list is sufficient. The freed node is a +`NodeSpec` with null children, `parent` set to the old stack top +index, and the original `key`/`value`/`color` preserved. ## `build_tree_account` adjustment @@ -410,10 +416,13 @@ After: Header: root=N3 top=N1 next=-- N0: B key=10 parent=N3 L=-- R=-- <- recolored B N1: key=5 color=B parent=-- L=-- R=-- <- freed - N2: R key=20 parent=N3 L=-- R=-- <- recolored R + N2: B key=20 parent=N3 L=-- R=-- <- recolored B N3: B key=15 parent=-- L=N0 R=N2 <- new root ``` +Trace: case 5 sets `distant_nephew = sibling` (N2), then case 6 +sets `distant_nephew->color = BLACK`. N2 ends up BLACK, not RED. + Dir_r variant (remove key=20): ```text @@ -427,103 +436,304 @@ Before: After: Header: root=N3 top=N2 next=-- N0: B key=10 parent=N3 L=-- R=-- <- recolored B - N1: R key=5 parent=N3 L=-- R=-- <- recolored R + N1: B key=5 parent=N3 L=-- R=-- <- recolored B N2: key=20 color=B parent=-- L=-- R=-- <- freed N3: B key=7 parent=-- L=N1 R=N0 <- new root ``` +Trace: case 5 sets `distant_nephew = sibling` (N1), then case 6 +sets `distant_nephew->color = BLACK`. N1 ends up BLACK, not RED. + ### Case 3 + case 4: red sibling, then recolor Red sibling is rotated, making the old close_nephew the new sibling. If the new sibling has two black/null nephews, recolor (case 4). -Dir_l variant (remove key=3): +Dir_l variant (remove key=5): ```text Before: Header: root=N0 top=-- next=-- N0: B key=10 parent=-- L=N1 R=N2 - N1: B key=5 parent=N0 L=N4 R=-- - N2: R key=20 parent=N0 L=N3 R=N5 + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=20 parent=N0 L=N3 R=N4 N3: B key=15 parent=N2 L=-- R=-- - N4: B key=3 parent=N1 L=-- R=-- + N4: B key=25 parent=N2 L=-- R=-- -After remove key=5 (successor swap from N4, delete N4 as black -leaf, dir=L relative to N1): - Header: root=N2 top=N4 next=-- - N0: B key=10 parent=N2 L=N1 R=N3 <- reparented - N1: B key=3 parent=N0 L=-- R=-- <- swapped key/val - N2: B key=20 parent=-- L=N0 R=N5 <- recolored B, new root - N3: R key=15 parent=N0 L=-- R=-- <- recolored R (case 4) - N4: key=3 color=B parent=-- L=-- R=-- <- freed - N5: B key=25 parent=N2 L=-- R=-- +After: + Header: root=N2 top=N1 next=-- + N0: B key=10 parent=N2 L=-- R=N3 <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=20 parent=-- L=N0 R=N4 <- new root, recolored B + N3: R key=15 parent=N0 L=-- R=-- <- recolored R (case 4) + N4: B key=25 parent=N2 L=-- R=-- ``` -These trees are moderately complex. Exact before/after states -should be verified by hand or with a reference implementation -during test construction. The spec lists the required paths; the -implementation fills in precise node layouts. +Trace: case 3 rotates N0 left (N2 becomes root), recolors +`N0=RED, N2=BLACK`, new sibling = N3. New nephews both null -> +case 4 (parent N0 is RED): `N3.color = RED, N0.color = BLACK`. + +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=N3 R=N4 + N2: B key=20 parent=N0 L=-- R=-- + N3: B key=3 parent=N1 L=-- R=-- + N4: B key=7 parent=N1 L=-- R=-- + +After: + Header: root=N1 top=N2 next=-- + N0: B key=10 parent=N1 L=N4 R=-- <- recolored B + N1: B key=5 parent=-- L=N3 R=N0 <- new root, recolored B + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: B key=3 parent=N1 L=-- R=-- + N4: R key=7 parent=N0 L=-- R=-- <- recolored R (case 4) +``` + +Trace: case 3 rotates N0 right (N1 becomes root), recolors +`N0=RED, N1=BLACK`, new sibling = N4. New nephews both null -> +case 4 (parent N0 is RED): `N4.color = RED, N0.color = BLACK`. ### Case 3 + case 6: red sibling, then distant nephew red After the case 3 rotation, the new sibling's distant nephew is red. Jump directly to case 6. -Dir_l and dir_r variants needed. +Dir_l variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=20 parent=N0 L=N3 R=N5 + N3: B key=15 parent=N2 L=-- R=N4 + N4: R key=17 parent=N3 L=-- R=-- + N5: B key=25 parent=N2 L=-- R=-- + +After: + Header: root=N2 top=N1 next=-- + N0: B key=10 parent=N3 L=-- R=-- <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=20 parent=-- L=N3 R=N5 <- new root, recolored B + N3: R key=15 parent=N2 L=N0 R=N4 <- recolored R + N4: B key=17 parent=N3 L=-- R=-- <- recolored B + N5: B key=25 parent=N2 L=-- R=-- +``` + +Trace: case 3 rotates N0 left (N2 becomes root), recolors +`N0=RED, N2=BLACK`, new sibling = N3. Distant nephew = +`N3.child[R]` = N4 (RED) -> case 6. Rotate N0 left again (N3 +becomes N0's parent), `N3.color = N0.color = RED`, +`N0.color = BLACK`, `N4.color = BLACK`. + +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=N4 R=N3 + N2: B key=20 parent=N0 L=-- R=-- + N3: B key=7 parent=N1 L=N5 R=-- + N4: B key=3 parent=N1 L=-- R=-- + N5: R key=6 parent=N3 L=-- R=-- + +After: + Header: root=N1 top=N2 next=-- + N0: B key=10 parent=N3 L=-- R=-- <- recolored B + N1: B key=5 parent=-- L=N4 R=N3 <- new root, recolored B + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: R key=7 parent=N1 L=N5 R=N0 <- recolored R + N4: B key=3 parent=N1 L=-- R=-- + N5: B key=6 parent=N3 L=-- R=-- <- recolored B +``` + +Trace: case 3 rotates N0 right (N1 becomes root), recolors +`N0=RED, N1=BLACK`, new sibling = N3. Distant nephew = +`N3.child[L]` = N5 (RED) -> case 6. Rotate N0 right again (N3 +becomes N0's parent), `N3.color = N0.color = RED`, +`N0.color = BLACK`, `N5.color = BLACK`. ### Case 3 + case 5 + case 6: red sibling, then double rotation After the case 3 rotation, the new sibling's close nephew is red and distant nephew is black. Case 5 rotates, then case 6 rotates. -Dir_l and dir_r variants needed. +Dir_l variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: R key=20 parent=N0 L=N3 R=N5 + N3: B key=15 parent=N2 L=N4 R=-- + N4: R key=13 parent=N3 L=-- R=-- + N5: B key=25 parent=N2 L=-- R=-- + +After: + Header: root=N2 top=N1 next=-- + N0: B key=10 parent=N4 L=-- R=-- <- recolored B + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=20 parent=-- L=N4 R=N5 <- root, recolored B + N3: B key=15 parent=N4 L=-- R=-- <- recolored B + N4: R key=13 parent=N2 L=N0 R=N3 <- recolored R + N5: B key=25 parent=N2 L=-- R=-- +``` + +Trace: case 3 rotates N0 left (N2 becomes root), recolors +`N0=RED, N2=BLACK`, new sibling = N3. Distant nephew = +`N3.child[R]` = null -> not red. Close nephew = +`N3.child[L]` = N4 (RED) -> case 5. Case 5 rotates N3 right +(N4 takes N3's place), `N3.color = RED`, `N4.color = BLACK`, +`distant_nephew = N3`, `sibling = N4`. Case 6 rotates N0 left +(N4 takes N0's place), `N4.color = N0.color = RED`, +`N0.color = BLACK`, `N3.color = BLACK`. + +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: R key=5 parent=N0 L=N4 R=N3 + N2: B key=20 parent=N0 L=-- R=-- + N3: B key=7 parent=N1 L=-- R=N5 + N4: B key=3 parent=N1 L=-- R=-- + N5: R key=8 parent=N3 L=-- R=-- + +After: + Header: root=N1 top=N2 next=-- + N0: B key=10 parent=N5 L=-- R=-- <- recolored B + N1: B key=5 parent=-- L=N4 R=N5 <- root, recolored B + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: B key=7 parent=N5 L=-- R=-- <- recolored B + N4: B key=3 parent=N1 L=-- R=-- + N5: R key=8 parent=N1 L=N3 R=N0 <- recolored R +``` + +Trace: case 3 rotates N0 right (N1 becomes root), recolors +`N0=RED, N1=BLACK`, new sibling = N3. Distant nephew = +`N3.child[L]` = null -> not red. Close nephew = +`N3.child[R]` = N5 (RED) -> case 5. Case 5 rotates N3 left +(N5 takes N3's place), `N3.color = RED`, `N5.color = BLACK`, +`distant_nephew = N3`, `sibling = N5`. Case 6 rotates N0 right +(N5 takes N0's place), `N5.color = N0.color = RED`, +`N0.color = BLACK`, `N3.color = BLACK`. ### Case 2: propagation Black sibling, both nephews black, black parent. Recolor sibling red and propagate upward with `node = parent`. -Dir_l variant (remove key=3): +Dir_l variant (remove key=5): ```text Before: Header: root=N0 top=-- next=-- N0: B key=10 parent=-- L=N1 R=N2 - N1: B key=5 parent=N0 L=N3 R=-- + N1: B key=5 parent=N0 L=-- R=-- N2: B key=15 parent=N0 L=-- R=-- - N3: B key=3 parent=N1 L=-- R=-- -After remove key=5 (successor swap from N3, delete N3 as black -leaf): - Header: root=N0 top=N3 next=-- - N0: B key=10 parent=-- L=N1 R=N2 - N1: B key=3 parent=N0 L=-- R=-- <- swapped key/val - N2: R key=15 parent=N0 L=-- R=-- <- recolored R (case 2) - N3: key=3 color=B parent=-- L=-- R=-- <- freed +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=-- R=N2 + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: R key=15 parent=N0 L=-- R=-- <- recolored R (case 2) ``` -Wait -- after case 2 recolors sibling and propagates to N0 (the -root), the while condition `parent = node->parent` is null, so -the loop exits. But N0 is already black, so the tree is valid -with a shorter black height. The resulting tree has N2 as red, -which combined with case 2's recolor of the sibling means the -tree stays balanced. +Trace: sibling N2 is BLACK, both nephews null, parent N0 is +BLACK -> case 2: `N2.color = RED`, `node = N0`, +`parent = N0.parent = null` -> loop exits (case 1: root). +Tree black height decreases by one uniformly. + +Dir_r variant (remove key=15): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=N2 next=-- + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- <- recolored R (case 2) + N2: key=15 color=B parent=-- L=-- R=-- <- freed +``` -Exact states for case 2 propagation chains (case 2 → case 4, -case 2 → case 6, etc.) require larger trees and should be -verified during implementation. +Trace: mirror of dir_l. ### Case 2 + case 4: propagate then red parent Case 2 propagates upward, reaching a red parent. Case 4 recolors and terminates. +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=20 parent=-- L=N1 R=N4 + N1: R key=10 parent=N0 L=N2 R=N3 + N2: B key=5 parent=N1 L=-- R=-- + N3: B key=15 parent=N1 L=-- R=-- + N4: B key=25 parent=N0 L=-- R=-- + +After (remove key=5): + Header: root=N0 top=N2 next=-- + N0: B key=20 parent=-- L=N1 R=N4 + N1: B key=10 parent=N0 L=-- R=N3 <- recolored B (case 4) + N2: key=5 color=B parent=-- L=-- R=-- <- freed + N3: R key=15 parent=N1 L=-- R=-- <- recolored R (case 4) + N4: B key=25 parent=N0 L=-- R=-- +``` + +Trace: N2 is black leaf, dir=L, parent=N1. Sibling N3 BLACK, +nephews null. `parent->color == RED` (N1 is RED) -> case 4: +`N3.color = RED`, `N1.color = BLACK`, return. Note: despite the +test name, this exercises case 4 directly (not case 2 then 4), +because the parent is already red on the first iteration. The +deeper tree (5 nodes vs 3 in the plain case 4 tests) exercises +the code path where the rebalanced subtree is not the root. + ### Case 2 + case 6: propagate then rotation Case 2 propagates upward, reaching a position where the distant nephew is red. Case 6 rotates and terminates. +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=20 parent=-- L=N1 R=N4 + N1: B key=10 parent=N0 L=N2 R=N3 + N2: B key=5 parent=N1 L=-- R=-- + N3: B key=15 parent=N1 L=-- R=-- + N4: B key=30 parent=N0 L=-- R=N5 + N5: R key=35 parent=N4 L=-- R=-- + +After (remove key=5): + Header: root=N4 top=N2 next=-- + N0: B key=20 parent=N4 L=N1 R=-- <- recolored B + N1: B key=10 parent=N0 L=-- R=N3 + N2: key=5 color=B parent=-- L=-- R=-- <- freed + N3: R key=15 parent=N1 L=-- R=-- <- recolored R (case 2) + N4: B key=30 parent=-- L=N0 R=N5 <- new root + N5: B key=35 parent=N4 L=-- R=-- <- recolored B +``` + +Trace: N2 is black leaf, dir=L, parent=N1. Sibling N3 BLACK, +nephews null, parent N1 BLACK -> case 2: `N3.color = RED`, +`node = N1`, `parent = N0`. Recompute `dir = direction(N1) = L`. +Sibling = N0.child[R] = N4 (BLACK). Distant nephew = +N4.child[R] = N5 (RED) -> case 6. Rotate N0 left: +`N4.color = N0.color = B`, `N0.color = BLACK`, +`N5.color = BLACK`. + ## Case 6: parent null check variants Case 6 rotates parent. If parent is the tree root, the rotation diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index c6650568..c753b545 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -325,15 +325,17 @@ are also overwritten by insert, so they do not need clearing. ### Return value -On success, return `RemoveReturn` packed in `r0`: - -```text -r0 = (value << 16) | REMOVE_STATUS_OK -``` - -This matches the `RemoveReturn` struct layout (`status` at bits -0-15, `value` at bits 16-31). Error codes are returned as plain -`r0` values with zero upper bits, so there is no ambiguity. +On success, return `r0 = 0` (`SUCCESS`). The SVM only persists +account modifications when the program returns zero; any non-zero +`r0` is treated as `ProgramError::Custom(r0)` and all account +changes are reverted. This means the removed value cannot be +encoded in `r0`. + +The removed value can be read from the freed node after +execution: since remove does not clear the freed node's `key`, +`value`, or `color` fields, the caller can dereference +`header.top` in the resulting account data to recover the +value that was associated with the removed key. ## Rust implementation notes From 179c166fd8f8250f813d79125162eac8a2132e4e Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:42:43 -0700 Subject: [PATCH 228/263] Add invariants spec --- examples/tree/specs/tree-invariants.md | 225 +++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 examples/tree/specs/tree-invariants.md diff --git a/examples/tree/specs/tree-invariants.md b/examples/tree/specs/tree-invariants.md new file mode 100644 index 00000000..f15dc9ee --- /dev/null +++ b/examples/tree/specs/tree-invariants.md @@ -0,0 +1,225 @@ +# Tree invariant specification + +## Scope + +Defines the structural invariants that every `TreeSpec` must +satisfy. These invariants are independent of the insert/remove +algorithm logic -- they follow directly from the definitions of a +binary search tree and a red-black tree. Test helpers in +`tests/common.rs` should verify these invariants on every +fabricated tree description (both before and after states) so that +specification errors surface as invariant violations rather than +silently producing incorrect test expectations. + +## Binary search tree invariant + +From Wikipedia: + +> A binary search tree is a rooted binary tree in which nodes are +> arranged in strict total order in which the nodes with keys +> greater than any particular node A is stored on the right +> sub-trees to that node A and the nodes with keys equal to or +> less than A are stored on the left sub-trees to A, satisfying +> the binary search property. + +### BST-1: ordering + +For every node N in the tree: + +- Every key in the left subtree of N is strictly less than N.key. +- Every key in the right subtree of N is strictly greater than + N.key. + +Note: the tree does not permit duplicate keys. Insert rejects +`KEY_EXISTS` and remove uses strict equality for lookup. + +### BST-2: parent-child consistency + +For every non-root node N: + +- N.parent is non-null. +- N appears as exactly one of `N.parent.child[L]` or + `N.parent.child[R]`. + +For the root node: + +- N.parent is null. +- `header.root` points to N. + +For every node N with a non-null child C at position `child[d]`: + +- C.parent equals N. + +## Red-black tree invariants + +From Wikipedia: + +> In addition to the requirements imposed on a binary search tree +> the following must be satisfied by a red-black tree: +> +> 1. Every node is either red or black. +> 1. All null nodes are considered black. +> 1. A red node does not have a red child. +> 1. Every path from a given node to any of its leaf nodes (that +> is, to any descendant null node) goes through the same number +> of black nodes. +> 1. (Conclusion) If a node N has exactly one child, the child +> must be red. If the child were black, its leaves would sit at +> a different black depth than N's null node (which is +> considered black by rule 2), violating requirement 4. + +The invariants below restate these rules with labels used +throughout the test framework. + +### RBT-1: valid coloring + +Every node is either red (1) or black (0). No other values are +permitted. (Wikipedia rule 1.) + +### RBT-2: null nodes are black + +All null child pointers are considered black. This is a +definitional rule used by the other invariants and does not +require an explicit check -- null is implicitly black in the +checks below. (Wikipedia rule 2.) + +### RBT-3: no red-red + +A red node does not have a red child. Equivalently: if a node is +red, both of its children (if non-null) must be black. (Wikipedia +rule 3.) + +### RBT-4: uniform black depth + +Every path from a given node to any of its descendant null nodes +passes through the same number of black nodes. This count +(excluding the node itself, including null as black) is the +node's _black height_. (Wikipedia rule 4.) + +### RBT-5: root is black + +The root of the tree must be black. (This is a consequence of +RBT-3 applied at the root's parent, which is null/black, but it +is listed explicitly because some formulations of the red-black +tree definition include it as a separate rule.) + +### RBT-C: one-child corollary + +If a node N has exactly one child, that child must be red. If +the child were black, its null leaves would sit at a different +black depth than N's null child (which is black by RBT-2), +violating RBT-4. (Wikipedia rule 5 / conclusion.) + +This is a derived property, not an independent axiom, but +checking it explicitly produces clearer error messages than +detecting the black-height mismatch. + +## Free stack invariants + +Freed nodes are linked through `StackNode.next` at offset 0 +(overlapping `TreeNode.parent`). Free stack nodes are not part of +the tree and must not be visited during BST/RBT traversal. + +### FS-1: stack top + +If `header.top` is non-null, it points to a valid node slot +within the account data. + +### FS-2: no overlap with tree + +No node reachable from `header.root` via parent/child pointers +appears on the free stack, and vice versa. The set of tree nodes +and the set of free stack nodes are disjoint. + +## Verification approach + +### Where to check + +Add an `assert_invariants(desc: &TreeSpec)` function in +`tests/common.rs`. This operates purely on the `TreeSpec` +description (node indices, not virtual addresses), making it +independent of account serialization. + +Call `assert_invariants` on: + +- Every `desc` (before state) passed to `run_remove_success`, + `run_insert_success`, and similar helpers. +- Every `exp` (expected after state) passed to these helpers. +- Every intermediate tree state in multi-step tests. + +This catches spec-level errors at test construction time, +before any program code executes. + +### What to check + +The function should verify, given a `TreeSpec`: + +1. **BST-1 (ordering):** In-order traversal of the tree (starting + from `root`, following `left`/`right` indices) yields strictly + increasing keys. +1. **BST-2 (parent-child consistency):** For each node, verify + that the parent index matches (root has no parent; non-root + nodes appear in their parent's child list). For each child + pointer, verify the child's parent points back. +1. **RBT-1 (valid coloring):** Every node's color is `B` or `R`. +1. **RBT-3 (no red-red):** If a node is red, its children (if + present) are black. +1. **RBT-4 (uniform black depth):** Compute the black height of + each node recursively. All paths from the root to null must + yield the same count. +1. **RBT-5 (root is black):** If root is non-null, its color is + `B`. +1. **RBT-C (one-child corollary):** If a node has exactly one + child, that child is red. +1. **FS-1 (stack top):** If `top` is `Some(i)`, then `i` is a + valid node index. +1. **FS-2 (disjoint sets):** Collect the set of node indices + reachable from root. Collect the set of node indices reachable + via the free stack (`top`, then following `parent` as + `StackNode.next`). Verify the two sets are disjoint and their + union covers all node indices in the buffer. + +### Freed nodes + +Freed nodes on the stack have null children (cleared by remove) +and use the `parent` field as `StackNode.next`. These nodes +must not be traversed as part of the BST/RBT checks. The +`TreeSpec` already distinguishes freed nodes implicitly: they +are reachable from `top` but not from `root`. + +To identify freed nodes from a `TreeSpec`: + +- Walk the free stack starting from `top`, following `parent` as + the next pointer, until null. +- All remaining nodes (reachable from `root`) are tree nodes and + must satisfy BST and RBT invariants. + +### Error reporting + +`assert_invariants` should return `Result<(), String>` with a +descriptive message identifying which invariant failed and which +node(s) are involved. Example: + +```text +RBT-3 (no red-red): N2 (RED) has red child N4 at child[R] +RBT-4 (uniform black depth): root black height L=3, R=2 +BST-1 (ordering): N3.key=15 in left subtree of N0.key=10 +``` + +### Interaction with existing tests + +The invariant checks run on `TreeSpec` descriptions, not on +program output. This makes them orthogonal to the program logic: + +- If a test's **before** state fails invariants, the test setup + is invalid and should be fixed in the test spec. +- If a test's **after** state fails invariants, the test + expectation is wrong and should be traced against the reference + algorithm. +- If the program produces output that passes `assert_tree_account` + but the expected `TreeSpec` fails invariants, the spec has a + bug. + +This separation means invariant checking does not depend on or +validate program correctness -- it validates the test +specifications themselves. From 3c2741d5f6333fee2110c355da19ba08a6062951 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:05:57 -0700 Subject: [PATCH 229/263] Add invariants --- examples/tree/specs/remove-tests.md | 87 ++++++--- examples/tree/specs/tree-invariants.md | 23 ++- examples/tree/src/tests.rs | 20 ++ examples/tree/src/tests/common.rs | 245 ++++++++++++++++++++++++ examples/tree/src/tests/insert.rs | 152 +++------------ examples/tree/src/tests/remove.rs | 255 ++++++++++++++----------- 6 files changed, 515 insertions(+), 267 deletions(-) diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index 854e87bb..bd927c4d 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -231,13 +231,13 @@ the successor instead. Before: Header: root=N0 top=-- next=-- N0: B key=10 parent=-- L=N1 R=N2 - N1: B key=5 parent=N0 L=-- R=-- + N1: R key=5 parent=N0 L=-- R=-- N2: R key=15 parent=N0 L=-- R=-- After remove key=10 (returns value=10): Header: root=N0 top=N2 next=-- N0: B key=15 val=15 parent=-- L=N1 R=-- <- copied from successor - N1: B key=5 parent=N0 L=-- R=-- + N1: R key=5 parent=N0 L=-- R=-- N2: key=15 color=R parent=-- L=-- R=-- <- freed (was successor) ``` @@ -368,34 +368,51 @@ After: The rotation transfers sibling's child on the `dir` side to parent. When that child is non-null, it must be reparented. -Dir_l variant (remove key=3): +The sibling must have both children non-null: the distant nephew +is RED (triggering case 6) and the close nephew is the new_child +that gets transferred. For a valid RBT with a black leaf on one +side and sibling bh=1 on the other, the sibling has two RED +children (both bh=0). + +Dir_l variant (remove key=5): ```text Before: Header: root=N0 top=-- next=-- N0: B key=10 parent=-- L=N1 R=N2 - N1: B key=5 parent=N0 L=N4 R=-- - N2: B key=20 parent=N0 L=N3 R=N5 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=20 parent=N0 L=N3 R=N4 N3: R key=15 parent=N2 L=-- R=-- - N4: B key=3 parent=N1 L=-- R=-- - N5: R key=25 parent=N2 L=-- R=-- - -After remove key=5 (successor swap: N1 gets key=3 from N4, -then delete N4 which is a black leaf): - Header: root=N0 top=N4 next=-- - N0: B key=10 parent=N2 L=N1 R=N3 <- reparented - N1: B key=3 parent=N0 L=-- R=-- <- copied from successor - N2: B key=20 parent=-- L=N0 R=N5 <- new root - N3: B key=15 parent=N0 L=-- R=-- <- reparented, recolored B - N4: key=3 color=B parent=-- L=-- R=-- <- freed - N5: B key=25 parent=N2 L=-- R=-- <- recolored B + N4: R key=25 parent=N2 L=-- R=-- + +After: + Header: root=N2 top=N1 next=-- + N0: B key=10 parent=N2 L=-- R=N3 <- R=N3 (new_child) + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=20 parent=-- L=N0 R=N4 <- new root + N3: R key=15 parent=N0 L=-- R=-- <- reparented to N0 + N4: B key=25 parent=N2 L=-- R=-- <- recolored B ``` -Wait -- this case is getting complex because it also involves a -successor swap. A cleaner test isolates the rotation by removing -a black leaf directly. Concrete before/after states for non-null -new_child cases will be determined during implementation when -exact tree shapes are constructed. +Dir_r variant (remove key=20): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N3 R=N4 + N2: B key=20 parent=N0 L=-- R=-- + N3: R key=3 parent=N1 L=-- R=-- + N4: R key=7 parent=N1 L=-- R=-- + +After: + Header: root=N1 top=N2 next=-- + N0: B key=10 parent=N1 L=N4 R=-- <- L=N4 (new_child) + N1: B key=5 parent=-- L=N3 R=N0 <- new root + N2: key=20 color=B parent=-- L=-- R=-- <- freed + N3: B key=3 parent=N1 L=-- R=-- <- recolored B + N4: R key=7 parent=N0 L=-- R=-- <- reparented to N0 +``` ### Case 5 + 6: close nephew red, distant nephew black @@ -706,6 +723,11 @@ the code path where the rebalanced subtree is not the root. Case 2 propagates upward, reaching a position where the distant nephew is red. Case 6 rotates and terminates. +The right subtree of the root must have bh=2 (matching the left) +with a RED distant nephew. This requires B(30) with B(25) left +and R(35) right, where R(35) has two B leaf children (33, 40), +giving bh=1 per child path under B(30). Total: 9 nodes. + ```text Before: Header: root=N0 top=-- next=-- @@ -713,26 +735,33 @@ Before: N1: B key=10 parent=N0 L=N2 R=N3 N2: B key=5 parent=N1 L=-- R=-- N3: B key=15 parent=N1 L=-- R=-- - N4: B key=30 parent=N0 L=-- R=N5 - N5: R key=35 parent=N4 L=-- R=-- + N4: B key=30 parent=N0 L=N5 R=N6 + N5: B key=25 parent=N4 L=-- R=-- + N6: R key=35 parent=N4 L=N7 R=N8 + N7: B key=33 parent=N6 L=-- R=-- + N8: B key=40 parent=N6 L=-- R=-- After (remove key=5): Header: root=N4 top=N2 next=-- - N0: B key=20 parent=N4 L=N1 R=-- <- recolored B + N0: B key=20 parent=N4 L=N1 R=N5 <- reparented, R=N5 N1: B key=10 parent=N0 L=-- R=N3 N2: key=5 color=B parent=-- L=-- R=-- <- freed N3: R key=15 parent=N1 L=-- R=-- <- recolored R (case 2) - N4: B key=30 parent=-- L=N0 R=N5 <- new root - N5: B key=35 parent=N4 L=-- R=-- <- recolored B + N4: B key=30 parent=-- L=N0 R=N6 <- new root + N5: B key=25 parent=N0 L=-- R=-- <- reparented to N0 + N6: B key=35 parent=N4 L=N7 R=N8 <- recolored B + N7: B key=33 parent=N6 L=-- R=-- + N8: B key=40 parent=N6 L=-- R=-- ``` Trace: N2 is black leaf, dir=L, parent=N1. Sibling N3 BLACK, nephews null, parent N1 BLACK -> case 2: `N3.color = RED`, `node = N1`, `parent = N0`. Recompute `dir = direction(N1) = L`. Sibling = N0.child[R] = N4 (BLACK). Distant nephew = -N4.child[R] = N5 (RED) -> case 6. Rotate N0 left: +N4.child[R] = N6 (RED) -> case 6. Rotate N0 left: N5 (B(25)) +reparented from N4.child[L] to N0.child[R]. `N4.color = N0.color = B`, `N0.color = BLACK`, -`N5.color = BLACK`. +`N6.color = BLACK`. ## Case 6: parent null check variants diff --git a/examples/tree/specs/tree-invariants.md b/examples/tree/specs/tree-invariants.md index f15dc9ee..0cd77ff9 100644 --- a/examples/tree/specs/tree-invariants.md +++ b/examples/tree/specs/tree-invariants.md @@ -96,12 +96,23 @@ passes through the same number of black nodes. This count (excluding the node itself, including null as black) is the node's _black height_. (Wikipedia rule 4.) -### RBT-5: root is black +### RBT-5: root is black (omitted) -The root of the tree must be black. (This is a consequence of -RBT-3 applied at the root's parent, which is null/black, but it -is listed explicitly because some formulations of the red-black -tree definition include it as a separate rule.) +From Wikipedia: + +> Some authors, e.g. Cormen & al., claim "the root is black" as +> fifth requirement; but not Mehlhorn & Sanders or Sedgewick & +> Wayne. Since the root can always be changed from red to black, +> this rule has little effect on analysis. This article also omits +> it, because it slightly disturbs the recursive algorithms and +> proofs. + +This invariant is **not checked** by `assert_invariants`. The +insert algorithm in this codebase follows the Wikipedia +formulation which omits the root-is-black rule. A red root is +valid: it does not violate any of the four core rules (RBT-1 +through RBT-4) and does not affect the structural correctness of +the tree. ### RBT-C: one-child corollary @@ -167,8 +178,6 @@ The function should verify, given a `TreeSpec`: 1. **RBT-4 (uniform black depth):** Compute the black height of each node recursively. All paths from the root to null must yield the same count. -1. **RBT-5 (root is black):** If root is non-null, its color is - `B`. 1. **RBT-C (one-child corollary):** If a node has exactly one child, that child is red. 1. **FS-1 (stack top):** If `top` is `Some(i)`, then `i` is a diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 6bff9e22..4abf5380 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -238,3 +238,23 @@ fn test_remove_input_checks() { fn test_remove_search() { print_comparison_table(remove::RemoveCase::SEARCH_CASES); } + +#[test] +fn test_remove_simple() { + print_comparison_table(remove::RemoveCase::SIMPLE_CASES); +} + +#[test] +fn test_remove_successor() { + print_comparison_table(remove::RemoveCase::SUCCESSOR_CASES); +} + +#[test] +fn test_remove_rebalance() { + print_comparison_table(remove::RemoveCase::REBALANCE_CASES); +} + +#[test] +fn test_multi_remove() { + print_comparison_table(remove::MultiRemoveCase::CASES); +} diff --git a/examples/tree/src/tests/common.rs b/examples/tree/src/tests/common.rs index 4e2a7ae6..f9a027a9 100644 --- a/examples/tree/src/tests/common.rs +++ b/examples/tree/src/tests/common.rs @@ -245,6 +245,251 @@ pub(super) fn assert_tree_account(data: &[u8], expected: &TreeSpec) -> Result<() } } +// --------------------------------------------------------------------------- +// Invariant checker (operates on TreeSpec, not account data) +// --------------------------------------------------------------------------- + +/// Check all structural invariants of a `TreeSpec`. +/// +/// Verifies BST ordering, parent-child consistency, RBT coloring rules, +/// and free stack validity. Returns `Ok(())` if all invariants hold, +/// or `Err` with descriptions of all violations found. +/// +/// See `specs/tree-invariants.md` for the full specification. +pub(super) fn assert_invariants(desc: &TreeSpec) -> Result<(), String> { + let mut errors = Vec::new(); + let n = desc.nodes.len(); + + // --- Collect tree nodes (reachable from root via child pointers) --- + let mut tree_set = vec![false; n]; + if let Some(root) = desc.root { + if root >= n { + errors.push(format!("root index {} out of bounds (n={})", root, n)); + } else { + collect_reachable(desc.nodes, root, &mut tree_set, &mut errors); + } + } + + // --- Collect free stack nodes --- + let mut stack_set = vec![false; n]; + { + let mut cur = desc.top; + while let Some(i) = cur { + if i >= n { + break; // Slot beyond described nodes (pre-allocated). + } + if stack_set[i] { + errors.push(format!("FS: cycle in free stack at N{}", i)); + break; + } + stack_set[i] = true; + cur = desc.nodes[i].parent; // parent field = StackNode.next + } + } + + // --- FS-2: disjoint sets and coverage --- + for i in 0..n { + if tree_set[i] && stack_set[i] { + errors.push(format!( + "FS-2 (disjoint): N{} in both tree and free stack", + i + )); + } + if !tree_set[i] && !stack_set[i] { + errors.push(format!( + "FS-2 (coverage): N{} neither in tree nor on free stack", + i + )); + } + } + + // --- BST and RBT checks (only on tree nodes) --- + if let Some(root) = desc.root { + if root < n { + // BST-2: root has no parent. + if desc.nodes[root].parent.is_some() { + errors.push(format!( + "BST-2: root N{} has parent={:?}", + root, desc.nodes[root].parent + )); + } + } + + for i in 0..n { + if !tree_set[i] { + continue; + } + let nd = &desc.nodes[i]; + + // RBT-1: valid coloring. + if nd.color != B && nd.color != R { + errors.push(format!("RBT-1 (valid coloring): N{} color={}", i, nd.color)); + } + + // BST-2: parent-child consistency (non-root). + if i != root { + match nd.parent { + None => errors.push(format!("BST-2: non-root N{} has no parent", i)), + Some(p) => { + if p >= n { + errors.push(format!("BST-2: N{}.parent={} out of bounds", i, p)); + } else { + let par = &desc.nodes[p]; + if par.left != Some(i) && par.right != Some(i) { + errors.push(format!( + "BST-2: N{}.parent=N{} but N{} has L={:?} R={:?}", + i, p, p, par.left, par.right + )); + } + } + } + } + } + + // BST-2: children point back. + if let Some(l) = nd.left { + if l < n && desc.nodes[l].parent != Some(i) { + errors.push(format!( + "BST-2: N{}.L=N{} but N{}.parent={:?}", + i, l, l, desc.nodes[l].parent + )); + } + } + if let Some(r) = nd.right { + if r < n && desc.nodes[r].parent != Some(i) { + errors.push(format!( + "BST-2: N{}.R=N{} but N{}.parent={:?}", + i, r, r, desc.nodes[r].parent + )); + } + } + + // RBT-3: no red-red. + if nd.color == R { + if let Some(l) = nd.left { + if l < n && desc.nodes[l].color == R { + errors.push(format!( + "RBT-3 (no red-red): N{} (RED) has red child N{} at L", + i, l + )); + } + } + if let Some(r) = nd.right { + if r < n && desc.nodes[r].color == R { + errors.push(format!( + "RBT-3 (no red-red): N{} (RED) has red child N{} at R", + i, r + )); + } + } + } + + // RBT-C: one-child corollary. + let has_l = nd.left.is_some(); + let has_r = nd.right.is_some(); + if has_l != has_r { + let child = nd.left.or(nd.right).unwrap(); + if child < n && desc.nodes[child].color != R { + errors.push(format!( + "RBT-C (one-child): N{} has one child N{} which is BLACK", + i, child + )); + } + } + } + + // BST-1: in-order traversal yields strictly increasing keys. + if root < n { + let mut keys = Vec::new(); + inorder_keys(desc.nodes, root, &mut keys); + for w in keys.windows(2) { + if w[0] >= w[1] { + errors.push(format!( + "BST-1 (ordering): keys not strictly increasing: {} >= {}", + w[0], w[1] + )); + break; + } + } + + // RBT-4: uniform black depth. + if let Err(e) = black_height(desc.nodes, root) { + errors.push(e); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors.join("; ")) + } +} + +/// Walk tree from `idx` via child pointers, marking visited nodes. +fn collect_reachable( + nodes: &[NodeSpec], + idx: usize, + visited: &mut Vec, + errors: &mut Vec, +) { + if idx >= nodes.len() { + errors.push(format!( + "child index {} out of bounds (n={})", + idx, + nodes.len() + )); + return; + } + if visited[idx] { + errors.push(format!("cycle in tree at N{}", idx)); + return; + } + visited[idx] = true; + if let Some(l) = nodes[idx].left { + collect_reachable(nodes, l, visited, errors); + } + if let Some(r) = nodes[idx].right { + collect_reachable(nodes, r, visited, errors); + } +} + +/// Collect keys via in-order traversal. +fn inorder_keys(nodes: &[NodeSpec], idx: usize, keys: &mut Vec) { + if let Some(l) = nodes[idx].left { + if l < nodes.len() { + inorder_keys(nodes, l, keys); + } + } + keys.push(nodes[idx].key); + if let Some(r) = nodes[idx].right { + if r < nodes.len() { + inorder_keys(nodes, r, keys); + } + } +} + +/// Compute the black height of a subtree. Returns `Err` if any node has +/// unequal left/right black heights (RBT-4 violation). +fn black_height(nodes: &[NodeSpec], idx: usize) -> Result { + let nd = &nodes[idx]; + let lbh = match nd.left { + Some(l) if l < nodes.len() => black_height(nodes, l)?, + _ => 0, + }; + let rbh = match nd.right { + Some(r) if r < nodes.len() => black_height(nodes, r)?, + _ => 0, + }; + if lbh != rbh { + return Err(format!( + "RBT-4 (uniform black depth): N{} (key={}) L black height={}, R black height={}", + idx, nd.key, lbh, rbh + )); + } + Ok(lbh + if nd.color == B { 1 } else { 0 }) +} + // --------------------------------------------------------------------------- // Shorthand constructors // --------------------------------------------------------------------------- diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index ac4d4353..5a185339 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -234,6 +234,12 @@ fn run_success( insert_key: u16, expected: &TreeSpec, ) -> CaseResult { + if let Err(e) = assert_invariants(desc) { + return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + } + if let Err(e) = assert_invariants(expected) { + return CaseResult { cu: 0, error: Some(format!("exp invariant: {}", e)) }; + } let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); let result = setup.mollusk.process_instruction(&instruction, &accounts); match &result.program_result { @@ -261,6 +267,9 @@ fn run_success( /// Run an insert and check for KEY_EXISTS error. fn run_dup_error(lang: ProgramLanguage, desc: &TreeSpec, insert_key: u16) -> CaseResult { + if let Err(e) = assert_invariants(desc) { + return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + } let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); check_error( &setup, @@ -316,16 +325,12 @@ pub(super) enum InsertCase { // Case 2+1: red uncle, propagate to black ancestor. Case21Left, Case21Right, - // Case 6: single rotation (outer child). + // Case 6: single rotation (outer child, null uncle). Case6LeftNull, Case6RightNull, - Case6LeftBlack, - Case6RightBlack, - // Case 5+6: double rotation (inner child). + // Case 5+6: double rotation (inner child, null uncle). Case56LeftNull, Case56RightNull, - Case56LeftBlack, - Case56RightBlack, // Case 6: non-null great-grandparent. Case6GgpLeftLeft, Case6GgpLeftRight, @@ -381,12 +386,8 @@ impl InsertCase { Self::Case21Right, Self::Case6LeftNull, Self::Case6RightNull, - Self::Case6LeftBlack, - Self::Case6RightBlack, Self::Case56LeftNull, Self::Case56RightNull, - Self::Case56LeftBlack, - Self::Case56RightBlack, Self::Case6GgpLeftLeft, Self::Case6GgpLeftRight, Self::Case6GgpRightRight, @@ -432,12 +433,8 @@ impl TestCase for InsertCase { Self::Case21Right => "Case 2+1: right", Self::Case6LeftNull => "Case 6: left-left null uncle", Self::Case6RightNull => "Case 6: right-right null uncle", - Self::Case6LeftBlack => "Case 6: left-left black uncle", - Self::Case6RightBlack => "Case 6: right-right black uncle", Self::Case56LeftNull => "Case 5+6: left-right null uncle", Self::Case56RightNull => "Case 5+6: right-left null uncle", - Self::Case56LeftBlack => "Case 5+6: left-right black uncle", - Self::Case56RightBlack => "Case 5+6: right-left black uncle", Self::Case6GgpLeftLeft => "Case 6: GGP non-null, LL GP-left", Self::Case6GgpLeftRight => "Case 6: GGP non-null, LL GP-right", Self::Case6GgpRightRight => "Case 6: GGP non-null, RR GP-right", @@ -903,52 +900,56 @@ impl TestCase for InsertCase { // ----- Case 2+1: red uncle, propagate to black ancestor ----- - // Before: B(20) root, B(10) left of root, R(5) left of 10, R(15) right of 10. - // After: B(20), R(10), B(5), B(15), R(1) inserted. + // Before: B(20) root, B(10) left with R(5)/R(15), B(25) right. + // After: B(20), R(10), B(5)/B(15), B(25), R(1) inserted. Self::Case21Left => { let desc = TreeSpec { root: Some(0), top: None, nodes: &[ - node(20, B, None, Some(1), None), + node(20, B, None, Some(1), Some(4)), node(10, B, Some(0), Some(2), Some(3)), node(5, R, Some(1), None, None), node(15, R, Some(1), None, None), + node(25, B, Some(0), None, None), ], }; let exp = TreeSpec { root: Some(0), top: None, nodes: &[ - node(20, B, None, Some(1), None), + node(20, B, None, Some(1), Some(4)), node(10, R, Some(0), Some(2), Some(3)), - node(5, B, Some(1), Some(4), None), + node(5, B, Some(1), Some(5), None), node(15, B, Some(1), None, None), + node(25, B, Some(0), None, None), node(1, R, Some(2), None, None), ], }; run_success(lang, &desc, 1, &exp) } - // Mirror: B(2) root, B(10) right of root, R(5) left of 10, R(15) right of 10. + // Mirror: B(2) root, B(1) left, B(10) right with R(5)/R(15). Self::Case21Right => { let desc = TreeSpec { root: Some(0), top: None, nodes: &[ - node(2, B, None, None, Some(1)), + node(2, B, None, Some(4), Some(1)), node(10, B, Some(0), Some(2), Some(3)), node(5, R, Some(1), None, None), node(15, R, Some(1), None, None), + node(1, B, Some(0), None, None), ], }; let exp = TreeSpec { root: Some(0), top: None, nodes: &[ - node(2, B, None, None, Some(1)), + node(2, B, None, Some(4), Some(1)), node(10, R, Some(0), Some(2), Some(3)), node(5, B, Some(1), None, None), - node(15, B, Some(1), None, Some(4)), + node(15, B, Some(1), None, Some(5)), + node(1, B, Some(0), None, None), node(20, R, Some(3), None, None).val(1), ], }; @@ -1001,55 +1002,6 @@ impl TestCase for InsertCase { }; run_success(lang, &desc, 20, &exp) } - // Left-left, black uncle: B(10) root, R(5) left, B(15) right, insert 1. - // After: B(5) new root, R(1) left, R(10) right with B(15) as 10's right. - Self::Case6LeftBlack => { - let desc = TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, B, Some(0), None, None), - ], - }; - let exp = TreeSpec { - root: Some(1), - top: None, - nodes: &[ - node(10, R, Some(1), None, Some(2)), - node(5, B, None, Some(3), Some(0)), - node(15, B, Some(0), None, None), - node(1, R, Some(1), None, None), - ], - }; - run_success(lang, &desc, 1, &exp) - } - // Right-right, black uncle: B(10) root, B(5) left, R(15) right, insert 20. - // After: B(15) new root, R(10) left with B(5) as 10's left, R(20) right. - Self::Case6RightBlack => { - let desc = TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = TreeSpec { - root: Some(2), - top: None, - nodes: &[ - node(10, R, Some(2), Some(1), None), - node(5, B, Some(0), None, None), - node(15, B, None, Some(0), Some(3)), - node(20, R, Some(2), None, None).val(1), - ], - }; - run_success(lang, &desc, 20, &exp) - } - // ----- Case 5+6: double rotation (inner child) ----- // Left-right, null uncle: B(10) root, R(5) left, insert 7. @@ -1096,55 +1048,6 @@ impl TestCase for InsertCase { }; run_success(lang, &desc, 12, &exp) } - // Left-right, black uncle: B(10) root, R(5) left, B(15) right, insert 7. - // After: B(7) new root, R(5) left, R(10) right with B(15) as 10's right. - Self::Case56LeftBlack => { - let desc = TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, B, Some(0), None, None), - ], - }; - let exp = TreeSpec { - root: Some(3), - top: None, - nodes: &[ - node(10, R, Some(3), None, Some(2)), - node(5, R, Some(3), None, None), - node(15, B, Some(0), None, None), - node(7, B, None, Some(1), Some(0)).val(1), - ], - }; - run_success(lang, &desc, 7, &exp) - } - // Right-left, black uncle: B(10) root, B(5) left, R(15) right, insert 12. - // After: B(12) new root, R(10) left with B(5) as 10's left, R(15) right. - Self::Case56RightBlack => { - let desc = TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), - node(15, R, Some(0), None, None), - ], - }; - let exp = TreeSpec { - root: Some(3), - top: None, - nodes: &[ - node(10, R, Some(3), Some(1), None), - node(5, B, Some(0), None, None), - node(15, R, Some(3), None, None), - node(12, B, None, Some(0), Some(2)).val(1), - ], - }; - run_success(lang, &desc, 12, &exp) - } - // ----- Case 6: non-null great-grandparent ----- // LL, GP is left child of GGP. Insert 1. @@ -1424,6 +1327,13 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) -> CaseRes let mut total_cu = 0u64; for (i, step) in steps.iter().enumerate() { + if let Err(e) = assert_invariants(&step.expected) { + return CaseResult { + cu: 0, + error: Some(format!("step {} (key={}) exp invariant: {}", i, step.key, e)), + }; + } + let insn_data = InsertInstruction { header: InstructionHeader { discriminator: TreeInstruction::Insert as u8, diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs index 77c608fa..35b01129 100644 --- a/examples/tree/src/tests/remove.rs +++ b/examples/tree/src/tests/remove.rs @@ -1,7 +1,7 @@ use super::common::*; use super::*; use tree_interface::{ - input_buffer, instruction, InsertInstruction, Instruction as TreeInstruction, + input_buffer, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, RemoveInstruction, StackNode, TreeHeader, TreeNode, }; @@ -63,23 +63,26 @@ fn remove_input_setup( // Helpers: remove runners // --------------------------------------------------------------------------- -/// Execute a remove and verify success with full tree state and return value. +/// Execute a remove and verify success with full tree state. /// -/// On success, the program returns `(value << 16) | REMOVE_STATUS_OK` encoded -/// as `ProgramError::Custom(...)`. +/// On success, the program returns 0. Account changes are only persisted +/// by the SVM when the program returns 0. fn run_remove_success( lang: ProgramLanguage, desc: &TreeSpec, remove_key: u16, - expected_value: u16, expected: &TreeSpec, ) -> CaseResult { + if let Err(e) = assert_invariants(desc) { + return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + } + if let Err(e) = assert_invariants(expected) { + return CaseResult { cu: 0, error: Some(format!("exp invariant: {}", e)) }; + } let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); - let expected_r0 = - ((expected_value as u32) << 16) | instruction::REMOVE_STATUS_OK as u32; let result = setup.mollusk.process_instruction(&instruction, &accounts); match &result.program_result { - MolluskResult::Failure(err) if *err == ProgramError::Custom(expected_r0) => { + MolluskResult::Success => { let tree_data = &result.resulting_accounts[AccountIndex::Tree as usize] .1 .data; @@ -96,10 +99,7 @@ fn run_remove_success( } other => CaseResult { cu: result.compute_units_consumed, - error: Some(format!( - "expected Failure(Custom({:#x})), got {:?}", - expected_r0, other - )), + error: Some(format!("expected Success, got {:?}", other)), }, } } @@ -110,6 +110,9 @@ fn run_remove_not_found( desc: &TreeSpec, remove_key: u16, ) -> CaseResult { + if let Err(e) = assert_invariants(desc) { + return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + } let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); check_error( &setup, @@ -125,7 +128,7 @@ fn run_remove_not_found( enum MultiStep { Insert { key: u16, value: u16 }, - Remove { key: u16, expected_value: u16 }, + Remove { key: u16 }, } struct MultiStepCase<'a> { @@ -143,7 +146,18 @@ fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase] let mut total_cu = 0u64; for (i, step) in steps.iter().enumerate() { - let (insn_bytes, expected_result): (Vec, _) = match &step.step { + if let Err(e) = assert_invariants(&step.expected) { + let step_desc = match &step.step { + MultiStep::Insert { key, .. } => format!("insert key={}", key), + MultiStep::Remove { key, .. } => format!("remove key={}", key), + }; + return CaseResult { + cu: 0, + error: Some(format!("step {} ({}) exp invariant: {}", i, step_desc, e)), + }; + } + + let insn_bytes: Vec = match &step.step { MultiStep::Insert { key, value } => { let insn = InsertInstruction { header: InstructionHeader { @@ -152,18 +166,16 @@ fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase] key: *key, value: *value, }; - (unsafe { as_bytes(&insn) }.to_vec(), None) + unsafe { as_bytes(&insn) }.to_vec() } - MultiStep::Remove { key, expected_value } => { + MultiStep::Remove { key } => { let insn = RemoveInstruction { header: InstructionHeader { discriminator: TreeInstruction::Remove as u8, }, key: *key, }; - let r0 = ((*expected_value as u32) << 16) - | instruction::REMOVE_STATUS_OK as u32; - (unsafe { as_bytes(&insn) }.to_vec(), Some(r0)) + unsafe { as_bytes(&insn) }.to_vec() } }; @@ -187,18 +199,8 @@ fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase] let result = setup.mollusk.process_instruction(&instruction, &accounts); total_cu += result.compute_units_consumed; - // Check program result. - let ok = match (&result.program_result, expected_result) { - (MolluskResult::Success, None) => true, - (MolluskResult::Failure(err), Some(r0)) - if *err == ProgramError::Custom(r0) => - { - true - } - _ => false, - }; - - if !ok { + // Both insert and remove return 0 on success. + if result.program_result != MolluskResult::Success { let step_desc = match &step.step { MultiStep::Insert { key, .. } => format!("insert key={}", key), MultiStep::Remove { key, .. } => format!("remove key={}", key), @@ -206,8 +208,8 @@ fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase] return CaseResult { cu: total_cu, error: Some(format!( - "step {} ({}): expected {:?}, got {:?}", - i, step_desc, expected_result, result.program_result + "step {} ({}): expected Success, got {:?}", + i, step_desc, result.program_result )), }; } @@ -504,7 +506,7 @@ impl TestCase for RemoveCase { top: Some(0), nodes: &[node(10, B, None, None, None)], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // Simple case 3: remove red leaf (left child). @@ -525,7 +527,7 @@ impl TestCase for RemoveCase { node(5, R, None, None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Simple case 3: remove red leaf (right child). @@ -546,7 +548,7 @@ impl TestCase for RemoveCase { node(15, R, None, None, None), ], }; - run_remove_success(lang, &desc, 15, 15, &exp) + run_remove_success(lang, &desc, 15, &exp) } // Simple case 1: one child at root (right child). @@ -567,7 +569,7 @@ impl TestCase for RemoveCase { node(15, B, None, None, None), ], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // Simple case 1: one child at root (left child). @@ -588,7 +590,7 @@ impl TestCase for RemoveCase { node(5, B, None, None, None), ], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // Simple case 1: one child non-root (right child). @@ -613,19 +615,21 @@ impl TestCase for RemoveCase { node(20, B, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 15, 15, &exp) + run_remove_success(lang, &desc, 15, &exp) } // ----- Successor swap ----- // Successor is immediate right child. + // B(10) with R(5) left, R(15) right. Remove 10: swap with + // successor N2(15), then delete N2 (red leaf, simple case 3). Self::SuccessorImmediate => { let desc = TreeSpec { root: Some(0), top: None, nodes: &[ node(10, B, None, Some(1), Some(2)), - node(5, B, Some(0), None, None), + node(5, R, Some(0), None, None), node(15, R, Some(0), None, None), ], }; @@ -634,11 +638,11 @@ impl TestCase for RemoveCase { top: Some(2), nodes: &[ node(15, B, None, Some(1), None).val(15), - node(5, B, Some(0), None, None), + node(5, R, Some(0), None, None), node(15, R, None, None, None), ], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // Successor with deep left descent. @@ -665,7 +669,7 @@ impl TestCase for RemoveCase { node(25, R, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // Successor with right child. @@ -690,7 +694,7 @@ impl TestCase for RemoveCase { node(20, B, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 10, 10, &exp) + run_remove_success(lang, &desc, 10, &exp) } // ----- Rebalancing ----- @@ -715,7 +719,7 @@ impl TestCase for RemoveCase { node(15, R, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 4 dir_r. @@ -738,7 +742,7 @@ impl TestCase for RemoveCase { node(15, B, None, None, None), ], }; - run_remove_success(lang, &desc, 15, 15, &exp) + run_remove_success(lang, &desc, 15, &exp) } // Case 6 dir_l: black sibling, distant nephew red. @@ -763,7 +767,7 @@ impl TestCase for RemoveCase { node(20, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 6 dir_r. @@ -788,7 +792,7 @@ impl TestCase for RemoveCase { node(3, B, Some(1), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 5+6 dir_l. @@ -809,11 +813,11 @@ impl TestCase for RemoveCase { nodes: &[ node(10, B, Some(3), None, None), node(5, B, None, None, None), - node(20, R, Some(3), None, None), + node(20, B, Some(3), None, None), node(15, B, None, Some(0), Some(2)), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 5+6 dir_r. @@ -833,12 +837,12 @@ impl TestCase for RemoveCase { top: Some(2), nodes: &[ node(10, B, Some(3), None, None), - node(5, R, Some(3), None, None), + node(5, B, Some(3), None, None), node(20, B, None, None, None), node(7, B, None, Some(1), Some(0)), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 3 -> 4 dir_l. @@ -865,7 +869,7 @@ impl TestCase for RemoveCase { node(25, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 3 -> 4 dir_r. @@ -892,7 +896,7 @@ impl TestCase for RemoveCase { node(7, R, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 3 -> 6 dir_l. @@ -916,12 +920,12 @@ impl TestCase for RemoveCase { node(10, B, Some(3), None, None), node(5, B, None, None, None), node(20, B, None, Some(3), Some(5)), - node(15, B, Some(2), Some(0), Some(4)), - node(17, R, Some(3), None, None), + node(15, R, Some(2), Some(0), Some(4)), + node(17, B, Some(3), None, None), node(25, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 3 -> 6 dir_r. @@ -945,12 +949,12 @@ impl TestCase for RemoveCase { node(10, B, Some(3), None, None), node(5, B, None, Some(4), Some(3)), node(20, B, None, None, None), - node(7, B, Some(1), Some(5), Some(0)), + node(7, R, Some(1), Some(5), Some(0)), node(3, B, Some(1), None, None), - node(6, R, Some(3), None, None), + node(6, B, Some(3), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 3 -> 5 -> 6 dir_l. @@ -974,12 +978,12 @@ impl TestCase for RemoveCase { node(10, B, Some(4), None, None), node(5, B, None, None, None), node(20, B, None, Some(4), Some(5)), - node(15, R, Some(4), None, None), - node(13, B, Some(2), Some(0), Some(3)), + node(15, B, Some(4), None, None), + node(13, R, Some(2), Some(0), Some(3)), node(25, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 3 -> 5 -> 6 dir_r. @@ -1003,12 +1007,12 @@ impl TestCase for RemoveCase { node(10, B, Some(5), None, None), node(5, B, None, Some(4), Some(5)), node(20, B, None, None, None), - node(7, R, Some(5), None, None), + node(7, B, Some(5), None, None), node(3, B, Some(1), None, None), - node(8, B, Some(1), Some(3), Some(0)), + node(8, R, Some(1), Some(3), Some(0)), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 2: propagate to root (dir_l). @@ -1031,7 +1035,7 @@ impl TestCase for RemoveCase { node(15, R, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 2: propagate to root (dir_r). @@ -1054,7 +1058,7 @@ impl TestCase for RemoveCase { node(15, B, None, None, None), ], }; - run_remove_success(lang, &desc, 15, 15, &exp) + run_remove_success(lang, &desc, 15, &exp) } // Case 2 -> 4: propagate then red parent. @@ -1081,10 +1085,13 @@ impl TestCase for RemoveCase { node(25, B, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 2 -> 6: propagate then distant nephew red. + // 9-node tree with bh=3 at root. Remove B(5) leaf: + // case 2 at B(10), propagate to B(20), then case 6 + // (distant nephew R(35) is red). Self::Case2Then6 => { let desc = TreeSpec { root: Some(0), @@ -1094,26 +1101,35 @@ impl TestCase for RemoveCase { node(10, B, Some(0), Some(2), Some(3)), node(5, B, Some(1), None, None), node(15, B, Some(1), None, None), - node(30, B, Some(0), None, Some(5)), - node(35, R, Some(4), None, None), + node(30, B, Some(0), Some(5), Some(6)), + node(25, B, Some(4), None, None), + node(35, R, Some(4), Some(7), Some(8)), + node(33, B, Some(6), None, None), + node(40, B, Some(6), None, None), ], }; let exp = TreeSpec { root: Some(4), top: Some(2), nodes: &[ - node(20, B, Some(4), Some(1), None), + node(20, B, Some(4), Some(1), Some(5)), node(10, B, Some(0), None, Some(3)), node(5, B, None, None, None), node(15, R, Some(1), None, None), - node(30, B, None, Some(0), Some(5)), - node(35, B, Some(4), None, None), + node(30, B, None, Some(0), Some(6)), + node(25, B, Some(0), None, None), + node(35, B, Some(4), Some(7), Some(8)), + node(33, B, Some(6), None, None), + node(40, B, Some(6), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 6 with non-null new_child dir_l. + // B(10) root, B(5) left, B(20) right with R(15)/R(25). + // Remove B(5): case 6 rotates left; new_child R(15) is + // reparented from B(20).child[L] to B(10).child[R]. Self::Case6NewChildL => { let desc = TreeSpec { root: Some(0), @@ -1122,7 +1138,7 @@ impl TestCase for RemoveCase { node(10, B, None, Some(1), Some(2)), node(5, B, Some(0), None, None), node(20, B, Some(0), Some(3), Some(4)), - node(15, B, Some(2), None, None), + node(15, R, Some(2), None, None), node(25, R, Some(2), None, None), ], }; @@ -1133,14 +1149,17 @@ impl TestCase for RemoveCase { node(10, B, Some(2), None, Some(3)), node(5, B, None, None, None), node(20, B, None, Some(0), Some(4)), - node(15, B, Some(0), None, None), + node(15, R, Some(0), None, None), node(25, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 6 with non-null new_child dir_r. + // B(10) root, B(5) left with R(3)/R(7), B(20) right. + // Remove B(20): case 6 rotates right; new_child R(7) is + // reparented from B(5).child[R] to B(10).child[L]. Self::Case6NewChildR => { let desc = TreeSpec { root: Some(0), @@ -1150,7 +1169,7 @@ impl TestCase for RemoveCase { node(5, B, Some(0), Some(3), Some(4)), node(20, B, Some(0), None, None), node(3, R, Some(1), None, None), - node(7, B, Some(1), None, None), + node(7, R, Some(1), None, None), ], }; let exp = TreeSpec { @@ -1161,10 +1180,10 @@ impl TestCase for RemoveCase { node(5, B, None, Some(3), Some(0)), node(20, B, None, None, None), node(3, B, Some(1), None, None), - node(7, B, Some(0), None, None), + node(7, R, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 6 parent=root dir_l (same tree as Case6L). @@ -1189,7 +1208,7 @@ impl TestCase for RemoveCase { node(20, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 6 parent=root dir_r. @@ -1214,10 +1233,14 @@ impl TestCase for RemoveCase { node(3, B, Some(1), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } // Case 6 parent=GGP left child dir_l. + // 8-node tree, bh=3 at root. N1(B(10)) is left child of + // root B(30). Remove B(5) from N1's left: case 6 rotates + // N1 left, N3(B(20)) takes N1's place. GGP N0 updates + // child[L] = N3. Self::Case6ParentGgpL => { let desc = TreeSpec { root: Some(0), @@ -1228,7 +1251,9 @@ impl TestCase for RemoveCase { node(5, B, Some(1), None, None), node(20, B, Some(1), None, Some(4)), node(25, R, Some(3), None, None), - node(35, B, Some(0), None, None), + node(40, B, Some(0), Some(6), Some(7)), + node(35, B, Some(5), None, None), + node(45, B, Some(5), None, None), ], }; let exp = TreeSpec { @@ -1240,39 +1265,49 @@ impl TestCase for RemoveCase { node(5, B, None, None, None), node(20, B, Some(0), Some(1), Some(4)), node(25, B, Some(3), None, None), - node(35, B, Some(0), None, None), + node(40, B, Some(0), Some(6), Some(7)), + node(35, B, Some(5), None, None), + node(45, B, Some(5), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 6 parent=GGP right child dir_r. + // 8-node tree, bh=3 at root. N1(B(20)) is right child of + // root B(5). Remove B(25) from N1's right: case 6 rotates + // N1 right, N2(B(10)) takes N1's place. GGP N0 updates + // child[R] = N2. Self::Case6ParentGgpR => { let desc = TreeSpec { root: Some(0), top: None, nodes: &[ - node(5, B, None, Some(4), Some(1)), + node(5, B, None, Some(5), Some(1)), node(20, B, Some(0), Some(2), Some(3)), - node(10, B, Some(1), Some(5), None), + node(10, B, Some(1), Some(4), None), node(25, B, Some(1), None, None), - node(3, B, Some(0), None, None), node(7, R, Some(2), None, None), + node(2, B, Some(0), Some(6), Some(7)), + node(1, B, Some(5), None, None), + node(3, B, Some(5), None, None), ], }; let exp = TreeSpec { root: Some(0), top: Some(3), nodes: &[ - node(5, B, None, Some(4), Some(2)), + node(5, B, None, Some(5), Some(2)), node(20, B, Some(2), None, None), - node(10, B, Some(0), Some(5), Some(1)), + node(10, B, Some(0), Some(4), Some(1)), node(25, B, None, None, None), - node(3, B, Some(0), None, None), node(7, B, Some(2), None, None), + node(2, B, Some(0), Some(6), Some(7)), + node(1, B, Some(5), None, None), + node(3, B, Some(5), None, None), ], }; - run_remove_success(lang, &desc, 25, 25, &exp) + run_remove_success(lang, &desc, 25, &exp) } // Case 3 parent=root dir_l. @@ -1299,7 +1334,7 @@ impl TestCase for RemoveCase { node(25, B, Some(2), None, None), ], }; - run_remove_success(lang, &desc, 5, 5, &exp) + run_remove_success(lang, &desc, 5, &exp) } // Case 3 parent=root dir_r. @@ -1326,7 +1361,7 @@ impl TestCase for RemoveCase { node(7, R, Some(0), None, None), ], }; - run_remove_success(lang, &desc, 20, 20, &exp) + run_remove_success(lang, &desc, 20, &exp) } } } @@ -1398,7 +1433,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 5, expected_value: 1 }, + step: MultiStep::Remove { key: 5 }, expected: TreeSpec { root: Some(0), top: Some(1), @@ -1507,7 +1542,7 @@ impl TestCase for MultiRemoveCase { // Remove all: 3, 20, 7, 12, 5, 15, 10. // Removing leaves first to simplify expected states. MultiStepCase { - step: MultiStep::Remove { key: 3, expected_value: 1 }, + step: MultiStep::Remove { key: 3 }, expected: TreeSpec { root: Some(0), top: Some(3), @@ -1523,7 +1558,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 20, expected_value: 1 }, + step: MultiStep::Remove { key: 20 }, expected: TreeSpec { root: Some(0), top: Some(6), @@ -1531,7 +1566,7 @@ impl TestCase for MultiRemoveCase { node(10, R, None, Some(1), Some(2)).val(1), node(5, B, Some(0), None, Some(4)).val(1), node(15, B, Some(0), Some(5), None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(1), None, None).val(1), node(12, R, Some(2), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1539,7 +1574,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 7, expected_value: 1 }, + step: MultiStep::Remove { key: 7 }, expected: TreeSpec { root: Some(0), top: Some(4), @@ -1547,7 +1582,7 @@ impl TestCase for MultiRemoveCase { node(10, R, None, Some(1), Some(2)).val(1), node(5, B, Some(0), None, None).val(1), node(15, B, Some(0), Some(5), None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(6), None, None).val(1), node(12, R, Some(2), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1555,7 +1590,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 12, expected_value: 1 }, + step: MultiStep::Remove { key: 12 }, expected: TreeSpec { root: Some(0), top: Some(5), @@ -1563,7 +1598,7 @@ impl TestCase for MultiRemoveCase { node(10, R, None, Some(1), Some(2)).val(1), node(5, B, Some(0), None, None).val(1), node(15, B, Some(0), None, None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(6), None, None).val(1), node(12, R, Some(4), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1571,7 +1606,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 5, expected_value: 1 }, + step: MultiStep::Remove { key: 5 }, expected: TreeSpec { root: Some(0), top: Some(1), @@ -1579,7 +1614,7 @@ impl TestCase for MultiRemoveCase { node(10, B, None, None, Some(2)).val(1), node(5, B, Some(5), None, None).val(1), node(15, R, Some(0), None, None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(6), None, None).val(1), node(12, R, Some(4), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1587,7 +1622,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 15, expected_value: 1 }, + step: MultiStep::Remove { key: 15 }, expected: TreeSpec { root: Some(0), top: Some(2), @@ -1595,7 +1630,7 @@ impl TestCase for MultiRemoveCase { node(10, B, None, None, None).val(1), node(5, B, Some(5), None, None).val(1), node(15, R, Some(1), None, None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(6), None, None).val(1), node(12, R, Some(4), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1603,7 +1638,7 @@ impl TestCase for MultiRemoveCase { }, }, MultiStepCase { - step: MultiStep::Remove { key: 10, expected_value: 1 }, + step: MultiStep::Remove { key: 10 }, expected: TreeSpec { root: None, top: Some(0), @@ -1611,7 +1646,7 @@ impl TestCase for MultiRemoveCase { node(10, B, Some(2), None, None).val(1), node(5, B, Some(5), None, None).val(1), node(15, R, Some(1), None, None).val(1), - node(3, R, Some(6), None, None).val(1), + node(3, R, None, None, None).val(1), node(7, R, Some(6), None, None).val(1), node(12, R, Some(4), None, None).val(1), node(20, R, Some(3), None, None).val(1), @@ -1655,7 +1690,7 @@ impl TestCase for MultiRemoveCase { }, // Remove 5: red leaf removal, N1 freed onto stack. MultiStepCase { - step: MultiStep::Remove { key: 5, expected_value: 5 }, + step: MultiStep::Remove { key: 5 }, expected: TreeSpec { root: Some(0), top: Some(1), From 109e52dcbdf49f3c8260afddbff59635e4311bf5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:52:40 -0700 Subject: [PATCH 230/263] Remove status return parts --- examples/tree/interface/src/common.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 655616da..de8333d6 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -273,13 +273,6 @@ pub struct RemoveInstruction { pub key: u16, } -#[repr(C, packed)] -/// Value in r0. -pub struct RemoveReturn { - status: u16, - value: u16, -} - constant_group! { /// Offsets for instruction processing. instruction { @@ -298,8 +291,6 @@ constant_group! { offset!(INSERT_VALUE, InsertInstruction.value), /// Key field in remove instruction. offset!(REMOVE_KEY, RemoveInstruction.key), - /// Status value for successful remove (first non-error code). - REMOVE_STATUS_OK: u16 = error::N_CODES as u16, } } From f98b2677f494d5674c78fdabb40618edb0654241 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:07:51 -0700 Subject: [PATCH 231/263] Add more insert testing tweaks --- docs/src/examples/tree.md | 2 +- examples/tree/artifacts/dumps/asm.txt | 723 +++++++++--------- examples/tree/artifacts/dumps/rs.txt | 395 +++++----- examples/tree/artifacts/rs-disassembly.s | 175 +++-- .../tree/artifacts/snippets/asm/constants.txt | 2 - .../artifacts/snippets/asm/insert-search.txt | 2 +- .../snippets/interface/instructions.txt | 9 - .../artifacts/snippets/rs/insert-search.txt | 4 +- .../artifacts/snippets/rs/remove-search.txt | 24 + .../tests/entrypoint_branching/result.txt | 6 +- .../initialize_create_account/result.txt | 18 +- .../tests/initialize_input_checks/result.txt | 102 +-- .../tests/initialize_pda_checks/result.txt | 24 +- .../artifacts/tests/insert_search/result.txt | 12 +- .../artifacts/tests/insert_to_tree/result.txt | 116 ++- .../artifacts/tests/multi_insert/result.txt | 38 +- .../tests/remove_input_checks/result.txt | 38 + .../tests/remove_input_checks/test.txt | 4 + .../artifacts/tests/remove_search/result.txt | 31 + .../artifacts/tests/remove_search/test.txt | 4 + examples/tree/specs/insert-tests.md | 42 +- examples/tree/src/program.rs | 34 +- examples/tree/src/tests.rs | 38 +- examples/tree/src/tree/tree.s | 4 +- 24 files changed, 987 insertions(+), 860 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/remove-search.txt create mode 100644 examples/tree/artifacts/tests/remove_input_checks/result.txt create mode 100644 examples/tree/artifacts/tests/remove_input_checks/test.txt create mode 100644 examples/tree/artifacts/tests/remove_search/result.txt create mode 100644 examples/tree/artifacts/tests/remove_search/test.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 8c5f2a72..0aa59640 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -272,7 +272,7 @@ not available in Rust, since the compiler enforces ::: details Benchmarking - + diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 2cfedfb2..5b9491b6 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3480 (bytes into file) + Start of section headers 3552 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xd98 +There are 7 section headers, starting at offset 0xde0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000b10 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000bf8 000bf8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000c98 000c98 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000cf8 000cf8 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000d38 000d38 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000d68 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000b58 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000c40 000c40 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000ce0 000ce0 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000d40 000d40 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000d80 000d80 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000db0 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000b10 0x000b10 R E 0x1000 - LOAD 0x000c98 0x0000000000000c98 0x0000000000000c98 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000bf8 0x0000000000000bf8 0x0000000000000bf8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000b58 0x000b58 R E 0x1000 + LOAD 0x000ce0 0x0000000000000ce0 0x0000000000000ce0 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000c40 0x0000000000000c40 0x0000000000000c40 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,24 +52,24 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xbf8 contains 10 entries +Dynamic section at offset 0xc40 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xd38 + 0x0000000000000011 (REL) 0xd80 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xc98 + 0x0000000000000006 (SYMTAB) 0xce0 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xcf8 + 0x0000000000000005 (STRTAB) 0xd40 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xd38 contains 3 entries +Relocation section '.rel.dyn' at offset 0xd80 contains 3 entries Offset Info Type Symbol's Value Symbol's Name -0000000000000240 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address -0000000000000460 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c -0000000000000700 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000248 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address +0000000000000468 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c +0000000000000708 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c Symbol table '.dynsym' contains 4 entries Num Value Size Type Bind Vis Ndx Name @@ -87,348 +87,357 @@ Disassembly of section .text 29 79 29 f8 ff 00 00 00 00 r9 = *(u64 *)(r2 - 0x8) 30 79 18 00 00 00 00 00 00 r8 = *(u64 *)(r1 + 0x0) 31 71 27 00 00 00 00 00 00 r7 = *(u8 *)(r2 + 0x0) - 32 15 07 70 00 01 00 00 00 if r7 == 0x1 goto +0x70 - 33 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 34 b7 00 00 00 0b 00 00 00 r0 = 0xb - 35 95 00 00 00 00 00 00 00 exit - 36 55 09 44 01 01 00 00 00 if r9 != 0x1 goto +0x144 - 37 55 08 45 01 04 00 00 00 if r8 != 0x4 goto +0x145 - 38 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 39 55 09 55 01 00 00 00 00 if r9 != 0x0 goto +0x155 - 40 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 41 55 09 51 01 ff 00 00 00 if r9 != 0xff goto +0x151 - 42 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 43 55 09 4d 01 00 00 00 00 if r9 != 0x0 goto +0x14d - 44 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 45 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 - 46 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 47 55 09 45 01 0e 00 00 00 if r9 != 0xe goto +0x145 - 48 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 49 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 - 50 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) - 51 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 53 5d 89 3b 01 00 00 00 00 if r9 != r8 goto +0x13b - 54 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) - 55 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 57 5d 89 37 01 00 00 00 00 if r9 != r8 goto +0x137 - 58 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) - 59 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 61 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 - 62 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) - 63 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 64 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 - 65 b7 02 00 00 00 00 00 00 r2 = 0x0 - 66 bf 13 00 00 00 00 00 00 r3 = r1 - 67 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 - 68 bf a4 00 00 00 00 00 00 r4 = r10 - 69 07 04 00 00 b0 ff ff ff r4 += -0x50 - 70 bf a5 00 00 00 00 00 00 r5 = r10 - 71 07 05 00 00 a0 fe ff ff r5 += -0x160 - 72 85 10 00 00 ff ff ff ff call -0x1 - 73 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) - 74 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 75 5d 89 23 01 00 00 00 00 if r9 != r8 goto +0x123 - 76 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) - 77 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 78 5d 89 20 01 00 00 00 00 if r9 != r8 goto +0x120 - 79 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) - 80 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 81 5d 89 1d 01 00 00 00 00 if r9 != r8 goto +0x11d - 82 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) - 83 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 84 5d 89 1a 01 00 00 00 00 if r9 != r8 goto +0x11a - 85 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 - 86 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 - 87 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) - 88 27 09 00 00 98 00 00 00 r9 *= 0x98 - 89 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 - 90 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 - 91 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) - 92 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 - 93 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) - 94 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 - 95 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) - 96 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 - 97 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) - 98 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 - 99 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 - 100 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 - 101 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 - 102 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 - 103 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 - 104 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 - 105 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 - 106 07 01 00 00 10 00 00 00 r1 += 0x10 - 107 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 - 108 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 - 109 07 01 00 00 20 00 00 00 r1 += 0x20 - 110 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 - 111 07 01 00 00 20 00 00 00 r1 += 0x20 - 112 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 - 113 07 01 00 00 10 00 00 00 r1 += 0x10 - 114 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 115 07 01 00 00 10 28 00 00 r1 += 0x2810 - 116 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 - 117 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 - 118 07 01 00 00 20 00 00 00 r1 += 0x20 - 119 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 - 120 07 01 00 00 20 00 00 00 r1 += 0x20 - 121 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 - 122 07 01 00 00 10 00 00 00 r1 += 0x10 - 123 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 124 bf 16 00 00 00 00 00 00 r6 = r1 - 125 07 04 00 00 30 00 00 00 r4 += 0x30 - 126 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 127 07 04 00 00 20 ff ff ff r4 += -0xe0 - 128 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 129 07 04 00 00 a1 ff ff ff r4 += -0x5f - 130 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 131 07 04 00 00 ff 00 00 00 r4 += 0xff - 132 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 - 133 07 04 00 00 f0 ff ff ff r4 += -0x10 - 134 bf a1 00 00 00 00 00 00 r1 = r10 - 135 07 01 00 00 d8 fe ff ff r1 += -0x128 - 136 bf a2 00 00 00 00 00 00 r2 = r10 - 137 07 02 00 00 20 ff ff ff r2 += -0xe0 - 138 b7 03 00 00 02 00 00 00 r3 = 0x2 - 139 b7 05 00 00 01 00 00 00 r5 = 0x1 - 140 85 10 00 00 ff ff ff ff call -0x1 - 141 bf 67 00 00 00 00 00 00 r7 = r6 - 142 07 07 00 00 18 00 00 00 r7 += 0x18 - 143 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 - 144 95 00 00 00 00 00 00 00 exit - 145 55 09 d7 00 05 00 00 00 if r9 != 0x5 goto +0xd7 - 146 a5 08 d8 00 02 00 00 00 if r8 < 0x2 goto +0xd8 - 147 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 148 55 09 e8 00 00 00 00 00 if r9 != 0x0 goto +0xe8 - 149 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 150 55 09 e4 00 ff 00 00 00 if r9 != 0xff goto +0xe4 - 151 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) - 152 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 153 55 08 d3 00 04 00 00 00 if r8 != 0x4 goto +0xd3 - 154 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 155 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 - 156 bf 97 00 00 00 00 00 00 r7 = r9 - 157 07 09 00 00 07 00 00 00 r9 += 0x7 - 158 57 09 00 00 f8 ff ff ff r9 &= -0x8 - 159 0f 19 00 00 00 00 00 00 r9 += r1 - 160 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 161 55 08 d5 00 ff 00 00 00 if r8 != 0xff goto +0xd5 - 162 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 163 55 08 d1 00 0e 00 00 00 if r8 != 0xe goto +0xd1 - 164 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 165 55 08 cd 00 ff 00 00 00 if r8 != 0xff goto +0xcd - 166 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) - 167 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 169 5d 48 c7 00 00 00 00 00 if r8 != r4 goto +0xc7 - 170 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) - 171 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 173 5d 48 c3 00 00 00 00 00 if r8 != r4 goto +0xc3 - 174 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) - 175 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 177 5d 48 bf 00 00 00 00 00 if r8 != r4 goto +0xbf - 178 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) - 179 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 180 5d 48 bc 00 00 00 00 00 if r8 != r4 goto +0xbc - 181 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) - 182 27 08 00 00 1d 00 00 00 r8 *= 0x1d - 183 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 - 184 7b 8a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r8 - 185 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 - 186 7a 0a f8 fe 0c 00 00 00 *(u64 *)(r10 - 0x108) = 0xc - 187 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 - 188 72 0a 18 ff 01 00 00 00 *(u8 *)(r10 - 0xe8) = 0x1 - 189 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 - 190 72 0a 89 ff 01 00 00 00 *(u8 *)(r10 - 0x77) = 0x1 - 191 bf 16 00 00 00 00 00 00 r6 = r1 - 192 07 01 00 00 10 00 00 00 r1 += 0x10 - 193 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 - 194 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 - 195 07 01 00 00 20 00 00 00 r1 += 0x20 - 196 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 - 197 07 01 00 00 20 00 00 00 r1 += 0x20 - 198 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 - 199 07 01 00 00 10 00 00 00 r1 += 0x10 - 200 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 - 201 07 01 00 00 10 28 00 00 r1 += 0x2810 - 202 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 - 203 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 - 204 07 01 00 00 20 00 00 00 r1 += 0x20 - 205 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 - 206 07 01 00 00 20 00 00 00 r1 += 0x20 - 207 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 - 208 07 01 00 00 10 00 00 00 r1 += 0x10 - 209 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 - 210 bf a4 00 00 00 00 00 00 r4 = r10 - 211 07 04 00 00 e0 ff ff ff r4 += -0x20 - 212 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 - 213 07 04 00 00 20 ff ff ff r4 += -0xe0 - 214 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 - 215 07 04 00 00 a1 ff ff ff r4 += -0x5f - 216 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 - 217 bf a1 00 00 00 00 00 00 r1 = r10 - 218 07 01 00 00 d8 fe ff ff r1 += -0x128 - 219 bf 28 00 00 00 00 00 00 r8 = r2 - 220 bf a2 00 00 00 00 00 00 r2 = r10 - 221 07 02 00 00 20 ff ff ff r2 += -0xe0 - 222 b7 03 00 00 02 00 00 00 r3 = 0x2 - 223 b7 05 00 00 00 00 00 00 r5 = 0x0 - 224 85 10 00 00 ff ff ff ff call -0x1 - 225 bf 82 00 00 00 00 00 00 r2 = r8 - 226 bf 61 00 00 00 00 00 00 r1 = r6 - 227 07 07 00 00 1d 00 00 00 r7 += 0x1d - 228 7b 71 b8 28 00 00 00 00 *(u64 *)(r1 + 0x28b8) = r7 - 229 79 17 d0 28 00 00 00 00 r7 = *(u64 *)(r1 + 0x28d0) - 230 bf 79 00 00 00 00 00 00 r9 = r7 - 231 07 07 00 00 1d 00 00 00 r7 += 0x1d - 232 7b 71 d0 28 00 00 00 00 *(u64 *)(r1 + 0x28d0) = r7 - 233 05 00 02 00 00 00 00 00 goto +0x2 - 234 79 98 00 00 00 00 00 00 r8 = *(u64 *)(r9 + 0x0) - 235 7b 81 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r8 - 236 61 24 01 00 00 00 00 00 r4 = *(u32 *)(r2 + 0x1) - 237 63 49 18 00 00 00 00 00 *(u32 *)(r9 + 0x18) = r4 - 238 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) - 239 b7 02 00 00 00 00 00 00 r2 = 0x0 + 32 15 07 71 00 01 00 00 00 if r7 == 0x1 goto +0x71 + 33 15 07 46 01 02 00 00 00 if r7 == 0x2 goto +0x146 + 34 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 35 b7 00 00 00 0b 00 00 00 r0 = 0xb + 36 95 00 00 00 00 00 00 00 exit + 37 55 09 4c 01 01 00 00 00 if r9 != 0x1 goto +0x14c + 38 55 08 4d 01 04 00 00 00 if r8 != 0x4 goto +0x14d + 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 40 55 09 5d 01 00 00 00 00 if r9 != 0x0 goto +0x15d + 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 42 55 09 59 01 ff 00 00 00 if r9 != 0xff goto +0x159 + 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 44 55 09 55 01 00 00 00 00 if r9 != 0x0 goto +0x155 + 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) + 46 55 09 51 01 ff 00 00 00 if r9 != 0xff goto +0x151 + 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) + 48 55 09 4d 01 0e 00 00 00 if r9 != 0xe goto +0x14d + 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) + 50 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 + 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) + 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll + 54 5d 89 43 01 00 00 00 00 if r9 != r8 goto +0x143 + 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) + 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll + 58 5d 89 3f 01 00 00 00 00 if r9 != r8 goto +0x13f + 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) + 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll + 62 5d 89 3b 01 00 00 00 00 if r9 != r8 goto +0x13b + 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) + 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d + 65 5d 89 38 01 00 00 00 00 if r9 != r8 goto +0x138 + 66 b7 02 00 00 00 00 00 00 r2 = 0x0 + 67 bf 13 00 00 00 00 00 00 r3 = r1 + 68 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 + 69 bf a4 00 00 00 00 00 00 r4 = r10 + 70 07 04 00 00 b0 ff ff ff r4 += -0x50 + 71 bf a5 00 00 00 00 00 00 r5 = r10 + 72 07 05 00 00 a0 fe ff ff r5 += -0x160 + 73 85 10 00 00 ff ff ff ff call -0x1 + 74 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) + 75 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) + 76 5d 89 2b 01 00 00 00 00 if r9 != r8 goto +0x12b + 77 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) + 78 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) + 79 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 + 80 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) + 81 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 82 5d 89 25 01 00 00 00 00 if r9 != r8 goto +0x125 + 83 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) + 84 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) + 85 5d 89 22 01 00 00 00 00 if r9 != r8 goto +0x122 + 86 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 87 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 + 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) + 89 27 09 00 00 98 00 00 00 r9 *= 0x98 + 90 7b 9a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r9 + 91 7a 0a ad fe 18 00 00 00 *(u64 *)(r10 - 0x153) = 0x18 + 92 79 39 00 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x0) + 93 7b 9a b5 fe 00 00 00 00 *(u64 *)(r10 - 0x14b) = r9 + 94 79 39 08 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x8) + 95 7b 9a bd fe 00 00 00 00 *(u64 *)(r10 - 0x143) = r9 + 96 79 39 10 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x10) + 97 7b 9a c5 fe 00 00 00 00 *(u64 *)(r10 - 0x13b) = r9 + 98 79 39 18 00 00 00 00 00 r9 = *(u64 *)(r3 + 0x18) + 99 7b 9a cd fe 00 00 00 00 *(u64 *)(r10 - 0x133) = r9 + 100 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 101 6a 0a 18 ff 01 01 00 00 *(u16 *)(r10 - 0xe8) = 0x101 + 102 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 103 6a 0a 88 ff 01 01 00 00 *(u16 *)(r10 - 0x78) = 0x101 + 104 7b 5a a0 ff 00 00 00 00 *(u64 *)(r10 - 0x60) = r5 + 105 7a 0a a8 ff 01 00 00 00 *(u64 *)(r10 - 0x58) = 0x1 + 106 7a 0a 98 ff 01 00 00 00 *(u64 *)(r10 - 0x68) = 0x1 + 107 07 01 00 00 10 00 00 00 r1 += 0x10 + 108 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 109 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 110 07 01 00 00 20 00 00 00 r1 += 0x20 + 111 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 112 07 01 00 00 20 00 00 00 r1 += 0x20 + 113 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 114 07 01 00 00 10 00 00 00 r1 += 0x10 + 115 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 116 07 01 00 00 10 28 00 00 r1 += 0x2810 + 117 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 118 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 + 119 07 01 00 00 20 00 00 00 r1 += 0x20 + 120 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 121 07 01 00 00 20 00 00 00 r1 += 0x20 + 122 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 123 07 01 00 00 10 00 00 00 r1 += 0x10 + 124 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 125 bf 16 00 00 00 00 00 00 r6 = r1 + 126 07 04 00 00 30 00 00 00 r4 += 0x30 + 127 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 128 07 04 00 00 20 ff ff ff r4 += -0xe0 + 129 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 130 07 04 00 00 a1 ff ff ff r4 += -0x5f + 131 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 132 07 04 00 00 ff 00 00 00 r4 += 0xff + 133 7b 4a 90 ff 00 00 00 00 *(u64 *)(r10 - 0x70) = r4 + 134 07 04 00 00 f0 ff ff ff r4 += -0x10 + 135 bf a1 00 00 00 00 00 00 r1 = r10 + 136 07 01 00 00 d8 fe ff ff r1 += -0x128 + 137 bf a2 00 00 00 00 00 00 r2 = r10 + 138 07 02 00 00 20 ff ff ff r2 += -0xe0 + 139 b7 03 00 00 02 00 00 00 r3 = 0x2 + 140 b7 05 00 00 01 00 00 00 r5 = 0x1 + 141 85 10 00 00 ff ff ff ff call -0x1 + 142 bf 67 00 00 00 00 00 00 r7 = r6 + 143 07 07 00 00 18 00 00 00 r7 += 0x18 + 144 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 + 145 95 00 00 00 00 00 00 00 exit + 146 55 09 df 00 05 00 00 00 if r9 != 0x5 goto +0xdf + 147 a5 08 e0 00 02 00 00 00 if r8 < 0x2 goto +0xe0 + 148 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 149 55 09 f0 00 00 00 00 00 if r9 != 0x0 goto +0xf0 + 150 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 151 55 09 ec 00 ff 00 00 00 if r9 != 0xff goto +0xec + 152 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) + 153 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 + 154 55 08 db 00 04 00 00 00 if r8 != 0x4 goto +0xdb + 155 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) + 156 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 + 157 bf 97 00 00 00 00 00 00 r7 = r9 + 158 07 09 00 00 07 00 00 00 r9 += 0x7 + 159 57 09 00 00 f8 ff ff ff r9 &= -0x8 + 160 0f 19 00 00 00 00 00 00 r9 += r1 + 161 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) + 162 55 08 dd 00 ff 00 00 00 if r8 != 0xff goto +0xdd + 163 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) + 164 55 08 d9 00 0e 00 00 00 if r8 != 0xe goto +0xd9 + 165 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) + 166 55 08 d5 00 ff 00 00 00 if r8 != 0xff goto +0xd5 + 167 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) + 168 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll + 170 5d 48 cf 00 00 00 00 00 if r8 != r4 goto +0xcf + 171 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) + 172 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll + 174 5d 48 cb 00 00 00 00 00 if r8 != r4 goto +0xcb + 175 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) + 176 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll + 178 5d 48 c7 00 00 00 00 00 if r8 != r4 goto +0xc7 + 179 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) + 180 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d + 181 5d 48 c4 00 00 00 00 00 if r8 != r4 goto +0xc4 + 182 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) + 183 27 08 00 00 1d 00 00 00 r8 *= 0x1d + 184 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 + 185 7b 8a a5 fe 00 00 00 00 *(u64 *)(r10 - 0x15b) = r8 + 186 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 + 187 7a 0a f8 fe 0c 00 00 00 *(u64 *)(r10 - 0x108) = 0xc + 188 6a 0a 08 ff 01 01 00 00 *(u16 *)(r10 - 0xf8) = 0x101 + 189 72 0a 18 ff 01 00 00 00 *(u8 *)(r10 - 0xe8) = 0x1 + 190 6a 0a 50 ff 01 01 00 00 *(u16 *)(r10 - 0xb0) = 0x101 + 191 72 0a 89 ff 01 00 00 00 *(u8 *)(r10 - 0x77) = 0x1 + 192 bf 16 00 00 00 00 00 00 r6 = r1 + 193 07 01 00 00 10 00 00 00 r1 += 0x10 + 194 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 0x100) = r1 + 195 7b 1a 20 ff 00 00 00 00 *(u64 *)(r10 - 0xe0) = r1 + 196 07 01 00 00 20 00 00 00 r1 += 0x20 + 197 7b 1a 40 ff 00 00 00 00 *(u64 *)(r10 - 0xc0) = r1 + 198 07 01 00 00 20 00 00 00 r1 += 0x20 + 199 7b 1a 28 ff 00 00 00 00 *(u64 *)(r10 - 0xd8) = r1 + 200 07 01 00 00 10 00 00 00 r1 += 0x10 + 201 7b 1a 38 ff 00 00 00 00 *(u64 *)(r10 - 0xc8) = r1 + 202 07 01 00 00 10 28 00 00 r1 += 0x2810 + 203 7b 1a 10 ff 00 00 00 00 *(u64 *)(r10 - 0xf0) = r1 + 204 7b 1a 58 ff 00 00 00 00 *(u64 *)(r10 - 0xa8) = r1 + 205 07 01 00 00 20 00 00 00 r1 += 0x20 + 206 7b 1a 78 ff 00 00 00 00 *(u64 *)(r10 - 0x88) = r1 + 207 07 01 00 00 20 00 00 00 r1 += 0x20 + 208 7b 1a 60 ff 00 00 00 00 *(u64 *)(r10 - 0xa0) = r1 + 209 07 01 00 00 10 00 00 00 r1 += 0x10 + 210 7b 1a 70 ff 00 00 00 00 *(u64 *)(r10 - 0x90) = r1 + 211 bf a4 00 00 00 00 00 00 r4 = r10 + 212 07 04 00 00 e0 ff ff ff r4 += -0x20 + 213 7b 4a d8 fe 00 00 00 00 *(u64 *)(r10 - 0x128) = r4 + 214 07 04 00 00 20 ff ff ff r4 += -0xe0 + 215 7b 4a e0 fe 00 00 00 00 *(u64 *)(r10 - 0x120) = r4 + 216 07 04 00 00 a1 ff ff ff r4 += -0x5f + 217 7b 4a f0 fe 00 00 00 00 *(u64 *)(r10 - 0x110) = r4 + 218 bf a1 00 00 00 00 00 00 r1 = r10 + 219 07 01 00 00 d8 fe ff ff r1 += -0x128 + 220 bf 28 00 00 00 00 00 00 r8 = r2 + 221 bf a2 00 00 00 00 00 00 r2 = r10 + 222 07 02 00 00 20 ff ff ff r2 += -0xe0 + 223 b7 03 00 00 02 00 00 00 r3 = 0x2 + 224 b7 05 00 00 00 00 00 00 r5 = 0x0 + 225 85 10 00 00 ff ff ff ff call -0x1 + 226 bf 82 00 00 00 00 00 00 r2 = r8 + 227 bf 61 00 00 00 00 00 00 r1 = r6 + 228 07 07 00 00 1d 00 00 00 r7 += 0x1d + 229 7b 71 b8 28 00 00 00 00 *(u64 *)(r1 + 0x28b8) = r7 + 230 79 17 d0 28 00 00 00 00 r7 = *(u64 *)(r1 + 0x28d0) + 231 bf 79 00 00 00 00 00 00 r9 = r7 + 232 07 07 00 00 1d 00 00 00 r7 += 0x1d + 233 7b 71 d0 28 00 00 00 00 *(u64 *)(r1 + 0x28d0) = r7 + 234 05 00 02 00 00 00 00 00 goto +0x2 + 235 79 98 00 00 00 00 00 00 r8 = *(u64 *)(r9 + 0x0) + 236 7b 81 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r8 + 237 61 24 01 00 00 00 00 00 r4 = *(u32 *)(r2 + 0x1) + 238 63 49 18 00 00 00 00 00 *(u32 *)(r9 + 0x18) = r4 + 239 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) 240 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) 241 15 03 06 00 00 00 00 00 if r3 == 0x0 goto +0x6 242 bf 32 00 00 00 00 00 00 r2 = r3 243 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) - 244 ad 54 07 00 00 00 00 00 if r4 < r5 goto +0x7 - 245 2d 54 0e 00 00 00 00 00 if r4 > r5 goto +0xe + 244 ad 54 08 00 00 00 00 00 if r4 < r5 goto +0x8 + 245 2d 54 0f 00 00 00 00 00 if r4 > r5 goto +0xf 246 b7 00 00 00 0e 00 00 00 r0 = 0xe 247 95 00 00 00 00 00 00 00 exit 248 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 - 249 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 - 250 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 - 251 95 00 00 00 00 00 00 00 exit - 252 79 23 08 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x8) - 253 55 03 f4 ff 00 00 00 00 if r3 != 0x0 goto -0xc - 254 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 - 255 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 - 256 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 - 257 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) - 258 55 06 09 00 00 00 00 00 if r6 != 0x0 goto +0x9 - 259 95 00 00 00 00 00 00 00 exit - 260 79 23 10 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x10) - 261 55 03 ec ff 00 00 00 00 if r3 != 0x0 goto -0x14 - 262 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 - 263 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 - 264 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 - 265 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) - 266 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 - 267 95 00 00 00 00 00 00 00 exit - 268 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) - 269 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 - 270 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 271 95 00 00 00 00 00 00 00 exit - 272 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) - 273 2d 45 27 00 00 00 00 00 if r5 > r4 goto +0x27 - 274 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) - 275 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 276 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 277 55 08 4a 00 00 00 00 00 if r8 != 0x0 goto +0x4a - 278 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) - 279 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 280 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) - 281 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 - 282 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 283 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 284 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 - 285 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 286 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 287 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 - 288 bf 29 00 00 00 00 00 00 r9 = r2 - 289 bf 62 00 00 00 00 00 00 r2 = r6 - 290 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 291 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) - 292 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 - 293 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 294 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 295 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 - 296 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 297 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 298 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa - 299 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 300 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 - 301 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 302 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 303 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 304 95 00 00 00 00 00 00 00 exit - 305 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 306 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 307 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 308 95 00 00 00 00 00 00 00 exit - 309 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 310 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 311 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 312 95 00 00 00 00 00 00 00 exit - 313 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) - 314 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 - 315 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) - 316 55 08 23 00 00 00 00 00 if r8 != 0x0 goto +0x23 - 317 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) - 318 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa - 319 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) - 320 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 - 321 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 322 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 - 323 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 - 324 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 - 325 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 - 326 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 - 327 bf 29 00 00 00 00 00 00 r9 = r2 - 328 bf 62 00 00 00 00 00 00 r2 = r6 - 329 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) - 330 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) - 331 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 - 332 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 - 333 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 - 334 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 - 335 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 - 336 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 - 337 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa - 338 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 339 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 - 340 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 - 341 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 342 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 343 95 00 00 00 00 00 00 00 exit - 344 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 - 345 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 346 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 347 95 00 00 00 00 00 00 00 exit - 348 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 - 349 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 350 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 351 95 00 00 00 00 00 00 00 exit - 352 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 - 353 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 - 354 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 - 355 bf 39 00 00 00 00 00 00 r9 = r3 - 356 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) - 357 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d - 358 95 00 00 00 00 00 00 00 exit - 359 b7 00 00 00 09 00 00 00 r0 = 0x9 - 360 95 00 00 00 00 00 00 00 exit - 361 b7 00 00 00 0c 00 00 00 r0 = 0xc - 362 95 00 00 00 00 00 00 00 exit - 363 b7 00 00 00 01 00 00 00 r0 = 0x1 - 364 95 00 00 00 00 00 00 00 exit - 365 b7 00 00 00 0d 00 00 00 r0 = 0xd - 366 95 00 00 00 00 00 00 00 exit - 367 b7 00 00 00 0a 00 00 00 r0 = 0xa - 368 95 00 00 00 00 00 00 00 exit - 369 b7 00 00 00 08 00 00 00 r0 = 0x8 - 370 95 00 00 00 00 00 00 00 exit - 371 b7 00 00 00 07 00 00 00 r0 = 0x7 - 372 95 00 00 00 00 00 00 00 exit - 373 b7 00 00 00 04 00 00 00 r0 = 0x4 - 374 95 00 00 00 00 00 00 00 exit - 375 b7 00 00 00 06 00 00 00 r0 = 0x6 - 376 95 00 00 00 00 00 00 00 exit - 377 b7 00 00 00 03 00 00 00 r0 = 0x3 - 378 95 00 00 00 00 00 00 00 exit - 379 b7 00 00 00 05 00 00 00 r0 = 0x5 - 380 95 00 00 00 00 00 00 00 exit - 381 b7 00 00 00 02 00 00 00 r0 = 0x2 - 382 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 249 b7 02 00 00 00 00 00 00 r2 = 0x0 + 250 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 251 7b 91 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r9 + 252 95 00 00 00 00 00 00 00 exit + 253 79 23 08 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x8) + 254 55 03 f3 ff 00 00 00 00 if r3 != 0x0 goto -0xd + 255 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 256 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 257 7b 92 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r9 + 258 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 259 55 06 09 00 00 00 00 00 if r6 != 0x0 goto +0x9 + 260 95 00 00 00 00 00 00 00 exit + 261 79 23 10 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x10) + 262 55 03 eb ff 00 00 00 00 if r3 != 0x0 goto -0x15 + 263 72 09 1c 00 01 00 00 00 *(u8 *)(r9 + 0x1c) = 0x1 + 264 7b 29 00 00 00 00 00 00 *(u64 *)(r9 + 0x0) = r2 + 265 7b 92 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r9 + 266 71 26 1c 00 00 00 00 00 r6 = *(u8 *)(r2 + 0x1c) + 267 55 06 01 00 00 00 00 00 if r6 != 0x0 goto +0x1 + 268 95 00 00 00 00 00 00 00 exit + 269 79 23 00 00 00 00 00 00 r3 = *(u64 *)(r2 + 0x0) + 270 55 03 02 00 00 00 00 00 if r3 != 0x0 goto +0x2 + 271 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 272 95 00 00 00 00 00 00 00 exit + 273 69 34 18 00 00 00 00 00 r4 = *(u16 *)(r3 + 0x18) + 274 2d 45 27 00 00 00 00 00 if r5 > r4 goto +0x27 + 275 79 37 10 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x10) + 276 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 277 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 278 55 08 4a 00 00 00 00 00 if r8 != 0x0 goto +0x4a + 279 79 26 10 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x10) + 280 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 281 79 68 08 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x8) + 282 7b 82 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r8 + 283 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 284 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 285 7b 26 08 00 00 00 00 00 *(u64 *)(r6 + 0x8) = r2 + 286 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 287 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 288 7b 63 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r6 + 289 bf 29 00 00 00 00 00 00 r9 = r2 + 290 bf 62 00 00 00 00 00 00 r2 = r6 + 291 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 292 79 28 10 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x10) + 293 7b 83 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = r8 + 294 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 295 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 296 7b 32 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = r3 + 297 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 298 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 299 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa + 300 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 301 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 + 302 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 303 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 304 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 305 95 00 00 00 00 00 00 00 exit + 306 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 307 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 308 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 309 95 00 00 00 00 00 00 00 exit + 310 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 311 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 312 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 313 95 00 00 00 00 00 00 00 exit + 314 79 37 08 00 00 00 00 00 r7 = *(u64 *)(r3 + 0x8) + 315 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 316 71 78 1c 00 00 00 00 00 r8 = *(u8 *)(r7 + 0x1c) + 317 55 08 23 00 00 00 00 00 if r8 != 0x0 goto +0x23 + 318 79 26 08 00 00 00 00 00 r6 = *(u64 *)(r2 + 0x8) + 319 5d 69 0a 00 00 00 00 00 if r9 != r6 goto +0xa + 320 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 321 7b 82 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r8 + 322 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 323 7b 28 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r2 + 324 7b 26 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r2 + 325 7b 36 00 00 00 00 00 00 *(u64 *)(r6 + 0x0) = r3 + 326 7b 62 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r6 + 327 7b 63 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r6 + 328 bf 29 00 00 00 00 00 00 r9 = r2 + 329 bf 62 00 00 00 00 00 00 r2 = r6 + 330 79 34 00 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x0) + 331 79 28 08 00 00 00 00 00 r8 = *(u64 *)(r2 + 0x8) + 332 7b 83 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = r8 + 333 15 08 01 00 00 00 00 00 if r8 == 0x0 goto +0x1 + 334 7b 38 00 00 00 00 00 00 *(u64 *)(r8 + 0x0) = r3 + 335 7b 32 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = r3 + 336 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 337 7b 23 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r2 + 338 15 04 0a 00 00 00 00 00 if r4 == 0x0 goto +0xa + 339 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) + 340 5d 83 04 00 00 00 00 00 if r3 != r8 goto +0x4 + 341 7b 24 10 00 00 00 00 00 *(u64 *)(r4 + 0x10) = r2 + 342 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 343 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 344 95 00 00 00 00 00 00 00 exit + 345 7b 24 08 00 00 00 00 00 *(u64 *)(r4 + 0x8) = r2 + 346 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 347 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 348 95 00 00 00 00 00 00 00 exit + 349 7b 21 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r2 + 350 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 351 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 352 95 00 00 00 00 00 00 00 exit + 353 72 02 1c 00 00 00 00 00 *(u8 *)(r2 + 0x1c) = 0x0 + 354 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 355 72 03 1c 00 01 00 00 00 *(u8 *)(r3 + 0x1c) = 0x1 + 356 bf 39 00 00 00 00 00 00 r9 = r3 + 357 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) + 358 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d + 359 95 00 00 00 00 00 00 00 exit + 360 55 09 09 00 03 00 00 00 if r9 != 0x3 goto +0x9 + 361 a5 08 0a 00 02 00 00 00 if r8 < 0x2 goto +0xa + 362 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) + 363 55 09 1a 00 00 00 00 00 if r9 != 0x0 goto +0x1a + 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) + 365 55 09 16 00 ff 00 00 00 if r9 != 0xff goto +0x16 + 366 b7 00 00 00 0f 00 00 00 r0 = 0xf + 367 95 00 00 00 00 00 00 00 exit + 368 b7 00 00 00 09 00 00 00 r0 = 0x9 + 369 95 00 00 00 00 00 00 00 exit + 370 b7 00 00 00 0c 00 00 00 r0 = 0xc + 371 95 00 00 00 00 00 00 00 exit + 372 b7 00 00 00 01 00 00 00 r0 = 0x1 + 373 95 00 00 00 00 00 00 00 exit + 374 b7 00 00 00 0d 00 00 00 r0 = 0xd + 375 95 00 00 00 00 00 00 00 exit + 376 b7 00 00 00 0a 00 00 00 r0 = 0xa + 377 95 00 00 00 00 00 00 00 exit + 378 b7 00 00 00 08 00 00 00 r0 = 0x8 + 379 95 00 00 00 00 00 00 00 exit + 380 b7 00 00 00 07 00 00 00 r0 = 0x7 + 381 95 00 00 00 00 00 00 00 exit + 382 b7 00 00 00 04 00 00 00 r0 = 0x4 + 383 95 00 00 00 00 00 00 00 exit + 384 b7 00 00 00 06 00 00 00 r0 = 0x6 + 385 95 00 00 00 00 00 00 00 exit + 386 b7 00 00 00 03 00 00 00 r0 = 0x3 + 387 95 00 00 00 00 00 00 00 exit + 388 b7 00 00 00 05 00 00 00 r0 = 0x5 + 389 95 00 00 00 00 00 00 00 exit + 390 b7 00 00 00 02 00 00 00 r0 = 0x2 + 391 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index 922b4abd..f7fe5af3 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 5816 (bytes into file) + Start of section headers 6000 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x16b8 +There are 8 section headers, starting at offset 0x1770 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000ca8 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000dc8 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000dd0 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000dd0 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000dd0 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001148 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 001186 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000d60 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 000e80 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 000e88 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 000e88 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 000e88 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001200 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 00123e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000ca8 0x000ca8 E 0x8 - LOAD 0x000dc8 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000dd0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000dd0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000d60 0x000d60 E 0x8 + LOAD 0x000e80 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x000e88 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x000e88 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3240 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3424 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -109,12 +109,12 @@ Disassembly of section .text 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] 20 55 05 ed 00 01 00 00 00 jne r5, 0x1, +0xed - 28 55 03 77 01 05 00 00 00 jne r3, 0x5, +0x177 - 30 a5 04 78 01 02 00 00 00 jlt r4, 0x2, +0x178 + 28 55 03 92 01 05 00 00 00 jne r3, 0x5, +0x192 + 30 a5 04 93 01 02 00 00 00 jlt r4, 0x2, +0x193 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 78 01 00 00 00 00 jne r3, 0x0, +0x178 + 40 55 03 93 01 00 00 00 00 jne r3, 0x0, +0x193 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 78 01 ff 00 00 00 jne r3, 0xff, +0x178 + 50 55 03 93 01 ff 00 00 00 jne r3, 0xff, +0x193 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] @@ -133,7 +133,7 @@ Disassembly of section .text d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 e0 05 00 09 00 00 00 00 00 ja +0x9 - e8 3d 45 6f 01 00 00 00 00 jge r5, r4, +0x16f + e8 3d 45 eb 00 00 00 00 00 jge r5, r4, +0xeb f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa 100 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 @@ -185,7 +185,7 @@ Disassembly of section .text 270 5d 31 81 00 00 00 00 00 jne r1, r3, +0x81 278 07 02 00 00 10 00 00 00 add64 r2, 0x10 280 05 00 80 00 00 00 00 00 ja +0x80 - 288 55 04 37 01 04 00 00 00 jne r4, 0x4, +0x137 + 288 55 04 b5 00 04 00 00 00 jne r4, 0x4, +0xb5 290 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] 298 bf 35 00 00 00 00 00 00 mov64 r5, r3 2a0 07 05 00 00 07 00 00 00 add64 r5, 0x7 @@ -193,11 +193,11 @@ Disassembly of section .text 2b0 bf 14 00 00 00 00 00 00 mov64 r4, r1 2b8 0f 54 00 00 00 00 00 00 add64 r4, r5 2c0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2c8 55 05 2b 01 ff 00 00 00 jne r5, 0xff, +0x12b + 2c8 55 05 46 01 ff 00 00 00 jne r5, 0xff, +0x146 2d0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2d8 55 05 2b 01 0e 00 00 00 jne r5, 0xe, +0x12b + 2d8 55 05 46 01 0e 00 00 00 jne r5, 0xe, +0x146 2e0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2e8 55 05 2d 01 ff 00 00 00 jne r5, 0xff, +0x12d + 2e8 55 05 46 01 ff 00 00 00 jne r5, 0xff, +0x146 2f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 2f8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 300 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 @@ -346,166 +346,189 @@ Disassembly of section .text 778 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] 780 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 788 05 00 57 ff 00 00 00 00 ja -0xa9 - 790 55 05 9e 00 00 00 00 00 jne r5, 0x0, +0x9e - 798 55 03 89 00 01 00 00 00 jne r3, 0x1, +0x89 - 7a0 55 04 8a 00 04 00 00 00 jne r4, 0x4, +0x8a - 7a8 9c 12 58 00 00 00 00 00 ldxdw r2, [r1 + 0x58] - 7b0 55 02 8a 00 00 00 00 00 jne r2, 0x0, +0x8a - 7b8 2c 12 68 28 00 00 00 00 ldxb w2, [r1 + 0x2868] - 7c0 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 7c8 9c 12 b8 28 00 00 00 00 ldxdw r2, [r1 + 0x28b8] - 7d0 55 02 98 00 00 00 00 00 jne r2, 0x0, +0x98 - 7d8 2c 12 c8 50 00 00 00 00 ldxb w2, [r1 + 0x50c8] - 7e0 55 02 88 00 ff 00 00 00 jne r2, 0xff, +0x88 - 7e8 9c 12 18 51 00 00 00 00 ldxdw r2, [r1 + 0x5118] - 7f0 55 02 88 00 0e 00 00 00 jne r2, 0xe, +0x88 - 7f8 2c 12 38 79 00 00 00 00 ldxb w2, [r1 + 0x7938] - 800 55 02 8a 00 ff 00 00 00 jne r2, 0xff, +0x8a - 808 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 810 b4 02 00 00 06 a7 d5 17 mov32 w2, 0x17d5a706 - 818 f7 02 00 00 19 2c 5c 51 hor64 r2, 0x515c2c19 - 820 9c 13 40 79 00 00 00 00 ldxdw r3, [r1 + 0x7940] - 828 5d 23 d1 ff 00 00 00 00 jne r3, r2, -0x2f - 830 b4 02 00 00 21 8c c9 4c mov32 w2, 0x4cc98c21 - 838 f7 02 00 00 3d 4a f1 7f hor64 r2, 0x7ff14a3d - 840 9c 13 48 79 00 00 00 00 ldxdw r3, [r1 + 0x7948] - 848 5d 23 cd ff 00 00 00 00 jne r3, r2, -0x33 - 850 b4 02 00 00 58 da ee 08 mov32 w2, 0x8eeda58 - 858 f7 02 00 00 9b a1 fd 44 hor64 r2, 0x44fda19b - 860 9c 13 50 79 00 00 00 00 ldxdw r3, [r1 + 0x7950] - 868 5d 23 c9 ff 00 00 00 00 jne r3, r2, -0x37 - 870 9c 12 58 79 00 00 00 00 ldxdw r2, [r1 + 0x7958] - 878 b4 03 00 00 e3 db d9 8a mov32 w3, -0x7526241d - 880 5d 32 c6 ff 00 00 00 00 jne r2, r3, -0x3a - 888 bf 16 00 00 00 00 00 00 mov64 r6, r1 - 890 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 898 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 8a0 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 8a8 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 8b0 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 8b8 bf 17 00 00 00 00 00 00 mov64 r7, r1 - 8c0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 8c8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 8d0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 8d8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 8e0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 8e8 5d 21 71 00 00 00 00 00 jne r1, r2, +0x71 - 8f0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 8f8 9c 72 78 28 00 00 00 00 ldxdw r2, [r7 + 0x2878] - 900 5d 21 6e 00 00 00 00 00 jne r1, r2, +0x6e - 908 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 910 9c 72 80 28 00 00 00 00 ldxdw r2, [r7 + 0x2880] - 918 5d 21 6b 00 00 00 00 00 jne r1, r2, +0x6b - 920 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - 928 9c 72 88 28 00 00 00 00 ldxdw r2, [r7 + 0x2888] - 930 5d 21 68 00 00 00 00 00 jne r1, r2, +0x68 - 938 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 940 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - 948 9c 72 90 79 00 00 00 00 ldxdw r2, [r7 + 0x7990] - 950 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - 958 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - 960 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - 968 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - 970 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - 978 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - 980 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - 988 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - 990 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - 998 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - 9a0 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - 9a8 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - 9b0 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - 9b8 bf 72 00 00 00 00 00 00 mov64 r2, r7 - 9c0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 9c8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - 9d0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - 9d8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - 9e0 bf 73 00 00 00 00 00 00 mov64 r3, r7 - 9e8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - 9f0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - 9f8 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a00 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - a08 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - a10 bf 73 00 00 00 00 00 00 mov64 r3, r7 - a18 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - a20 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - a28 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - a30 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a38 07 01 00 00 30 00 00 00 add64 r1, 0x30 - a40 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - a48 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a50 07 01 00 00 60 00 00 00 add64 r1, 0x60 - a58 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - a60 bf 71 00 00 00 00 00 00 mov64 r1, r7 - a68 07 01 00 00 50 00 00 00 add64 r1, 0x50 - a70 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - a78 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - a80 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - a88 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - a90 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - a98 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - aa0 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - aa8 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - ab0 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - ab8 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - ac0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - ac8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - ad0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - ad8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - ae0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - ae8 07 01 00 00 10 00 00 00 add64 r1, 0x10 - af0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - af8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b00 07 01 00 00 48 00 00 00 add64 r1, 0x48 - b08 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - b10 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b18 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - b20 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - b28 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - b30 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - b38 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b40 07 01 00 00 0f 00 00 00 add64 r1, 0xf - b48 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - b50 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - b58 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b60 07 01 00 00 20 01 00 00 add64 r1, 0x120 - b68 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - b70 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - b78 bf a1 00 00 00 00 00 00 mov64 r1, r10 - b80 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - b88 bf a2 00 00 00 00 00 00 mov64 r2, r10 - b90 07 02 00 00 68 00 00 00 add64 r2, 0x68 - b98 bf a4 00 00 00 00 00 00 mov64 r4, r10 - ba0 07 04 00 00 30 01 00 00 add64 r4, 0x130 - ba8 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - bb0 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - bb8 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - bc0 bf 71 00 00 00 00 00 00 mov64 r1, r7 - bc8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - bd0 9f 17 d0 28 00 00 00 00 stxdw [r7 + 0x28d0], r1 - bd8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - be0 05 00 5a ff 00 00 00 00 ja -0xa6 - be8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - bf0 05 00 58 ff 00 00 00 00 ja -0xa8 - bf8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - c00 05 00 56 ff 00 00 00 00 ja -0xaa - c08 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - c10 05 00 54 ff 00 00 00 00 ja -0xac - c18 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - c20 05 00 52 ff 00 00 00 00 ja -0xae - c28 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - c30 05 00 50 ff 00 00 00 00 ja -0xb0 - c38 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - c40 05 00 4e ff 00 00 00 00 ja -0xb2 - c48 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - c50 05 00 4c ff 00 00 00 00 ja -0xb4 - c58 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - c60 05 00 4a ff 00 00 00 00 ja -0xb6 - c68 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - c70 05 00 48 ff 00 00 00 00 ja -0xb8 - c78 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - c80 05 00 46 ff 00 00 00 00 ja -0xba - c88 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - c90 05 00 44 ff 00 00 00 00 ja -0xbc - c98 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - ca0 05 00 42 ff 00 00 00 00 ja -0xbe \ No newline at end of file + 790 55 05 18 00 02 00 00 00 jne r5, 0x2, +0x18 + 798 55 03 a4 00 03 00 00 00 jne r3, 0x3, +0xa4 + 7a0 a5 04 a5 00 02 00 00 00 jlt r4, 0x2, +0xa5 + 7a8 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] + 7b0 55 03 a5 00 00 00 00 00 jne r3, 0x0, +0xa5 + 7b8 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] + 7c0 55 03 a5 00 ff 00 00 00 jne r3, 0xff, +0xa5 + 7c8 b7 00 00 00 0f 00 00 00 mov64 r0, 0xf + 7d0 9c 11 c0 28 00 00 00 00 ldxdw r1, [r1 + 0x28c0] + 7d8 15 01 db ff 00 00 00 00 jeq r1, 0x0, -0x25 + 7e0 3c 22 01 00 00 00 00 00 ldxh w2, [r2 + 0x1] + 7e8 05 00 02 00 00 00 00 00 ja +0x2 + 7f0 9c 11 10 00 00 00 00 00 ldxdw r1, [r1 + 0x10] + 7f8 15 01 d7 ff 00 00 00 00 jeq r1, 0x0, -0x29 + 800 3c 13 18 00 00 00 00 00 ldxh w3, [r1 + 0x18] + 808 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 810 2d 34 fb ff 00 00 00 00 jgt r4, r3, -0x5 + 818 3d 34 bc ff 00 00 00 00 jge r4, r3, -0x44 + 820 9c 11 08 00 00 00 00 00 ldxdw r1, [r1 + 0x8] + 828 55 01 fa ff 00 00 00 00 jne r1, 0x0, -0x6 + 830 05 00 d0 ff 00 00 00 00 ja -0x30 + 838 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + 840 05 00 ce ff 00 00 00 00 ja -0x32 + 848 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + 850 05 00 cc ff 00 00 00 00 ja -0x34 + 858 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 860 55 05 9d 00 00 00 00 00 jne r5, 0x0, +0x9d + 868 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a + 870 55 04 8b 00 04 00 00 00 jne r4, 0x4, +0x8b + 878 9c 81 58 00 00 00 00 00 ldxdw r1, [r8 + 0x58] + 880 55 01 8b 00 00 00 00 00 jne r1, 0x0, +0x8b + 888 2c 81 68 28 00 00 00 00 ldxb w1, [r8 + 0x2868] + 890 55 01 8b 00 ff 00 00 00 jne r1, 0xff, +0x8b + 898 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 8a0 55 01 93 00 00 00 00 00 jne r1, 0x0, +0x93 + 8a8 2c 81 c8 50 00 00 00 00 ldxb w1, [r8 + 0x50c8] + 8b0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + 8b8 9c 81 18 51 00 00 00 00 ldxdw r1, [r8 + 0x5118] + 8c0 55 01 89 00 0e 00 00 00 jne r1, 0xe, +0x89 + 8c8 2c 81 38 79 00 00 00 00 ldxb w1, [r8 + 0x7938] + 8d0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + 8d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 8e0 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 + 8e8 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 + 8f0 9c 82 40 79 00 00 00 00 ldxdw r2, [r8 + 0x7940] + 8f8 5d 12 b7 ff 00 00 00 00 jne r2, r1, -0x49 + 900 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 + 908 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d + 910 9c 82 48 79 00 00 00 00 ldxdw r2, [r8 + 0x7948] + 918 5d 12 b3 ff 00 00 00 00 jne r2, r1, -0x4d + 920 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 + 928 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b + 930 9c 82 50 79 00 00 00 00 ldxdw r2, [r8 + 0x7950] + 938 5d 12 af ff 00 00 00 00 jne r2, r1, -0x51 + 940 bf 87 00 00 00 00 00 00 mov64 r7, r8 + 948 9c 71 58 79 00 00 00 00 ldxdw r1, [r7 + 0x7958] + 950 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d + 958 5d 21 ab ff 00 00 00 00 jne r1, r2, -0x55 + 960 bf 76 00 00 00 00 00 00 mov64 r6, r7 + 968 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 970 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 978 07 04 00 00 68 00 00 00 add64 r4, 0x68 + 980 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 988 07 05 00 00 0f 00 00 00 add64 r5, 0xf + 990 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 998 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 9a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 9a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 9b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + 9b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 9c0 5d 21 6d 00 00 00 00 00 jne r1, r2, +0x6d + 9c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + 9d0 9c 82 78 28 00 00 00 00 ldxdw r2, [r8 + 0x2878] + 9d8 5d 21 6a 00 00 00 00 00 jne r1, r2, +0x6a + 9e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + 9e8 9c 82 80 28 00 00 00 00 ldxdw r2, [r8 + 0x2880] + 9f0 5d 21 67 00 00 00 00 00 jne r1, r2, +0x67 + 9f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + a00 9c 82 88 28 00 00 00 00 ldxdw r2, [r8 + 0x2888] + a08 5d 21 64 00 00 00 00 00 jne r1, r2, +0x64 + a10 bf 81 00 00 00 00 00 00 mov64 r1, r8 + a18 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + a20 9c 82 90 79 00 00 00 00 ldxdw r2, [r8 + 0x7990] + a28 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + a30 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + a38 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + a40 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + a48 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + a50 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + a58 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + a60 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + a68 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + a70 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + a78 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + a80 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + a88 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + a90 bf 82 00 00 00 00 00 00 mov64 r2, r8 + a98 07 02 00 00 10 00 00 00 add64 r2, 0x10 + aa0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + aa8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + ab0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + ab8 bf 83 00 00 00 00 00 00 mov64 r3, r8 + ac0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + ac8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + ad0 bf 83 00 00 00 00 00 00 mov64 r3, r8 + ad8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + ae0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + ae8 bf 83 00 00 00 00 00 00 mov64 r3, r8 + af0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + af8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + b00 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + b08 bf 81 00 00 00 00 00 00 mov64 r1, r8 + b10 07 01 00 00 30 00 00 00 add64 r1, 0x30 + b18 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + b20 bf 81 00 00 00 00 00 00 mov64 r1, r8 + b28 07 01 00 00 60 00 00 00 add64 r1, 0x60 + b30 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + b38 bf 81 00 00 00 00 00 00 mov64 r1, r8 + b40 07 01 00 00 50 00 00 00 add64 r1, 0x50 + b48 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + b50 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + b58 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + b60 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + b68 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + b70 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + b78 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + b80 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + b88 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + b90 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + b98 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + ba0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + ba8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + bb0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + bb8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + bc0 07 01 00 00 10 00 00 00 add64 r1, 0x10 + bc8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + bd0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + bd8 07 01 00 00 48 00 00 00 add64 r1, 0x48 + be0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + be8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + bf0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + bf8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + c00 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + c08 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + c10 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c18 07 01 00 00 0f 00 00 00 add64 r1, 0xf + c20 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + c28 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + c30 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c38 07 01 00 00 20 01 00 00 add64 r1, 0x120 + c40 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + c48 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + c50 bf a1 00 00 00 00 00 00 mov64 r1, r10 + c58 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + c60 bf a2 00 00 00 00 00 00 mov64 r2, r10 + c68 07 02 00 00 68 00 00 00 add64 r2, 0x68 + c70 bf a4 00 00 00 00 00 00 mov64 r4, r10 + c78 07 04 00 00 30 01 00 00 add64 r4, 0x130 + c80 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + c88 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + c90 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + c98 bf 81 00 00 00 00 00 00 mov64 r1, r8 + ca0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + ca8 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + cb0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + cb8 05 00 3f ff 00 00 00 00 ja -0xc1 + cc0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + cc8 05 00 3d ff 00 00 00 00 ja -0xc3 + cd0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + cd8 05 00 3b ff 00 00 00 00 ja -0xc5 + ce0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + ce8 05 00 39 ff 00 00 00 00 ja -0xc7 + cf0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + cf8 05 00 37 ff 00 00 00 00 ja -0xc9 + d00 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + d08 05 00 35 ff 00 00 00 00 ja -0xcb + d10 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + d18 05 00 33 ff 00 00 00 00 ja -0xcd + d20 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + d28 05 00 31 ff 00 00 00 00 ja -0xcf + d30 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + d38 05 00 2f ff 00 00 00 00 ja -0xd1 + d40 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + d48 05 00 2d ff 00 00 00 00 ja -0xd3 + d50 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + d58 05 00 2b ff 00 00 00 00 ja -0xd5 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 5210c7da..0f855acb 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -6,12 +6,12 @@ entrypoint: ldxdw r3, [r2-8] ldxb r5, [r2+0] jne r5, 1, jmp_0780 - jne r3, 5, jmp_0bd8 - jlt r4, 2, jmp_0be8 + jne r3, 5, jmp_0cb0 + jlt r4, 2, jmp_0cc0 ldxdw r3, [r1+88] - jne r3, 0, jmp_0bf8 + jne r3, 0, jmp_0cd0 ldxb r3, [r1+10344] - jne r3, 255, jmp_0c08 + jne r3, 255, jmp_0ce0 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] @@ -36,7 +36,7 @@ jmp_00b0: ja jmp_0120 jmp_00e8: - jge r5, r4, jmp_0c58 + jge r5, r4, jmp_0838 ldxdw r4, [r2+8] jne r4, 0, jmp_00b0 stxdw [r3+0], r2 @@ -106,7 +106,7 @@ jmp_0268: ja jmp_0698 jmp_0278: - jne r4, 4, jmp_0c38 + jne r4, 4, jmp_0828 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -114,11 +114,11 @@ jmp_0278: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0c18 + jne r5, 255, jmp_0cf0 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0c28 + jne r5, 14, jmp_0d00 ldxb r5, [r4+31032] - jne r5, 255, jmp_0c48 + jne r5, 255, jmp_0d10 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 @@ -297,44 +297,81 @@ jmp_0738: ja jmp_0238 jmp_0780: - jne r5, 0, jmp_0c68 - jne r3, 1, jmp_0bd8 - jne r4, 4, jmp_0be8 - ldxdw r2, [r1+88] - jne r2, 0, jmp_0bf8 - ldxb r2, [r1+10344] - jne r2, 255, jmp_0c08 - ldxdw r2, [r1+10424] - jne r2, 0, jmp_0c78 - ldxb r2, [r1+20680] - jne r2, 255, jmp_0c18 - ldxdw r2, [r1+20760] - jne r2, 14, jmp_0c28 - ldxb r2, [r1+31032] - jne r2, 255, jmp_0c48 + jne r5, 2, jmp_0848 + jne r3, 3, jmp_0cb0 + jlt r4, 2, jmp_0cc0 + ldxdw r3, [r1+88] + jne r3, 0, jmp_0cd0 + ldxb r3, [r1+10344] + jne r3, 255, jmp_0ce0 + mov64 r0, 15 + ldxdw r1, [r1+10432] + jeq r1, 0, jmp_06a8 + ldxh r2, [r2+1] + ja jmp_07f0 + +jmp_07e0: + ldxdw r1, [r1+16] + jeq r1, 0, jmp_06a8 + +jmp_07f0: + ldxh r3, [r1+24] + mov64 r4, r2 + jgt r4, r3, jmp_07e0 + jge r4, r3, jmp_05f0 + ldxdw r1, [r1+8] + jne r1, 0, jmp_07f0 + ja jmp_06a8 + +jmp_0828: + mov64 r0, 13 + ja jmp_06a8 + +jmp_0838: + mov64 r0, 14 + ja jmp_06a8 + +jmp_0848: + mov64 r8, r1 + jne r5, 0, jmp_0d30 + jne r3, 1, jmp_0cb0 + jne r4, 4, jmp_0cc0 + ldxdw r1, [r8+88] + jne r1, 0, jmp_0cd0 + ldxb r1, [r8+10344] + jne r1, 255, jmp_0ce0 + ldxdw r1, [r8+10424] + jne r1, 0, jmp_0d20 + ldxb r1, [r8+20680] + jne r1, 255, jmp_0cf0 + ldxdw r1, [r8+20760] + jne r1, 14, jmp_0d00 + ldxb r1, [r8+31032] + jne r1, 255, jmp_0d10 mov64 r0, 8 - mov32 r2, 399877894 - hor64 r2, 1364995097 - ldxdw r3, [r1+31040] - jne r3, r2, jmp_06a8 - mov32 r2, 1288277025 - hor64 r2, 2146519613 - ldxdw r3, [r1+31048] - jne r3, r2, jmp_06a8 - mov32 r2, 149871192 - hor64 r2, 1157472667 - ldxdw r3, [r1+31056] - jne r3, r2, jmp_06a8 - ldxdw r2, [r1+31064] - mov32 r3, -1965433885 - jne r2, r3, jmp_06a8 - mov64 r6, r1 + mov32 r1, 399877894 + hor64 r1, 1364995097 + ldxdw r2, [r8+31040] + jne r2, r1, jmp_06a8 + mov32 r1, 1288277025 + hor64 r1, 2146519613 + ldxdw r2, [r8+31048] + jne r2, r1, jmp_06a8 + mov32 r1, 149871192 + hor64 r1, 1157472667 + ldxdw r2, [r8+31056] + jne r2, r1, jmp_06a8 + mov64 r7, r8 + ldxdw r1, [r7+31064] + mov32 r2, -1965433885 + jne r1, r2, jmp_06a8 + mov64 r6, r7 add64 r6, 41401 mov64 r4, r10 add64 r4, 104 mov64 r5, r10 add64 r5, 15 - mov64 r7, r1 + mov64 r1, r7 mov64 r2, 0 mov64 r3, r6 call sol_try_find_program_address @@ -343,17 +380,17 @@ jmp_0780: ldxdw r2, [r7+10352] jne r1, r2, jmp_06a8 ldxdw r1, [r10+112] - ldxdw r2, [r7+10360] + ldxdw r2, [r8+10360] jne r1, r2, jmp_06a8 ldxdw r1, [r10+120] - ldxdw r2, [r7+10368] + ldxdw r2, [r8+10368] jne r1, r2, jmp_06a8 ldxdw r1, [r10+128] - ldxdw r2, [r7+10376] + ldxdw r2, [r8+10376] jne r1, r2, jmp_06a8 - mov64 r1, r7 + mov64 r1, r8 add64 r1, 10352 - ldxdw r2, [r7+31120] + ldxdw r2, [r8+31120] ldxdw r3, [r6+24] stxdw [r10+60], r3 ldxdw r3, [r6+16] @@ -367,28 +404,28 @@ jmp_0780: stdw [r10+28], 24 stw [r10+16], 0 stxdw [r10+88], r1 - mov64 r2, r7 + mov64 r2, r8 add64 r2, 16 stxdw [r10+72], r2 sth [r10+96], 257 sth [r10+80], 257 - mov64 r3, r7 + mov64 r3, r8 add64 r3, 10384 stxdw [r10+192], r3 - mov64 r3, r7 + mov64 r3, r8 add64 r3, 10432 stxdw [r10+184], r3 - mov64 r3, r7 + mov64 r3, r8 add64 r3, 10416 stxdw [r10+168], r3 stxdw [r10+160], r1 - mov64 r1, r7 + mov64 r1, r8 add64 r1, 48 stxdw [r10+136], r1 - mov64 r1, r7 + mov64 r1, r8 add64 r1, 96 stxdw [r10+128], r1 - mov64 r1, r7 + mov64 r1, r8 add64 r1, 80 stxdw [r10+112], r1 stxdw [r10+104], r2 @@ -432,51 +469,43 @@ jmp_0780: mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c - mov64 r1, r7 + mov64 r1, r8 add64 r1, 10456 - stxdw [r7+10448], r1 + stxdw [r8+10448], r1 ja jmp_05f0 -jmp_0bd8: +jmp_0cb0: mov64 r0, 12 ja jmp_06a8 -jmp_0be8: +jmp_0cc0: mov64 r0, 1 ja jmp_06a8 -jmp_0bf8: +jmp_0cd0: mov64 r0, 2 ja jmp_06a8 -jmp_0c08: +jmp_0ce0: mov64 r0, 5 ja jmp_06a8 -jmp_0c18: +jmp_0cf0: mov64 r0, 6 ja jmp_06a8 -jmp_0c28: +jmp_0d00: mov64 r0, 4 ja jmp_06a8 -jmp_0c38: - mov64 r0, 13 - ja jmp_06a8 - -jmp_0c48: +jmp_0d10: mov64 r0, 7 ja jmp_06a8 -jmp_0c58: - mov64 r0, 14 +jmp_0d20: + mov64 r0, 3 ja jmp_06a8 -jmp_0c68: +jmp_0d30: mov64 r0, 11 ja jmp_06a8 - -jmp_0c78: - mov64 r0, 3 - ja jmp_06a8 diff --git a/examples/tree/artifacts/snippets/asm/constants.txt b/examples/tree/artifacts/snippets/asm/constants.txt index 5e0c72b4..d6bec776 100644 --- a/examples/tree/artifacts/snippets/asm/constants.txt +++ b/examples/tree/artifacts/snippets/asm/constants.txt @@ -124,8 +124,6 @@ .equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. .equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. -# Status value for successful remove (first non-error code). -.equ INSN_REMOVE_STATUS_OK, 15 # Init stack frame layout. # ------------------------ diff --git a/examples/tree/artifacts/snippets/asm/insert-search.txt b/examples/tree/artifacts/snippets/asm/insert-search.txt index 6b43d467..7bbb1c8f 100644 --- a/examples/tree/artifacts/snippets/asm/insert-search.txt +++ b/examples/tree/artifacts/snippets/asm/insert-search.txt @@ -1,6 +1,5 @@ insert_search: # r9 = node ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; - mov64 r2, NULL # r2 = parent = null; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; jeq r3, NULL, insert_root @@ -16,6 +15,7 @@ insert_root: # Root is null: new node becomes root. # --------------------------------------------------------------------- stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + mov64 r2, NULL # r2 = parent = null; stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = null; stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; exit diff --git a/examples/tree/artifacts/snippets/interface/instructions.txt b/examples/tree/artifacts/snippets/interface/instructions.txt index a81ac2ca..a0c98eff 100644 --- a/examples/tree/artifacts/snippets/interface/instructions.txt +++ b/examples/tree/artifacts/snippets/interface/instructions.txt @@ -31,13 +31,6 @@ pub struct RemoveInstruction { pub key: u16, } -#[repr(C, packed)] -/// Value in r0. -pub struct RemoveReturn { - status: u16, - value: u16, -} - constant_group! { /// Offsets for instruction processing. instruction { @@ -56,7 +49,5 @@ constant_group! { offset!(INSERT_VALUE, InsertInstruction.value), /// Key field in remove instruction. offset!(REMOVE_KEY, RemoveInstruction.key), - /// Status value for successful remove (first non-error code). - REMOVE_STATUS_OK: u16 = error::N_CODES as u16, } } diff --git a/examples/tree/artifacts/snippets/rs/insert-search.txt b/examples/tree/artifacts/snippets/rs/insert-search.txt index 4d6d7f98..68640e07 100644 --- a/examples/tree/artifacts/snippets/rs/insert-search.txt +++ b/examples/tree/artifacts/snippets/rs/insert-search.txt @@ -1,15 +1,15 @@ let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); - let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; // Root is null: new node becomes root. if cursor.is_null() { (*node).color = Color::Red; - (*node).parent = parent; + (*node).parent = null_mut(); (*tree_header).root = node; return SUCCESS; } + let mut parent: *mut TreeNode; loop { parent = cursor; let cursor_key = (*cursor).key; diff --git a/examples/tree/artifacts/snippets/rs/remove-search.txt b/examples/tree/artifacts/snippets/rs/remove-search.txt new file mode 100644 index 00000000..ca7eb05c --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-search.txt @@ -0,0 +1,24 @@ + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); + let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); + let mut node = (*tree_header).root; + + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + + loop { + let node_key = (*node).key; + if key > node_key { + node = (*node).child[tree::DIR_R]; + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + } else if key < node_key { + node = (*node).child[tree::DIR_L]; + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + } else { + break; + } + } \ No newline at end of file diff --git a/examples/tree/artifacts/tests/entrypoint_branching/result.txt b/examples/tree/artifacts/tests/entrypoint_branching/result.txt index 02744479..9d4f1aea 100644 --- a/examples/tree/artifacts/tests/entrypoint_branching/result.txt +++ b/examples/tree/artifacts/tests/entrypoint_branching/result.txt @@ -1,10 +1,10 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction discriminator | 7 | 9 | +2 | +28.6% | +| Invalid instruction discriminator | 8 | 11 | +3 | +37.5% | test tests::test_entrypoint_branching ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 7 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_create_account/result.txt b/examples/tree/artifacts/tests/initialize_create_account/result.txt index ac84fbbb..67c9695b 100644 --- a/examples/tree/artifacts/tests/initialize_create_account/result.txt +++ b/examples/tree/artifacts/tests/initialize_create_account/result.txt @@ -1,36 +1,36 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| System Program is wrong address | 2446 | 107 | 139 | +32 | +29.9% | -| User has insufficient Lamports | 2596 | 107 | 139 | +32 | +29.9% | -| CreateAccount happy path | 2596 | 111 | 145 | +34 | +30.6% | +| System Program is wrong address | 2446 | 108 | 142 | +34 | +31.5% | +| User has insufficient Lamports | 2596 | 108 | 142 | +34 | +31.5% | +| CreateAccount happy path | 2596 | 112 | 148 | +36 | +32.1% | test tests::test_initialize_create_account ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2554 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Unknown program 11111111111111111111111111111111 -[ ... DEBUG ... ] Program DASMAC... consumed 2585 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2588 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: An account required by the instruction is missing [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 [ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2703 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2704 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Transfer: insufficient lamports 0, need 528960 [ ... DEBUG ... ] Program 11111111111111111111111111111111 failed: custom program error: 0x1 -[ ... DEBUG ... ] Program DASMAC... consumed 2735 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2738 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2707 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2708 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program 11111111111111111111111111111111 invoke [2] [ ... DEBUG ... ] Program 11111111111111111111111111111111 success -[ ... DEBUG ... ] Program DASMAC... consumed 2741 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 2744 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_input_checks/result.txt b/examples/tree/artifacts/tests/initialize_input_checks/result.txt index a7dcd6ae..b452491f 100644 --- a/examples/tree/artifacts/tests/initialize_input_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_input_checks/result.txt @@ -1,122 +1,122 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Invalid instruction data length | 8 | 10 | +2 | +25.0% | -| Too few accounts | 9 | 11 | +2 | +22.2% | -| Too many accounts | 9 | 11 | +2 | +22.2% | -| User has nonzero data length | 11 | 13 | +2 | +18.2% | -| Tree account is duplicate | 13 | 15 | +2 | +15.4% | -| Tree has nonzero data length | 15 | 17 | +2 | +13.3% | -| System program is duplicate | 17 | 19 | +2 | +11.8% | -| System program wrong data length | 19 | 21 | +2 | +10.5% | -| Rent sysvar is duplicate | 21 | 23 | +2 | +9.5% | -| Rent address mismatch word 0 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 1 | 24 | 26 | +2 | +8.3% | -| Rent address mismatch word 2 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 3 | 27 | 30 | +3 | +11.1% | -| Rent address mismatch word 4 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 5 | 30 | 34 | +4 | +13.3% | -| Rent address mismatch word 6 | 33 | 37 | +4 | +12.1% | -| Rent address mismatch word 7 | 33 | 37 | +4 | +12.1% | +| Invalid instruction data length | 9 | 12 | +3 | +33.3% | +| Too few accounts | 10 | 13 | +3 | +30.0% | +| Too many accounts | 10 | 13 | +3 | +30.0% | +| User has nonzero data length | 12 | 15 | +3 | +25.0% | +| Tree account is duplicate | 14 | 17 | +3 | +21.4% | +| Tree has nonzero data length | 16 | 19 | +3 | +18.8% | +| System program is duplicate | 18 | 21 | +3 | +16.7% | +| System program wrong data length | 20 | 23 | +3 | +15.0% | +| Rent sysvar is duplicate | 22 | 25 | +3 | +13.6% | +| Rent address mismatch word 0 | 25 | 28 | +3 | +12.0% | +| Rent address mismatch word 1 | 25 | 28 | +3 | +12.0% | +| Rent address mismatch word 2 | 28 | 32 | +4 | +14.3% | +| Rent address mismatch word 3 | 28 | 32 | +4 | +14.3% | +| Rent address mismatch word 4 | 31 | 36 | +5 | +16.1% | +| Rent address mismatch word 5 | 31 | 36 | +5 | +16.1% | +| Rent address mismatch word 6 | 34 | 40 | +6 | +17.6% | +| Rent address mismatch word 7 | 34 | 40 | +6 | +17.6% | test tests::test_initialize_input_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 12 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 17 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 19 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 20 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 22 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt index c306b324..544de8c8 100644 --- a/examples/tree/artifacts/tests/initialize_pda_checks/result.txt +++ b/examples/tree/artifacts/tests/initialize_pda_checks/result.txt @@ -1,31 +1,31 @@ | Test case | Fixed CU costs | ASM (net CUs) | Rust (net CUs) | Overhead | Overhead % | |-----------|----------------|---------------|----------------|----------|------------| -| PDA mismatch chunk 0 | 1500 | 44 | 52 | +8 | +18.2% | -| PDA mismatch chunk 1 | 1500 | 47 | 55 | +8 | +17.0% | -| PDA mismatch chunk 2 | 1500 | 50 | 58 | +8 | +16.0% | -| PDA mismatch chunk 3 | 1500 | 53 | 61 | +8 | +15.1% | +| PDA mismatch chunk 0 | 1500 | 45 | 55 | +10 | +22.2% | +| PDA mismatch chunk 1 | 1500 | 48 | 58 | +10 | +20.8% | +| PDA mismatch chunk 2 | 1500 | 51 | 61 | +10 | +19.6% | +| PDA mismatch chunk 3 | 1500 | 54 | 64 | +10 | +18.5% | test tests::test_initialize_pda_checks ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1544 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1545 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1552 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1547 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1548 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1555 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1550 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1551 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1558 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1553 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1554 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 1561 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 1564 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa \ No newline at end of file diff --git a/examples/tree/artifacts/tests/insert_search/result.txt b/examples/tree/artifacts/tests/insert_search/result.txt index dd5a1650..173d658d 100644 --- a/examples/tree/artifacts/tests/insert_search/result.txt +++ b/examples/tree/artifacts/tests/insert_search/result.txt @@ -1,23 +1,23 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Dup at root | 26 | 30 | +4 | +15.4% | -| Dup in left | 31 | 37 | +6 | +19.4% | -| Dup in right | 32 | 36 | +4 | +12.5% | +| Dup at root | 25 | 30 | +5 | +20.0% | +| Dup in left | 30 | 37 | +7 | +23.3% | +| Dup in right | 31 | 36 | +5 | +16.1% | test tests::test_insert_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/insert_to_tree/result.txt b/examples/tree/artifacts/tests/insert_to_tree/result.txt index df758a7c..a7ec0cf1 100644 --- a/examples/tree/artifacts/tests/insert_to_tree/result.txt +++ b/examples/tree/artifacts/tests/insert_to_tree/result.txt @@ -1,32 +1,28 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | Empty tree | 24 | 27 | +3 | +12.5% | -| Case 1: left child | 31 | 38 | +7 | +22.6% | -| Case 1: right child | 32 | 37 | +5 | +15.6% | -| Case 4: left child | 34 | 42 | +8 | +23.5% | -| Case 4: right child | 35 | 42 | +7 | +20.0% | -| Case 2+3: left-left | 50 | 60 | +10 | +20.0% | -| Case 2+3: left-right | 51 | 60 | +9 | +17.6% | -| Case 2+3: right-left | 51 | 58 | +7 | +13.7% | -| Case 2+3: right-right | 52 | 58 | +6 | +11.5% | -| Case 2+1: left | 57 | 69 | +12 | +21.1% | -| Case 2+1: right | 60 | 66 | +6 | +10.0% | -| Case 6: left-left null uncle | 55 | 67 | +12 | +21.8% | -| Case 6: right-right null uncle | 57 | 65 | +8 | +14.0% | -| Case 6: left-left black uncle | 57 | 69 | +12 | +21.1% | -| Case 6: right-right black uncle | 59 | 68 | +9 | +15.3% | -| Case 5+6: left-right null uncle | 65 | 74 | +9 | +13.8% | -| Case 5+6: right-left null uncle | 65 | 72 | +7 | +10.8% | -| Case 5+6: left-right black uncle | 67 | 76 | +9 | +13.4% | -| Case 5+6: right-left black uncle | 67 | 75 | +8 | +11.9% | -| Case 6: GGP non-null, LL GP-left | 62 | 78 | +16 | +25.8% | -| Case 6: GGP non-null, LL GP-right | 63 | 78 | +15 | +23.8% | -| Case 6: GGP non-null, RR GP-right | 65 | 76 | +11 | +16.9% | -| Case 6: GGP non-null, RR GP-left | 64 | 76 | +12 | +18.8% | -| Case 2+6: non-null new_child dir_l | 84 | 100 | +16 | +19.0% | -| Case 2+6: non-null new_child dir_r | 88 | 96 | +8 | +9.1% | -| Case 2+5+6: non-null new_child dir_l | 95 | 106 | +11 | +11.6% | -| Case 2+5+6: non-null new_child dir_r | 97 | 104 | +7 | +7.2% | +| Case 1: left child | 30 | 38 | +8 | +26.7% | +| Case 1: right child | 31 | 37 | +6 | +19.4% | +| Case 4: left child | 33 | 42 | +9 | +27.3% | +| Case 4: right child | 34 | 42 | +8 | +23.5% | +| Case 2+3: left-left | 49 | 60 | +11 | +22.4% | +| Case 2+3: left-right | 50 | 60 | +10 | +20.0% | +| Case 2+3: right-left | 50 | 58 | +8 | +16.0% | +| Case 2+3: right-right | 51 | 58 | +7 | +13.7% | +| Case 2+1: left | 56 | 69 | +13 | +23.2% | +| Case 2+1: right | 59 | 66 | +7 | +11.9% | +| Case 6: left-left null uncle | 54 | 67 | +13 | +24.1% | +| Case 6: right-right null uncle | 56 | 65 | +9 | +16.1% | +| Case 5+6: left-right null uncle | 64 | 74 | +10 | +15.6% | +| Case 5+6: right-left null uncle | 64 | 72 | +8 | +12.5% | +| Case 6: GGP non-null, LL GP-left | 61 | 78 | +17 | +27.9% | +| Case 6: GGP non-null, LL GP-right | 62 | 78 | +16 | +25.8% | +| Case 6: GGP non-null, RR GP-right | 64 | 76 | +12 | +18.8% | +| Case 6: GGP non-null, RR GP-left | 63 | 76 | +13 | +20.6% | +| Case 2+6: non-null new_child dir_l | 83 | 100 | +17 | +20.5% | +| Case 2+6: non-null new_child dir_r | 87 | 96 | +9 | +10.3% | +| Case 2+5+6: non-null new_child dir_l | 94 | 106 | +12 | +12.8% | +| Case 2+5+6: non-null new_child dir_r | 96 | 104 | +8 | +8.3% | test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units @@ -35,157 +31,133 @@ test tests::test_insert_to_tree ... ok [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 66 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 69 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 74 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 72 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 67 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 75 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 61 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 62 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 76 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 84 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 100 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 87 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 96 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 95 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 94 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 106 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 97 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 96 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 104 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/multi_insert/result.txt b/examples/tree/artifacts/tests/multi_insert/result.txt index f07a976e..4cd05d76 100644 --- a/examples/tree/artifacts/tests/multi_insert/result.txt +++ b/examples/tree/artifacts/tests/multi_insert/result.txt @@ -1,19 +1,19 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| 3-node balanced (10,5,15) | 90 | 106 | +16 | +17.8% | -| Left-skew rotation (10,5,1) | 113 | 136 | +23 | +20.4% | -| Right-skew rotation (10,15,20) | 116 | 134 | +18 | +15.5% | -| Zigzag double rotation (10,5,7) | 123 | 143 | +20 | +16.3% | -| 7-node full tree (10,5,15,3,7,12,20) | 252 | 297 | +45 | +17.9% | +| 3-node balanced (10,5,15) | 88 | 106 | +18 | +20.5% | +| Left-skew rotation (10,5,1) | 111 | 136 | +25 | +22.5% | +| Right-skew rotation (10,15,20) | 114 | 134 | +20 | +17.5% | +| Zigzag double rotation (10,5,7) | 121 | 143 | +22 | +18.2% | +| 7-node full tree (10,5,15,3,7,12,20) | 246 | 297 | +51 | +20.7% | test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -28,10 +28,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -46,10 +46,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 35 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -64,10 +64,10 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 65 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 64 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units @@ -82,22 +82,22 @@ test tests::test_multi_insert ... ok [ ... DEBUG ... ] Program DASMAC... consumed 24 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 34 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 50 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 49 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 36 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 37 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 27 of 1400000 compute units diff --git a/examples/tree/artifacts/tests/remove_input_checks/result.txt b/examples/tree/artifacts/tests/remove_input_checks/result.txt new file mode 100644 index 00000000..39952db4 --- /dev/null +++ b/examples/tree/artifacts/tests/remove_input_checks/result.txt @@ -0,0 +1,38 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Data too short | 8 | 10 | +2 | +25.0% | +| Data too long | 8 | 10 | +2 | +25.0% | +| Too few accounts | 9 | 11 | +2 | +22.2% | +| User has data | 11 | 13 | +2 | +18.2% | +| Tree is duplicate | 13 | 15 | +2 | +15.4% | +test tests::test_remove_input_checks ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 10 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xc +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 9 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 11 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5 \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_input_checks/test.txt b/examples/tree/artifacts/tests/remove_input_checks/test.txt new file mode 100644 index 00000000..d2700325 --- /dev/null +++ b/examples/tree/artifacts/tests/remove_input_checks/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_remove_input_checks() { + print_comparison_table(remove::RemoveCase::INPUT_CASES); +} \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_search/result.txt b/examples/tree/artifacts/tests/remove_search/result.txt new file mode 100644 index 00000000..719dbeae --- /dev/null +++ b/examples/tree/artifacts/tests/remove_search/result.txt @@ -0,0 +1,31 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| Empty tree | 13 | 16 | +3 | +23.1% | +| Not found (left) | 13 | 25 | +12 | +92.3% | +| Not found (right) | 13 | 23 | +10 | +76.9% | +| Not found (deep) | 13 | 30 | +17 | +130.8% | +test tests::test_remove_search ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_search/test.txt b/examples/tree/artifacts/tests/remove_search/test.txt new file mode 100644 index 00000000..23652da4 --- /dev/null +++ b/examples/tree/artifacts/tests/remove_search/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_remove_search() { + print_comparison_table(remove::RemoveCase::SEARCH_CASES); +} \ No newline at end of file diff --git a/examples/tree/specs/insert-tests.md b/examples/tree/specs/insert-tests.md index c59a17b9..187564c7 100644 --- a/examples/tree/specs/insert-tests.md +++ b/examples/tree/specs/insert-tests.md @@ -216,22 +216,13 @@ After: N2: R key=1 parent=N1 L=-- R=-- <- inserted ``` -Left-left, black uncle variant (insert key=1): - -```text -Before: - Header: root=N0 top=N3 next= - N0: B key=10 parent=-- L=N1 R=N2 - N1: R key=5 parent=N0 L=-- R=-- - N2: B key=15 parent=N0 L=-- R=-- - -After: - Header: root=N1 top=-- next= - N0: R key=10 parent=N1 L=-- R=N2 <- recolored R - N1: B key=5 parent=-- L=N3 R=N0 <- recolored B, new root - N2: B key=15 parent=N0 L=-- R=-- - N3: R key=1 parent=N1 L=-- R=-- <- inserted -``` +A non-null black uncle at the same depth as a null uncle is +impossible in a valid red-black tree. The parent is red (otherwise +no fixup triggers), so it contributes 0 to the black height. A +non-null black uncle contributes at least 1. These cannot balance +(RBT-4 violation). A non-null black uncle only appears after +case 2 propagation up the tree, which is covered by the case 2+6 +tests below. Right-right variants: mirror of above (insert key=20, parent is R(15), rotation goes left). @@ -257,22 +248,9 @@ After: N2: B key=7 parent=-- L=N1 R=N0 <- inserted, new root ``` -Left-right, black uncle variant (insert key=7): - -```text -Before: - Header: root=N0 top=N3 next= - N0: B key=10 parent=-- L=N1 R=N2 - N1: R key=5 parent=N0 L=-- R=-- - N2: B key=15 parent=N0 L=-- R=-- - -After: - Header: root=N3 top=-- next= - N0: R key=10 parent=N3 L=-- R=N2 <- recolored R - N1: R key=5 parent=N3 L=-- R=-- - N2: B key=15 parent=N0 L=-- R=-- - N3: B key=7 parent=-- L=N1 R=N0 <- inserted, new root -``` +As with case 6 above, a non-null black uncle at the same depth +is impossible in a valid red-black tree (RBT-4). Case 2+5+6 +tests cover the non-null black uncle scenario via propagation. Right-left variants: mirror of above (insert key=12, parent is R(15), double rotation goes right then left). diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 3a43e60f..f8f78a63 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -301,17 +301,17 @@ unsafe fn insert( // ANCHOR: insert-search let key = ldxh(instruction_data, instruction::INSERT_KEY_OFF); - let mut parent: *mut TreeNode = null_mut(); let mut cursor = (*tree_header).root; // Root is null: new node becomes root. if cursor.is_null() { (*node).color = Color::Red; - (*node).parent = parent; + (*node).parent = null_mut(); (*tree_header).root = node; return SUCCESS; } + let mut parent: *mut TreeNode; loop { parent = cursor; let cursor_key = (*cursor).key; @@ -545,7 +545,35 @@ unsafe fn remove( let _tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); // ANCHOR_END: remove-input-checks - error::KEY_DOES_NOT_EXIST.into() + // ANCHOR: remove-search + let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); + let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); + let mut node = (*tree_header).root; + + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + + loop { + let node_key = (*node).key; + if key > node_key { + node = (*node).child[tree::DIR_R]; + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + } else if key < node_key { + node = (*node).child[tree::DIR_L]; + if node.is_null() { + return error::KEY_DOES_NOT_EXIST.into(); + } + } else { + break; + } + } + // ANCHOR_END: remove-search + + // TODO: successor swap, simple removal, rebalancing, recycle. + 0 } // ANCHOR: initialize-input-checks diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index 4abf5380..a1251c1c 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -239,22 +239,22 @@ fn test_remove_search() { print_comparison_table(remove::RemoveCase::SEARCH_CASES); } -#[test] -fn test_remove_simple() { - print_comparison_table(remove::RemoveCase::SIMPLE_CASES); -} - -#[test] -fn test_remove_successor() { - print_comparison_table(remove::RemoveCase::SUCCESSOR_CASES); -} - -#[test] -fn test_remove_rebalance() { - print_comparison_table(remove::RemoveCase::REBALANCE_CASES); -} - -#[test] -fn test_multi_remove() { - print_comparison_table(remove::MultiRemoveCase::CASES); -} +// #[test] +// fn test_remove_simple() { +// print_comparison_table(remove::RemoveCase::SIMPLE_CASES); +// } + +// #[test] +// fn test_remove_successor() { +// print_comparison_table(remove::RemoveCase::SUCCESSOR_CASES); +// } + +// #[test] +// fn test_remove_rebalance() { +// print_comparison_table(remove::RemoveCase::REBALANCE_CASES); +// } + +// #[test] +// fn test_multi_remove() { +// print_comparison_table(remove::MultiRemoveCase::CASES); +// } diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 393f8165..1c7e73d3 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -125,8 +125,6 @@ .equ INSN_INSERT_KEY_OFF, 1 # Key field in insert instruction. .equ INSN_INSERT_VALUE_OFF, 3 # Value field in insert instruction. .equ INSN_REMOVE_KEY_OFF, 1 # Key field in remove instruction. -# Status value for successful remove (first non-error code). -.equ INSN_REMOVE_STATUS_OK, 15 # Init stack frame layout. # ------------------------ @@ -671,7 +669,6 @@ insert_store_key_value_pair: # ANCHOR: insert-search insert_search: # r9 = node ldxh r4, [r2 + INSN_INSERT_KEY_OFF] # r4 = insn.key; - mov64 r2, NULL # r2 = parent = null; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = cursor = root; jeq r3, NULL, insert_root @@ -687,6 +684,7 @@ insert_root: # Root is null: new node becomes root. # --------------------------------------------------------------------- stb [r9 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # node.color = red; + mov64 r2, NULL # r2 = parent = null; stxdw [r9 + TREE_NODE_PARENT_OFF], r2 # node.parent = null; stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r9 # root = node; exit From 42fe1030f73f120e4ddc7aa69b235613c59d5a69 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:29:53 -0700 Subject: [PATCH 232/263] Implement remove search --- examples/tree/artifacts/dumps/asm.txt | 148 ++++++++++-------- .../artifacts/snippets/asm/remove-search.txt | 25 +++ .../artifacts/tests/remove_search/result.txt | 16 +- examples/tree/src/tree/tree.s | 29 ++++ 4 files changed, 143 insertions(+), 75 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/remove-search.txt diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 5b9491b6..a96f1ca9 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3552 (bytes into file) + Start of section headers 3664 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xde0 +There are 7 section headers, starting at offset 0xe50 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000b58 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000c40 000c40 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000ce0 000ce0 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000d40 000d40 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000d80 000d80 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000db0 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000bc8 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000cb0 000cb0 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000d50 000d50 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000db0 000db0 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000df0 000df0 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000e20 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000b58 0x000b58 R E 0x1000 - LOAD 0x000ce0 0x0000000000000ce0 0x0000000000000ce0 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000c40 0x0000000000000c40 0x0000000000000c40 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000bc8 0x000bc8 R E 0x1000 + LOAD 0x000d50 0x0000000000000d50 0x0000000000000d50 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000cb0 0x0000000000000cb0 0x0000000000000cb0 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xc40 contains 10 entries +Dynamic section at offset 0xcb0 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xd80 + 0x0000000000000011 (REL) 0xdf0 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xce0 + 0x0000000000000006 (SYMTAB) 0xd50 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xd40 + 0x0000000000000005 (STRTAB) 0xdb0 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xd80 contains 3 entries +Relocation section '.rel.dyn' at offset 0xdf0 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000248 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000468 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -92,32 +92,32 @@ Disassembly of section .text 34 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 35 b7 00 00 00 0b 00 00 00 r0 = 0xb 36 95 00 00 00 00 00 00 00 exit - 37 55 09 4c 01 01 00 00 00 if r9 != 0x1 goto +0x14c - 38 55 08 4d 01 04 00 00 00 if r8 != 0x4 goto +0x14d + 37 55 09 5a 01 01 00 00 00 if r9 != 0x1 goto +0x15a + 38 55 08 5b 01 04 00 00 00 if r8 != 0x4 goto +0x15b 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 5d 01 00 00 00 00 if r9 != 0x0 goto +0x15d + 40 55 09 6b 01 00 00 00 00 if r9 != 0x0 goto +0x16b 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 59 01 ff 00 00 00 if r9 != 0xff goto +0x159 + 42 55 09 67 01 ff 00 00 00 if r9 != 0xff goto +0x167 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 55 01 00 00 00 00 if r9 != 0x0 goto +0x155 + 44 55 09 63 01 00 00 00 00 if r9 != 0x0 goto +0x163 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 51 01 ff 00 00 00 if r9 != 0xff goto +0x151 + 46 55 09 5f 01 ff 00 00 00 if r9 != 0xff goto +0x15f 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 4d 01 0e 00 00 00 if r9 != 0xe goto +0x14d + 48 55 09 5b 01 0e 00 00 00 if r9 != 0xe goto +0x15b 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 49 01 ff 00 00 00 if r9 != 0xff goto +0x149 + 50 55 09 57 01 ff 00 00 00 if r9 != 0xff goto +0x157 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 43 01 00 00 00 00 if r9 != r8 goto +0x143 + 54 5d 89 51 01 00 00 00 00 if r9 != r8 goto +0x151 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 3f 01 00 00 00 00 if r9 != r8 goto +0x13f + 58 5d 89 4d 01 00 00 00 00 if r9 != r8 goto +0x14d 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 3b 01 00 00 00 00 if r9 != r8 goto +0x13b + 62 5d 89 49 01 00 00 00 00 if r9 != r8 goto +0x149 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 38 01 00 00 00 00 if r9 != r8 goto +0x138 + 65 5d 89 46 01 00 00 00 00 if r9 != r8 goto +0x146 66 b7 02 00 00 00 00 00 00 r2 = 0x0 67 bf 13 00 00 00 00 00 00 r3 = r1 68 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -128,16 +128,16 @@ Disassembly of section .text 73 85 10 00 00 ff ff ff ff call -0x1 74 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 75 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 76 5d 89 2b 01 00 00 00 00 if r9 != r8 goto +0x12b + 76 5d 89 39 01 00 00 00 00 if r9 != r8 goto +0x139 77 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 78 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 79 5d 89 28 01 00 00 00 00 if r9 != r8 goto +0x128 + 79 5d 89 36 01 00 00 00 00 if r9 != r8 goto +0x136 80 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 81 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 82 5d 89 25 01 00 00 00 00 if r9 != r8 goto +0x125 + 82 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 83 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 84 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 85 5d 89 22 01 00 00 00 00 if r9 != r8 goto +0x122 + 85 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 86 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 87 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -198,15 +198,15 @@ Disassembly of section .text 143 07 07 00 00 18 00 00 00 r7 += 0x18 144 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 145 95 00 00 00 00 00 00 00 exit - 146 55 09 df 00 05 00 00 00 if r9 != 0x5 goto +0xdf - 147 a5 08 e0 00 02 00 00 00 if r8 < 0x2 goto +0xe0 + 146 55 09 ed 00 05 00 00 00 if r9 != 0x5 goto +0xed + 147 a5 08 ee 00 02 00 00 00 if r8 < 0x2 goto +0xee 148 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 149 55 09 f0 00 00 00 00 00 if r9 != 0x0 goto +0xf0 + 149 55 09 fe 00 00 00 00 00 if r9 != 0x0 goto +0xfe 150 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 151 55 09 ec 00 ff 00 00 00 if r9 != 0xff goto +0xec + 151 55 09 fa 00 ff 00 00 00 if r9 != 0xff goto +0xfa 152 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 153 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 154 55 08 db 00 04 00 00 00 if r8 != 0x4 goto +0xdb + 154 55 08 e9 00 04 00 00 00 if r8 != 0x4 goto +0xe9 155 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 156 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 157 bf 97 00 00 00 00 00 00 r7 = r9 @@ -214,23 +214,23 @@ Disassembly of section .text 159 57 09 00 00 f8 ff ff ff r9 &= -0x8 160 0f 19 00 00 00 00 00 00 r9 += r1 161 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 162 55 08 dd 00 ff 00 00 00 if r8 != 0xff goto +0xdd + 162 55 08 eb 00 ff 00 00 00 if r8 != 0xff goto +0xeb 163 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 164 55 08 d9 00 0e 00 00 00 if r8 != 0xe goto +0xd9 + 164 55 08 e7 00 0e 00 00 00 if r8 != 0xe goto +0xe7 165 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 166 55 08 d5 00 ff 00 00 00 if r8 != 0xff goto +0xd5 + 166 55 08 e3 00 ff 00 00 00 if r8 != 0xff goto +0xe3 167 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 168 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 170 5d 48 cf 00 00 00 00 00 if r8 != r4 goto +0xcf + 170 5d 48 dd 00 00 00 00 00 if r8 != r4 goto +0xdd 171 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 172 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 174 5d 48 cb 00 00 00 00 00 if r8 != r4 goto +0xcb + 174 5d 48 d9 00 00 00 00 00 if r8 != r4 goto +0xd9 175 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 176 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 178 5d 48 c7 00 00 00 00 00 if r8 != r4 goto +0xc7 + 178 5d 48 d5 00 00 00 00 00 if r8 != r4 goto +0xd5 179 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 180 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 181 5d 48 c4 00 00 00 00 00 if r8 != r4 goto +0xc4 + 181 5d 48 d2 00 00 00 00 00 if r8 != r4 goto +0xd2 182 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 183 27 08 00 00 1d 00 00 00 r8 *= 0x1d 184 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -409,35 +409,49 @@ Disassembly of section .text 357 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) 358 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d 359 95 00 00 00 00 00 00 00 exit - 360 55 09 09 00 03 00 00 00 if r9 != 0x3 goto +0x9 - 361 a5 08 0a 00 02 00 00 00 if r8 < 0x2 goto +0xa + 360 55 09 17 00 03 00 00 00 if r9 != 0x3 goto +0x17 + 361 a5 08 18 00 02 00 00 00 if r8 < 0x2 goto +0x18 362 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 363 55 09 1a 00 00 00 00 00 if r9 != 0x0 goto +0x1a + 363 55 09 28 00 00 00 00 00 if r9 != 0x0 goto +0x28 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 365 55 09 16 00 ff 00 00 00 if r9 != 0xff goto +0x16 - 366 b7 00 00 00 0f 00 00 00 r0 = 0xf - 367 95 00 00 00 00 00 00 00 exit - 368 b7 00 00 00 09 00 00 00 r0 = 0x9 - 369 95 00 00 00 00 00 00 00 exit - 370 b7 00 00 00 0c 00 00 00 r0 = 0xc - 371 95 00 00 00 00 00 00 00 exit - 372 b7 00 00 00 01 00 00 00 r0 = 0x1 - 373 95 00 00 00 00 00 00 00 exit - 374 b7 00 00 00 0d 00 00 00 r0 = 0xd + 365 55 09 24 00 ff 00 00 00 if r9 != 0xff goto +0x24 + 366 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) + 367 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) + 368 15 03 09 00 00 00 00 00 if r3 == 0x0 goto +0x9 + 369 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) + 370 1d 54 09 00 00 00 00 00 if r4 == r5 goto +0x9 + 371 2d 54 04 00 00 00 00 00 if r4 > r5 goto +0x4 + 372 79 33 08 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x8) + 373 55 03 fb ff 00 00 00 00 if r3 != 0x0 goto -0x5 + 374 b7 00 00 00 0f 00 00 00 r0 = 0xf 375 95 00 00 00 00 00 00 00 exit - 376 b7 00 00 00 0a 00 00 00 r0 = 0xa - 377 95 00 00 00 00 00 00 00 exit - 378 b7 00 00 00 08 00 00 00 r0 = 0x8 + 376 79 33 10 00 00 00 00 00 r3 = *(u64 *)(r3 + 0x10) + 377 55 03 f7 ff 00 00 00 00 if r3 != 0x0 goto -0x9 + 378 b7 00 00 00 0f 00 00 00 r0 = 0xf 379 95 00 00 00 00 00 00 00 exit - 380 b7 00 00 00 07 00 00 00 r0 = 0x7 + 380 b7 00 00 00 00 00 00 00 r0 = 0x0 381 95 00 00 00 00 00 00 00 exit - 382 b7 00 00 00 04 00 00 00 r0 = 0x4 + 382 b7 00 00 00 09 00 00 00 r0 = 0x9 383 95 00 00 00 00 00 00 00 exit - 384 b7 00 00 00 06 00 00 00 r0 = 0x6 + 384 b7 00 00 00 0c 00 00 00 r0 = 0xc 385 95 00 00 00 00 00 00 00 exit - 386 b7 00 00 00 03 00 00 00 r0 = 0x3 + 386 b7 00 00 00 01 00 00 00 r0 = 0x1 387 95 00 00 00 00 00 00 00 exit - 388 b7 00 00 00 05 00 00 00 r0 = 0x5 + 388 b7 00 00 00 0d 00 00 00 r0 = 0xd 389 95 00 00 00 00 00 00 00 exit - 390 b7 00 00 00 02 00 00 00 r0 = 0x2 - 391 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 390 b7 00 00 00 0a 00 00 00 r0 = 0xa + 391 95 00 00 00 00 00 00 00 exit + 392 b7 00 00 00 08 00 00 00 r0 = 0x8 + 393 95 00 00 00 00 00 00 00 exit + 394 b7 00 00 00 07 00 00 00 r0 = 0x7 + 395 95 00 00 00 00 00 00 00 exit + 396 b7 00 00 00 04 00 00 00 r0 = 0x4 + 397 95 00 00 00 00 00 00 00 exit + 398 b7 00 00 00 06 00 00 00 r0 = 0x6 + 399 95 00 00 00 00 00 00 00 exit + 400 b7 00 00 00 03 00 00 00 r0 = 0x3 + 401 95 00 00 00 00 00 00 00 exit + 402 b7 00 00 00 05 00 00 00 r0 = 0x5 + 403 95 00 00 00 00 00 00 00 exit + 404 b7 00 00 00 02 00 00 00 r0 = 0x2 + 405 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-search.txt b/examples/tree/artifacts/snippets/asm/remove-search.txt new file mode 100644 index 00000000..fee63bf5 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-search.txt @@ -0,0 +1,25 @@ +remove_search: + ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = node = root; + jeq r3, NULL, e_key_does_not_exist + +remove_search_loop: + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = node.key; + jeq r4, r5, remove_found + jgt r4, r5, remove_search_r + +remove_search_l: + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = node.child[L]; + jne r3, NULL, remove_search_loop + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + +remove_search_r: + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = node.child[R]; + jne r3, NULL, remove_search_loop + +e_key_does_not_exist: + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + +remove_found: # r3 = found node \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_search/result.txt b/examples/tree/artifacts/tests/remove_search/result.txt index 719dbeae..873e3f2c 100644 --- a/examples/tree/artifacts/tests/remove_search/result.txt +++ b/examples/tree/artifacts/tests/remove_search/result.txt @@ -1,30 +1,30 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Empty tree | 13 | 16 | +3 | +23.1% | -| Not found (left) | 13 | 25 | +12 | +92.3% | -| Not found (right) | 13 | 23 | +10 | +76.9% | -| Not found (deep) | 13 | 30 | +17 | +130.8% | +| Empty tree | 16 | 16 | +0 | +0.0% | +| Not found (left) | 21 | 25 | +4 | +19.0% | +| Not found (right) | 21 | 23 | +2 | +9.5% | +| Not found (deep) | 26 | 30 | +4 | +15.4% | test tests::test_remove_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 1c7e73d3..c2d65ea0 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -884,9 +884,38 @@ remove: jne r9, IB_NON_DUP_MARKER, e_tree_duplicate # ANCHOR_END: remove-input-checks +# ANCHOR: remove-search +remove_search: + ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; + ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = node = root; + jeq r3, NULL, e_key_does_not_exist + +remove_search_loop: + ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = node.key; + jeq r4, r5, remove_found + jgt r4, r5, remove_search_r + +remove_search_l: + ldxdw r3, [r3 + TREE_NODE_CHILD_L_OFF] # r3 = node.child[L]; + jne r3, NULL, remove_search_loop mov64 r0, E_KEY_DOES_NOT_EXIST exit +remove_search_r: + ldxdw r3, [r3 + TREE_NODE_CHILD_R_OFF] # r3 = node.child[R]; + jne r3, NULL, remove_search_loop + +e_key_does_not_exist: + mov64 r0, E_KEY_DOES_NOT_EXIST + exit + +remove_found: # r3 = found node +# ANCHOR_END: remove-search + + # TODO: successor swap, simple removal, rebalancing, recycle. + mov64 r0, 0 + exit + e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From 2de25874a8cab6f2d0784157f839b6975797b91e Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:47:04 -0700 Subject: [PATCH 233/263] Implement remove search with parity --- examples/tree/artifacts/dumps/asm.txt | 6 +++--- examples/tree/artifacts/snippets/asm/remove-search.txt | 2 +- examples/tree/artifacts/snippets/rs/remove-search.txt | 2 +- examples/tree/artifacts/tests/remove_search/result.txt | 4 ++-- examples/tree/src/program.rs | 2 +- examples/tree/src/tree/tree.s | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index a96f1ca9..f00297fc 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -415,9 +415,9 @@ Disassembly of section .text 363 55 09 28 00 00 00 00 00 if r9 != 0x0 goto +0x28 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) 365 55 09 24 00 ff 00 00 00 if r9 != 0xff goto +0x24 - 366 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) - 367 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) - 368 15 03 09 00 00 00 00 00 if r3 == 0x0 goto +0x9 + 366 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) + 367 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa + 368 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) 369 69 35 18 00 00 00 00 00 r5 = *(u16 *)(r3 + 0x18) 370 1d 54 09 00 00 00 00 00 if r4 == r5 goto +0x9 371 2d 54 04 00 00 00 00 00 if r4 > r5 goto +0x4 diff --git a/examples/tree/artifacts/snippets/asm/remove-search.txt b/examples/tree/artifacts/snippets/asm/remove-search.txt index fee63bf5..c253bf91 100644 --- a/examples/tree/artifacts/snippets/asm/remove-search.txt +++ b/examples/tree/artifacts/snippets/asm/remove-search.txt @@ -1,7 +1,7 @@ remove_search: - ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = node = root; jeq r3, NULL, e_key_does_not_exist + ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; remove_search_loop: ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = node.key; diff --git a/examples/tree/artifacts/snippets/rs/remove-search.txt b/examples/tree/artifacts/snippets/rs/remove-search.txt index ca7eb05c..4b152a1d 100644 --- a/examples/tree/artifacts/snippets/rs/remove-search.txt +++ b/examples/tree/artifacts/snippets/rs/remove-search.txt @@ -1,11 +1,11 @@ let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); let mut node = (*tree_header).root; if node.is_null() { return error::KEY_DOES_NOT_EXIST.into(); } + let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); loop { let node_key = (*node).key; if key > node_key { diff --git a/examples/tree/artifacts/tests/remove_search/result.txt b/examples/tree/artifacts/tests/remove_search/result.txt index 873e3f2c..2d327c3b 100644 --- a/examples/tree/artifacts/tests/remove_search/result.txt +++ b/examples/tree/artifacts/tests/remove_search/result.txt @@ -1,12 +1,12 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Empty tree | 16 | 16 | +0 | +0.0% | +| Empty tree | 15 | 16 | +1 | +6.7% | | Not found (left) | 21 | 25 | +4 | +19.0% | | Not found (right) | 21 | 23 | +2 | +9.5% | | Not found (deep) | 26 | 30 | +4 | +15.4% | test tests::test_remove_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 16 of 1400000 compute units diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index f8f78a63..97f398b6 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -547,13 +547,13 @@ unsafe fn remove( // ANCHOR: remove-search let tree_header: *mut TreeHeader = input.add(input_buffer::TREE_DATA_OFF as usize).cast(); - let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); let mut node = (*tree_header).root; if node.is_null() { return error::KEY_DOES_NOT_EXIST.into(); } + let key = ldxh(instruction_data, instruction::REMOVE_KEY_OFF); loop { let node_key = (*node).key; if key > node_key { diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index c2d65ea0..6ffb9a4d 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -886,9 +886,9 @@ remove: # ANCHOR: remove-search remove_search: - ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; ldxdw r3, [r1 + IB_TREE_DATA_ROOT_OFF] # r3 = node = root; jeq r3, NULL, e_key_does_not_exist + ldxh r4, [r2 + INSN_REMOVE_KEY_OFF] # r4 = key; remove_search_loop: ldxh r5, [r3 + TREE_NODE_KEY_OFF] # r5 = node.key; From 748542e40f2c058b780b55bb64b25353fb7679dd Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:06:39 -0700 Subject: [PATCH 234/263] Update specs per Wikipedia --- examples/tree/specs/remove-tests.md | 60 +++++++++++++++++++++++++++++ examples/tree/specs/remove.md | 58 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index bd927c4d..9bd8f020 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -126,6 +126,46 @@ mutates one property, and expects the corresponding error. Search error tests must also verify the tree account data is unchanged after the failed instruction. +## Wikipedia reference -- simple cases + +Verbatim from Wikipedia, preceding the rebalancing algorithm: + +> When the deleted node has 2 children (non-NULL), then we can +> swap its value with its in-order successor (the leftmost child +> of the right subtree), and then delete the successor instead. +> Since the successor is leftmost, it can only have a right +> child (non-NULL) or no child at all. +> +> When the deleted node has only 1 child (non-NULL). In this +> case, just replace the node with its child, and color it +> black. The single child (non-NULL) must be red according to +> conclusion 5, and the deleted node must be black according to +> requirement 3. +> +> When the deleted node has no children (both NULL) and is the +> root, replace it with NULL. The tree is empty. +> +> When the deleted node has no children (both NULL), and is red, +> simply remove the leaf node. +> +> When the deleted node has no children (both NULL), and is +> black, deleting it will create an imbalance, and requires a +> rebalance, as covered in the next section. +> +> **Removal of a black non-root leaf** +> +> The complex case is when N is not the root, colored black and +> has no proper child (⇔ only NULL children). In the first +> iteration, N is replaced by NULL. + +Mapping to test sections: + +- 2-child case → Successor swap tests (#16--#18). +- 1-child case → Simple case 1 tests (#13--#15). +- Root leaf → Simple case 2 test (#10). +- Red leaf → Simple case 3 tests (#11--#12). +- Black leaf → Rebalancing tests (#19--#42). + ## Simple removal cases These cases do not trigger rebalancing. @@ -291,6 +331,26 @@ After remove key=10 (returns value=10): Successor N2 has one child (N3). Simple case 1: replace N2 with N3, recolor N3 black. +## Wikipedia reference -- rebalancing loop invariant + +Verbatim from Wikipedia, following the rebalancing algorithm: + +> The rebalancing loop of the delete operation has the following +> invariant: +> +> At the beginning of each iteration the black height of N +> equals the iteration number minus one, which means that in the +> first iteration it is zero and that N is a true black node in +> higher iterations. +> +> The number of black nodes on the paths through N is one less +> than before the deletion, whereas it is unchanged on all other +> paths, so that there is a black-violation at P if other paths +> exist. +> +> All other properties (including requirement 3) are satisfied +> throughout the tree. + ## Rebalancing cases Entry condition: a black leaf was removed from `parent.child[dir]`. diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index c753b545..8038c2b3 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -84,6 +84,46 @@ two-account path). 1. Recycle the removed node to the free stack. 1. Return `RemoveReturn { value, REMOVE_STATUS_OK }`. +### Wikipedia reference -- simple cases + +Verbatim from Wikipedia, preceding the rebalancing algorithm: + +> When the deleted node has 2 children (non-NULL), then we can +> swap its value with its in-order successor (the leftmost child +> of the right subtree), and then delete the successor instead. +> Since the successor is leftmost, it can only have a right +> child (non-NULL) or no child at all. +> +> When the deleted node has only 1 child (non-NULL). In this +> case, just replace the node with its child, and color it +> black. The single child (non-NULL) must be red according to +> conclusion 5, and the deleted node must be black according to +> requirement 3. +> +> When the deleted node has no children (both NULL) and is the +> root, replace it with NULL. The tree is empty. +> +> When the deleted node has no children (both NULL), and is red, +> simply remove the leaf node. +> +> When the deleted node has no children (both NULL), and is +> black, deleting it will create an imbalance, and requires a +> rebalance, as covered in the next section. +> +> **Removal of a black non-root leaf** +> +> The complex case is when N is not the root, colored black and +> has no proper child (⇔ only NULL children). In the first +> iteration, N is replaced by NULL. + +Mapping to implementation steps: + +- 2-child case → Step 2 (successor swap). +- 1-child case → Step 3, simple case 1. +- Root leaf → Step 3, simple case 2. +- Red leaf → Step 3, simple case 3. +- Black leaf → Step 3, simple case 4 + Step 4 (rebalancing). + ### Step 1 -- search Based on the insert search pattern but without inlined fixup @@ -195,6 +235,24 @@ parent.child[dir] = null ### Step 4 -- rebalancing (simple case 4 only) +Verbatim from Wikipedia, following the rebalancing algorithm: + +> The rebalancing loop of the delete operation has the following +> invariant: +> +> At the beginning of each iteration the black height of N +> equals the iteration number minus one, which means that in the +> first iteration it is zero and that N is a true black node in +> higher iterations. +> +> The number of black nodes on the paths through N is one less +> than before the deletion, whereas it is unchanged on all other +> paths, so that there is a black-violation at P if other paths +> exist. +> +> All other properties (including requirement 3) are satisfied +> throughout the tree. + Entry: `parent` is the former parent of the removed node, `dir` is the direction of the removed node relative to `parent`. From 9f00707f443bc1ff2bf2230d5bcf5eb64e9c3eb8 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 19:46:58 -0700 Subject: [PATCH 235/263] Architect simple remove control flow --- .../snippets/rs/remove-delete-simple-1.txt | 4 +++ examples/tree/specs/remove.md | 30 ++++++++++--------- examples/tree/src/program.rs | 26 ++++++++++++++-- 3 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt diff --git a/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt b/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt new file mode 100644 index 00000000..ac2944da --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt @@ -0,0 +1,4 @@ + let parent = (*node).parent; + if !(*node).child[tree::DIR_L].is_null() { + if !(*node).child[tree::DIR_R].is_null() { + // Simple case 1. \ No newline at end of file diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index 8038c2b3..03bcd24a 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -116,13 +116,13 @@ Verbatim from Wikipedia, preceding the rebalancing algorithm: > has no proper child (⇔ only NULL children). In the first > iteration, N is replaced by NULL. -Mapping to implementation steps: +Mapping to simple cases and implementation steps: -- 2-child case → Step 2 (successor swap). -- 1-child case → Step 3, simple case 1. -- Root leaf → Step 3, simple case 2. -- Red leaf → Step 3, simple case 3. -- Black leaf → Step 3, simple case 4 + Step 4 (rebalancing). +- Simple case 1 (2 children) → Step 2 (successor swap). +- Simple case 2 (1 child) → Step 3. +- Simple case 3 (root leaf) → Step 3. +- Simple case 4 (red leaf) → Step 3. +- Simple case 5 (black leaf) → Step 3 + Step 4 (rebalancing). ### Step 1 -- search @@ -162,10 +162,12 @@ remove_found: Rust uses the existing `search()` function, which has the same logic in compact form. -### Step 2 -- BST delete preparation +### Step 2 -- BST delete preparation (simple case 1) -If `node` has two non-null children, find the in-order successor -(leftmost node in the right subtree) and copy its data: +**Simple case 1 -- two children** (both children non-null): + +Find the in-order successor (leftmost node in the right subtree) +and copy its data: ```text successor = node.child[R] @@ -186,7 +188,7 @@ If `node` originally had zero or one child, this step is skipped. Let `child` be the non-null child of `node` (or null if `node` is a leaf), and `parent = node.parent`. -**Simple case 1 -- one child** (`child != null`): +**Simple case 2 -- one child** (`child != null`): In a valid red-black tree, a node with exactly one child must be black, and the child must be red. Replace node with child and @@ -203,7 +205,7 @@ child.color = Black No rebalancing needed. -**Simple case 2 -- root leaf** (`parent == null`, no children): +**Simple case 3 -- root leaf** (`parent == null`, no children): ```text tree.root = null @@ -211,7 +213,7 @@ tree.root = null No rebalancing needed. -**Simple case 3 -- red leaf** (`node.color == Red`, +**Simple case 4 -- red leaf** (`node.color == Red`, `parent != null`): ```text @@ -220,7 +222,7 @@ parent.child[direction(node)] = null No rebalancing needed. -**Simple case 4 -- black leaf** (`node.color == Black`, +**Simple case 5 -- black leaf** (`node.color == Black`, `parent != null`): Detach the node, then rebalance. The direction must be computed @@ -233,7 +235,7 @@ parent.child[dir] = null # Execute rebalancing with (parent, dir). ``` -### Step 4 -- rebalancing (simple case 4 only) +### Step 4 -- rebalancing (simple case 5 only) Verbatim from Wikipedia, following the rebalancing algorithm: diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 97f398b6..7e77e137 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -572,8 +572,30 @@ unsafe fn remove( } // ANCHOR_END: remove-search - // TODO: successor swap, simple removal, rebalancing, recycle. - 0 + // ANCHOR: remove-delete-simple-1 + let parent = (*node).parent; + if !(*node).child[tree::DIR_L].is_null() { + if !(*node).child[tree::DIR_R].is_null() { + // Simple case 1. + // ANCHOR_END: remove-delete-simple-1 + } else { + // Simple case 2. + return SUCCESS; + } + }; + if !(*node).child[tree::DIR_R].is_null() { + // Simple case 2. + return SUCCESS; + } else if unlikely(parent.is_null()) { + // Simple case 3 + return SUCCESS; + } else if (*node).color == Color::Red { + // Simple case 4. + return SUCCESS; + } else { + // Simple case 5. + }; + SUCCESS } // ANCHOR: initialize-input-checks From 9b33df6f905acb87af32734484e8a913f228e707 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 19:55:56 -0700 Subject: [PATCH 236/263] Add simple remove cases --- .../snippets/rs/remove-delete-simple-1.txt | 4 -- .../artifacts/snippets/rs/remove-simple-1.txt | 14 ++++++ .../artifacts/snippets/rs/remove-simple-2.txt | 10 ++++ examples/tree/src/program.rs | 50 +++++++++++++++---- 4 files changed, 65 insertions(+), 13 deletions(-) delete mode 100644 examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt create mode 100644 examples/tree/artifacts/snippets/rs/remove-simple-1.txt create mode 100644 examples/tree/artifacts/snippets/rs/remove-simple-2.txt diff --git a/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt b/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt deleted file mode 100644 index ac2944da..00000000 --- a/examples/tree/artifacts/snippets/rs/remove-delete-simple-1.txt +++ /dev/null @@ -1,4 +0,0 @@ - let parent = (*node).parent; - if !(*node).child[tree::DIR_L].is_null() { - if !(*node).child[tree::DIR_R].is_null() { - // Simple case 1. \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-1.txt b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt new file mode 100644 index 00000000..73affe1e --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt @@ -0,0 +1,14 @@ + if !(*node).child[tree::DIR_L].is_null() { + if !(*node).child[tree::DIR_R].is_null() { + // Simple case 1: successor swap. + let mut successor = (*node).child[tree::DIR_R]; + loop { + let left = (*successor).child[tree::DIR_L]; + if left.is_null() { + break; + } + successor = left; + } + (*node).key = (*successor).key; + (*node).value = (*successor).value; + node = successor; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-2.txt b/examples/tree/artifacts/snippets/rs/remove-simple-2.txt new file mode 100644 index 00000000..4f283024 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-simple-2.txt @@ -0,0 +1,10 @@ + } else { + // Simple case 2: one child (L). + let child = (*node).child[tree::DIR_L]; + remove_simple_2_child_replace!(node, child, tree_header); + } + }; + if !(*node).child[tree::DIR_R].is_null() { + // Simple case 2: one child (R). + let child = (*node).child[tree::DIR_R]; + remove_simple_2_child_replace!(node, child, tree_header); \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 7e77e137..4bb2e3bb 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -138,6 +138,24 @@ macro_rules! check_cpi_accounts { }; } +macro_rules! remove_simple_2_child_replace { + ($node:expr, $child:expr, $tree_header:expr) => { + let parent = (*$node).parent; + (*$child).parent = parent; + (*$child).color = Color::Black; + if !parent.is_null() { + if $node == (*parent).child[tree::DIR_R] { + (*parent).child[tree::DIR_R] = $child; + } else { + (*parent).child[tree::DIR_L] = $child; + } + } else { + (*$tree_header).root = $child; + } + return SUCCESS; + }; +} + // ANCHOR: entrypoint-branching no_allocator!(); nostd_panic_handler!(); @@ -572,21 +590,35 @@ unsafe fn remove( } // ANCHOR_END: remove-search - // ANCHOR: remove-delete-simple-1 - let parent = (*node).parent; + // ANCHOR: remove-simple-1 if !(*node).child[tree::DIR_L].is_null() { if !(*node).child[tree::DIR_R].is_null() { - // Simple case 1. - // ANCHOR_END: remove-delete-simple-1 + // Simple case 1: successor swap. + let mut successor = (*node).child[tree::DIR_R]; + loop { + let left = (*successor).child[tree::DIR_L]; + if left.is_null() { + break; + } + successor = left; + } + (*node).key = (*successor).key; + (*node).value = (*successor).value; + node = successor; + // ANCHOR_END: remove-simple-1 + // ANCHOR: remove-simple-2 } else { - // Simple case 2. - return SUCCESS; + // Simple case 2: one child (L). + let child = (*node).child[tree::DIR_L]; + remove_simple_2_child_replace!(node, child, tree_header); } }; if !(*node).child[tree::DIR_R].is_null() { - // Simple case 2. - return SUCCESS; - } else if unlikely(parent.is_null()) { + // Simple case 2: one child (R). + let child = (*node).child[tree::DIR_R]; + remove_simple_2_child_replace!(node, child, tree_header); + // ANCHOR_END: remove-simple-2 + } else if unlikely((*node).parent.is_null()) { // Simple case 3 return SUCCESS; } else if (*node).color == Color::Red { From c5983e579a61b5b3c9eb128796c9825343e4e9c2 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:31:13 -0700 Subject: [PATCH 237/263] Update simple remove --- .../artifacts/snippets/rs/remove-complex.txt | 1 + .../artifacts/snippets/rs/remove-simple-1.txt | 8 +- .../artifacts/snippets/rs/remove-simple-3.txt | 4 + .../artifacts/snippets/rs/remove-simple-4.txt | 9 + examples/tree/specs/remove-tests.md | 196 ++++++++++-------- examples/tree/specs/remove.md | 16 +- examples/tree/src/program.rs | 45 +++- examples/tree/src/tests.rs | 13 +- examples/tree/src/tests/remove.rs | 43 +++- 9 files changed, 205 insertions(+), 130 deletions(-) create mode 100644 examples/tree/artifacts/snippets/rs/remove-complex.txt create mode 100644 examples/tree/artifacts/snippets/rs/remove-simple-3.txt create mode 100644 examples/tree/artifacts/snippets/rs/remove-simple-4.txt diff --git a/examples/tree/artifacts/snippets/rs/remove-complex.txt b/examples/tree/artifacts/snippets/rs/remove-complex.txt new file mode 100644 index 00000000..5c6f12f3 --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-complex.txt @@ -0,0 +1 @@ + remove_recycle_node!(node, tree_header); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-1.txt b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt index 73affe1e..e93430f5 100644 --- a/examples/tree/artifacts/snippets/rs/remove-simple-1.txt +++ b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt @@ -9,6 +9,10 @@ } successor = left; } - (*node).key = (*successor).key; - (*node).value = (*successor).value; + // Copy successor's key/value to the found node as a u32 + // pair. The successor's fields are left as-is (insert + // overwrites both when reusing the node from the stack). + let node_kv: *mut u32 = addr_of_mut!((*node).key).cast(); + let successor_kv: *const u32 = addr_of!((*successor).key).cast(); + node_kv.write_unaligned(read_unaligned(successor_kv)); node = successor; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-3.txt b/examples/tree/artifacts/snippets/rs/remove-simple-3.txt new file mode 100644 index 00000000..edc8e40b --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-simple-3.txt @@ -0,0 +1,4 @@ + } else if unlikely((*node).parent.is_null()) { + // Simple case 3: root leaf. + (*tree_header).root = null_mut(); + remove_recycle_node!(node, tree_header); \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-4.txt b/examples/tree/artifacts/snippets/rs/remove-simple-4.txt new file mode 100644 index 00000000..cf38478e --- /dev/null +++ b/examples/tree/artifacts/snippets/rs/remove-simple-4.txt @@ -0,0 +1,9 @@ + } else if (*node).color == Color::Red { + // Simple case 4: red leaf. + let parent = (*node).parent; + if node == (*parent).child[tree::DIR_R] { + (*parent).child[tree::DIR_R] = null_mut(); + } else { + (*parent).child[tree::DIR_L] = null_mut(); + } + remove_recycle_node!(node, tree_header); \ No newline at end of file diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index 9bd8f020..c74c7622 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -160,60 +160,23 @@ Verbatim from Wikipedia, preceding the rebalancing algorithm: Mapping to test sections: -- 2-child case → Successor swap tests (#16--#18). -- 1-child case → Simple case 1 tests (#13--#15). -- Root leaf → Simple case 2 test (#10). -- Red leaf → Simple case 3 tests (#11--#12). -- Black leaf → Rebalancing tests (#19--#42). +- Simple case 1 (2 children) → Successor swap tests (#17--#19). +- Simple case 2 (1 child) → Tests #10--#13. +- Simple case 3 (root leaf) → Test #14. +- Simple case 4 (red leaf) → Tests #15--#16. +- Complex case (black leaf) → Rebalancing tests (#20--#43). ## Simple removal cases These cases do not trigger rebalancing. -### Simple case 2: remove root leaf - -Single-node tree. Root becomes null, node is freed. - -```text -Before: - Header: root=N0 top=-- next=-- - N0: B key=10 val=10 parent=-- L=-- R=-- - -After remove key=10 (returns value=10): - Header: root=-- top=N0 next=-- - N0: key=10 val=10 color=B parent=-- L=-- R=-- <- freed -``` - -`parent` (= `StackNode.next`) is null because the stack was empty. - -### Simple case 3: remove red leaf - -Red leaf with a black parent. Detach the leaf. - -Left child variant (remove key=5): - -```text -Before: - Header: root=N0 top=-- next=-- - N0: B key=10 parent=-- L=N1 R=-- - N1: R key=5 parent=N0 L=-- R=-- - -After: - Header: root=N0 top=N1 next=-- - N0: B key=10 parent=-- L=-- R=-- - N1: key=5 color=R parent=-- L=-- R=-- <- freed -``` - -Right child variant (remove key=15): mirror with N1 as right -child of N0. - -### Simple case 1: node with one child +### Simple case 2: node with one child A node with exactly one child must be black, and the child must be red (RB invariant). Replace the node with its child and recolor the child black. -Right child variant (remove key=10): +Right child at root (remove key=10): ```text Before: @@ -227,7 +190,7 @@ After: N1: B key=15 parent=-- L=-- R=-- <- recolored B, new root ``` -Left child variant (remove key=10, child is N1 at L): +Left child at root (remove key=10, child is N1 at L): ```text Before: @@ -241,7 +204,7 @@ After: N1: B key=5 parent=-- L=-- R=-- <- recolored B, new root ``` -Non-root variant (remove key=15): +Non-root right child (remove key=15): ```text Before: @@ -259,6 +222,61 @@ After: N3: B key=20 parent=N0 L=-- R=-- <- recolored B ``` +Non-root left child (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=N3 R=-- + N2: B key=15 parent=N0 L=-- R=-- + N3: R key=3 parent=N1 L=-- R=-- + +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=N3 R=N2 + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=15 parent=N0 L=-- R=-- + N3: B key=3 parent=N0 L=-- R=-- <- recolored B +``` + +### Simple case 3: remove root leaf + +Single-node tree. Root becomes null, node is freed. + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 val=10 parent=-- L=-- R=-- + +After remove key=10 (returns value=10): + Header: root=-- top=N0 next=-- + N0: key=10 val=10 color=B parent=-- L=-- R=-- <- freed +``` + +`parent` (= `StackNode.next`) is null because the stack was empty. + +### Simple case 4: remove red leaf + +Red leaf with a black parent. Detach the leaf. + +Left child variant (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=-- + N1: R key=5 parent=N0 L=-- R=-- + +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=-- R=-- + N1: key=5 color=R parent=-- L=-- R=-- <- freed +``` + +Right child variant (remove key=15): mirror with N1 as right +child of N0. + ## Successor swap cases When the node to delete has two children, copy key/value from @@ -864,61 +882,57 @@ case 6. | 8 | Not found (right) | | 9 | Not found (deep) | -### Simple removal - -| # | Case | Direction | -| --- | --------------------------------- | --------- | -| 10 | Root leaf (simple case 2) | -- | -| 11 | Red leaf (simple case 3) | L | -| 12 | Red leaf (simple case 3) | R | -| 13 | One child at root (simple case 1) | R child | -| 14 | One child at root (simple case 1) | L child | -| 15 | One child non-root (sc 1) | R child | - -### Successor swap +### Simple removal (no rebalancing) -| # | Case | -| --- | -------------------------- | -| 16 | Immediate right child | -| 17 | Deep left descent | -| 18 | Successor with right child | +| # | Case | Direction | +| --- | ------------------------------- | --------- | +| 10 | One child at root (sc 2) | R child | +| 11 | One child at root (sc 2) | L child | +| 12 | One child non-root (sc 2) | R child | +| 13 | One child non-root (sc 2) | L child | +| 14 | Root leaf (sc 3) | -- | +| 15 | Red leaf (sc 4) | L | +| 16 | Red leaf (sc 4) | R | +| 17 | Successor immediate R (sc 1) | -- | +| 18 | Successor deep L descent (sc 1) | -- | +| 19 | Successor with R child (sc 1) | -- | -### Rebalancing (black leaf removal) +### Rebalancing (complex case, black leaf removal) | # | Path | Dir | | --- | ----------------------------- | --- | -| 19 | Case 4 | L | -| 20 | Case 4 | R | -| 21 | Case 6 | L | -| 22 | Case 6 | R | -| 23 | Case 5 + 6 | L | -| 24 | Case 5 + 6 | R | -| 25 | Case 3 → 4 | L | -| 26 | Case 3 → 4 | R | -| 27 | Case 3 → 6 | L | -| 28 | Case 3 → 6 | R | -| 29 | Case 3 → 5 → 6 | L | -| 30 | Case 3 → 5 → 6 | R | -| 31 | Case 2 (propagate to root) | L | -| 32 | Case 2 (propagate to root) | R | -| 33 | Case 2 → 4 | -- | -| 34 | Case 2 → 6 | -- | -| 35 | Case 6 non-null new_child | L | -| 36 | Case 6 non-null new_child | R | -| 37 | Case 6 parent=root | L | -| 38 | Case 6 parent=root | R | -| 39 | Case 6 parent=GGP left child | L | -| 40 | Case 6 parent=GGP right child | R | -| 41 | Case 3 parent=root | L | -| 42 | Case 3 parent=root | R | +| 20 | Case 4 | L | +| 21 | Case 4 | R | +| 22 | Case 6 | L | +| 23 | Case 6 | R | +| 24 | Case 5 + 6 | L | +| 25 | Case 5 + 6 | R | +| 26 | Case 3 → 4 | L | +| 27 | Case 3 → 4 | R | +| 28 | Case 3 → 6 | L | +| 29 | Case 3 → 6 | R | +| 30 | Case 3 → 5 → 6 | L | +| 31 | Case 3 → 5 → 6 | R | +| 32 | Case 2 (propagate to root) | L | +| 33 | Case 2 (propagate to root) | R | +| 34 | Case 2 → 4 | -- | +| 35 | Case 2 → 6 | -- | +| 36 | Case 6 non-null new_child | L | +| 37 | Case 6 non-null new_child | R | +| 38 | Case 6 parent=root | L | +| 39 | Case 6 parent=root | R | +| 40 | Case 6 parent=GGP left child | L | +| 41 | Case 6 parent=GGP right child | R | +| 42 | Case 3 parent=root | L | +| 43 | Case 3 parent=root | R | ### Multi-step integration | # | Case | | --- | --------------------------------- | -| 43 | Insert 3, remove 1 (minimal) | -| 44 | Insert 7, remove all (full cycle) | -| 45 | Insert-remove-insert (recycling) | +| 44 | Insert 3, remove 1 (minimal) | +| 45 | Insert 7, remove all (full cycle) | +| 46 | Insert-remove-insert (recycling) | ## Multi-step integration tests diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index 03bcd24a..86fc07af 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -16,8 +16,8 @@ The implementation proceeds incrementally: branch, and input validation for both `tree.s` and `program.rs`. 1. **Search.** BST key lookup returning the found node or error. 1. **BST delete preparation and simple removal.** Successor swap, - simple cases 1-4. -1. **Rebalancing.** Simple case 4 fixup loop using + simple cases 1--4. +1. **Rebalancing.** Complex case (black leaf) fixup loop using `rotate_subtree`. 1. **Node recycling and return value.** Free-stack push and `RemoveReturn` encoding. @@ -116,13 +116,13 @@ Verbatim from Wikipedia, preceding the rebalancing algorithm: > has no proper child (⇔ only NULL children). In the first > iteration, N is replaced by NULL. -Mapping to simple cases and implementation steps: +Mapping to cases and implementation steps: - Simple case 1 (2 children) → Step 2 (successor swap). - Simple case 2 (1 child) → Step 3. - Simple case 3 (root leaf) → Step 3. - Simple case 4 (red leaf) → Step 3. -- Simple case 5 (black leaf) → Step 3 + Step 4 (rebalancing). +- Complex case (black leaf) → Step 4 (rebalancing). ### Step 1 -- search @@ -222,7 +222,7 @@ parent.child[direction(node)] = null No rebalancing needed. -**Simple case 5 -- black leaf** (`node.color == Black`, +**Complex case -- black leaf** (`node.color == Black`, `parent != null`): Detach the node, then rebalance. The direction must be computed @@ -235,7 +235,7 @@ parent.child[dir] = null # Execute rebalancing with (parent, dir). ``` -### Step 4 -- rebalancing (simple case 5 only) +### Step 4 -- rebalancing (complex case only) Verbatim from Wikipedia, following the rebalancing algorithm: @@ -514,14 +514,14 @@ Sibling is black, `distant_nephew` is red. `new_child` is ## Key invariants - `direction(node)` requires `node.parent` to be non-null. This - holds at every call site: simple case 4 guarantees a non-null + holds at every call site: the complex case guarantees a non-null parent at entry, and the while condition filters null parents on re-entry. - A node with exactly one child must be black with a red child. This follows from red-black tree properties (equal black height on all paths). - The in-order successor has no left child. It may have a right - child, which is handled by simple case 1 after the swap. + child, which is handled by simple case 2 after the swap. - After case 3 (red sibling rotation), the new sibling is `close_nephew` from before the rotation. The algorithm reassigns `sibling = close_nephew` before checking nephews. diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 4bb2e3bb..bf82a6b9 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -138,6 +138,16 @@ macro_rules! check_cpi_accounts { }; } +macro_rules! remove_recycle_node { + ($node:expr, $tree_header:expr) => { + (*$node).child[tree::DIR_L] = null_mut(); + (*$node).child[tree::DIR_R] = null_mut(); + (*$node).parent = (*$tree_header).top.cast(); + (*$tree_header).top = $node.cast(); + return SUCCESS; + }; +} + macro_rules! remove_simple_2_child_replace { ($node:expr, $child:expr, $tree_header:expr) => { let parent = (*$node).parent; @@ -152,7 +162,7 @@ macro_rules! remove_simple_2_child_replace { } else { (*$tree_header).root = $child; } - return SUCCESS; + remove_recycle_node!($node, $tree_header); }; } @@ -602,8 +612,12 @@ unsafe fn remove( } successor = left; } - (*node).key = (*successor).key; - (*node).value = (*successor).value; + // Copy successor's key/value to the found node as a u32 + // pair. The successor's fields are left as-is (insert + // overwrites both when reusing the node from the stack). + let node_kv: *mut u32 = addr_of_mut!((*node).key).cast(); + let successor_kv: *const u32 = addr_of!((*successor).key).cast(); + node_kv.write_unaligned(read_unaligned(successor_kv)); node = successor; // ANCHOR_END: remove-simple-1 // ANCHOR: remove-simple-2 @@ -618,16 +632,27 @@ unsafe fn remove( let child = (*node).child[tree::DIR_R]; remove_simple_2_child_replace!(node, child, tree_header); // ANCHOR_END: remove-simple-2 + // ANCHOR: remove-simple-3 } else if unlikely((*node).parent.is_null()) { - // Simple case 3 - return SUCCESS; + // Simple case 3: root leaf. + (*tree_header).root = null_mut(); + remove_recycle_node!(node, tree_header); + // ANCHOR_END: remove-simple-3 + // ANCHOR: remove-simple-4 } else if (*node).color == Color::Red { - // Simple case 4. - return SUCCESS; - } else { - // Simple case 5. + // Simple case 4: red leaf. + let parent = (*node).parent; + if node == (*parent).child[tree::DIR_R] { + (*parent).child[tree::DIR_R] = null_mut(); + } else { + (*parent).child[tree::DIR_L] = null_mut(); + } + remove_recycle_node!(node, tree_header); + // ANCHOR_END: remove-simple-4 }; - SUCCESS + // ANCHOR: remove-complex + remove_recycle_node!(node, tree_header); + // ANCHOR_END: remove-complex } // ANCHOR: initialize-input-checks diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index a1251c1c..bbfcc014 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -239,15 +239,10 @@ fn test_remove_search() { print_comparison_table(remove::RemoveCase::SEARCH_CASES); } -// #[test] -// fn test_remove_simple() { -// print_comparison_table(remove::RemoveCase::SIMPLE_CASES); -// } - -// #[test] -// fn test_remove_successor() { -// print_comparison_table(remove::RemoveCase::SUCCESSOR_CASES); -// } +#[test] +fn test_remove_simple() { + print_comparison_table(remove::RemoveCase::SIMPLE_CASES); +} // #[test] // fn test_remove_rebalance() { diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs index 35b01129..dba6b97b 100644 --- a/examples/tree/src/tests/remove.rs +++ b/examples/tree/src/tests/remove.rs @@ -256,8 +256,9 @@ pub(super) enum RemoveCase { SimpleRedLeafR, SimpleOneChildRootR, SimpleOneChildRootL, - SimpleOneChildNonRoot, - // Successor swap (cases 16-18). + SimpleOneChildNonRootR, + SimpleOneChildNonRootL, + // Successor swap (cases 17-19). SuccessorImmediate, SuccessorDeep, SuccessorWithChild, @@ -305,15 +306,13 @@ impl RemoveCase { ]; pub(super) const SIMPLE_CASES: &'static [Self] = &[ + Self::SimpleOneChildRootR, + Self::SimpleOneChildRootL, + Self::SimpleOneChildNonRootR, + Self::SimpleOneChildNonRootL, Self::SimpleRootLeaf, Self::SimpleRedLeafL, Self::SimpleRedLeafR, - Self::SimpleOneChildRootR, - Self::SimpleOneChildRootL, - Self::SimpleOneChildNonRoot, - ]; - - pub(super) const SUCCESSOR_CASES: &'static [Self] = &[ Self::SuccessorImmediate, Self::SuccessorDeep, Self::SuccessorWithChild, @@ -364,7 +363,8 @@ impl TestCase for RemoveCase { Self::SimpleRedLeafR => "Red leaf R (sc 3)", Self::SimpleOneChildRootR => "One child root R (sc 1)", Self::SimpleOneChildRootL => "One child root L (sc 1)", - Self::SimpleOneChildNonRoot => "One child non-root (sc 1)", + Self::SimpleOneChildNonRootR => "One child non-root R (sc 2)", + Self::SimpleOneChildNonRootL => "One child non-root L (sc 2)", Self::SuccessorImmediate => "Successor immediate R", Self::SuccessorDeep => "Successor deep L descent", Self::SuccessorWithChild => "Successor with R child", @@ -594,7 +594,7 @@ impl TestCase for RemoveCase { } // Simple case 1: one child non-root (right child). - Self::SimpleOneChildNonRoot => { + Self::SimpleOneChildNonRootR => { let desc = TreeSpec { root: Some(0), top: None, @@ -617,6 +617,29 @@ impl TestCase for RemoveCase { }; run_remove_success(lang, &desc, 15, &exp) } + Self::SimpleOneChildNonRootL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), Some(3), None), + node(15, B, Some(0), None, None), + node(3, R, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, Some(3), Some(2)), + node(5, B, None, None, None), + node(15, B, Some(0), None, None), + node(3, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, &exp) + } // ----- Successor swap ----- From 81606da5669711ffd5d81b276f7edbbcb3a09eba Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:34:22 -0700 Subject: [PATCH 238/263] Tweak read/write --- examples/tree/artifacts/snippets/rs/remove-simple-1.txt | 6 +++--- examples/tree/src/program.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tree/artifacts/snippets/rs/remove-simple-1.txt b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt index e93430f5..ec13ff51 100644 --- a/examples/tree/artifacts/snippets/rs/remove-simple-1.txt +++ b/examples/tree/artifacts/snippets/rs/remove-simple-1.txt @@ -12,7 +12,7 @@ // Copy successor's key/value to the found node as a u32 // pair. The successor's fields are left as-is (insert // overwrites both when reusing the node from the stack). - let node_kv: *mut u32 = addr_of_mut!((*node).key).cast(); - let successor_kv: *const u32 = addr_of!((*successor).key).cast(); - node_kv.write_unaligned(read_unaligned(successor_kv)); + let node_kv = addr_of_mut!((*node).key).cast::(); + let successor_kv = addr_of!((*successor).key).cast::(); + *node_kv = *successor_kv; node = successor; \ No newline at end of file diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index bf82a6b9..a678abc1 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -615,9 +615,9 @@ unsafe fn remove( // Copy successor's key/value to the found node as a u32 // pair. The successor's fields are left as-is (insert // overwrites both when reusing the node from the stack). - let node_kv: *mut u32 = addr_of_mut!((*node).key).cast(); - let successor_kv: *const u32 = addr_of!((*successor).key).cast(); - node_kv.write_unaligned(read_unaligned(successor_kv)); + let node_kv = addr_of_mut!((*node).key).cast::(); + let successor_kv = addr_of!((*successor).key).cast::(); + *node_kv = *successor_kv; node = successor; // ANCHOR_END: remove-simple-1 // ANCHOR: remove-simple-2 From 959d07ff70f017b721d2b8285e235bbc83d9acce Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:44:52 -0700 Subject: [PATCH 239/263] Incorporate prelim remov algo docs --- docs/src/examples/tree.md | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 0aa59640..b25826bc 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -280,6 +280,52 @@ not available in Rust, since the compiler enforces +## Remove + +### Input checks + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-input-checks.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-input-checks.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + +### Search + +::: details Implementations + +::: code-group + + + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-search.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-search.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + ## :white_check_mark: All tests ::: details `tests.rs` From 40e9bba0f8ad2da9ed7f448c3936f93e41288628 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:44:00 -0700 Subject: [PATCH 240/263] Port simple remove algos --- docs/src/examples/tree.md | 8 - examples/tree/artifacts/dumps/asm.txt | 189 ++++--- examples/tree/artifacts/dumps/rs.txt | 479 ++++++++++-------- examples/tree/artifacts/rs-disassembly.s | 182 +++++-- .../artifacts/snippets/asm/remove-search.txt | 4 +- .../snippets/asm/remove-simple-1.txt | 20 + .../snippets/asm/remove-simple-2.txt | 23 + .../snippets/asm/remove-simple-3.txt | 7 + .../snippets/asm/remove-simple-4.txt | 12 + .../artifacts/tests/remove_search/result.txt | 12 +- .../artifacts/tests/remove_simple/result.txt | 73 +++ .../artifacts/tests/remove_simple/test.txt | 4 + examples/tree/src/tree/tree.s | 88 +++- 13 files changed, 754 insertions(+), 347 deletions(-) create mode 100644 examples/tree/artifacts/snippets/asm/remove-simple-1.txt create mode 100644 examples/tree/artifacts/snippets/asm/remove-simple-2.txt create mode 100644 examples/tree/artifacts/snippets/asm/remove-simple-3.txt create mode 100644 examples/tree/artifacts/snippets/asm/remove-simple-4.txt create mode 100644 examples/tree/artifacts/tests/remove_simple/result.txt create mode 100644 examples/tree/artifacts/tests/remove_simple/test.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index b25826bc..d6110aff 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -326,14 +326,6 @@ not available in Rust, since the compiler enforces -## :white_check_mark: All tests - -::: details `tests.rs` - -<<< ../../../examples/tree/src/tests.rs{rs:line-numbers} - -::: - [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism [pda]: https://solana.com/docs/core/pda [tail call]: https://en.wikipedia.org/wiki/Tail_call diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index f00297fc..e8757780 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3664 (bytes into file) + Start of section headers 3992 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xe50 +There are 7 section headers, starting at offset 0xf98 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000bc8 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000cb0 000cb0 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000d50 000d50 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000db0 000db0 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000df0 000df0 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000e20 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000d10 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000df8 000df8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000e98 000e98 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000ef8 000ef8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000000f38 000f38 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 000f68 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000bc8 0x000bc8 R E 0x1000 - LOAD 0x000d50 0x0000000000000d50 0x0000000000000d50 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000cb0 0x0000000000000cb0 0x0000000000000cb0 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000d10 0x000d10 R E 0x1000 + LOAD 0x000e98 0x0000000000000e98 0x0000000000000e98 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000df8 0x0000000000000df8 0x0000000000000df8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xcb0 contains 10 entries +Dynamic section at offset 0xdf8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xdf0 + 0x0000000000000011 (REL) 0xf38 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xd50 + 0x0000000000000006 (SYMTAB) 0xe98 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xdb0 + 0x0000000000000005 (STRTAB) 0xef8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xdf0 contains 3 entries +Relocation section '.rel.dyn' at offset 0xf38 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000248 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000468 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -92,32 +92,32 @@ Disassembly of section .text 34 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 35 b7 00 00 00 0b 00 00 00 r0 = 0xb 36 95 00 00 00 00 00 00 00 exit - 37 55 09 5a 01 01 00 00 00 if r9 != 0x1 goto +0x15a - 38 55 08 5b 01 04 00 00 00 if r8 != 0x4 goto +0x15b + 37 55 09 83 01 01 00 00 00 if r9 != 0x1 goto +0x183 + 38 55 08 84 01 04 00 00 00 if r8 != 0x4 goto +0x184 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 6b 01 00 00 00 00 if r9 != 0x0 goto +0x16b + 40 55 09 94 01 00 00 00 00 if r9 != 0x0 goto +0x194 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 67 01 ff 00 00 00 if r9 != 0xff goto +0x167 + 42 55 09 90 01 ff 00 00 00 if r9 != 0xff goto +0x190 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 63 01 00 00 00 00 if r9 != 0x0 goto +0x163 + 44 55 09 8c 01 00 00 00 00 if r9 != 0x0 goto +0x18c 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 5f 01 ff 00 00 00 if r9 != 0xff goto +0x15f + 46 55 09 88 01 ff 00 00 00 if r9 != 0xff goto +0x188 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 5b 01 0e 00 00 00 if r9 != 0xe goto +0x15b + 48 55 09 84 01 0e 00 00 00 if r9 != 0xe goto +0x184 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 57 01 ff 00 00 00 if r9 != 0xff goto +0x157 + 50 55 09 80 01 ff 00 00 00 if r9 != 0xff goto +0x180 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 51 01 00 00 00 00 if r9 != r8 goto +0x151 + 54 5d 89 7a 01 00 00 00 00 if r9 != r8 goto +0x17a 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 4d 01 00 00 00 00 if r9 != r8 goto +0x14d + 58 5d 89 76 01 00 00 00 00 if r9 != r8 goto +0x176 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 49 01 00 00 00 00 if r9 != r8 goto +0x149 + 62 5d 89 72 01 00 00 00 00 if r9 != r8 goto +0x172 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 46 01 00 00 00 00 if r9 != r8 goto +0x146 + 65 5d 89 6f 01 00 00 00 00 if r9 != r8 goto +0x16f 66 b7 02 00 00 00 00 00 00 r2 = 0x0 67 bf 13 00 00 00 00 00 00 r3 = r1 68 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -128,16 +128,16 @@ Disassembly of section .text 73 85 10 00 00 ff ff ff ff call -0x1 74 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 75 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 76 5d 89 39 01 00 00 00 00 if r9 != r8 goto +0x139 + 76 5d 89 62 01 00 00 00 00 if r9 != r8 goto +0x162 77 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 78 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 79 5d 89 36 01 00 00 00 00 if r9 != r8 goto +0x136 + 79 5d 89 5f 01 00 00 00 00 if r9 != r8 goto +0x15f 80 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 81 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 82 5d 89 33 01 00 00 00 00 if r9 != r8 goto +0x133 + 82 5d 89 5c 01 00 00 00 00 if r9 != r8 goto +0x15c 83 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 84 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 85 5d 89 30 01 00 00 00 00 if r9 != r8 goto +0x130 + 85 5d 89 59 01 00 00 00 00 if r9 != r8 goto +0x159 86 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 87 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -198,15 +198,15 @@ Disassembly of section .text 143 07 07 00 00 18 00 00 00 r7 += 0x18 144 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 145 95 00 00 00 00 00 00 00 exit - 146 55 09 ed 00 05 00 00 00 if r9 != 0x5 goto +0xed - 147 a5 08 ee 00 02 00 00 00 if r8 < 0x2 goto +0xee + 146 55 09 16 01 05 00 00 00 if r9 != 0x5 goto +0x116 + 147 a5 08 17 01 02 00 00 00 if r8 < 0x2 goto +0x117 148 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 149 55 09 fe 00 00 00 00 00 if r9 != 0x0 goto +0xfe + 149 55 09 27 01 00 00 00 00 if r9 != 0x0 goto +0x127 150 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 151 55 09 fa 00 ff 00 00 00 if r9 != 0xff goto +0xfa + 151 55 09 23 01 ff 00 00 00 if r9 != 0xff goto +0x123 152 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 153 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 154 55 08 e9 00 04 00 00 00 if r8 != 0x4 goto +0xe9 + 154 55 08 12 01 04 00 00 00 if r8 != 0x4 goto +0x112 155 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 156 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 157 bf 97 00 00 00 00 00 00 r7 = r9 @@ -214,23 +214,23 @@ Disassembly of section .text 159 57 09 00 00 f8 ff ff ff r9 &= -0x8 160 0f 19 00 00 00 00 00 00 r9 += r1 161 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 162 55 08 eb 00 ff 00 00 00 if r8 != 0xff goto +0xeb + 162 55 08 14 01 ff 00 00 00 if r8 != 0xff goto +0x114 163 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 164 55 08 e7 00 0e 00 00 00 if r8 != 0xe goto +0xe7 + 164 55 08 10 01 0e 00 00 00 if r8 != 0xe goto +0x110 165 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 166 55 08 e3 00 ff 00 00 00 if r8 != 0xff goto +0xe3 + 166 55 08 0c 01 ff 00 00 00 if r8 != 0xff goto +0x10c 167 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 168 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 170 5d 48 dd 00 00 00 00 00 if r8 != r4 goto +0xdd + 170 5d 48 06 01 00 00 00 00 if r8 != r4 goto +0x106 171 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 172 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 174 5d 48 d9 00 00 00 00 00 if r8 != r4 goto +0xd9 + 174 5d 48 02 01 00 00 00 00 if r8 != r4 goto +0x102 175 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 176 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 178 5d 48 d5 00 00 00 00 00 if r8 != r4 goto +0xd5 + 178 5d 48 fe 00 00 00 00 00 if r8 != r4 goto +0xfe 179 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 180 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 181 5d 48 d2 00 00 00 00 00 if r8 != r4 goto +0xd2 + 181 5d 48 fb 00 00 00 00 00 if r8 != r4 goto +0xfb 182 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 183 27 08 00 00 1d 00 00 00 r8 *= 0x1d 184 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -409,12 +409,12 @@ Disassembly of section .text 357 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) 358 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d 359 95 00 00 00 00 00 00 00 exit - 360 55 09 17 00 03 00 00 00 if r9 != 0x3 goto +0x17 - 361 a5 08 18 00 02 00 00 00 if r8 < 0x2 goto +0x18 + 360 55 09 40 00 03 00 00 00 if r9 != 0x3 goto +0x40 + 361 a5 08 41 00 02 00 00 00 if r8 < 0x2 goto +0x41 362 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 363 55 09 28 00 00 00 00 00 if r9 != 0x0 goto +0x28 + 363 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 365 55 09 24 00 ff 00 00 00 if r9 != 0xff goto +0x24 + 365 55 09 4d 00 ff 00 00 00 if r9 != 0xff goto +0x4d 366 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) 367 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa 368 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) @@ -429,29 +429,70 @@ Disassembly of section .text 377 55 03 f7 ff 00 00 00 00 if r3 != 0x0 goto -0x9 378 b7 00 00 00 0f 00 00 00 r0 = 0xf 379 95 00 00 00 00 00 00 00 exit - 380 b7 00 00 00 00 00 00 00 r0 = 0x0 - 381 95 00 00 00 00 00 00 00 exit - 382 b7 00 00 00 09 00 00 00 r0 = 0x9 - 383 95 00 00 00 00 00 00 00 exit - 384 b7 00 00 00 0c 00 00 00 r0 = 0xc - 385 95 00 00 00 00 00 00 00 exit - 386 b7 00 00 00 01 00 00 00 r0 = 0x1 - 387 95 00 00 00 00 00 00 00 exit - 388 b7 00 00 00 0d 00 00 00 r0 = 0xd - 389 95 00 00 00 00 00 00 00 exit - 390 b7 00 00 00 0a 00 00 00 r0 = 0xa - 391 95 00 00 00 00 00 00 00 exit - 392 b7 00 00 00 08 00 00 00 r0 = 0x8 - 393 95 00 00 00 00 00 00 00 exit - 394 b7 00 00 00 07 00 00 00 r0 = 0x7 - 395 95 00 00 00 00 00 00 00 exit - 396 b7 00 00 00 04 00 00 00 r0 = 0x4 - 397 95 00 00 00 00 00 00 00 exit - 398 b7 00 00 00 06 00 00 00 r0 = 0x6 - 399 95 00 00 00 00 00 00 00 exit - 400 b7 00 00 00 03 00 00 00 r0 = 0x3 - 401 95 00 00 00 00 00 00 00 exit - 402 b7 00 00 00 05 00 00 00 r0 = 0x5 - 403 95 00 00 00 00 00 00 00 exit - 404 b7 00 00 00 02 00 00 00 r0 = 0x2 - 405 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 380 79 34 08 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x8) + 381 15 04 09 00 00 00 00 00 if r4 == 0x0 goto +0x9 + 382 79 35 10 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x10) + 383 15 05 09 00 00 00 00 00 if r5 == 0x0 goto +0x9 + 384 79 54 08 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x8) + 385 15 04 02 00 00 00 00 00 if r4 == 0x0 goto +0x2 + 386 bf 45 00 00 00 00 00 00 r5 = r4 + 387 05 00 fc ff 00 00 00 00 goto -0x4 + 388 61 54 18 00 00 00 00 00 r4 = *(u32 *)(r5 + 0x18) + 389 63 43 18 00 00 00 00 00 *(u32 *)(r3 + 0x18) = r4 + 390 bf 53 00 00 00 00 00 00 r3 = r5 + 391 79 34 10 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x10) + 392 15 04 0c 00 00 00 00 00 if r4 == 0x0 goto +0xc + 393 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 394 7b 54 00 00 00 00 00 00 *(u64 *)(r4 + 0x0) = r5 + 395 72 04 1c 00 00 00 00 00 *(u8 *)(r4 + 0x1c) = 0x0 + 396 15 05 06 00 00 00 00 00 if r5 == 0x0 goto +0x6 + 397 79 56 10 00 00 00 00 00 r6 = *(u64 *)(r5 + 0x10) + 398 5d 63 02 00 00 00 00 00 if r3 != r6 goto +0x2 + 399 7b 45 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = r4 + 400 05 00 10 00 00 00 00 00 goto +0x10 + 401 7b 45 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = r4 + 402 05 00 0e 00 00 00 00 00 goto +0xe + 403 7b 41 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r4 + 404 05 00 0c 00 00 00 00 00 goto +0xc + 405 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 406 55 05 02 00 00 00 00 00 if r5 != 0x0 goto +0x2 + 407 7a 01 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = 0x0 + 408 05 00 08 00 00 00 00 00 goto +0x8 + 409 71 34 1c 00 00 00 00 00 r4 = *(u8 *)(r3 + 0x1c) + 410 55 04 06 00 01 00 00 00 if r4 != 0x1 goto +0x6 + 411 79 54 10 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x10) + 412 5d 43 02 00 00 00 00 00 if r3 != r4 goto +0x2 + 413 7a 05 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = 0x0 + 414 05 00 02 00 00 00 00 00 goto +0x2 + 415 7a 05 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = 0x0 + 416 05 00 00 00 00 00 00 00 goto +0x0 + 417 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 418 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 419 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 420 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 421 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 422 95 00 00 00 00 00 00 00 exit + 423 b7 00 00 00 09 00 00 00 r0 = 0x9 + 424 95 00 00 00 00 00 00 00 exit + 425 b7 00 00 00 0c 00 00 00 r0 = 0xc + 426 95 00 00 00 00 00 00 00 exit + 427 b7 00 00 00 01 00 00 00 r0 = 0x1 + 428 95 00 00 00 00 00 00 00 exit + 429 b7 00 00 00 0d 00 00 00 r0 = 0xd + 430 95 00 00 00 00 00 00 00 exit + 431 b7 00 00 00 0a 00 00 00 r0 = 0xa + 432 95 00 00 00 00 00 00 00 exit + 433 b7 00 00 00 08 00 00 00 r0 = 0x8 + 434 95 00 00 00 00 00 00 00 exit + 435 b7 00 00 00 07 00 00 00 r0 = 0x7 + 436 95 00 00 00 00 00 00 00 exit + 437 b7 00 00 00 04 00 00 00 r0 = 0x4 + 438 95 00 00 00 00 00 00 00 exit + 439 b7 00 00 00 06 00 00 00 r0 = 0x6 + 440 95 00 00 00 00 00 00 00 exit + 441 b7 00 00 00 03 00 00 00 r0 = 0x3 + 442 95 00 00 00 00 00 00 00 exit + 443 b7 00 00 00 05 00 00 00 r0 = 0x5 + 444 95 00 00 00 00 00 00 00 exit + 445 b7 00 00 00 02 00 00 00 r0 = 0x2 + 446 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index f7fe5af3..e158bb4d 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 6000 (bytes into file) + Start of section headers 6536 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x1770 +There are 8 section headers, starting at offset 0x1988 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000d60 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 000e80 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 000e88 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 000e88 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 000e88 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001200 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 00123e 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 000f78 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 001098 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 0010a0 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 0010a0 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 0010a0 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001418 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 001456 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000d60 0x000d60 E 0x8 - LOAD 0x000e80 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x000e88 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x000e88 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000f78 0x000f78 E 0x8 + LOAD 0x001098 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x0010a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x0010a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3424 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 3960 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -109,12 +109,12 @@ Disassembly of section .text 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] 20 55 05 ed 00 01 00 00 00 jne r5, 0x1, +0xed - 28 55 03 92 01 05 00 00 00 jne r3, 0x5, +0x192 - 30 a5 04 93 01 02 00 00 00 jlt r4, 0x2, +0x193 + 28 55 03 d3 01 05 00 00 00 jne r3, 0x5, +0x1d3 + 30 a5 04 d4 01 02 00 00 00 jlt r4, 0x2, +0x1d4 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 93 01 00 00 00 00 jne r3, 0x0, +0x193 + 40 55 03 d4 01 00 00 00 00 jne r3, 0x0, +0x1d4 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 93 01 ff 00 00 00 jne r3, 0xff, +0x193 + 50 55 03 d4 01 ff 00 00 00 jne r3, 0xff, +0x1d4 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] @@ -133,7 +133,7 @@ Disassembly of section .text d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 e0 05 00 09 00 00 00 00 00 ja +0x9 - e8 3d 45 eb 00 00 00 00 00 jge r5, r4, +0xeb + e8 3d 45 2c 01 00 00 00 00 jge r5, r4, +0x12c f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa 100 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 @@ -185,7 +185,7 @@ Disassembly of section .text 270 5d 31 81 00 00 00 00 00 jne r1, r3, +0x81 278 07 02 00 00 10 00 00 00 add64 r2, 0x10 280 05 00 80 00 00 00 00 00 ja +0x80 - 288 55 04 b5 00 04 00 00 00 jne r4, 0x4, +0xb5 + 288 55 04 b8 00 04 00 00 00 jne r4, 0x4, +0xb8 290 9c 13 b8 28 00 00 00 00 ldxdw r3, [r1 + 0x28b8] 298 bf 35 00 00 00 00 00 00 mov64 r5, r3 2a0 07 05 00 00 07 00 00 00 add64 r5, 0x7 @@ -193,11 +193,11 @@ Disassembly of section .text 2b0 bf 14 00 00 00 00 00 00 mov64 r4, r1 2b8 0f 54 00 00 00 00 00 00 add64 r4, r5 2c0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2c8 55 05 46 01 ff 00 00 00 jne r5, 0xff, +0x146 + 2c8 55 05 87 01 ff 00 00 00 jne r5, 0xff, +0x187 2d0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2d8 55 05 46 01 0e 00 00 00 jne r5, 0xe, +0x146 + 2d8 55 05 87 01 0e 00 00 00 jne r5, 0xe, +0x187 2e0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2e8 55 05 46 01 ff 00 00 00 jne r5, 0xff, +0x146 + 2e8 55 05 87 01 ff 00 00 00 jne r5, 0xff, +0x187 2f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 2f8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 300 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 @@ -346,189 +346,256 @@ Disassembly of section .text 778 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] 780 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 788 05 00 57 ff 00 00 00 00 ja -0xa9 - 790 55 05 18 00 02 00 00 00 jne r5, 0x2, +0x18 - 798 55 03 a4 00 03 00 00 00 jne r3, 0x3, +0xa4 - 7a0 a5 04 a5 00 02 00 00 00 jlt r4, 0x2, +0xa5 + 790 55 05 59 00 02 00 00 00 jne r5, 0x2, +0x59 + 798 55 03 e5 00 03 00 00 00 jne r3, 0x3, +0xe5 + 7a0 a5 04 e6 00 02 00 00 00 jlt r4, 0x2, +0xe6 7a8 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 7b0 55 03 a5 00 00 00 00 00 jne r3, 0x0, +0xa5 + 7b0 55 03 e6 00 00 00 00 00 jne r3, 0x0, +0xe6 7b8 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 7c0 55 03 a5 00 ff 00 00 00 jne r3, 0xff, +0xa5 + 7c0 55 03 e6 00 ff 00 00 00 jne r3, 0xff, +0xe6 7c8 b7 00 00 00 0f 00 00 00 mov64 r0, 0xf - 7d0 9c 11 c0 28 00 00 00 00 ldxdw r1, [r1 + 0x28c0] - 7d8 15 01 db ff 00 00 00 00 jeq r1, 0x0, -0x25 - 7e0 3c 22 01 00 00 00 00 00 ldxh w2, [r2 + 0x1] - 7e8 05 00 02 00 00 00 00 00 ja +0x2 - 7f0 9c 11 10 00 00 00 00 00 ldxdw r1, [r1 + 0x10] - 7f8 15 01 d7 ff 00 00 00 00 jeq r1, 0x0, -0x29 - 800 3c 13 18 00 00 00 00 00 ldxh w3, [r1 + 0x18] - 808 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 810 2d 34 fb ff 00 00 00 00 jgt r4, r3, -0x5 - 818 3d 34 bc ff 00 00 00 00 jge r4, r3, -0x44 - 820 9c 11 08 00 00 00 00 00 ldxdw r1, [r1 + 0x8] - 828 55 01 fa ff 00 00 00 00 jne r1, 0x0, -0x6 - 830 05 00 d0 ff 00 00 00 00 ja -0x30 - 838 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd - 840 05 00 ce ff 00 00 00 00 ja -0x32 - 848 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - 850 05 00 cc ff 00 00 00 00 ja -0x34 - 858 bf 18 00 00 00 00 00 00 mov64 r8, r1 - 860 55 05 9d 00 00 00 00 00 jne r5, 0x0, +0x9d - 868 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a - 870 55 04 8b 00 04 00 00 00 jne r4, 0x4, +0x8b - 878 9c 81 58 00 00 00 00 00 ldxdw r1, [r8 + 0x58] - 880 55 01 8b 00 00 00 00 00 jne r1, 0x0, +0x8b - 888 2c 81 68 28 00 00 00 00 ldxb w1, [r8 + 0x2868] - 890 55 01 8b 00 ff 00 00 00 jne r1, 0xff, +0x8b - 898 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - 8a0 55 01 93 00 00 00 00 00 jne r1, 0x0, +0x93 - 8a8 2c 81 c8 50 00 00 00 00 ldxb w1, [r8 + 0x50c8] - 8b0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 - 8b8 9c 81 18 51 00 00 00 00 ldxdw r1, [r8 + 0x5118] - 8c0 55 01 89 00 0e 00 00 00 jne r1, 0xe, +0x89 - 8c8 2c 81 38 79 00 00 00 00 ldxb w1, [r8 + 0x7938] - 8d0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 - 8d8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - 8e0 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 - 8e8 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 - 8f0 9c 82 40 79 00 00 00 00 ldxdw r2, [r8 + 0x7940] - 8f8 5d 12 b7 ff 00 00 00 00 jne r2, r1, -0x49 - 900 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 - 908 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d - 910 9c 82 48 79 00 00 00 00 ldxdw r2, [r8 + 0x7948] - 918 5d 12 b3 ff 00 00 00 00 jne r2, r1, -0x4d - 920 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 - 928 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b - 930 9c 82 50 79 00 00 00 00 ldxdw r2, [r8 + 0x7950] - 938 5d 12 af ff 00 00 00 00 jne r2, r1, -0x51 - 940 bf 87 00 00 00 00 00 00 mov64 r7, r8 - 948 9c 71 58 79 00 00 00 00 ldxdw r1, [r7 + 0x7958] - 950 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d - 958 5d 21 ab ff 00 00 00 00 jne r1, r2, -0x55 - 960 bf 76 00 00 00 00 00 00 mov64 r6, r7 - 968 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - 970 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 978 07 04 00 00 68 00 00 00 add64 r4, 0x68 - 980 bf a5 00 00 00 00 00 00 mov64 r5, r10 - 988 07 05 00 00 0f 00 00 00 add64 r5, 0xf - 990 bf 71 00 00 00 00 00 00 mov64 r1, r7 - 998 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - 9a0 bf 63 00 00 00 00 00 00 mov64 r3, r6 - 9a8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - 9b0 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - 9b8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - 9c0 5d 21 6d 00 00 00 00 00 jne r1, r2, +0x6d - 9c8 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - 9d0 9c 82 78 28 00 00 00 00 ldxdw r2, [r8 + 0x2878] - 9d8 5d 21 6a 00 00 00 00 00 jne r1, r2, +0x6a - 9e0 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - 9e8 9c 82 80 28 00 00 00 00 ldxdw r2, [r8 + 0x2880] - 9f0 5d 21 67 00 00 00 00 00 jne r1, r2, +0x67 - 9f8 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - a00 9c 82 88 28 00 00 00 00 ldxdw r2, [r8 + 0x2888] - a08 5d 21 64 00 00 00 00 00 jne r1, r2, +0x64 - a10 bf 81 00 00 00 00 00 00 mov64 r1, r8 - a18 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - a20 9c 82 90 79 00 00 00 00 ldxdw r2, [r8 + 0x7990] - a28 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - a30 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - a38 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - a40 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - a48 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - a50 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - a58 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - a60 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - a68 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - a70 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - a78 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - a80 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - a88 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - a90 bf 82 00 00 00 00 00 00 mov64 r2, r8 - a98 07 02 00 00 10 00 00 00 add64 r2, 0x10 - aa0 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - aa8 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - ab0 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - ab8 bf 83 00 00 00 00 00 00 mov64 r3, r8 - ac0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - ac8 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - ad0 bf 83 00 00 00 00 00 00 mov64 r3, r8 - ad8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - ae0 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - ae8 bf 83 00 00 00 00 00 00 mov64 r3, r8 - af0 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - af8 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - b00 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - b08 bf 81 00 00 00 00 00 00 mov64 r1, r8 - b10 07 01 00 00 30 00 00 00 add64 r1, 0x30 - b18 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - b20 bf 81 00 00 00 00 00 00 mov64 r1, r8 - b28 07 01 00 00 60 00 00 00 add64 r1, 0x60 - b30 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - b38 bf 81 00 00 00 00 00 00 mov64 r1, r8 - b40 07 01 00 00 50 00 00 00 add64 r1, 0x50 - b48 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - b50 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - b58 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - b60 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - b68 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - b70 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - b78 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - b80 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - b88 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - b90 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - b98 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - ba0 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - ba8 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - bb0 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - bb8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bc0 07 01 00 00 10 00 00 00 add64 r1, 0x10 - bc8 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - bd0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bd8 07 01 00 00 48 00 00 00 add64 r1, 0x48 - be0 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - be8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - bf0 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - bf8 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - c00 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - c08 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - c10 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c18 07 01 00 00 0f 00 00 00 add64 r1, 0xf - c20 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - c28 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - c30 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c38 07 01 00 00 20 01 00 00 add64 r1, 0x120 - c40 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - c48 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - c50 bf a1 00 00 00 00 00 00 mov64 r1, r10 - c58 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - c60 bf a2 00 00 00 00 00 00 mov64 r2, r10 - c68 07 02 00 00 68 00 00 00 add64 r2, 0x68 - c70 bf a4 00 00 00 00 00 00 mov64 r4, r10 - c78 07 04 00 00 30 01 00 00 add64 r4, 0x130 - c80 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - c88 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - c90 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - c98 bf 81 00 00 00 00 00 00 mov64 r1, r8 - ca0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - ca8 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - cb0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - cb8 05 00 3f ff 00 00 00 00 ja -0xc1 - cc0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - cc8 05 00 3d ff 00 00 00 00 ja -0xc3 - cd0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - cd8 05 00 3b ff 00 00 00 00 ja -0xc5 - ce0 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - ce8 05 00 39 ff 00 00 00 00 ja -0xc7 - cf0 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - cf8 05 00 37 ff 00 00 00 00 ja -0xc9 - d00 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - d08 05 00 35 ff 00 00 00 00 ja -0xcb - d10 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - d18 05 00 33 ff 00 00 00 00 ja -0xcd - d20 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - d28 05 00 31 ff 00 00 00 00 ja -0xcf - d30 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - d38 05 00 2f ff 00 00 00 00 ja -0xd1 - d40 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - d48 05 00 2d ff 00 00 00 00 ja -0xd3 - d50 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - d58 05 00 2b ff 00 00 00 00 ja -0xd5 \ No newline at end of file + 7d0 9c 14 c0 28 00 00 00 00 ldxdw r4, [r1 + 0x28c0] + 7d8 15 04 db ff 00 00 00 00 jeq r4, 0x0, -0x25 + 7e0 bf 13 00 00 00 00 00 00 mov64 r3, r1 + 7e8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 7f0 3c 25 01 00 00 00 00 00 ldxh w5, [r2 + 0x1] + 7f8 05 00 02 00 00 00 00 00 ja +0x2 + 800 9c 44 10 00 00 00 00 00 ldxdw r4, [r4 + 0x10] + 808 15 04 d5 ff 00 00 00 00 jeq r4, 0x0, -0x2b + 810 3c 46 18 00 00 00 00 00 ldxh w6, [r4 + 0x18] + 818 bf 57 00 00 00 00 00 00 mov64 r7, r5 + 820 2d 67 fb ff 00 00 00 00 jgt r7, r6, -0x5 + 828 9c 42 08 00 00 00 00 00 ldxdw r2, [r4 + 0x8] + 830 3d 67 05 00 00 00 00 00 jge r7, r6, +0x5 + 838 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 840 55 02 f9 ff 00 00 00 00 jne r2, 0x0, -0x7 + 848 05 00 cd ff 00 00 00 00 ja -0x33 + 850 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd + 858 05 00 cb ff 00 00 00 00 ja -0x35 + 860 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 + 868 9c 45 10 00 00 00 00 00 ldxdw r5, [r4 + 0x10] + 870 15 05 1d 00 00 00 00 00 jeq r5, 0x0, +0x1d + 878 bf 52 00 00 00 00 00 00 mov64 r2, r5 + 880 9c 25 08 00 00 00 00 00 ldxdw r5, [r2 + 0x8] + 888 55 05 fd ff 00 00 00 00 jne r5, 0x0, -0x3 + 890 8c 25 18 00 00 00 00 00 ldxw w5, [r2 + 0x18] + 898 8f 54 18 00 00 00 00 00 stxw [r4 + 0x18], w5 + 8a0 05 00 01 00 00 00 00 00 ja +0x1 + 8a8 bf 42 00 00 00 00 00 00 mov64 r2, r4 + 8b0 9c 25 00 00 00 00 00 00 ldxdw r5, [r2 + 0x0] + 8b8 bf 24 00 00 00 00 00 00 mov64 r4, r2 + 8c0 07 04 00 00 08 00 00 00 add64 r4, 0x8 + 8c8 9c 20 10 00 00 00 00 00 ldxdw r0, [r2 + 0x10] + 8d0 15 00 07 00 00 00 00 00 jeq r0, 0x0, +0x7 + 8d8 9f 50 00 00 00 00 00 00 stxdw [r0 + 0x0], r5 + 8e0 27 00 1c 00 00 00 00 00 stb [r0 + 0x1c], 0x0 + 8e8 15 05 1a 00 00 00 00 00 jeq r5, 0x0, +0x1a + 8f0 9c 53 10 00 00 00 00 00 ldxdw r3, [r5 + 0x10] + 8f8 1d 32 16 00 00 00 00 00 jeq r2, r3, +0x16 + 900 07 05 00 00 08 00 00 00 add64 r5, 0x8 + 908 05 00 15 00 00 00 00 00 ja +0x15 + 910 15 05 c4 00 00 00 00 00 jeq r5, 0x0, +0xc4 + 918 2c 23 1c 00 00 00 00 00 ldxb w3, [r2 + 0x1c] + 920 55 03 14 00 01 00 00 00 jne r3, 0x1, +0x14 + 928 9c 50 10 00 00 00 00 00 ldxdw r0, [r5 + 0x10] + 930 b7 03 00 00 10 00 00 00 mov64 r3, 0x10 + 938 1d 02 01 00 00 00 00 00 jeq r2, r0, +0x1 + 940 b7 03 00 00 08 00 00 00 mov64 r3, 0x8 + 948 0f 35 00 00 00 00 00 00 add64 r5, r3 + 950 97 05 00 00 00 00 00 00 stdw [r5 + 0x0], 0x0 + 958 05 00 0d 00 00 00 00 00 ja +0xd + 960 bf 45 00 00 00 00 00 00 mov64 r5, r4 + 968 07 05 00 00 08 00 00 00 add64 r5, 0x8 + 970 9c 40 00 00 00 00 00 00 ldxdw r0, [r4 + 0x0] + 978 9f 02 00 00 00 00 00 00 stxdw [r2 + 0x0], r0 + 980 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 988 15 00 10 00 00 00 00 00 jeq r0, 0x0, +0x10 + 990 9c 03 10 00 00 00 00 00 ldxdw r3, [r0 + 0x10] + 998 1d 34 0c 00 00 00 00 00 jeq r4, r3, +0xc + 9a0 07 00 00 00 08 00 00 00 add64 r0, 0x8 + 9a8 05 00 0b 00 00 00 00 00 ja +0xb + 9b0 07 05 00 00 10 00 00 00 add64 r5, 0x10 + 9b8 bf 53 00 00 00 00 00 00 mov64 r3, r5 + 9c0 9f 03 00 00 00 00 00 00 stxdw [r3 + 0x0], r0 + 9c8 97 04 08 00 00 00 00 00 stdw [r4 + 0x8], 0x0 + 9d0 97 04 00 00 00 00 00 00 stdw [r4 + 0x0], 0x0 + 9d8 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] + 9e0 9f 32 00 00 00 00 00 00 stxdw [r2 + 0x0], r3 + 9e8 9f 21 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r2 + 9f0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 9f8 05 00 97 ff 00 00 00 00 ja -0x69 + a00 07 00 00 00 10 00 00 00 add64 r0, 0x10 + a08 bf 03 00 00 00 00 00 00 mov64 r3, r0 + a10 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + a18 97 05 08 00 00 00 00 00 stdw [r5 + 0x8], 0x0 + a20 97 05 00 00 00 00 00 00 stdw [r5 + 0x0], 0x0 + a28 9c 12 c8 28 00 00 00 00 ldxdw r2, [r1 + 0x28c8] + a30 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + a38 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 + a40 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + a48 05 00 8d ff 00 00 00 00 ja -0x73 + a50 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + a58 05 00 8b ff 00 00 00 00 ja -0x75 + a60 bf 18 00 00 00 00 00 00 mov64 r8, r1 + a68 55 05 9f 00 00 00 00 00 jne r5, 0x0, +0x9f + a70 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a + a78 55 04 8b 00 04 00 00 00 jne r4, 0x4, +0x8b + a80 9c 81 58 00 00 00 00 00 ldxdw r1, [r8 + 0x58] + a88 55 01 8b 00 00 00 00 00 jne r1, 0x0, +0x8b + a90 2c 81 68 28 00 00 00 00 ldxb w1, [r8 + 0x2868] + a98 55 01 8b 00 ff 00 00 00 jne r1, 0xff, +0x8b + aa0 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + aa8 55 01 95 00 00 00 00 00 jne r1, 0x0, +0x95 + ab0 2c 81 c8 50 00 00 00 00 ldxb w1, [r8 + 0x50c8] + ab8 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + ac0 9c 81 18 51 00 00 00 00 ldxdw r1, [r8 + 0x5118] + ac8 55 01 89 00 0e 00 00 00 jne r1, 0xe, +0x89 + ad0 2c 81 38 79 00 00 00 00 ldxb w1, [r8 + 0x7938] + ad8 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + ae0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + ae8 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 + af0 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 + af8 9c 82 40 79 00 00 00 00 ldxdw r2, [r8 + 0x7940] + b00 5d 12 76 ff 00 00 00 00 jne r2, r1, -0x8a + b08 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 + b10 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d + b18 9c 82 48 79 00 00 00 00 ldxdw r2, [r8 + 0x7948] + b20 5d 12 72 ff 00 00 00 00 jne r2, r1, -0x8e + b28 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 + b30 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b + b38 9c 82 50 79 00 00 00 00 ldxdw r2, [r8 + 0x7950] + b40 5d 12 6e ff 00 00 00 00 jne r2, r1, -0x92 + b48 bf 87 00 00 00 00 00 00 mov64 r7, r8 + b50 9c 71 58 79 00 00 00 00 ldxdw r1, [r7 + 0x7958] + b58 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d + b60 5d 21 6a ff 00 00 00 00 jne r1, r2, -0x96 + b68 bf 76 00 00 00 00 00 00 mov64 r6, r7 + b70 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + b78 bf a4 00 00 00 00 00 00 mov64 r4, r10 + b80 07 04 00 00 68 00 00 00 add64 r4, 0x68 + b88 bf a5 00 00 00 00 00 00 mov64 r5, r10 + b90 07 05 00 00 0f 00 00 00 add64 r5, 0xf + b98 bf 71 00 00 00 00 00 00 mov64 r1, r7 + ba0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + ba8 bf 63 00 00 00 00 00 00 mov64 r3, r6 + bb0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + bb8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] + bc0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + bc8 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f + bd0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] + bd8 9c 82 78 28 00 00 00 00 ldxdw r2, [r8 + 0x2878] + be0 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c + be8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] + bf0 9c 82 80 28 00 00 00 00 ldxdw r2, [r8 + 0x2880] + bf8 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 + c00 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] + c08 9c 82 88 28 00 00 00 00 ldxdw r2, [r8 + 0x2888] + c10 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 + c18 bf 81 00 00 00 00 00 00 mov64 r1, r8 + c20 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + c28 9c 82 90 79 00 00 00 00 ldxdw r2, [r8 + 0x7990] + c30 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + c38 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 + c40 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + c48 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 + c50 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + c58 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 + c60 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + c68 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 + c70 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + c78 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 + c80 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 + c88 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 + c90 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 + c98 bf 82 00 00 00 00 00 00 mov64 r2, r8 + ca0 07 02 00 00 10 00 00 00 add64 r2, 0x10 + ca8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 + cb0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 + cb8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 + cc0 bf 83 00 00 00 00 00 00 mov64 r3, r8 + cc8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + cd0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 + cd8 bf 83 00 00 00 00 00 00 mov64 r3, r8 + ce0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + ce8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 + cf0 bf 83 00 00 00 00 00 00 mov64 r3, r8 + cf8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + d00 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 + d08 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 + d10 bf 81 00 00 00 00 00 00 mov64 r1, r8 + d18 07 01 00 00 30 00 00 00 add64 r1, 0x30 + d20 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 + d28 bf 81 00 00 00 00 00 00 mov64 r1, r8 + d30 07 01 00 00 60 00 00 00 add64 r1, 0x60 + d38 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 + d40 bf 81 00 00 00 00 00 00 mov64 r1, r8 + d48 07 01 00 00 50 00 00 00 add64 r1, 0x50 + d50 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 + d58 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 + d60 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 + d68 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 + d70 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 + d78 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 + d80 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 + d88 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 + d90 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + d98 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 + da0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + da8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 + db0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 + db8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 + dc0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + dc8 07 01 00 00 10 00 00 00 add64 r1, 0x10 + dd0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 + dd8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + de0 07 01 00 00 48 00 00 00 add64 r1, 0x48 + de8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 + df0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + df8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 + e00 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 + e08 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 + e10 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 + e18 bf a1 00 00 00 00 00 00 mov64 r1, r10 + e20 07 01 00 00 0f 00 00 00 add64 r1, 0xf + e28 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 + e30 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 + e38 bf a1 00 00 00 00 00 00 mov64 r1, r10 + e40 07 01 00 00 20 01 00 00 add64 r1, 0x120 + e48 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 + e50 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 + e58 bf a1 00 00 00 00 00 00 mov64 r1, r10 + e60 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 + e68 bf a2 00 00 00 00 00 00 mov64 r2, r10 + e70 07 02 00 00 68 00 00 00 add64 r2, 0x68 + e78 bf a4 00 00 00 00 00 00 mov64 r4, r10 + e80 07 04 00 00 30 01 00 00 add64 r4, 0x130 + e88 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + e90 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + e98 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + ea0 bf 81 00 00 00 00 00 00 mov64 r1, r8 + ea8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + eb0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + eb8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + ec0 05 00 fe fe 00 00 00 00 ja -0x102 + ec8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + ed0 05 00 fc fe 00 00 00 00 ja -0x104 + ed8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + ee0 05 00 fa fe 00 00 00 00 ja -0x106 + ee8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + ef0 05 00 f8 fe 00 00 00 00 ja -0x108 + ef8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + f00 05 00 f6 fe 00 00 00 00 ja -0x10a + f08 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + f10 05 00 f4 fe 00 00 00 00 ja -0x10c + f18 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + f20 05 00 f2 fe 00 00 00 00 ja -0x10e + f28 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + f30 05 00 f0 fe 00 00 00 00 ja -0x110 + f38 97 01 c0 28 00 00 00 00 stdw [r1 + 0x28c0], 0x0 + f40 05 00 50 ff 00 00 00 00 ja -0xb0 + f48 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + f50 05 00 ec fe 00 00 00 00 ja -0x114 + f58 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + f60 05 00 ea fe 00 00 00 00 ja -0x116 + f68 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + f70 05 00 e8 fe 00 00 00 00 ja -0x118 \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 0f855acb..1eab8172 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -6,12 +6,12 @@ entrypoint: ldxdw r3, [r2-8] ldxb r5, [r2+0] jne r5, 1, jmp_0780 - jne r3, 5, jmp_0cb0 - jlt r4, 2, jmp_0cc0 + jne r3, 5, jmp_0e90 + jlt r4, 2, jmp_0ea0 ldxdw r3, [r1+88] - jne r3, 0, jmp_0cd0 + jne r3, 0, jmp_0eb0 ldxb r3, [r1+10344] - jne r3, 255, jmp_0ce0 + jne r3, 255, jmp_0ec0 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] @@ -36,7 +36,7 @@ jmp_00b0: ja jmp_0120 jmp_00e8: - jge r5, r4, jmp_0838 + jge r5, r4, jmp_0a18 ldxdw r4, [r2+8] jne r4, 0, jmp_00b0 stxdw [r3+0], r2 @@ -106,7 +106,7 @@ jmp_0268: ja jmp_0698 jmp_0278: - jne r4, 4, jmp_0828 + jne r4, 4, jmp_0830 ldxdw r3, [r1+10424] mov64 r5, r3 add64 r5, 7 @@ -114,11 +114,11 @@ jmp_0278: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0cf0 + jne r5, 255, jmp_0ed0 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0d00 + jne r5, 14, jmp_0ee0 ldxb r5, [r4+31032] - jne r5, 255, jmp_0d10 + jne r5, 255, jmp_0ef0 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 @@ -297,57 +297,143 @@ jmp_0738: ja jmp_0238 jmp_0780: - jne r5, 2, jmp_0848 - jne r3, 3, jmp_0cb0 - jlt r4, 2, jmp_0cc0 + jne r5, 2, jmp_0a28 + jne r3, 3, jmp_0e90 + jlt r4, 2, jmp_0ea0 ldxdw r3, [r1+88] - jne r3, 0, jmp_0cd0 + jne r3, 0, jmp_0eb0 ldxb r3, [r1+10344] - jne r3, 255, jmp_0ce0 + jne r3, 255, jmp_0ec0 mov64 r0, 15 - ldxdw r1, [r1+10432] - jeq r1, 0, jmp_06a8 - ldxh r2, [r2+1] + ldxdw r3, [r1+10432] + jeq r3, 0, jmp_06a8 + ldxh r4, [r2+1] ja jmp_07f0 jmp_07e0: - ldxdw r1, [r1+16] - jeq r1, 0, jmp_06a8 + ldxdw r3, [r3+16] + jeq r3, 0, jmp_06a8 jmp_07f0: - ldxh r3, [r1+24] - mov64 r4, r2 - jgt r4, r3, jmp_07e0 - jge r4, r3, jmp_05f0 - ldxdw r1, [r1+8] - jne r1, 0, jmp_07f0 + ldxh r5, [r3+24] + mov64 r6, r4 + jgt r6, r5, jmp_07e0 + ldxdw r2, [r3+8] + jge r6, r5, jmp_0840 + mov64 r3, r2 + jne r2, 0, jmp_07f0 ja jmp_06a8 -jmp_0828: +jmp_0830: mov64 r0, 13 ja jmp_06a8 -jmp_0838: +jmp_0840: + jeq r2, 0, jmp_0888 + ldxdw r4, [r3+16] + jeq r4, 0, jmp_0928 + +jmp_0858: + mov64 r2, r4 + ldxdw r4, [r2+8] + jne r4, 0, jmp_0858 + ldxw r4, [r2+24] + stxw [r3+24], r4 + ja jmp_0890 + +jmp_0888: + mov64 r2, r3 + +jmp_0890: + ldxdw r4, [r2+0] + mov64 r3, r2 + add64 r3, 8 + ldxdw r5, [r2+16] + jeq r5, 0, jmp_08f0 + stxdw [r5+0], r4 + stb [r5+28], 0 + jeq r4, 0, jmp_0978 + ldxdw r0, [r4+16] + jeq r2, r0, jmp_0988 + stxdw [r4+8], r5 + ja jmp_09e8 + +jmp_08f0: + jeq r4, 0, jmp_0f00 + ldxb r5, [r2+28] + jne r5, 1, jmp_09e8 + ldxdw r5, [r4+16] + jeq r2, r5, jmp_09e0 + stdw [r4+8], 0 + ja jmp_09e8 + +jmp_0928: + mov64 r4, r3 + add64 r4, 8 + ldxdw r5, [r3+0] + stxdw [r2+0], r5 + stb [r2+28], 0 + jeq r5, 0, jmp_0998 + ldxdw r0, [r5+16] + jeq r3, r0, jmp_09a8 + stxdw [r5+8], r2 + ja jmp_09b0 + +jmp_0978: + stxdw [r1+10432], r5 + ja jmp_09e8 + +jmp_0988: + stxdw [r4+16], r5 + ja jmp_09e8 + +jmp_0998: + stxdw [r1+10432], r2 + ja jmp_09b0 + +jmp_09a8: + stxdw [r5+16], r2 + +jmp_09b0: + stdw [r4+8], 0 + stdw [r4+0], 0 + ldxdw r2, [r1+10440] + stxdw [r3+0], r2 + stxdw [r1+10440], r3 + ja jmp_05f0 + +jmp_09e0: + stdw [r4+16], 0 + +jmp_09e8: + stdw [r3+8], 0 + stdw [r3+0], 0 + ldxdw r3, [r1+10440] + stxdw [r2+0], r3 + stxdw [r1+10440], r2 + ja jmp_05f0 + +jmp_0a18: mov64 r0, 14 ja jmp_06a8 -jmp_0848: +jmp_0a28: mov64 r8, r1 - jne r5, 0, jmp_0d30 - jne r3, 1, jmp_0cb0 - jne r4, 4, jmp_0cc0 + jne r5, 0, jmp_0f20 + jne r3, 1, jmp_0e90 + jne r4, 4, jmp_0ea0 ldxdw r1, [r8+88] - jne r1, 0, jmp_0cd0 + jne r1, 0, jmp_0eb0 ldxb r1, [r8+10344] - jne r1, 255, jmp_0ce0 + jne r1, 255, jmp_0ec0 ldxdw r1, [r8+10424] - jne r1, 0, jmp_0d20 + jne r1, 0, jmp_0f10 ldxb r1, [r8+20680] - jne r1, 255, jmp_0cf0 + jne r1, 255, jmp_0ed0 ldxdw r1, [r8+20760] - jne r1, 14, jmp_0d00 + jne r1, 14, jmp_0ee0 ldxb r1, [r8+31032] - jne r1, 255, jmp_0d10 + jne r1, 255, jmp_0ef0 mov64 r0, 8 mov32 r1, 399877894 hor64 r1, 1364995097 @@ -474,38 +560,42 @@ jmp_0848: stxdw [r8+10448], r1 ja jmp_05f0 -jmp_0cb0: +jmp_0e90: mov64 r0, 12 ja jmp_06a8 -jmp_0cc0: +jmp_0ea0: mov64 r0, 1 ja jmp_06a8 -jmp_0cd0: +jmp_0eb0: mov64 r0, 2 ja jmp_06a8 -jmp_0ce0: +jmp_0ec0: mov64 r0, 5 ja jmp_06a8 -jmp_0cf0: +jmp_0ed0: mov64 r0, 6 ja jmp_06a8 -jmp_0d00: +jmp_0ee0: mov64 r0, 4 ja jmp_06a8 -jmp_0d10: +jmp_0ef0: mov64 r0, 7 ja jmp_06a8 -jmp_0d20: +jmp_0f00: + stdw [r1+10432], 0 + ja jmp_09e8 + +jmp_0f10: mov64 r0, 3 ja jmp_06a8 -jmp_0d30: +jmp_0f20: mov64 r0, 11 ja jmp_06a8 diff --git a/examples/tree/artifacts/snippets/asm/remove-search.txt b/examples/tree/artifacts/snippets/asm/remove-search.txt index c253bf91..72a634af 100644 --- a/examples/tree/artifacts/snippets/asm/remove-search.txt +++ b/examples/tree/artifacts/snippets/asm/remove-search.txt @@ -20,6 +20,4 @@ remove_search_r: e_key_does_not_exist: mov64 r0, E_KEY_DOES_NOT_EXIST - exit - -remove_found: # r3 = found node \ No newline at end of file + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-1.txt b/examples/tree/artifacts/snippets/asm/remove-simple-1.txt new file mode 100644 index 00000000..3e2c7a65 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-simple-1.txt @@ -0,0 +1,20 @@ +remove_found: + ldxdw r4, [r3 + TREE_NODE_CHILD_L_OFF] # r4 = node.child[L]; + jeq r4, NULL, remove_check_child_r + ldxdw r5, [r3 + TREE_NODE_CHILD_R_OFF] # r5 = node.child[R]; + jeq r5, NULL, remove_simple_2_child_l + + # Simple case 1: successor swap. + # --------------------------------------------------------------------- +remove_successor_loop: + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = successor.child[L]; + jeq r4, NULL, remove_successor_copy + mov64 r5, r4 # successor = left; + ja remove_successor_loop + +remove_successor_copy: + # Copy key/value pair as u32 from successor to found node. + # --------------------------------------------------------------------- + ldxw r4, [r5 + TREE_NODE_KEY_OFF] # r4 = successor.{key,value}; + stxw [r3 + TREE_NODE_KEY_OFF], r4 # node.{key,value} = r4; + mov64 r3, r5 # node = successor; \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-2.txt b/examples/tree/artifacts/snippets/asm/remove-simple-2.txt new file mode 100644 index 00000000..70b91b94 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-simple-2.txt @@ -0,0 +1,23 @@ +remove_check_child_r: # r3 = node + ldxdw r4, [r3 + TREE_NODE_CHILD_R_OFF] # r4 = node.child[R]; + jeq r4, NULL, remove_check_simple_3_4 + +remove_simple_2_child_l: # r4 = child + # Simple case 2: replace node with child, recolor child black. + # --------------------------------------------------------------------- + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + stxdw [r4 + TREE_NODE_PARENT_OFF], r5 # child.parent = parent; + stb [r4 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # child.color = black; + jeq r5, NULL, remove_simple_2_root + ldxdw r6, [r5 + TREE_NODE_CHILD_R_OFF] # r6 = parent.child[R]; + jne r3, r6, remove_simple_2_dir_l + stxdw [r5 + TREE_NODE_CHILD_R_OFF], r4 # parent.child[R] = child; + ja remove_recycle + +remove_simple_2_dir_l: + stxdw [r5 + TREE_NODE_CHILD_L_OFF], r4 # parent.child[L] = child; + ja remove_recycle + +remove_simple_2_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r4 # tree.root = child; + ja remove_recycle \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-3.txt b/examples/tree/artifacts/snippets/asm/remove-simple-3.txt new file mode 100644 index 00000000..7db07b3c --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-simple-3.txt @@ -0,0 +1,7 @@ +remove_check_simple_3_4: # r3 = node + # Simple case 3: root leaf — clear root. + # --------------------------------------------------------------------- + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + jne r5, NULL, remove_check_simple_4 + stdw [r1 + IB_TREE_DATA_ROOT_OFF], NULL # tree.root = null; + ja remove_recycle \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-4.txt b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt new file mode 100644 index 00000000..e8aa2c39 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt @@ -0,0 +1,12 @@ +remove_check_simple_4: # r5 = parent + # Simple case 4: red leaf — detach from parent. + # --------------------------------------------------------------------- + ldxb r4, [r3 + TREE_NODE_COLOR_OFF] # r4 = node.color; + jne r4, TREE_COLOR_R, remove_complex + ldxdw r4, [r5 + TREE_NODE_CHILD_R_OFF] # r4 = parent.child[R]; + jne r3, r4, remove_simple_4_dir_l + stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; + ja remove_recycle + +remove_simple_4_dir_l: + stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_search/result.txt b/examples/tree/artifacts/tests/remove_search/result.txt index 2d327c3b..50254ed4 100644 --- a/examples/tree/artifacts/tests/remove_search/result.txt +++ b/examples/tree/artifacts/tests/remove_search/result.txt @@ -1,9 +1,9 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| | Empty tree | 15 | 16 | +1 | +6.7% | -| Not found (left) | 21 | 25 | +4 | +19.0% | -| Not found (right) | 21 | 23 | +2 | +9.5% | -| Not found (deep) | 26 | 30 | +4 | +15.4% | +| Not found (left) | 21 | 28 | +7 | +33.3% | +| Not found (right) | 21 | 25 | +4 | +19.0% | +| Not found (deep) | 26 | 33 | +7 | +26.9% | test tests::test_remove_search ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 15 of 1400000 compute units @@ -15,17 +15,17 @@ test tests::test_remove_search ... ok [ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 21 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 25 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 26 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xf \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_simple/result.txt b/examples/tree/artifacts/tests/remove_simple/result.txt new file mode 100644 index 00000000..42da4596 --- /dev/null +++ b/examples/tree/artifacts/tests/remove_simple/result.txt @@ -0,0 +1,73 @@ +| Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | +|-----------|-----------|------------|----------|------------| +| One child root R (sc 1) | 32 | 43 | +11 | +34.4% | +| One child root L (sc 1) | 32 | 42 | +10 | +31.2% | +| One child non-root R (sc 2) | 39 | 52 | +13 | +33.3% | +| One child non-root L (sc 2) | 39 | 54 | +15 | +38.5% | +| Root leaf (sc 2) | 30 | 42 | +12 | +40.0% | +| Red leaf L (sc 3) | 39 | 56 | +17 | +43.6% | +| Red leaf R (sc 3) | 39 | 53 | +14 | +35.9% | +| Successor immediate R | 41 | 55 | +14 | +34.1% | +| Successor deep L descent | 45 | 59 | +14 | +31.1% | +| Successor with R child | 41 | 54 | +13 | +31.7% | +test tests::test_remove_simple ... ok +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_simple/test.txt b/examples/tree/artifacts/tests/remove_simple/test.txt new file mode 100644 index 00000000..3e523a84 --- /dev/null +++ b/examples/tree/artifacts/tests/remove_simple/test.txt @@ -0,0 +1,4 @@ +#[test] +fn test_remove_simple() { + print_comparison_table(remove::RemoveCase::SIMPLE_CASES); +} \ No newline at end of file diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 6ffb9a4d..10c112a8 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -908,14 +908,94 @@ remove_search_r: e_key_does_not_exist: mov64 r0, E_KEY_DOES_NOT_EXIST exit - -remove_found: # r3 = found node # ANCHOR_END: remove-search - # TODO: successor swap, simple removal, rebalancing, recycle. - mov64 r0, 0 +# ANCHOR: remove-simple-1 +remove_found: + ldxdw r4, [r3 + TREE_NODE_CHILD_L_OFF] # r4 = node.child[L]; + jeq r4, NULL, remove_check_child_r + ldxdw r5, [r3 + TREE_NODE_CHILD_R_OFF] # r5 = node.child[R]; + jeq r5, NULL, remove_simple_2_child_l + + # Simple case 1: successor swap. + # --------------------------------------------------------------------- +remove_successor_loop: + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = successor.child[L]; + jeq r4, NULL, remove_successor_copy + mov64 r5, r4 # successor = left; + ja remove_successor_loop + +remove_successor_copy: + # Copy key/value pair as u32 from successor to found node. + # --------------------------------------------------------------------- + ldxw r4, [r5 + TREE_NODE_KEY_OFF] # r4 = successor.{key,value}; + stxw [r3 + TREE_NODE_KEY_OFF], r4 # node.{key,value} = r4; + mov64 r3, r5 # node = successor; +# ANCHOR_END: remove-simple-1 + +# ANCHOR: remove-simple-2 +remove_check_child_r: # r3 = node + ldxdw r4, [r3 + TREE_NODE_CHILD_R_OFF] # r4 = node.child[R]; + jeq r4, NULL, remove_check_simple_3_4 + +remove_simple_2_child_l: # r4 = child + # Simple case 2: replace node with child, recolor child black. + # --------------------------------------------------------------------- + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + stxdw [r4 + TREE_NODE_PARENT_OFF], r5 # child.parent = parent; + stb [r4 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # child.color = black; + jeq r5, NULL, remove_simple_2_root + ldxdw r6, [r5 + TREE_NODE_CHILD_R_OFF] # r6 = parent.child[R]; + jne r3, r6, remove_simple_2_dir_l + stxdw [r5 + TREE_NODE_CHILD_R_OFF], r4 # parent.child[R] = child; + ja remove_recycle + +remove_simple_2_dir_l: + stxdw [r5 + TREE_NODE_CHILD_L_OFF], r4 # parent.child[L] = child; + ja remove_recycle + +remove_simple_2_root: + stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r4 # tree.root = child; + ja remove_recycle +# ANCHOR_END: remove-simple-2 + +# ANCHOR: remove-simple-3 +remove_check_simple_3_4: # r3 = node + # Simple case 3: root leaf — clear root. + # --------------------------------------------------------------------- + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + jne r5, NULL, remove_check_simple_4 + stdw [r1 + IB_TREE_DATA_ROOT_OFF], NULL # tree.root = null; + ja remove_recycle +# ANCHOR_END: remove-simple-3 + +# ANCHOR: remove-simple-4 +remove_check_simple_4: # r5 = parent + # Simple case 4: red leaf — detach from parent. + # --------------------------------------------------------------------- + ldxb r4, [r3 + TREE_NODE_COLOR_OFF] # r4 = node.color; + jne r4, TREE_COLOR_R, remove_complex + ldxdw r4, [r5 + TREE_NODE_CHILD_R_OFF] # r4 = parent.child[R]; + jne r3, r4, remove_simple_4_dir_l + stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; + ja remove_recycle + +remove_simple_4_dir_l: + stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; +# ANCHOR_END: remove-simple-4 + +remove_recycle: + # Recycle node to free stack. + # --------------------------------------------------------------------- + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; exit +remove_complex: + # TODO: complex case (black non-root leaf). e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From 5d28e5ef5a723ea23fd337346c5177bf8c2dd572 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:05:11 -0700 Subject: [PATCH 241/263] Update test spec --- examples/tree/specs/remove-tests.md | 189 +++++++++++++++++++++------- examples/tree/src/tree/tree.s | 7 +- 2 files changed, 149 insertions(+), 47 deletions(-) diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index c74c7622..33d078b6 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -160,11 +160,11 @@ Verbatim from Wikipedia, preceding the rebalancing algorithm: Mapping to test sections: -- Simple case 1 (2 children) → Successor swap tests (#17--#19). -- Simple case 2 (1 child) → Tests #10--#13. -- Simple case 3 (root leaf) → Test #14. -- Simple case 4 (red leaf) → Tests #15--#16. -- Complex case (black leaf) → Rebalancing tests (#20--#43). +- Simple case 1 (2 children) → Successor swap tests (#19--#21). +- Simple case 2 (1 child) → Tests #10--#15. +- Simple case 3 (root leaf) → Test #16. +- Simple case 4 (red leaf) → Tests #17--#18. +- Complex case (black leaf) → Rebalancing tests (#22--#45). ## Simple removal cases @@ -240,6 +240,54 @@ After: N3: B key=3 parent=N0 L=-- R=-- <- recolored B ``` +Non-root right child, left position (remove key=5): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=N3 + N2: B key=15 parent=N0 L=-- R=-- + N3: R key=7 parent=N1 L=-- R=-- + +After: + Header: root=N0 top=N1 next=-- + N0: B key=10 parent=-- L=N3 R=N2 + N1: key=5 color=B parent=-- L=-- R=-- <- freed + N2: B key=15 parent=N0 L=-- R=-- + N3: B key=7 parent=N0 L=-- R=-- <- recolored B +``` + +Node N1 has only a right child and is the left child of its +parent. Exercises `parent.child[L] = child` in the R-child call +site of `remove_simple_2_child_replace` (Rust line 633). In the +assembly, exercises `remove_simple_2_dir_l` entered via +`remove_check_child_r`. + +Non-root left child, right position (remove key=15): + +```text +Before: + Header: root=N0 top=-- next=-- + N0: B key=10 parent=-- L=N1 R=N2 + N1: B key=5 parent=N0 L=-- R=-- + N2: B key=15 parent=N0 L=N3 R=-- + N3: R key=12 parent=N2 L=-- R=-- + +After: + Header: root=N0 top=N2 next=-- + N0: B key=10 parent=-- L=N1 R=N3 + N1: B key=5 parent=N0 L=-- R=-- + N2: key=15 color=B parent=-- L=-- R=-- <- freed + N3: B key=12 parent=N0 L=-- R=-- <- recolored B +``` + +Node N2 has only a left child and is the right child of its +parent. Exercises `parent.child[R] = child` in the L-child call +site of `remove_simple_2_child_replace` (Rust line 627). In the +assembly, exercises `parent.child[R] = child` entered via +`remove_simple_2_child_l` from the simple-1 L-only branch. + ### Simple case 3: remove root leaf Single-node tree. Root becomes null, node is freed. @@ -349,6 +397,57 @@ After remove key=10 (returns value=10): Successor N2 has one child (N3). Simple case 1: replace N2 with N3, recolor N3 black. +## Simple case branch coverage + +### Assembly branches (`tree.s`) + +Each branch corresponds to a conditional jump in the remove path. +"Taken/not-taken" refers to the `jeq`/`jne` outcome. + +| ID | Branch | Tests | +| --- | ------------------------- | ------------- | +| B1 | found : L==null | 10,12,14--18 | +| B2 | found : R==null | 11,13,15 | +| B3 | found : both non-null | 19--21 | +| B4 | successor : L==null | 19,21 | +| B5 | successor : L!=null | 20 | +| B6 | check_child_r : R==null | 14--20 | +| B7 | check_child_r : R!=null | 10,12,21 | +| B8 | simple_2 : parent==null | 10,11 | +| B9 | simple_2 : R direction | 12,15,21 | +| B10 | simple_2 : L direction | 13,14 | +| B11 | simple_3_4 : parent==null | 16 | +| B12 | simple_3_4 : parent!=null | 17--20 | +| B13 | simple_4 : color!=RED | (rebalancing) | +| B14 | simple_4 : R direction | 18,19 | +| B15 | simple_4 : L direction | 17,20 | + +All branches except B13 are exercised by the simple removal +tests. B13 is the entry to the complex rebalancing case, covered +by tests #22--#45. + +### Rust macro call-site coverage + +`remove_simple_2_child_replace!` expands at two call sites, +producing separate compiled code for each. Full branch coverage +requires exercising all three parent-direction branches at each +site. + +| Site | Parent dir | Tests | +| ---- | ---------- | ------ | +| L627 | null | 11 | +| L627 | R | 15 | +| L627 | L | 13 | +| R633 | null | 10 | +| R633 | R | 12, 21 | +| R633 | L | 14 | + +`remove_recycle_node!` is a straight-line macro (no branches) +called from four sites: both `remove_simple_2_child_replace` +expansions, simple case 3, and simple case 4. All sites are +exercised by the simple tests. The free-stack state (empty vs +non-empty) is covered by tests #46--#48 (multi-step integration). + ## Wikipedia reference -- rebalancing loop invariant Verbatim from Wikipedia, following the rebalancing algorithm: @@ -884,55 +983,57 @@ case 6. ### Simple removal (no rebalancing) -| # | Case | Direction | -| --- | ------------------------------- | --------- | -| 10 | One child at root (sc 2) | R child | -| 11 | One child at root (sc 2) | L child | -| 12 | One child non-root (sc 2) | R child | -| 13 | One child non-root (sc 2) | L child | -| 14 | Root leaf (sc 3) | -- | -| 15 | Red leaf (sc 4) | L | -| 16 | Red leaf (sc 4) | R | -| 17 | Successor immediate R (sc 1) | -- | -| 18 | Successor deep L descent (sc 1) | -- | -| 19 | Successor with R child (sc 1) | -- | +| # | Case | Direction | +| --- | ------------------------------- | -------------- | +| 10 | One child at root (sc 2) | R child | +| 11 | One child at root (sc 2) | L child | +| 12 | One child non-root (sc 2) | R child, R pos | +| 13 | One child non-root (sc 2) | L child, L pos | +| 14 | One child non-root (sc 2) | R child, L pos | +| 15 | One child non-root (sc 2) | L child, R pos | +| 16 | Root leaf (sc 3) | -- | +| 17 | Red leaf (sc 4) | L | +| 18 | Red leaf (sc 4) | R | +| 19 | Successor immediate R (sc 1) | -- | +| 20 | Successor deep L descent (sc 1) | -- | +| 21 | Successor with R child (sc 1) | -- | ### Rebalancing (complex case, black leaf removal) | # | Path | Dir | | --- | ----------------------------- | --- | -| 20 | Case 4 | L | -| 21 | Case 4 | R | -| 22 | Case 6 | L | -| 23 | Case 6 | R | -| 24 | Case 5 + 6 | L | -| 25 | Case 5 + 6 | R | -| 26 | Case 3 → 4 | L | -| 27 | Case 3 → 4 | R | -| 28 | Case 3 → 6 | L | -| 29 | Case 3 → 6 | R | -| 30 | Case 3 → 5 → 6 | L | -| 31 | Case 3 → 5 → 6 | R | -| 32 | Case 2 (propagate to root) | L | -| 33 | Case 2 (propagate to root) | R | -| 34 | Case 2 → 4 | -- | -| 35 | Case 2 → 6 | -- | -| 36 | Case 6 non-null new_child | L | -| 37 | Case 6 non-null new_child | R | -| 38 | Case 6 parent=root | L | -| 39 | Case 6 parent=root | R | -| 40 | Case 6 parent=GGP left child | L | -| 41 | Case 6 parent=GGP right child | R | -| 42 | Case 3 parent=root | L | -| 43 | Case 3 parent=root | R | +| 22 | Case 4 | L | +| 23 | Case 4 | R | +| 24 | Case 6 | L | +| 25 | Case 6 | R | +| 26 | Case 5 + 6 | L | +| 27 | Case 5 + 6 | R | +| 28 | Case 3 → 4 | L | +| 29 | Case 3 → 4 | R | +| 30 | Case 3 → 6 | L | +| 31 | Case 3 → 6 | R | +| 32 | Case 3 → 5 → 6 | L | +| 33 | Case 3 → 5 → 6 | R | +| 34 | Case 2 (propagate to root) | L | +| 35 | Case 2 (propagate to root) | R | +| 36 | Case 2 → 4 | -- | +| 37 | Case 2 → 6 | -- | +| 38 | Case 6 non-null new_child | L | +| 39 | Case 6 non-null new_child | R | +| 40 | Case 6 parent=root | L | +| 41 | Case 6 parent=root | R | +| 42 | Case 6 parent=GGP left child | L | +| 43 | Case 6 parent=GGP right child | R | +| 44 | Case 3 parent=root | L | +| 45 | Case 3 parent=root | R | ### Multi-step integration | # | Case | | --- | --------------------------------- | -| 44 | Insert 3, remove 1 (minimal) | -| 45 | Insert 7, remove all (full cycle) | -| 46 | Insert-remove-insert (recycling) | +| 46 | Insert 3, remove 1 (minimal) | +| 47 | Insert 7, remove all (full cycle) | +| 48 | Insert-remove-insert (recycling) | ## Multi-step integration tests diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 10c112a8..7de30290 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -982,8 +982,12 @@ remove_check_simple_4: # r5 remove_simple_4_dir_l: stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; + ja remove_recycle # ANCHOR_END: remove-simple-4 +remove_complex: + # TODO: complex case (black non-root leaf). + remove_recycle: # Recycle node to free stack. # --------------------------------------------------------------------- @@ -994,9 +998,6 @@ remove_recycle: stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; exit -remove_complex: - # TODO: complex case (black non-root leaf). - e_instruction_data: mov64 r0, E_INSTRUCTION_DATA exit From ecdff115d465b869309b0cdebc3ab4e35a15d219 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:18:22 -0700 Subject: [PATCH 242/263] UPdate tests --- docs/src/examples/tree.md | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index d6110aff..83936a35 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -326,6 +326,58 @@ not available in Rust, since the compiler enforces +### Simple cases + + + +::: details Simple case 1: successor swap + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-simple-1.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-simple-1.txt{rs} [Rust] + +::: + +::: details Simple case 2: one-child replacement + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-simple-2.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-simple-2.txt{rs} [Rust] + +::: + +::: details Simple case 3: root leaf + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-simple-3.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-simple-3.txt{rs} [Rust] + +::: + +::: details Simple case 4: red leaf + +::: code-group + +<<< ../../../examples/tree/artifacts/snippets/asm/remove-simple-4.txt{asm} [Assembly] + +<<< ../../../examples/tree/artifacts/snippets/rs/remove-simple-4.txt{rs} [Rust] + +::: + +::: details Benchmarking + + + +::: + + + [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism [pda]: https://solana.com/docs/core/pda [tail call]: https://en.wikipedia.org/wiki/Tail_call From 94b36dfee58c1594662f5c001d3f4fe9670e5e0d Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:18:43 -0700 Subject: [PATCH 243/263] Update tests --- .../snippets/asm/remove-simple-4.txt | 3 +- .../artifacts/tests/remove_simple/result.txt | 34 +++++-- examples/tree/src/tests/remove.rs | 99 +++++++++++++++---- 3 files changed, 105 insertions(+), 31 deletions(-) diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-4.txt b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt index e8aa2c39..b3d7133e 100644 --- a/examples/tree/artifacts/snippets/asm/remove-simple-4.txt +++ b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt @@ -9,4 +9,5 @@ remove_check_simple_4: # r5 ja remove_recycle remove_simple_4_dir_l: - stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; \ No newline at end of file + stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; + ja remove_recycle \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_simple/result.txt b/examples/tree/artifacts/tests/remove_simple/result.txt index 42da4596..3c3d435f 100644 --- a/examples/tree/artifacts/tests/remove_simple/result.txt +++ b/examples/tree/artifacts/tests/remove_simple/result.txt @@ -1,15 +1,17 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| One child root R (sc 1) | 32 | 43 | +11 | +34.4% | -| One child root L (sc 1) | 32 | 42 | +10 | +31.2% | -| One child non-root R (sc 2) | 39 | 52 | +13 | +33.3% | -| One child non-root L (sc 2) | 39 | 54 | +15 | +38.5% | -| Root leaf (sc 2) | 30 | 42 | +12 | +40.0% | -| Red leaf L (sc 3) | 39 | 56 | +17 | +43.6% | -| Red leaf R (sc 3) | 39 | 53 | +14 | +35.9% | -| Successor immediate R | 41 | 55 | +14 | +34.1% | -| Successor deep L descent | 45 | 59 | +14 | +31.1% | -| Successor with R child | 41 | 54 | +13 | +31.7% | +| One child root R (sc 2) | 32 | 43 | +11 | +34.4% | +| One child root L (sc 2) | 32 | 42 | +10 | +31.2% | +| One child non-root R,R (sc 2) | 39 | 52 | +13 | +33.3% | +| One child non-root L,L (sc 2) | 39 | 54 | +15 | +38.5% | +| One child non-root R,L (sc 2) | 39 | 55 | +16 | +41.0% | +| One child non-root L,R (sc 2) | 39 | 51 | +12 | +30.8% | +| Root leaf (sc 3) | 30 | 42 | +12 | +40.0% | +| Red leaf L (sc 4) | 39 | 56 | +17 | +43.6% | +| Red leaf R (sc 4) | 39 | 53 | +14 | +35.9% | +| Successor immediate R (sc 1) | 41 | 55 | +14 | +34.1% | +| Successor deep L descent (sc 1) | 45 | 59 | +14 | +31.1% | +| Successor with R child (sc 1) | 41 | 54 | +13 | +31.7% | test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units @@ -36,6 +38,18 @@ test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs index dba6b97b..9cd83b61 100644 --- a/examples/tree/src/tests/remove.rs +++ b/examples/tree/src/tests/remove.rs @@ -250,7 +250,7 @@ pub(super) enum RemoveCase { SearchNotFoundLeft, SearchNotFoundRight, SearchNotFoundDeep, - // Simple removal (cases 10-15). + // Simple removal (cases 10-18). SimpleRootLeaf, SimpleRedLeafL, SimpleRedLeafR, @@ -258,11 +258,13 @@ pub(super) enum RemoveCase { SimpleOneChildRootL, SimpleOneChildNonRootR, SimpleOneChildNonRootL, - // Successor swap (cases 17-19). + SimpleOneChildNonRootRL, + SimpleOneChildNonRootLR, + // Successor swap (cases 19-21). SuccessorImmediate, SuccessorDeep, SuccessorWithChild, - // Rebalancing (cases 19-42). + // Rebalancing (cases 22-45). Case4L, Case4R, Case6L, @@ -310,6 +312,8 @@ impl RemoveCase { Self::SimpleOneChildRootL, Self::SimpleOneChildNonRootR, Self::SimpleOneChildNonRootL, + Self::SimpleOneChildNonRootRL, + Self::SimpleOneChildNonRootLR, Self::SimpleRootLeaf, Self::SimpleRedLeafL, Self::SimpleRedLeafR, @@ -358,16 +362,18 @@ impl TestCase for RemoveCase { Self::SearchNotFoundLeft => "Not found (left)", Self::SearchNotFoundRight => "Not found (right)", Self::SearchNotFoundDeep => "Not found (deep)", - Self::SimpleRootLeaf => "Root leaf (sc 2)", - Self::SimpleRedLeafL => "Red leaf L (sc 3)", - Self::SimpleRedLeafR => "Red leaf R (sc 3)", - Self::SimpleOneChildRootR => "One child root R (sc 1)", - Self::SimpleOneChildRootL => "One child root L (sc 1)", - Self::SimpleOneChildNonRootR => "One child non-root R (sc 2)", - Self::SimpleOneChildNonRootL => "One child non-root L (sc 2)", - Self::SuccessorImmediate => "Successor immediate R", - Self::SuccessorDeep => "Successor deep L descent", - Self::SuccessorWithChild => "Successor with R child", + Self::SimpleRootLeaf => "Root leaf (sc 3)", + Self::SimpleRedLeafL => "Red leaf L (sc 4)", + Self::SimpleRedLeafR => "Red leaf R (sc 4)", + Self::SimpleOneChildRootR => "One child root R (sc 2)", + Self::SimpleOneChildRootL => "One child root L (sc 2)", + Self::SimpleOneChildNonRootR => "One child non-root R,R (sc 2)", + Self::SimpleOneChildNonRootL => "One child non-root L,L (sc 2)", + Self::SimpleOneChildNonRootRL => "One child non-root R,L (sc 2)", + Self::SimpleOneChildNonRootLR => "One child non-root L,R (sc 2)", + Self::SuccessorImmediate => "Successor immediate R (sc 1)", + Self::SuccessorDeep => "Successor deep L descent (sc 1)", + Self::SuccessorWithChild => "Successor with R child (sc 1)", Self::Case4L => "Case 4 dir_l", Self::Case4R => "Case 4 dir_r", Self::Case6L => "Case 6 dir_l", @@ -494,7 +500,7 @@ impl TestCase for RemoveCase { // ----- Simple removal ----- - // Simple case 2: remove root leaf. + // Simple case 3: root leaf. Self::SimpleRootLeaf => { let desc = TreeSpec { root: Some(0), @@ -509,7 +515,7 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 10, &exp) } - // Simple case 3: remove red leaf (left child). + // Simple case 4: red leaf (left child). Self::SimpleRedLeafL => { let desc = TreeSpec { root: Some(0), @@ -530,7 +536,7 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 5, &exp) } - // Simple case 3: remove red leaf (right child). + // Simple case 4: red leaf (right child). Self::SimpleRedLeafR => { let desc = TreeSpec { root: Some(0), @@ -551,7 +557,7 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 15, &exp) } - // Simple case 1: one child at root (right child). + // Simple case 2: one child at root (right child). Self::SimpleOneChildRootR => { let desc = TreeSpec { root: Some(0), @@ -572,7 +578,7 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 10, &exp) } - // Simple case 1: one child at root (left child). + // Simple case 2: one child at root (left child). Self::SimpleOneChildRootL => { let desc = TreeSpec { root: Some(0), @@ -593,7 +599,7 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 10, &exp) } - // Simple case 1: one child non-root (right child). + // Simple case 2: one child non-root (R child, R pos). Self::SimpleOneChildNonRootR => { let desc = TreeSpec { root: Some(0), @@ -617,6 +623,7 @@ impl TestCase for RemoveCase { }; run_remove_success(lang, &desc, 15, &exp) } + // Simple case 2: one child non-root (L child, L pos). Self::SimpleOneChildNonRootL => { let desc = TreeSpec { root: Some(0), @@ -641,11 +648,63 @@ impl TestCase for RemoveCase { run_remove_success(lang, &desc, 5, &exp) } + // Simple case 2: one child non-root (R child, L pos). + // Node has R child, node is L child of parent. + Self::SimpleOneChildNonRootRL => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, Some(3)), + node(15, B, Some(0), None, None), + node(7, R, Some(1), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, Some(3), Some(2)), + node(5, B, None, None, None), + node(15, B, Some(0), None, None), + node(7, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 5, &exp) + } + + // Simple case 2: one child non-root (L child, R pos). + // Node has L child, node is R child of parent. + Self::SimpleOneChildNonRootLR => { + let desc = TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, B, Some(0), None, None), + node(15, B, Some(0), Some(3), None), + node(12, R, Some(2), None, None), + ], + }; + let exp = TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), Some(3)), + node(5, B, Some(0), None, None), + node(15, B, None, None, None), + node(12, B, Some(0), None, None), + ], + }; + run_remove_success(lang, &desc, 15, &exp) + } + // ----- Successor swap ----- // Successor is immediate right child. // B(10) with R(5) left, R(15) right. Remove 10: swap with - // successor N2(15), then delete N2 (red leaf, simple case 3). + // successor N2(15), then delete N2 (red leaf, simple case 4). Self::SuccessorImmediate => { let desc = TreeSpec { root: Some(0), From b6b46230d120f9d09f856d959048cf5ac61b40bd Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:35:31 -0700 Subject: [PATCH 244/263] Re-order tests --- .../artifacts/tests/remove_simple/result.txt | 60 +++++++++---------- examples/tree/src/tests/remove.rs | 30 +++++----- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/examples/tree/artifacts/tests/remove_simple/result.txt b/examples/tree/artifacts/tests/remove_simple/result.txt index 3c3d435f..b37ff895 100644 --- a/examples/tree/artifacts/tests/remove_simple/result.txt +++ b/examples/tree/artifacts/tests/remove_simple/result.txt @@ -1,19 +1,37 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| One child root R (sc 2) | 32 | 43 | +11 | +34.4% | -| One child root L (sc 2) | 32 | 42 | +10 | +31.2% | -| One child non-root R,R (sc 2) | 39 | 52 | +13 | +33.3% | -| One child non-root L,L (sc 2) | 39 | 54 | +15 | +38.5% | -| One child non-root R,L (sc 2) | 39 | 55 | +16 | +41.0% | -| One child non-root L,R (sc 2) | 39 | 51 | +12 | +30.8% | -| Root leaf (sc 3) | 30 | 42 | +12 | +40.0% | -| Red leaf L (sc 4) | 39 | 56 | +17 | +43.6% | -| Red leaf R (sc 4) | 39 | 53 | +14 | +35.9% | -| Successor immediate R (sc 1) | 41 | 55 | +14 | +34.1% | -| Successor deep L descent (sc 1) | 45 | 59 | +14 | +31.1% | -| Successor with R child (sc 1) | 41 | 54 | +13 | +31.7% | +| Successor immediate R (SC 1) | 41 | 55 | +14 | +34.1% | +| Successor deep L descent (SC 1) | 45 | 59 | +14 | +31.1% | +| Successor with R child (SC 1) | 41 | 54 | +13 | +31.7% | +| One child root R (SC 2) | 32 | 43 | +11 | +34.4% | +| One child root L (SC 2) | 32 | 42 | +10 | +31.2% | +| One child non-root R,R (SC 2) | 39 | 52 | +13 | +33.3% | +| One child non-root L,L (SC 2) | 39 | 54 | +15 | +38.5% | +| One child non-root R,L (SC 2) | 39 | 55 | +16 | +41.0% | +| One child non-root L,R (SC 2) | 39 | 51 | +12 | +30.8% | +| Root leaf (SC 3) | 30 | 42 | +12 | +40.0% | +| Red leaf L (SC 4) | 39 | 56 | +17 | +43.6% | +| Red leaf R (SC 4) | 39 | 53 | +14 | +35.9% | test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] +[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... success +[ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] @@ -66,22 +84,4 @@ test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units -[ ... DEBUG ... ] Program DASMAC... success -[ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs index 9cd83b61..50315928 100644 --- a/examples/tree/src/tests/remove.rs +++ b/examples/tree/src/tests/remove.rs @@ -308,6 +308,9 @@ impl RemoveCase { ]; pub(super) const SIMPLE_CASES: &'static [Self] = &[ + Self::SuccessorImmediate, + Self::SuccessorDeep, + Self::SuccessorWithChild, Self::SimpleOneChildRootR, Self::SimpleOneChildRootL, Self::SimpleOneChildNonRootR, @@ -317,9 +320,6 @@ impl RemoveCase { Self::SimpleRootLeaf, Self::SimpleRedLeafL, Self::SimpleRedLeafR, - Self::SuccessorImmediate, - Self::SuccessorDeep, - Self::SuccessorWithChild, ]; pub(super) const REBALANCE_CASES: &'static [Self] = &[ @@ -362,18 +362,18 @@ impl TestCase for RemoveCase { Self::SearchNotFoundLeft => "Not found (left)", Self::SearchNotFoundRight => "Not found (right)", Self::SearchNotFoundDeep => "Not found (deep)", - Self::SimpleRootLeaf => "Root leaf (sc 3)", - Self::SimpleRedLeafL => "Red leaf L (sc 4)", - Self::SimpleRedLeafR => "Red leaf R (sc 4)", - Self::SimpleOneChildRootR => "One child root R (sc 2)", - Self::SimpleOneChildRootL => "One child root L (sc 2)", - Self::SimpleOneChildNonRootR => "One child non-root R,R (sc 2)", - Self::SimpleOneChildNonRootL => "One child non-root L,L (sc 2)", - Self::SimpleOneChildNonRootRL => "One child non-root R,L (sc 2)", - Self::SimpleOneChildNonRootLR => "One child non-root L,R (sc 2)", - Self::SuccessorImmediate => "Successor immediate R (sc 1)", - Self::SuccessorDeep => "Successor deep L descent (sc 1)", - Self::SuccessorWithChild => "Successor with R child (sc 1)", + Self::SimpleRootLeaf => "Root leaf (SC 3)", + Self::SimpleRedLeafL => "Red leaf L (SC 4)", + Self::SimpleRedLeafR => "Red leaf R (SC 4)", + Self::SimpleOneChildRootR => "One child root R (SC 2)", + Self::SimpleOneChildRootL => "One child root L (SC 2)", + Self::SimpleOneChildNonRootR => "One child non-root R,R (SC 2)", + Self::SimpleOneChildNonRootL => "One child non-root L,L (SC 2)", + Self::SimpleOneChildNonRootRL => "One child non-root R,L (SC 2)", + Self::SimpleOneChildNonRootLR => "One child non-root L,R (SC 2)", + Self::SuccessorImmediate => "Successor immediate R (SC 1)", + Self::SuccessorDeep => "Successor deep L descent (SC 1)", + Self::SuccessorWithChild => "Successor with R child (SC 1)", Self::Case4L => "Case 4 dir_l", Self::Case4R => "Case 4 dir_r", Self::Case6L => "Case 6 dir_l", From 376933a99cfb4b91ba444c692dd2d6f9a09df8b3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:13:59 -0800 Subject: [PATCH 245/263] Remove prompt hook --- .claude/settings.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 2cd35ba3..00000000 --- a/.claude/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hooks": { - "Stop": [ - { - "hooks": [ - { - "type": "prompt", - "prompt": "Evaluate whether the interaction you just completed warrants self-improvement. If this was a substantive task (not a trivial question or explanation), check what was learned and take action:\n\n- Repeated instruction (corrected 2+ times): add it to CLAUDE.md.\n- Design decision: write or update a spec.\n- Repeatable workflow: propose a skill.\n- Must always happen: propose a hook.\n- Learned pattern: save to memory.\n\nIf nothing applies, do nothing.", - "timeout": 30 - } - ] - } - ] - } -} \ No newline at end of file From e6d643139ba3ccd071c35ea83a1cfbfd4ad16b79 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:14:57 -0800 Subject: [PATCH 246/263] Add Pentagon skills --- .claude/skills/manage-pentagon-agent | 1 + .claude/skills/manage-pentagon-canvas | 1 + .claude/skills/manage-pentagon-role | 1 + .claude/skills/manage-pentagon-team | 1 + .claude/skills/send-pentagon-message | 1 + 5 files changed, 5 insertions(+) create mode 120000 .claude/skills/manage-pentagon-agent create mode 120000 .claude/skills/manage-pentagon-canvas create mode 120000 .claude/skills/manage-pentagon-role create mode 120000 .claude/skills/manage-pentagon-team create mode 120000 .claude/skills/send-pentagon-message diff --git a/.claude/skills/manage-pentagon-agent b/.claude/skills/manage-pentagon-agent new file mode 120000 index 00000000..ae21c7ba --- /dev/null +++ b/.claude/skills/manage-pentagon-agent @@ -0,0 +1 @@ +/Users/alex/.pentagon/skills/manage-pentagon-agent \ No newline at end of file diff --git a/.claude/skills/manage-pentagon-canvas b/.claude/skills/manage-pentagon-canvas new file mode 120000 index 00000000..4ad17639 --- /dev/null +++ b/.claude/skills/manage-pentagon-canvas @@ -0,0 +1 @@ +/Users/alex/.pentagon/skills/manage-pentagon-canvas \ No newline at end of file diff --git a/.claude/skills/manage-pentagon-role b/.claude/skills/manage-pentagon-role new file mode 120000 index 00000000..193d74f3 --- /dev/null +++ b/.claude/skills/manage-pentagon-role @@ -0,0 +1 @@ +/Users/alex/.pentagon/skills/manage-pentagon-role \ No newline at end of file diff --git a/.claude/skills/manage-pentagon-team b/.claude/skills/manage-pentagon-team new file mode 120000 index 00000000..5523ef51 --- /dev/null +++ b/.claude/skills/manage-pentagon-team @@ -0,0 +1 @@ +/Users/alex/.pentagon/skills/manage-pentagon-team \ No newline at end of file diff --git a/.claude/skills/send-pentagon-message b/.claude/skills/send-pentagon-message new file mode 120000 index 00000000..34abeeab --- /dev/null +++ b/.claude/skills/send-pentagon-message @@ -0,0 +1 @@ +/Users/alex/.pentagon/skills/send-pentagon-message \ No newline at end of file From 36ea9695d13f5875a3887e1aaa98ea085b2480fe Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:15:08 -0800 Subject: [PATCH 247/263] Add example disassembly skill --- .claude/commands/disassemble-example.md | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .claude/commands/disassemble-example.md diff --git a/.claude/commands/disassemble-example.md b/.claude/commands/disassemble-example.md new file mode 100644 index 00000000..acc056c1 --- /dev/null +++ b/.claude/commands/disassemble-example.md @@ -0,0 +1,30 @@ +Quick compile and disassemble cycle for a specific example program. + +Run the following commands sequentially from the example directory at +`examples/$ARGUMENTS`: + +1. Remove stale binary: + +```sh +rm -f ../target/deploy/${ARGUMENTS//-/_}.so +``` + +2. Build for the disassembly architecture: + +```sh +cargo build-sbf --arch v2 --tools-version 1.52 +``` + +3. Disassemble and write output: + +```sh +sbpf disassemble ../target/deploy/${ARGUMENTS//-/_}.so \ + > artifacts/rs-disassembly.s +``` + +If `$ARGUMENTS` is empty, infer the example name from the current +conversation context (e.g. recent file paths or discussion). If you still +cannot determine it, ask which example to disassemble. + +Report the result. Show the disassembly content or the relevant section +if the user is focused on specific functions. From 43a26db957021765a87200c1aa09743d38690790 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Mar 2026 18:04:55 -0800 Subject: [PATCH 248/263] Update inlining --- examples/tree/artifacts/dumps/asm.txt | 224 ++++++++++-------- .../snippets/asm/remove-simple-2.txt | 21 +- .../snippets/asm/remove-simple-3.txt | 7 +- .../snippets/asm/remove-simple-4.txt | 14 +- .../artifacts/tests/remove_simple/result.txt | 48 ++-- examples/tree/specs/parity-workflow.md | 122 ++++++++++ examples/tree/specs/remove-tests.md | 66 +++--- examples/tree/specs/remove.md | 77 ++++++ examples/tree/src/tree/tree.s | 48 +++- 9 files changed, 459 insertions(+), 168 deletions(-) create mode 100644 examples/tree/specs/parity-workflow.md diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index e8757780..508111c9 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 3992 (bytes into file) + Start of section headers 4232 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0xf98 +There are 7 section headers, starting at offset 0x1088 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000d10 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000df8 000df8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000e98 000e98 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000ef8 000ef8 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000000f38 000f38 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 000f68 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000e00 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 0000000000000ee8 000ee8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000000f88 000f88 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 0000000000000fe8 000fe8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 0000000000001028 001028 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 001058 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000d10 0x000d10 R E 0x1000 - LOAD 0x000e98 0x0000000000000e98 0x0000000000000e98 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000df8 0x0000000000000df8 0x0000000000000df8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000e00 0x000e00 R E 0x1000 + LOAD 0x000f88 0x0000000000000f88 0x0000000000000f88 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x000ee8 0x0000000000000ee8 0x0000000000000ee8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xdf8 contains 10 entries +Dynamic section at offset 0xee8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0xf38 + 0x0000000000000011 (REL) 0x1028 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xe98 + 0x0000000000000006 (SYMTAB) 0xf88 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xef8 + 0x0000000000000005 (STRTAB) 0xfe8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0xf38 contains 3 entries +Relocation section '.rel.dyn' at offset 0x1028 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000248 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000468 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -92,32 +92,32 @@ Disassembly of section .text 34 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 35 b7 00 00 00 0b 00 00 00 r0 = 0xb 36 95 00 00 00 00 00 00 00 exit - 37 55 09 83 01 01 00 00 00 if r9 != 0x1 goto +0x183 - 38 55 08 84 01 04 00 00 00 if r8 != 0x4 goto +0x184 + 37 55 09 a1 01 01 00 00 00 if r9 != 0x1 goto +0x1a1 + 38 55 08 a2 01 04 00 00 00 if r8 != 0x4 goto +0x1a2 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 94 01 00 00 00 00 if r9 != 0x0 goto +0x194 + 40 55 09 b2 01 00 00 00 00 if r9 != 0x0 goto +0x1b2 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 90 01 ff 00 00 00 if r9 != 0xff goto +0x190 + 42 55 09 ae 01 ff 00 00 00 if r9 != 0xff goto +0x1ae 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 8c 01 00 00 00 00 if r9 != 0x0 goto +0x18c + 44 55 09 aa 01 00 00 00 00 if r9 != 0x0 goto +0x1aa 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 88 01 ff 00 00 00 if r9 != 0xff goto +0x188 + 46 55 09 a6 01 ff 00 00 00 if r9 != 0xff goto +0x1a6 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 84 01 0e 00 00 00 if r9 != 0xe goto +0x184 + 48 55 09 a2 01 0e 00 00 00 if r9 != 0xe goto +0x1a2 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 80 01 ff 00 00 00 if r9 != 0xff goto +0x180 + 50 55 09 9e 01 ff 00 00 00 if r9 != 0xff goto +0x19e 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 7a 01 00 00 00 00 if r9 != r8 goto +0x17a + 54 5d 89 98 01 00 00 00 00 if r9 != r8 goto +0x198 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 76 01 00 00 00 00 if r9 != r8 goto +0x176 + 58 5d 89 94 01 00 00 00 00 if r9 != r8 goto +0x194 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 72 01 00 00 00 00 if r9 != r8 goto +0x172 + 62 5d 89 90 01 00 00 00 00 if r9 != r8 goto +0x190 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 6f 01 00 00 00 00 if r9 != r8 goto +0x16f + 65 5d 89 8d 01 00 00 00 00 if r9 != r8 goto +0x18d 66 b7 02 00 00 00 00 00 00 r2 = 0x0 67 bf 13 00 00 00 00 00 00 r3 = r1 68 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -128,16 +128,16 @@ Disassembly of section .text 73 85 10 00 00 ff ff ff ff call -0x1 74 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 75 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 76 5d 89 62 01 00 00 00 00 if r9 != r8 goto +0x162 + 76 5d 89 80 01 00 00 00 00 if r9 != r8 goto +0x180 77 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 78 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 79 5d 89 5f 01 00 00 00 00 if r9 != r8 goto +0x15f + 79 5d 89 7d 01 00 00 00 00 if r9 != r8 goto +0x17d 80 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 81 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 82 5d 89 5c 01 00 00 00 00 if r9 != r8 goto +0x15c + 82 5d 89 7a 01 00 00 00 00 if r9 != r8 goto +0x17a 83 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 84 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 85 5d 89 59 01 00 00 00 00 if r9 != r8 goto +0x159 + 85 5d 89 77 01 00 00 00 00 if r9 != r8 goto +0x177 86 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 87 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -198,15 +198,15 @@ Disassembly of section .text 143 07 07 00 00 18 00 00 00 r7 += 0x18 144 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 145 95 00 00 00 00 00 00 00 exit - 146 55 09 16 01 05 00 00 00 if r9 != 0x5 goto +0x116 - 147 a5 08 17 01 02 00 00 00 if r8 < 0x2 goto +0x117 + 146 55 09 34 01 05 00 00 00 if r9 != 0x5 goto +0x134 + 147 a5 08 35 01 02 00 00 00 if r8 < 0x2 goto +0x135 148 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 149 55 09 27 01 00 00 00 00 if r9 != 0x0 goto +0x127 + 149 55 09 45 01 00 00 00 00 if r9 != 0x0 goto +0x145 150 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 151 55 09 23 01 ff 00 00 00 if r9 != 0xff goto +0x123 + 151 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 152 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 153 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 154 55 08 12 01 04 00 00 00 if r8 != 0x4 goto +0x112 + 154 55 08 30 01 04 00 00 00 if r8 != 0x4 goto +0x130 155 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 156 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 157 bf 97 00 00 00 00 00 00 r7 = r9 @@ -214,23 +214,23 @@ Disassembly of section .text 159 57 09 00 00 f8 ff ff ff r9 &= -0x8 160 0f 19 00 00 00 00 00 00 r9 += r1 161 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 162 55 08 14 01 ff 00 00 00 if r8 != 0xff goto +0x114 + 162 55 08 32 01 ff 00 00 00 if r8 != 0xff goto +0x132 163 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 164 55 08 10 01 0e 00 00 00 if r8 != 0xe goto +0x110 + 164 55 08 2e 01 0e 00 00 00 if r8 != 0xe goto +0x12e 165 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 166 55 08 0c 01 ff 00 00 00 if r8 != 0xff goto +0x10c + 166 55 08 2a 01 ff 00 00 00 if r8 != 0xff goto +0x12a 167 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 168 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 170 5d 48 06 01 00 00 00 00 if r8 != r4 goto +0x106 + 170 5d 48 24 01 00 00 00 00 if r8 != r4 goto +0x124 171 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 172 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 174 5d 48 02 01 00 00 00 00 if r8 != r4 goto +0x102 + 174 5d 48 20 01 00 00 00 00 if r8 != r4 goto +0x120 175 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 176 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 178 5d 48 fe 00 00 00 00 00 if r8 != r4 goto +0xfe + 178 5d 48 1c 01 00 00 00 00 if r8 != r4 goto +0x11c 179 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 180 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 181 5d 48 fb 00 00 00 00 00 if r8 != r4 goto +0xfb + 181 5d 48 19 01 00 00 00 00 if r8 != r4 goto +0x119 182 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 183 27 08 00 00 1d 00 00 00 r8 *= 0x1d 184 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -409,12 +409,12 @@ Disassembly of section .text 357 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) 358 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d 359 95 00 00 00 00 00 00 00 exit - 360 55 09 40 00 03 00 00 00 if r9 != 0x3 goto +0x40 - 361 a5 08 41 00 02 00 00 00 if r8 < 0x2 goto +0x41 + 360 55 09 5e 00 03 00 00 00 if r9 != 0x3 goto +0x5e + 361 a5 08 5f 00 02 00 00 00 if r8 < 0x2 goto +0x5f 362 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 363 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 + 363 55 09 6f 00 00 00 00 00 if r9 != 0x0 goto +0x6f 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 365 55 09 4d 00 ff 00 00 00 if r9 != 0xff goto +0x4d + 365 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b 366 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) 367 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa 368 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) @@ -441,58 +441,88 @@ Disassembly of section .text 389 63 43 18 00 00 00 00 00 *(u32 *)(r3 + 0x18) = r4 390 bf 53 00 00 00 00 00 00 r3 = r5 391 79 34 10 00 00 00 00 00 r4 = *(u64 *)(r3 + 0x10) - 392 15 04 0c 00 00 00 00 00 if r4 == 0x0 goto +0xc + 392 15 04 1b 00 00 00 00 00 if r4 == 0x0 goto +0x1b 393 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) 394 7b 54 00 00 00 00 00 00 *(u64 *)(r4 + 0x0) = r5 395 72 04 1c 00 00 00 00 00 *(u8 *)(r4 + 0x1c) = 0x0 - 396 15 05 06 00 00 00 00 00 if r5 == 0x0 goto +0x6 + 396 15 05 10 00 00 00 00 00 if r5 == 0x0 goto +0x10 397 79 56 10 00 00 00 00 00 r6 = *(u64 *)(r5 + 0x10) - 398 5d 63 02 00 00 00 00 00 if r3 != r6 goto +0x2 + 398 5d 63 07 00 00 00 00 00 if r3 != r6 goto +0x7 399 7b 45 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = r4 - 400 05 00 10 00 00 00 00 00 goto +0x10 - 401 7b 45 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = r4 - 402 05 00 0e 00 00 00 00 00 goto +0xe - 403 7b 41 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r4 - 404 05 00 0c 00 00 00 00 00 goto +0xc - 405 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) - 406 55 05 02 00 00 00 00 00 if r5 != 0x0 goto +0x2 - 407 7a 01 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = 0x0 - 408 05 00 08 00 00 00 00 00 goto +0x8 - 409 71 34 1c 00 00 00 00 00 r4 = *(u8 *)(r3 + 0x1c) - 410 55 04 06 00 01 00 00 00 if r4 != 0x1 goto +0x6 - 411 79 54 10 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x10) - 412 5d 43 02 00 00 00 00 00 if r3 != r4 goto +0x2 - 413 7a 05 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = 0x0 - 414 05 00 02 00 00 00 00 00 goto +0x2 - 415 7a 05 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = 0x0 - 416 05 00 00 00 00 00 00 00 goto +0x0 - 417 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 - 418 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 - 419 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) - 420 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 - 421 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 - 422 95 00 00 00 00 00 00 00 exit - 423 b7 00 00 00 09 00 00 00 r0 = 0x9 - 424 95 00 00 00 00 00 00 00 exit - 425 b7 00 00 00 0c 00 00 00 r0 = 0xc - 426 95 00 00 00 00 00 00 00 exit - 427 b7 00 00 00 01 00 00 00 r0 = 0x1 + 400 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 401 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 402 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 403 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 404 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 405 95 00 00 00 00 00 00 00 exit + 406 7b 45 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = r4 + 407 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 408 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 409 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 410 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 411 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 412 95 00 00 00 00 00 00 00 exit + 413 7b 41 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = r4 + 414 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 415 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 416 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 417 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 418 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 419 95 00 00 00 00 00 00 00 exit + 420 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 421 55 05 07 00 00 00 00 00 if r5 != 0x0 goto +0x7 + 422 7a 01 c0 28 00 00 00 00 *(u64 *)(r1 + 0x28c0) = 0x0 + 423 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 424 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 425 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 426 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 427 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 428 95 00 00 00 00 00 00 00 exit - 429 b7 00 00 00 0d 00 00 00 r0 = 0xd - 430 95 00 00 00 00 00 00 00 exit - 431 b7 00 00 00 0a 00 00 00 r0 = 0xa - 432 95 00 00 00 00 00 00 00 exit - 433 b7 00 00 00 08 00 00 00 r0 = 0x8 - 434 95 00 00 00 00 00 00 00 exit - 435 b7 00 00 00 07 00 00 00 r0 = 0x7 - 436 95 00 00 00 00 00 00 00 exit - 437 b7 00 00 00 04 00 00 00 r0 = 0x4 - 438 95 00 00 00 00 00 00 00 exit - 439 b7 00 00 00 06 00 00 00 r0 = 0x6 - 440 95 00 00 00 00 00 00 00 exit - 441 b7 00 00 00 03 00 00 00 r0 = 0x3 - 442 95 00 00 00 00 00 00 00 exit - 443 b7 00 00 00 05 00 00 00 r0 = 0x5 - 444 95 00 00 00 00 00 00 00 exit - 445 b7 00 00 00 02 00 00 00 r0 = 0x2 - 446 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 429 71 34 1c 00 00 00 00 00 r4 = *(u8 *)(r3 + 0x1c) + 430 55 04 10 00 01 00 00 00 if r4 != 0x1 goto +0x10 + 431 79 54 10 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x10) + 432 5d 43 07 00 00 00 00 00 if r3 != r4 goto +0x7 + 433 7a 05 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = 0x0 + 434 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 435 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 436 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 437 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 438 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 439 95 00 00 00 00 00 00 00 exit + 440 7a 05 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = 0x0 + 441 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 442 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 443 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 444 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 445 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 446 95 00 00 00 00 00 00 00 exit + 447 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 + 448 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 + 449 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 450 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 + 451 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 + 452 95 00 00 00 00 00 00 00 exit + 453 b7 00 00 00 09 00 00 00 r0 = 0x9 + 454 95 00 00 00 00 00 00 00 exit + 455 b7 00 00 00 0c 00 00 00 r0 = 0xc + 456 95 00 00 00 00 00 00 00 exit + 457 b7 00 00 00 01 00 00 00 r0 = 0x1 + 458 95 00 00 00 00 00 00 00 exit + 459 b7 00 00 00 0d 00 00 00 r0 = 0xd + 460 95 00 00 00 00 00 00 00 exit + 461 b7 00 00 00 0a 00 00 00 r0 = 0xa + 462 95 00 00 00 00 00 00 00 exit + 463 b7 00 00 00 08 00 00 00 r0 = 0x8 + 464 95 00 00 00 00 00 00 00 exit + 465 b7 00 00 00 07 00 00 00 r0 = 0x7 + 466 95 00 00 00 00 00 00 00 exit + 467 b7 00 00 00 04 00 00 00 r0 = 0x4 + 468 95 00 00 00 00 00 00 00 exit + 469 b7 00 00 00 06 00 00 00 r0 = 0x6 + 470 95 00 00 00 00 00 00 00 exit + 471 b7 00 00 00 03 00 00 00 r0 = 0x3 + 472 95 00 00 00 00 00 00 00 exit + 473 b7 00 00 00 05 00 00 00 r0 = 0x5 + 474 95 00 00 00 00 00 00 00 exit + 475 b7 00 00 00 02 00 00 00 r0 = 0x2 + 476 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-2.txt b/examples/tree/artifacts/snippets/asm/remove-simple-2.txt index 70b91b94..34c9f2b3 100644 --- a/examples/tree/artifacts/snippets/asm/remove-simple-2.txt +++ b/examples/tree/artifacts/snippets/asm/remove-simple-2.txt @@ -12,12 +12,27 @@ remove_simple_2_child_l: # r4 ldxdw r6, [r5 + TREE_NODE_CHILD_R_OFF] # r6 = parent.child[R]; jne r3, r6, remove_simple_2_dir_l stxdw [r5 + TREE_NODE_CHILD_R_OFF], r4 # parent.child[R] = child; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_2_dir_l: stxdw [r5 + TREE_NODE_CHILD_L_OFF], r4 # parent.child[L] = child; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_2_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r4 # tree.root = child; - ja remove_recycle \ No newline at end of file + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-3.txt b/examples/tree/artifacts/snippets/asm/remove-simple-3.txt index 7db07b3c..b09f3383 100644 --- a/examples/tree/artifacts/snippets/asm/remove-simple-3.txt +++ b/examples/tree/artifacts/snippets/asm/remove-simple-3.txt @@ -4,4 +4,9 @@ remove_check_simple_3_4: # r3 ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; jne r5, NULL, remove_check_simple_4 stdw [r1 + IB_TREE_DATA_ROOT_OFF], NULL # tree.root = null; - ja remove_recycle \ No newline at end of file + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/asm/remove-simple-4.txt b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt index b3d7133e..54dea2a2 100644 --- a/examples/tree/artifacts/snippets/asm/remove-simple-4.txt +++ b/examples/tree/artifacts/snippets/asm/remove-simple-4.txt @@ -6,8 +6,18 @@ remove_check_simple_4: # r5 ldxdw r4, [r5 + TREE_NODE_CHILD_R_OFF] # r4 = parent.child[R]; jne r3, r4, remove_simple_4_dir_l stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_4_dir_l: stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; - ja remove_recycle \ No newline at end of file + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_simple/result.txt b/examples/tree/artifacts/tests/remove_simple/result.txt index b37ff895..81647402 100644 --- a/examples/tree/artifacts/tests/remove_simple/result.txt +++ b/examples/tree/artifacts/tests/remove_simple/result.txt @@ -1,86 +1,86 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Successor immediate R (SC 1) | 41 | 55 | +14 | +34.1% | -| Successor deep L descent (SC 1) | 45 | 59 | +14 | +31.1% | -| Successor with R child (SC 1) | 41 | 54 | +13 | +31.7% | -| One child root R (SC 2) | 32 | 43 | +11 | +34.4% | -| One child root L (SC 2) | 32 | 42 | +10 | +31.2% | -| One child non-root R,R (SC 2) | 39 | 52 | +13 | +33.3% | -| One child non-root L,L (SC 2) | 39 | 54 | +15 | +38.5% | -| One child non-root R,L (SC 2) | 39 | 55 | +16 | +41.0% | -| One child non-root L,R (SC 2) | 39 | 51 | +12 | +30.8% | -| Root leaf (SC 3) | 30 | 42 | +12 | +40.0% | -| Red leaf L (SC 4) | 39 | 56 | +17 | +43.6% | -| Red leaf R (SC 4) | 39 | 53 | +14 | +35.9% | +| Successor immediate R (SC 1) | 40 | 55 | +15 | +37.5% | +| Successor deep L descent (SC 1) | 44 | 59 | +15 | +34.1% | +| Successor with R child (SC 1) | 40 | 54 | +14 | +35.0% | +| One child root R (SC 2) | 31 | 43 | +12 | +38.7% | +| One child root L (SC 2) | 31 | 42 | +11 | +35.5% | +| One child non-root R,R (SC 2) | 38 | 52 | +14 | +36.8% | +| One child non-root L,L (SC 2) | 38 | 54 | +16 | +42.1% | +| One child non-root R,L (SC 2) | 38 | 55 | +17 | +44.7% | +| One child non-root L,R (SC 2) | 38 | 51 | +13 | +34.2% | +| Root leaf (SC 3) | 29 | 42 | +13 | +44.8% | +| Red leaf L (SC 4) | 38 | 56 | +18 | +47.4% | +| Red leaf R (SC 4) | 38 | 53 | +15 | +39.5% | test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 45 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 41 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 32 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 30 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 39 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units diff --git a/examples/tree/specs/parity-workflow.md b/examples/tree/specs/parity-workflow.md new file mode 100644 index 00000000..744237ff --- /dev/null +++ b/examples/tree/specs/parity-workflow.md @@ -0,0 +1,122 @@ +# Parity workflow + +Reusable workflow for verifying that Rust and assembly +implementations produce equivalent behavior and comparable +instruction-level output. Applicable to any example in +`examples/`. + +## Generating and comparing disassembly + +Use `/disassemble-example ` to generate Rust disassembly +(e.g., `/disassemble-example tree`). The output lives at +`examples//artifacts/rs-disassembly.s`. Compare it +side-by-side with the corresponding assembly source: + +- Run `/disassemble-example ` to regenerate the Rust + disassembly artifact. +- Open `examples//artifacts/rs-disassembly.s` and locate + the function or block under review. +- Open the corresponding section of the assembly source and + align the two side by side. +- Walk through instruction by instruction, noting structural + differences: extra jumps, reordered operations, missing + inlining, different register usage. + +The goal is structural equivalence, not byte-identical output. +The Rust compiler may reorder instructions or use different +registers while producing equivalent behavior. + +## Identifying optimization opportunities + +Disassembly comparison reveals concrete optimization targets. +Look for: + +- **Duplicated instruction sequences.** Repeated blocks that + could be factored into a shared label or inlined at each site. +- **Unnecessary jumps.** Branches to code that immediately + follows — often introduced by nested `if/else` or macro + expansion. +- **Register pressure differences.** Cases where the Rust + compiler spills to the stack while the assembly keeps values + in registers, or vice versa. +- **Missed inlining opportunities.** Function calls that the + compiler did not inline despite `#[inline(always)]`, or + macros that expand into more instructions than the equivalent + hand-written code. + +Macro expansion can produce duplicated code at each call site. +Before restructuring to eliminate duplication, evaluate whether +it actually hurts CU count — the compiler often optimizes each +expansion independently, producing tighter code than a unified +block. Only restructure when measurable improvement is +confirmed. + +## Branch coverage verification checklist + +Trace each test through both the Rust and assembly +implementations to confirm that both paths execute the same +logical branches. + +- Start with a branch table that maps each conditional jump to + the test numbers that exercise it. For example, the "Assembly + branches" table in `remove-tests.md`: + + ```text + | ID | Branch | Tests | + | --- | ------------------------- | ----------------- | + | B1 | found : L==null | 10,12,14,16,17,18 | + ... + ``` + +- For each branch ID, pick a representative test and manually + trace it through the assembly path, confirming which branch + is taken or not taken. + +- Trace the same test through the Rust path, confirming the + corresponding conditional takes the same direction. + +- Record any discrepancies. A branch exercised in assembly but + unreachable in Rust (or vice versa) indicates a structural + divergence that must be resolved. + +Use the branch-to-test mapping format as a template for new +instructions. Each new instruction's spec should include an +equivalent table covering every conditional jump in both +implementations. + +## Iterative optimization loop + +Parity verification is iterative. The cycle: + +- **Edit code.** Make a targeted change to the Rust + implementation (restructure control flow, adjust macro + boundaries, inline a helper). +- **Regenerate disassembly.** Run `/disassemble-example ` + to produce updated Rust disassembly. +- **Compare with assembly.** Diff the new disassembly against + the assembly source to confirm the change had the intended + effect. +- **Run tests.** Run `/build-example ` and wait for the + full pipeline to finish (build, dump, disassemble, test, + snippets, verification). Then check the result file at + `examples//artifacts/tests/*/result.txt` to confirm + all tests pass and review the CU comparison table for + overhead changes. +- **Verify parity.** Confirm that the Rust disassembly now + matches the assembly structure more closely (or produces + equivalent/better code). Use the CU table in the result + file as the ground truth for overhead — do not manually + calculate CU from logs. +- **Repeat.** Continue until the target section is at parity. + +Stop when one of these conditions holds: + +- The Rust disassembly matches the assembly structure for the + section under review (same labels, same branch topology, same + instruction count within a small margin). +- The Rust disassembly produces demonstrably better code (fewer + instructions, fewer branches) while maintaining identical + test results. +- The Rust overhead is within acceptable bounds for the use + case, or further optimization would require restructuring + that degrades code clarity without meaningful CU improvement. diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index 33d078b6..9450aad9 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -404,23 +404,23 @@ N3, recolor N3 black. Each branch corresponds to a conditional jump in the remove path. "Taken/not-taken" refers to the `jeq`/`jne` outcome. -| ID | Branch | Tests | -| --- | ------------------------- | ------------- | -| B1 | found : L==null | 10,12,14--18 | -| B2 | found : R==null | 11,13,15 | -| B3 | found : both non-null | 19--21 | -| B4 | successor : L==null | 19,21 | -| B5 | successor : L!=null | 20 | -| B6 | check_child_r : R==null | 14--20 | -| B7 | check_child_r : R!=null | 10,12,21 | -| B8 | simple_2 : parent==null | 10,11 | -| B9 | simple_2 : R direction | 12,15,21 | -| B10 | simple_2 : L direction | 13,14 | -| B11 | simple_3_4 : parent==null | 16 | -| B12 | simple_3_4 : parent!=null | 17--20 | -| B13 | simple_4 : color!=RED | (rebalancing) | -| B14 | simple_4 : R direction | 18,19 | -| B15 | simple_4 : L direction | 17,20 | +| ID | Branch | Tests | +| --- | ------------------------- | ----------------- | +| B1 | found : L==null | 10,12,14,16,17,18 | +| B2 | found : R==null | 11,13,15 | +| B3 | found : both non-null | 19--21 | +| B4 | successor : L==null | 19,20,21 | +| B5 | successor : L!=null | 20 | +| B6 | check_child_r : R==null | 16,17,18,19,20 | +| B7 | check_child_r : R!=null | 10,12,14,21 | +| B8 | simple_2 : parent==null | 10,11 | +| B9 | simple_2 : R direction | 12,15,21 | +| B10 | simple_2 : L direction | 13,14 | +| B11 | simple_3_4 : parent==null | 16 | +| B12 | simple_3_4 : parent!=null | 17--20 | +| B13 | simple_4 : color!=RED | (rebalancing) | +| B14 | simple_4 : R direction | 18,19 | +| B15 | simple_4 : L direction | 17,20 | All branches except B13 are exercised by the simple removal tests. B13 is the entry to the complex rebalancing case, covered @@ -430,23 +430,27 @@ by tests #22--#45. `remove_simple_2_child_replace!` expands at two call sites, producing separate compiled code for each. Full branch coverage -requires exercising all three parent-direction branches at each -site. - -| Site | Parent dir | Tests | -| ---- | ---------- | ------ | -| L627 | null | 11 | -| L627 | R | 15 | -| L627 | L | 13 | -| R633 | null | 10 | -| R633 | R | 12, 21 | -| R633 | L | 14 | +requires exercising all three parent-direction branches at both +sites. + +| Site | Parent dir | Tests | +| ------- | ---------- | ------ | +| L-child | null | 11 | +| L-child | R | 15 | +| L-child | L | 13 | +| R-child | null | 10 | +| R-child | R | 12, 21 | +| R-child | L | 14 | `remove_recycle_node!` is a straight-line macro (no branches) -called from four sites: both `remove_simple_2_child_replace` +called from four sites: both `remove_simple_2_child_replace!` expansions, simple case 3, and simple case 4. All sites are -exercised by the simple tests. The free-stack state (empty vs -non-empty) is covered by tests #46--#48 (multi-step integration). +exercised by the simple tests. + +Any macro used for decomposition must have its call-site +variants covered by tests. Free-stack state (empty vs +non-empty) is covered by the multi-step integration tests +(#46--#48). ## Wikipedia reference -- rebalancing loop invariant diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index 86fc07af..b81d216a 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -425,6 +425,83 @@ value that was associated with the removed key. - Inline case 5+6 at each goto site (four sites: two inside the red-sibling block, two outside). +## Rust implementation — macro-based decomposition + +The Rust remove function uses nested conditional checks with +macros for code reuse. After finding the node to remove and +saving `value = node.value`: + +- Check if left child exists. If yes, check right child: + - Both children present → **simple case 1** (successor swap). + Copy key/value from the in-order successor to the found + node, then reassign `node = successor`. Fall through to + check the successor's right child. + - Left child only → **simple case 2** (L-only child). Invoke + `remove_simple_2_child_replace!` with + `child = node.child[L]`. +- Check right child (reached when no left child, or after + simple case 1): + - Right child present → **simple case 3** (R-only child). + Invoke `remove_simple_2_child_replace!` with + `child = node.child[R]`. + - No right child → **simple case 4** (leaf removal). Handle + root-leaf, red-leaf, or black-leaf (complex case) inline. + +`remove_simple_2_child_replace!` handles child replacement at +two call sites (one for the L-child case, one for the R-child +case). Each expansion produces independent compiled code. +`remove_recycle_node!` handles recycling the removed node at +each removal path. + +This macro-based structure with nested `if/else` produces +better compiler output than a linear restructure. The compiler +optimizes each macro expansion independently, producing tighter +code than a unified block. + +## Recycle inlining optimization + +The six `ja remove_recycle` jumps in `tree.s` are each inlined with +the 5-instruction recycle sequence plus `exit`. The +`remove_recycle:` label is preserved as a reference comment in the +assembly source. + +Rationale: this matches what the Rust compiler already does. The +Rust `remove()` function has no shared recycle subroutine — each +removal path inlines the free-stack push and exit. Inlining in +assembly eliminates six jumps to a shared epilogue, trading code +size for fewer branch instructions. + +The inlined sequence at each site: + +- Null both child pointers (`child[L]` and `child[R]`). +- Load current `tree_header.top`. +- Set `node.next = old_top` (using the `StackNode.next` overlay at + offset 0). +- Set `tree_header.top = node`. +- `exit`. + +## Child replacement — assembly vs Rust + +The assembly uses a single `remove_simple_2_child_l` block for +both the L-only child path (simple case 2) and the R-only child +path reached via `remove_check_child_r` (simple case 3). Both +paths load the child pointer into `r4` before jumping to the +shared block, regardless of direction. In assembly, explicit +register management makes a unified block natural. + +The Rust intentionally uses two `remove_simple_2_child_replace!` +call sites rather than a unified block. Each call site handles a +different direction (L-child vs R-child path), and the compiler +optimizes each expansion independently. This produces tighter +code than a single shared block because the compiler can +specialize each path. + +The two approaches achieve equivalent results: + +- Assembly: unified block with child pointer in `r4`, + direction-agnostic. +- Rust: separate macro expansions, compiler-optimized per path. + ## Assembly implementation notes The remove instruction label is added after the insert instruction diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 7de30290..3a191969 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -948,15 +948,30 @@ remove_simple_2_child_l: # r4 ldxdw r6, [r5 + TREE_NODE_CHILD_R_OFF] # r6 = parent.child[R]; jne r3, r6, remove_simple_2_dir_l stxdw [r5 + TREE_NODE_CHILD_R_OFF], r4 # parent.child[R] = child; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_2_dir_l: stxdw [r5 + TREE_NODE_CHILD_L_OFF], r4 # parent.child[L] = child; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_2_root: stxdw [r1 + IB_TREE_DATA_ROOT_OFF], r4 # tree.root = child; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit # ANCHOR_END: remove-simple-2 # ANCHOR: remove-simple-3 @@ -966,7 +981,12 @@ remove_check_simple_3_4: # r3 ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; jne r5, NULL, remove_check_simple_4 stdw [r1 + IB_TREE_DATA_ROOT_OFF], NULL # tree.root = null; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit # ANCHOR_END: remove-simple-3 # ANCHOR: remove-simple-4 @@ -978,19 +998,25 @@ remove_check_simple_4: # r5 ldxdw r4, [r5 + TREE_NODE_CHILD_R_OFF] # r4 = parent.child[R]; jne r3, r4, remove_simple_4_dir_l stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit remove_simple_4_dir_l: stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; - ja remove_recycle + stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + exit # ANCHOR_END: remove-simple-4 remove_complex: # TODO: complex case (black non-root leaf). - -remove_recycle: - # Recycle node to free stack. - # --------------------------------------------------------------------- stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; @@ -998,6 +1024,8 @@ remove_recycle: stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; exit + # remove_recycle: (inlined at each site above) + e_instruction_data: mov64 r0, E_INSTRUCTION_DATA exit From 4c18d3976948361c10790a7901f075ba0f098e3a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Mon, 2 Mar 2026 18:39:28 -0800 Subject: [PATCH 249/263] Add overhead analysis --- examples/tree/specs/cu-overhead-analysis.md | 102 ++++++++++++++++++++ examples/tree/specs/parity-workflow.md | 18 ++++ 2 files changed, 120 insertions(+) create mode 100644 examples/tree/specs/cu-overhead-analysis.md diff --git a/examples/tree/specs/cu-overhead-analysis.md b/examples/tree/specs/cu-overhead-analysis.md new file mode 100644 index 00000000..14254574 --- /dev/null +++ b/examples/tree/specs/cu-overhead-analysis.md @@ -0,0 +1,102 @@ +# CU overhead analysis + +Methodology for attributing CU overhead in Rust implementations +relative to hand-written assembly. Produces actionable +optimization targets. + +## Inputs + +Each analysis requires: + +- ASM snippet for the section under review (from + `artifacts/tests/*/snippets/`). +- RS disassembly snippet for the same section (from + `artifacts/rs-disassembly.s`). +- CU table from `artifacts/tests/*/result.txt`. +- Relevant algorithm spec for context (from `specs/`). + +## Workflow + +### Step 1 — Section isolation + +Pick one ANCHOR section. Work on one section at a time. +Identify the corresponding ASM and RS code blocks. + +### Step 2 — Instruction count + +Count executed instructions per test case path for both ASM +and RS. Record the delta (RS - ASM) for each test case. + +### Step 3 — Structural alignment + +Walk both snippets in parallel, marking each instruction as: + +- **Matched.** Same operation, same position. +- **Reordered.** Same operation, different position. +- **Extra (RS).** Present in RS but not ASM. +- **Extra (ASM).** Present in ASM but not RS. +- **Divergent.** Different operation at corresponding position. + +### Step 4 — Overhead classification + +Classify every extra RS instruction into a category: + +| Category | Code | Description | +| ---------------- | ---- | ----------------------------------------------- | +| Redundant branch | RB | Null check or conditional that ASM avoids. | +| Macrodup. | MD | Instruction duplicated across macro exp. sites. | +| Register reload | RR | Value loaded from memory that ASM keeps in reg. | +| Register spill | RS | Stack spill/reload from register pressure. | +| Jump overhead | JO | Extra branch to reach shared code. | +| Compiler art. | CA | No logical purpose (nop, identity move). | + +### Step 5 — Per-test CU attribution + +For each test case, trace the executed path and attribute the +CU delta to specific extra instructions with their category +codes. + +### Step 6 — Pattern aggregation + +Aggregate across all test cases: + +- Total extra CUs per category. +- Percentage of total overhead per category. +- Reducibility assessment (can this overhead be eliminated + through Rust source changes?). + +### Step 7 — Optimization target ranking + +Rank by reducible CUs (highest first). Each target becomes a +work item for Engineering. + +## Deliverable format + +Each analysis produces a document at +`examples//specs/cu-analysis-
.md` containing: + +- Summary table (section, test count, mean/min/max overhead). +- Per-test attribution tables. +- Pattern aggregation table. +- Optimization targets (prioritized). +- Engineering recommendations. + +## Overhead baselines + +- **Target:** \<=10% for hot paths. +- **Acceptable:** 10-20% for cold paths. +- **Needs work:** >20%. + +## Relationship to parity workflow + +Analysis runs first to identify WHERE overhead comes from and +WHY. The parity optimization loop (see `parity-workflow.md`) +then drives improvements on the identified targets. After +Engineering implements changes, Analysis re-measures to confirm +overhead reduction. + +```text +Analysis identifies overhead → Spec documents targets → +Engineering optimizes Rust → Build + test → Analysis +re-measures → QA verifies → repeat until baseline met +``` diff --git a/examples/tree/specs/parity-workflow.md b/examples/tree/specs/parity-workflow.md index 744237ff..cbbe6a1a 100644 --- a/examples/tree/specs/parity-workflow.md +++ b/examples/tree/specs/parity-workflow.md @@ -120,3 +120,21 @@ Stop when one of these conditions holds: - The Rust overhead is within acceptable bounds for the use case, or further optimization would require restructuring that degrades code clarity without meaningful CU improvement. + +## CU overhead analysis + +Before optimizing, run the CU overhead analysis workflow to +identify WHERE overhead comes from and prioritize targets. See +`cu-overhead-analysis.md` for the full methodology. + +The analysis pipeline feeds into the optimization loop: + +- **Analysis** identifies overhead sources and classifies them + (redundant branches, macro duplication, register spills, + etc.). +- **Optimization targets** are ranked by reducible CUs and + handed to Engineering. +- **This parity workflow** drives the iterative optimization + cycle on each target. +- **Analysis re-measures** after each optimization to confirm + overhead reduction. From 968f97ed7b01e044af6d6ae02680ca08eb75688b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Mar 2026 12:21:02 -0800 Subject: [PATCH 250/263] Add preliminary remove complex impl --- examples/tree/src/program.rs | 90 +++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index a678abc1..34155b43 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -651,7 +651,90 @@ unsafe fn remove( // ANCHOR_END: remove-simple-4 }; // ANCHOR: remove-complex - remove_recycle_node!(node, tree_header); + let mut parent = (*node).parent; + let mut dir = direction(node); + (*parent).child[dir] = null_mut(); + let removed_node = node; + + let mut sibling: *mut TreeNode; + let mut close_nephew: *mut TreeNode; + let mut distant_nephew: *mut TreeNode; + // 0 = done (cases 1/2/4), 5 = case 5+6, 6 = case 6 only. + let mut exit_case: u32 = 0; + + loop { + sibling = (*parent).child[1 - dir]; + distant_nephew = (*sibling).child[1 - dir]; + close_nephew = (*sibling).child[dir]; + + if (*sibling).color == Color::Red { + // Case 3. + rotate_subtree(tree_header, parent, dir); + (*parent).color = Color::Red; + (*sibling).color = Color::Black; + sibling = close_nephew; + + distant_nephew = (*sibling).child[1 - dir]; + if !distant_nephew.is_null() && (*distant_nephew).color == Color::Red { + exit_case = 6; + break; + } + close_nephew = (*sibling).child[dir]; + if !close_nephew.is_null() && (*close_nephew).color == Color::Red { + exit_case = 5; + break; + } + + // Case 4. + (*sibling).color = Color::Red; + (*parent).color = Color::Black; + break; + } + + if !distant_nephew.is_null() && (*distant_nephew).color == Color::Red { + exit_case = 6; + break; + } + + if !close_nephew.is_null() && (*close_nephew).color == Color::Red { + exit_case = 5; + break; + } + + if (*parent).color == Color::Red { + // Case 4. + (*sibling).color = Color::Red; + (*parent).color = Color::Black; + break; + } + + // Case 2. + (*sibling).color = Color::Red; + node = parent; + parent = (*node).parent; + if parent.is_null() { + break; + } + dir = direction(node); + } + + // Case 5 falls through to case 6. + if exit_case == 5 { + rotate_subtree(tree_header, sibling, 1 - dir); + (*sibling).color = Color::Red; + (*close_nephew).color = Color::Black; + distant_nephew = sibling; + sibling = close_nephew; + } + + if exit_case >= 5 { + rotate_subtree(tree_header, parent, dir); + (*sibling).color = read_unaligned(addr_of!((*parent).color)); + (*parent).color = Color::Black; + (*distant_nephew).color = Color::Black; + } + + remove_recycle_node!(removed_node, tree_header); // ANCHOR_END: remove-complex } @@ -810,6 +893,11 @@ unsafe fn initialize( SUCCESS } +#[inline(always)] +unsafe fn direction(node: *const TreeNode) -> usize { + (node == (*(*node).parent).child[tree::DIR_R]) as usize +} + #[inline(always)] unsafe fn search(tree_header: *const TreeHeader, key: u16) -> *mut TreeNode { let mut node = (*tree_header).root; From d864460bf8f1637c0aef1cc0db622b4ff4e19b8a Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:11:00 -0800 Subject: [PATCH 251/263] Add first pass of remove-complex algo --- examples/tree/src/tree/tree.s | 102 +++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 3a191969..51dfef9c 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1015,16 +1015,112 @@ remove_simple_4_dir_l: exit # ANCHOR_END: remove-simple-4 +# ANCHOR: remove-complex remove_complex: - # TODO: complex case (black non-root leaf). + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + ldxb r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L]; + jne r3, r4, remove_complex_dir_r # if node != parent.child[L] goto remove_complex_dir_r +remove_complex_dir_l: + # Prepare to loop for when node direction is left. + # --------------------------------------------------------------------- + stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; + ja remove_complex_loop_dir_l # goto remove_complex_loop_dir_l +remove_complex_dir_r: + # Prepare to loop for when node direction is right. + # --------------------------------------------------------------------- + stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; +remove_complex_loop_dir_r: + # Rebalance loop for when node direction is right. + # --------------------------------------------------------------------- + ldxdw r6, [r4 + TREE_NODE_CHILD_L_OFF] # r6 = sibling = parent.child[1 - dir]; + ldxdw r7, [r6 + TREE_NODE_CHILD_L_OFF] # r7 = distant_nephew = sibling.child[1 - dir]; + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = close_nephew = sibling.child[dir]; + # Check for red sibling. + # --------------------------------------------------------------------- + ldxb r9, [r6 + TREE_NODE_COLOR_OFF] # r9 = sibling.color; + jeq r9, TREE_COLOR_R, remove_complex_loop_dir_r_sibling_red # if sibling.color == red goto remove_complex_loop_dir_r_sibling_red + # Check for red distant nephew. + # --------------------------------------------------------------------- + jeq r7, NULL, remove_complex_loop_dir_r_check_case_5 # if distant_nephew == null goto remove_complex_loop_dir_r_check_case_5 + ldxb r9, [r7 + TREE_NODE_COLOR_OFF] # r9 = distant_nephew.color; + jeq r9, TREE_COLOR_R, remove_complex_case_6_dir_r # if distant_nephew.color == red goto remove_complex_case_6_dir_r +remove_complex_loop_dir_r_check_case_5: + # Check for red close nephew. + # --------------------------------------------------------------------- + jeq r8, NULL, remove_complex_loop_dir_r_check_case_1 # if close_nephew == null goto remove_complex_loop_dir_r_check_case_1 + ldxb r9, [r8 + TREE_NODE_COLOR_OFF] # r9 = close_nephew.color; + jeq r9, TREE_COLOR_R, remove_complex_case_5_dir_r # if close_nephew.color == red goto remove_complex_case_5_dir_r +remove_complex_loop_dir_r_check_case_1: + # Check for no parent. + # --------------------------------------------------------------------- + jeq r5, NULL, remove_complex_recycle_node # if parent == null goto remove_complex_recycle_node; + # Check for red parent. + # --------------------------------------------------------------------- + ldxb r9, [r5 + TREE_NODE_COLOR_OFF] # r9 = parent.color; + jne r9, TREE_COLOR_R, remove_complex_loop_dir_r_case_2 # if parent.color != red goto remove_complex_loop_dir_r_case_2 + ldxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + ldxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + ja remove_complex_recycle_node # goto remove_complex_recycle_node; +remove_complex_loop_dir_r_case_2: + # Fall through to case 2 at end of loop. + # --------------------------------------------------------------------- + ldxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + mov64 r3, r5 # node = parent; + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # parent = node.parent; + # Check if parent exists, and if so, get direction for next loop. + # --------------------------------------------------------------------- + jeq r5, NULL, remove_complex_case_5_dir_r # if parent == null goto remove_complex_case_5_dir_r + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L] + jeq r3, r4, remove_complex_dir_l # if node == parent.child[L] goto remove_complex_dir_l + ja remove_complex_dir_r # goto remove_complex_dir_r +remove_complex_case_5_dir_r: + # rotate_subtree(tree, sibling, 1-dir) + stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stxb [r8 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # close_nephew.color = black; + mov64 r7, r6 # distant_nephew = sibling; + mov64 r6, r8 # sibling = close_nephew; +remove_complex_case_6_dir_r: + # rotate_subtree(tree, parent, dir) + ldxb r4, [r5 + TREE_NODE_COLOR_OFF] # r4 = parent.color; + stxb [r6, + TREE_NODE_COLOR_OFF], r4 # sibling.color = parent.color; + stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stxb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # distant_nephew.color = black; + ja remove_complex_recycle_node +remove_complex_loop_dir_r_sibling_red: + # Rebalance for red sibling case. + # --------------------------------------------------------------------- + # rotate_subtree(tree, parent, dir) + stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # parent.color = red; + stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # sibling.color = black; + mov64 r6, r8 # sibling = close_nephew; + ldxdw r4, [r6 + TREE_NODE_CHILD_L_OFF] # r4 = sibling.child[L]; + mov64 r7, r4 # distant_nephew = sibling.child[L]; + jeq r7, NULL, remove_complex_loop_dir_r_sibling_red_check_case_5 # if distant_nephew == null goto remove_complex_loop_dir_r_sibling_red_check_case_5 + ldxb r4, [r7 + TREE_NODE_COLOR_OFF] # r4 = distant_nephew.color; + jeq r4, TREE_COLOR_R, remove_complex_case_6_dir_r # if distant_nephew.color == red goto remove_complex_case_6_dir_r +remove_complex_loop_dir_r_sibling_red_check_case_5: + ldxdw r4, [r6 + TREE_NODE_CHILD_R_OFF] # r4 = sibling.child[R]; + mov64 r8, r4 # close_nephew = sibling.child[R]; + jeq r8, NULL, remove_complex_loop_dir_r_sibling_red_case_4 # if close_nephew == null goto remove_complex_loop_dir_r_sibling_red_case_4 + ldxb r4, [r8 + TREE_NODE_COLOR_OFF] # r4 = close_nephew.color; + jeq r4, TREE_COLOR_R, remove_complex_case_5_dir_r # if close_nephew.color == red goto remove_complex_case_5_dir_r +remove_complex_loop_dir_r_sibling_red_case_4: + stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + ja remove_complex_recycle_node + +remove_complex_loop_dir_l: + # Mirror of remove_complex_loop_r. + # Needs all the other sub labels for the same cases, but with dir reversed. + +remove_complex_recycle_node: stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; exit - - # remove_recycle: (inlined at each site above) +# ANCHOR_END: remove-complex e_instruction_data: mov64 r0, E_INSTRUCTION_DATA From bef60018a8fd475739b93dce36bad07974e9e15b Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:23:26 -0800 Subject: [PATCH 252/263] Fix minor impl issues --- examples/tree/src/tree/tree.s | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index 51dfef9c..a4cc51a8 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1018,7 +1018,7 @@ remove_simple_4_dir_l: # ANCHOR: remove-complex remove_complex: ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; - ldxb r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L]; + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L]; jne r3, r4, remove_complex_dir_r # if node != parent.child[L] goto remove_complex_dir_r remove_complex_dir_l: # Prepare to loop for when node direction is left. @@ -1032,9 +1032,9 @@ remove_complex_dir_r: remove_complex_loop_dir_r: # Rebalance loop for when node direction is right. # --------------------------------------------------------------------- - ldxdw r6, [r4 + TREE_NODE_CHILD_L_OFF] # r6 = sibling = parent.child[1 - dir]; - ldxdw r7, [r6 + TREE_NODE_CHILD_L_OFF] # r7 = distant_nephew = sibling.child[1 - dir]; - ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = close_nephew = sibling.child[dir]; + ldxdw r6, [r5 + TREE_NODE_CHILD_L_OFF] # r6 = sibling = parent.child[L]; + ldxdw r7, [r6 + TREE_NODE_CHILD_L_OFF] # r7 = distant_nephew = sibling.child[L]; + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = close_nephew = sibling.child[R]; # Check for red sibling. # --------------------------------------------------------------------- ldxb r9, [r6 + TREE_NODE_COLOR_OFF] # r9 = sibling.color; @@ -1058,21 +1058,21 @@ remove_complex_loop_dir_r_check_case_1: # --------------------------------------------------------------------- ldxb r9, [r5 + TREE_NODE_COLOR_OFF] # r9 = parent.color; jne r9, TREE_COLOR_R, remove_complex_loop_dir_r_case_2 # if parent.color != red goto remove_complex_loop_dir_r_case_2 - ldxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; - ldxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; ja remove_complex_recycle_node # goto remove_complex_recycle_node; remove_complex_loop_dir_r_case_2: # Fall through to case 2 at end of loop. # --------------------------------------------------------------------- - ldxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; mov64 r3, r5 # node = parent; ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # parent = node.parent; # Check if parent exists, and if so, get direction for next loop. # --------------------------------------------------------------------- jeq r5, NULL, remove_complex_case_5_dir_r # if parent == null goto remove_complex_case_5_dir_r ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L] - jeq r3, r4, remove_complex_dir_l # if node == parent.child[L] goto remove_complex_dir_l - ja remove_complex_dir_r # goto remove_complex_dir_r + jeq r3, r4, remove_complex_loop_dir_l # if node == parent.child[L] goto remove_complex_loop_dir_l + ja remove_complex_loop_dir_r # goto remove_complex_loop_dir_r remove_complex_case_5_dir_r: # rotate_subtree(tree, sibling, 1-dir) stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; @@ -1082,7 +1082,7 @@ remove_complex_case_5_dir_r: remove_complex_case_6_dir_r: # rotate_subtree(tree, parent, dir) ldxb r4, [r5 + TREE_NODE_COLOR_OFF] # r4 = parent.color; - stxb [r6, + TREE_NODE_COLOR_OFF], r4 # sibling.color = parent.color; + stxb [r6 + TREE_NODE_COLOR_OFF], r4 # sibling.color = parent.color; stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; stxb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # distant_nephew.color = black; ja remove_complex_recycle_node From a4dbdf7716a7a01741580c01074e42f7c977dd24 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:41:26 -0800 Subject: [PATCH 253/263] Add more fixes --- examples/tree/src/tree/tree.s | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/tree/src/tree/tree.s b/examples/tree/src/tree/tree.s index a4cc51a8..924c45a3 100644 --- a/examples/tree/src/tree/tree.s +++ b/examples/tree/src/tree/tree.s @@ -1017,6 +1017,7 @@ remove_simple_4_dir_l: # ANCHOR: remove-complex remove_complex: + mov64 r2, r3 # r2 = deleted node (save for recycle); ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L]; jne r3, r4, remove_complex_dir_r # if node != parent.child[L] goto remove_complex_dir_r @@ -1075,23 +1076,23 @@ remove_complex_loop_dir_r_case_2: ja remove_complex_loop_dir_r # goto remove_complex_loop_dir_r remove_complex_case_5_dir_r: # rotate_subtree(tree, sibling, 1-dir) - stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; - stxb [r8 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # close_nephew.color = black; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r8 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # close_nephew.color = black; mov64 r7, r6 # distant_nephew = sibling; mov64 r6, r8 # sibling = close_nephew; remove_complex_case_6_dir_r: # rotate_subtree(tree, parent, dir) ldxb r4, [r5 + TREE_NODE_COLOR_OFF] # r4 = parent.color; stxb [r6 + TREE_NODE_COLOR_OFF], r4 # sibling.color = parent.color; - stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; - stxb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # distant_nephew.color = black; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # distant_nephew.color = black; ja remove_complex_recycle_node remove_complex_loop_dir_r_sibling_red: # Rebalance for red sibling case. # --------------------------------------------------------------------- # rotate_subtree(tree, parent, dir) - stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # parent.color = red; - stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # sibling.color = black; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # parent.color = red; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # sibling.color = black; mov64 r6, r8 # sibling = close_nephew; ldxdw r4, [r6 + TREE_NODE_CHILD_L_OFF] # r4 = sibling.child[L]; mov64 r7, r4 # distant_nephew = sibling.child[L]; @@ -1105,8 +1106,8 @@ remove_complex_loop_dir_r_sibling_red_check_case_5: ldxb r4, [r8 + TREE_NODE_COLOR_OFF] # r4 = close_nephew.color; jeq r4, TREE_COLOR_R, remove_complex_case_5_dir_r # if close_nephew.color == red goto remove_complex_case_5_dir_r remove_complex_loop_dir_r_sibling_red_case_4: - stxb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; - stxb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; ja remove_complex_recycle_node remove_complex_loop_dir_l: @@ -1114,11 +1115,11 @@ remove_complex_loop_dir_l: # Needs all the other sub labels for the same cases, but with dir reversed. remove_complex_recycle_node: - stdw [r3 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; - stdw [r3 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + stdw [r2 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r2 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; - stxdw [r3 + TREE_NODE_PARENT_OFF], r4 # node.next = top; - stxdw [r1 + IB_TREE_DATA_TOP_OFF], r3 # header.top = node; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r2 # header.top = node; exit # ANCHOR_END: remove-complex From 38caa6ad7b0e19646c364a568c841cc2b7dc36af Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:59:19 -0800 Subject: [PATCH 254/263] Tidy up docs --- docs/src/examples/tree.md | 11 ++ .../artifacts/snippets/asm/remove-complex.txt | 105 ++++++++++++++++++ .../artifacts/snippets/rs/remove-complex.txt | 85 +++++++++++++- 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 examples/tree/artifacts/snippets/asm/remove-complex.txt diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 83936a35..8f80298b 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -10,12 +10,19 @@ side-by-side with as much implementation parity as possible, using C-style Rust (raw pointers, direct [syscalls](../indices/syscalls.md)) to minimize compiler overhead. +The example implements a full insertion algorithm and simple removal algorithms +(no rebalancing on remove). The full remove implementation is left as an +exercise to the reader. + ::: details Core data structures <<< ../../../examples/tree/artifacts/snippets/interface/tree-defs-common.txt{rs} ::: +Note that these data structures rely on direct addressing, which may be broken +by [ABI v2]. + ## Build support Constants, error codes, and C bindings are derived in a shared interface using @@ -173,6 +180,8 @@ not available in Rust, since the compiler enforces ### Allocate +See [`AccountView::resize_unchecked`] for reference implementation. + ::: details Implementations ::: code-group @@ -378,6 +387,8 @@ not available in Rust, since the compiler enforces +[`AccountView::resize_unchecked`]: https://github.com/anza-xyz/solana-sdk/blob/bn254@v3.2.1/account-view/src/lib.rs#L363 +[abi v2]: https://github.com/solana-foundation/solana-improvement-documents/pull/177/changes#r2861798899 [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism [pda]: https://solana.com/docs/core/pda [tail call]: https://en.wikipedia.org/wiki/Tail_call diff --git a/examples/tree/artifacts/snippets/asm/remove-complex.txt b/examples/tree/artifacts/snippets/asm/remove-complex.txt new file mode 100644 index 00000000..e0384604 --- /dev/null +++ b/examples/tree/artifacts/snippets/asm/remove-complex.txt @@ -0,0 +1,105 @@ +remove_complex: + mov64 r2, r3 # r2 = deleted node (save for recycle); + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # r5 = parent; + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L]; + jne r3, r4, remove_complex_dir_r # if node != parent.child[L] goto remove_complex_dir_r +remove_complex_dir_l: + # Prepare to loop for when node direction is left. + # --------------------------------------------------------------------- + stdw [r5 + TREE_NODE_CHILD_L_OFF], NULL # parent.child[L] = null; + ja remove_complex_loop_dir_l # goto remove_complex_loop_dir_l +remove_complex_dir_r: + # Prepare to loop for when node direction is right. + # --------------------------------------------------------------------- + stdw [r5 + TREE_NODE_CHILD_R_OFF], NULL # parent.child[R] = null; +remove_complex_loop_dir_r: + # Rebalance loop for when node direction is right. + # --------------------------------------------------------------------- + ldxdw r6, [r5 + TREE_NODE_CHILD_L_OFF] # r6 = sibling = parent.child[L]; + ldxdw r7, [r6 + TREE_NODE_CHILD_L_OFF] # r7 = distant_nephew = sibling.child[L]; + ldxdw r8, [r6 + TREE_NODE_CHILD_R_OFF] # r8 = close_nephew = sibling.child[R]; + # Check for red sibling. + # --------------------------------------------------------------------- + ldxb r9, [r6 + TREE_NODE_COLOR_OFF] # r9 = sibling.color; + jeq r9, TREE_COLOR_R, remove_complex_loop_dir_r_sibling_red # if sibling.color == red goto remove_complex_loop_dir_r_sibling_red + # Check for red distant nephew. + # --------------------------------------------------------------------- + jeq r7, NULL, remove_complex_loop_dir_r_check_case_5 # if distant_nephew == null goto remove_complex_loop_dir_r_check_case_5 + ldxb r9, [r7 + TREE_NODE_COLOR_OFF] # r9 = distant_nephew.color; + jeq r9, TREE_COLOR_R, remove_complex_case_6_dir_r # if distant_nephew.color == red goto remove_complex_case_6_dir_r +remove_complex_loop_dir_r_check_case_5: + # Check for red close nephew. + # --------------------------------------------------------------------- + jeq r8, NULL, remove_complex_loop_dir_r_check_case_1 # if close_nephew == null goto remove_complex_loop_dir_r_check_case_1 + ldxb r9, [r8 + TREE_NODE_COLOR_OFF] # r9 = close_nephew.color; + jeq r9, TREE_COLOR_R, remove_complex_case_5_dir_r # if close_nephew.color == red goto remove_complex_case_5_dir_r +remove_complex_loop_dir_r_check_case_1: + # Check for no parent. + # --------------------------------------------------------------------- + jeq r5, NULL, remove_complex_recycle_node # if parent == null goto remove_complex_recycle_node; + # Check for red parent. + # --------------------------------------------------------------------- + ldxb r9, [r5 + TREE_NODE_COLOR_OFF] # r9 = parent.color; + jne r9, TREE_COLOR_R, remove_complex_loop_dir_r_case_2 # if parent.color != red goto remove_complex_loop_dir_r_case_2 + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + ja remove_complex_recycle_node # goto remove_complex_recycle_node; +remove_complex_loop_dir_r_case_2: + # Fall through to case 2 at end of loop. + # --------------------------------------------------------------------- + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + mov64 r3, r5 # node = parent; + ldxdw r5, [r3 + TREE_NODE_PARENT_OFF] # parent = node.parent; + # Check if parent exists, and if so, get direction for next loop. + # --------------------------------------------------------------------- + jeq r5, NULL, remove_complex_case_5_dir_r # if parent == null goto remove_complex_case_5_dir_r + ldxdw r4, [r5 + TREE_NODE_CHILD_L_OFF] # r4 = parent.child[L] + jeq r3, r4, remove_complex_loop_dir_l # if node == parent.child[L] goto remove_complex_loop_dir_l + ja remove_complex_loop_dir_r # goto remove_complex_loop_dir_r +remove_complex_case_5_dir_r: + # rotate_subtree(tree, sibling, 1-dir) + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r8 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # close_nephew.color = black; + mov64 r7, r6 # distant_nephew = sibling; + mov64 r6, r8 # sibling = close_nephew; +remove_complex_case_6_dir_r: + # rotate_subtree(tree, parent, dir) + ldxb r4, [r5 + TREE_NODE_COLOR_OFF] # r4 = parent.color; + stxb [r6 + TREE_NODE_COLOR_OFF], r4 # sibling.color = parent.color; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + stb [r7 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # distant_nephew.color = black; + ja remove_complex_recycle_node +remove_complex_loop_dir_r_sibling_red: + # Rebalance for red sibling case. + # --------------------------------------------------------------------- + # rotate_subtree(tree, parent, dir) + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # parent.color = red; + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # sibling.color = black; + mov64 r6, r8 # sibling = close_nephew; + ldxdw r4, [r6 + TREE_NODE_CHILD_L_OFF] # r4 = sibling.child[L]; + mov64 r7, r4 # distant_nephew = sibling.child[L]; + jeq r7, NULL, remove_complex_loop_dir_r_sibling_red_check_case_5 # if distant_nephew == null goto remove_complex_loop_dir_r_sibling_red_check_case_5 + ldxb r4, [r7 + TREE_NODE_COLOR_OFF] # r4 = distant_nephew.color; + jeq r4, TREE_COLOR_R, remove_complex_case_6_dir_r # if distant_nephew.color == red goto remove_complex_case_6_dir_r +remove_complex_loop_dir_r_sibling_red_check_case_5: + ldxdw r4, [r6 + TREE_NODE_CHILD_R_OFF] # r4 = sibling.child[R]; + mov64 r8, r4 # close_nephew = sibling.child[R]; + jeq r8, NULL, remove_complex_loop_dir_r_sibling_red_case_4 # if close_nephew == null goto remove_complex_loop_dir_r_sibling_red_case_4 + ldxb r4, [r8 + TREE_NODE_COLOR_OFF] # r4 = close_nephew.color; + jeq r4, TREE_COLOR_R, remove_complex_case_5_dir_r # if close_nephew.color == red goto remove_complex_case_5_dir_r +remove_complex_loop_dir_r_sibling_red_case_4: + stb [r6 + TREE_NODE_COLOR_OFF], TREE_COLOR_R # sibling.color = red; + stb [r5 + TREE_NODE_COLOR_OFF], TREE_COLOR_B # parent.color = black; + ja remove_complex_recycle_node + +remove_complex_loop_dir_l: + # Mirror of remove_complex_loop_r. + # Needs all the other sub labels for the same cases, but with dir reversed. + +remove_complex_recycle_node: + stdw [r2 + TREE_NODE_CHILD_L_OFF], NULL # node.child[L] = null; + stdw [r2 + TREE_NODE_CHILD_R_OFF], NULL # node.child[R] = null; + ldxdw r4, [r1 + IB_TREE_DATA_TOP_OFF] # r4 = header.top; + stxdw [r2 + TREE_NODE_PARENT_OFF], r4 # node.next = top; + stxdw [r1 + IB_TREE_DATA_TOP_OFF], r2 # header.top = node; + exit \ No newline at end of file diff --git a/examples/tree/artifacts/snippets/rs/remove-complex.txt b/examples/tree/artifacts/snippets/rs/remove-complex.txt index 5c6f12f3..a2edc32a 100644 --- a/examples/tree/artifacts/snippets/rs/remove-complex.txt +++ b/examples/tree/artifacts/snippets/rs/remove-complex.txt @@ -1 +1,84 @@ - remove_recycle_node!(node, tree_header); \ No newline at end of file + let mut parent = (*node).parent; + let mut dir = direction(node); + (*parent).child[dir] = null_mut(); + let removed_node = node; + + let mut sibling: *mut TreeNode; + let mut close_nephew: *mut TreeNode; + let mut distant_nephew: *mut TreeNode; + // 0 = done (cases 1/2/4), 5 = case 5+6, 6 = case 6 only. + let mut exit_case: u32 = 0; + + loop { + sibling = (*parent).child[1 - dir]; + distant_nephew = (*sibling).child[1 - dir]; + close_nephew = (*sibling).child[dir]; + + if (*sibling).color == Color::Red { + // Case 3. + rotate_subtree(tree_header, parent, dir); + (*parent).color = Color::Red; + (*sibling).color = Color::Black; + sibling = close_nephew; + + distant_nephew = (*sibling).child[1 - dir]; + if !distant_nephew.is_null() && (*distant_nephew).color == Color::Red { + exit_case = 6; + break; + } + close_nephew = (*sibling).child[dir]; + if !close_nephew.is_null() && (*close_nephew).color == Color::Red { + exit_case = 5; + break; + } + + // Case 4. + (*sibling).color = Color::Red; + (*parent).color = Color::Black; + break; + } + + if !distant_nephew.is_null() && (*distant_nephew).color == Color::Red { + exit_case = 6; + break; + } + + if !close_nephew.is_null() && (*close_nephew).color == Color::Red { + exit_case = 5; + break; + } + + if (*parent).color == Color::Red { + // Case 4. + (*sibling).color = Color::Red; + (*parent).color = Color::Black; + break; + } + + // Case 2. + (*sibling).color = Color::Red; + node = parent; + parent = (*node).parent; + if parent.is_null() { + break; + } + dir = direction(node); + } + + // Case 5 falls through to case 6. + if exit_case == 5 { + rotate_subtree(tree_header, sibling, 1 - dir); + (*sibling).color = Color::Red; + (*close_nephew).color = Color::Black; + distant_nephew = sibling; + sibling = close_nephew; + } + + if exit_case >= 5 { + rotate_subtree(tree_header, parent, dir); + (*sibling).color = read_unaligned(addr_of!((*parent).color)); + (*parent).color = Color::Black; + (*distant_nephew).color = Color::Black; + } + + remove_recycle_node!(removed_node, tree_header); \ No newline at end of file From 846982770e57d8c16286cae6f8c4243d932de6c3 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:01:30 -0800 Subject: [PATCH 255/263] Remove warning escapes --- examples/tree/interface/src/lib.rs | 1 - examples/tree/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/tree/interface/src/lib.rs b/examples/tree/interface/src/lib.rs index 77215faf..4194df4e 100644 --- a/examples/tree/interface/src/lib.rs +++ b/examples/tree/interface/src/lib.rs @@ -1,5 +1,4 @@ #![no_std] -#![allow(unused)] extern crate alloc; diff --git a/examples/tree/src/lib.rs b/examples/tree/src/lib.rs index 4690eac5..569ef2f5 100644 --- a/examples/tree/src/lib.rs +++ b/examples/tree/src/lib.rs @@ -1,5 +1,4 @@ #![cfg_attr(not(test), no_std)] -#![allow(unused)] mod program; #[cfg(test)] From 1d5b2f25674d88f57d0ca6ad05bd72e032c9d2ec Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:02:51 -0800 Subject: [PATCH 256/263] Run format --- docs/src/examples/tree.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 8f80298b..a39f45f2 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -199,6 +199,7 @@ See [`AccountView::resize_unchecked`] for reference implementation. + ::: From ec82c57dcabd1c86dfcc75e536f476e8d2fe2d7c Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:11:12 -0800 Subject: [PATCH 257/263] RUn quick-lint --- docs/src/examples/tree.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index a39f45f2..2f857bfc 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -388,11 +388,11 @@ See [`AccountView::resize_unchecked`] for reference implementation. -[`AccountView::resize_unchecked`]: https://github.com/anza-xyz/solana-sdk/blob/bn254@v3.2.1/account-view/src/lib.rs#L363 [abi v2]: https://github.com/solana-foundation/solana-improvement-documents/pull/177/changes#r2861798899 [ilp]: https://en.wikipedia.org/wiki/Instruction-level_parallelism [pda]: https://solana.com/docs/core/pda [tail call]: https://en.wikipedia.org/wiki/Tail_call [wikipedia tree page]: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree +[`accountview::resize_unchecked`]: https://github.com/anza-xyz/solana-sdk/blob/bn254@v3.2.1/account-view/src/lib.rs#L363 [`pinocchio`]: https://github.com/anza-xyz/pinocchio [`simd-0321`]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0321-vm-r2-instruction-data-pointer.md From b9e88f3bdd050fd2c32c4271bdc813cac862506f Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:11:54 -0800 Subject: [PATCH 258/263] Run lint/fmt --- .../snippets/interface/tree-defs-common.txt | 2 +- examples/tree/interface/src/common.rs | 2 +- examples/tree/specs/cu-overhead-analysis.md | 2 + .../specs/insert-fixup-hardcoded-branches.md | 5 +- examples/tree/specs/insert-fixup-rotation.md | 4 + examples/tree/specs/insert-tests.md | 4 + examples/tree/specs/remove-tests.md | 4 + examples/tree/specs/remove.md | 6 + examples/tree/specs/test-framework-cleanup.md | 6 + examples/tree/specs/tree-invariants.md | 6 + examples/tree/src/tests/common.rs | 2 + examples/tree/src/tests/init.rs | 15 +- examples/tree/src/tests/insert.rs | 455 ++++++------ examples/tree/src/tests/remove.rs | 657 +++++++++--------- 14 files changed, 616 insertions(+), 554 deletions(-) diff --git a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt index af8c71db..d7218122 100644 --- a/examples/tree/artifacts/snippets/interface/tree-defs-common.txt +++ b/examples/tree/artifacts/snippets/interface/tree-defs-common.txt @@ -34,7 +34,7 @@ constant_group! { #[repr(C, packed)] /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { - /// Aboslute pointer to tree root in memory map. + /// Absolute pointer to tree root in memory map. pub root: *mut TreeNode, /// Absolute pointer to stack top in memory map. pub top: *mut StackNode, diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index de8333d6..36796dda 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -215,7 +215,7 @@ constant_group! { #[repr(C, packed)] /// Tree account data header. Contains pointer to tree root and top of free node stack. pub struct TreeHeader { - /// Aboslute pointer to tree root in memory map. + /// Absolute pointer to tree root in memory map. pub root: *mut TreeNode, /// Absolute pointer to stack top in memory map. pub top: *mut StackNode, diff --git a/examples/tree/specs/cu-overhead-analysis.md b/examples/tree/specs/cu-overhead-analysis.md index 14254574..40afc584 100644 --- a/examples/tree/specs/cu-overhead-analysis.md +++ b/examples/tree/specs/cu-overhead-analysis.md @@ -1,3 +1,5 @@ + + # CU overhead analysis Methodology for attributing CU overhead in Rust implementations diff --git a/examples/tree/specs/insert-fixup-hardcoded-branches.md b/examples/tree/specs/insert-fixup-hardcoded-branches.md index 8455414b..274edd30 100644 --- a/examples/tree/specs/insert-fixup-hardcoded-branches.md +++ b/examples/tree/specs/insert-fixup-hardcoded-branches.md @@ -238,8 +238,9 @@ operation (e.g. delete) needs them, they can be re-added. ## Child direction assignment The initial `let dir = if key > ... { DIR_R } else { DIR_L }` -before the loop is replaced with `let child_dir = (key > (*parent).key) as usize` to use branchless bool-to-index. This -matches the existing search pattern in `program.rs:616`. +before the loop is replaced with +`let child_dir = (key > (*parent).key) as usize` to use branchless +bool-to-index. This matches the existing search pattern in `program.rs:616`. ## Verification diff --git a/examples/tree/specs/insert-fixup-rotation.md b/examples/tree/specs/insert-fixup-rotation.md index 675ba081..700b42be 100644 --- a/examples/tree/specs/insert-fixup-rotation.md +++ b/examples/tree/specs/insert-fixup-rotation.md @@ -1,3 +1,7 @@ + + + + # Insert fixup rotation specification ## Scope diff --git a/examples/tree/specs/insert-tests.md b/examples/tree/specs/insert-tests.md index 187564c7..add31a66 100644 --- a/examples/tree/specs/insert-tests.md +++ b/examples/tree/specs/insert-tests.md @@ -1,3 +1,7 @@ + + + + # Insert-to-tree test specification ## Scope diff --git a/examples/tree/specs/remove-tests.md b/examples/tree/specs/remove-tests.md index 9450aad9..500bea5b 100644 --- a/examples/tree/specs/remove-tests.md +++ b/examples/tree/specs/remove-tests.md @@ -1,3 +1,7 @@ + + + + # Remove-to-tree test specification ## Scope diff --git a/examples/tree/specs/remove.md b/examples/tree/specs/remove.md index b81d216a..968aa3fb 100644 --- a/examples/tree/specs/remove.md +++ b/examples/tree/specs/remove.md @@ -1,3 +1,9 @@ + + + + + + # Remove instruction specification ## Scope diff --git a/examples/tree/specs/test-framework-cleanup.md b/examples/tree/specs/test-framework-cleanup.md index 89358b8d..5da2803d 100644 --- a/examples/tree/specs/test-framework-cleanup.md +++ b/examples/tree/specs/test-framework-cleanup.md @@ -1,3 +1,9 @@ + + + + + + # Test framework cleanup specification ## Scope diff --git a/examples/tree/specs/tree-invariants.md b/examples/tree/specs/tree-invariants.md index 0cd77ff9..9ae752e5 100644 --- a/examples/tree/specs/tree-invariants.md +++ b/examples/tree/specs/tree-invariants.md @@ -1,3 +1,9 @@ + + + + + + # Tree invariant specification ## Scope diff --git a/examples/tree/src/tests/common.rs b/examples/tree/src/tests/common.rs index f9a027a9..19c13d17 100644 --- a/examples/tree/src/tests/common.rs +++ b/examples/tree/src/tests/common.rs @@ -1,3 +1,5 @@ +// cspell:word inorder +// cspell:word vaddr use super::*; use tree_interface::{input_buffer, tree, Color, StackNode, TreeHeader, TreeNode}; diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 98b9233e..602da474 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -81,7 +81,13 @@ fn run_address_mismatch( expected_error: error_codes::error, ) -> CaseResult { let (setup, mut instruction, mut accounts) = pda_init_setup(lang); - flip_account_address(&mut instruction, &mut accounts, account_index, chunk_index, chunk_size); + flip_account_address( + &mut instruction, + &mut accounts, + account_index, + chunk_index, + chunk_size, + ); check_error(&setup, &instruction, &accounts, expected_error) } @@ -395,12 +401,7 @@ impl TestCase for InitCase { let (setup, instruction, mut accounts) = pda_init_setup(lang); accounts[AccountIndex::User as usize].1.lamports = 0; // SystemError::ResultWithNegativeLamports. - check_result( - &setup, - &instruction, - &accounts, - ProgramError::Custom(1), - ) + check_result(&setup, &instruction, &accounts, ProgramError::Custom(1)) } Self::SystemProgramAddress => { let (setup, mut instruction, mut accounts) = pda_init_setup(lang); diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 5a185339..0c8b15a7 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -1,3 +1,4 @@ +// cspell:word sysprog use super::common::*; use super::*; use tree_interface::{ @@ -183,7 +184,6 @@ fn insert_max_data_setup( (setup, instruction, accounts) } - // --------------------------------------------------------------------------- // Helpers: tree test setup and runners // --------------------------------------------------------------------------- @@ -235,10 +235,16 @@ fn run_success( expected: &TreeSpec, ) -> CaseResult { if let Err(e) = assert_invariants(desc) { - return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("desc invariant: {}", e)), + }; } if let Err(e) = assert_invariants(expected) { - return CaseResult { cu: 0, error: Some(format!("exp invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("exp invariant: {}", e)), + }; } let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); let result = setup.mollusk.process_instruction(&instruction, &accounts); @@ -268,7 +274,10 @@ fn run_success( /// Run an insert and check for KEY_EXISTS error. fn run_dup_error(lang: ProgramLanguage, desc: &TreeSpec, insert_key: u16) -> CaseResult { if let Err(e) = assert_invariants(desc) { - return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("desc invariant: {}", e)), + }; } let (setup, instruction, accounts) = insert_tree_setup(lang, desc, insert_key); check_error( @@ -279,7 +288,6 @@ fn run_dup_error(lang: ProgramLanguage, desc: &TreeSpec, insert_key: u16) -> Cas ) } - // --------------------------------------------------------------------------- // Test case enum // --------------------------------------------------------------------------- @@ -1310,7 +1318,6 @@ impl TestCase for InsertCase { // Multi-insert integration tests // --------------------------------------------------------------------------- - struct MultiInsertStep<'a> { key: u16, expected: TreeSpec<'a>, @@ -1321,8 +1328,7 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) -> CaseRes let (system_program_pubkey, _) = program::keyed_account_for_system_program(); let user_pubkey = Pubkey::new_unique(); - let (tree_pubkey, mut tree_account) = - build_empty_tree(steps.len(), &setup.program_id); + let (tree_pubkey, mut tree_account) = build_empty_tree(steps.len(), &setup.program_id); let mut total_cu = 0u64; @@ -1330,7 +1336,10 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) -> CaseRes if let Err(e) = assert_invariants(&step.expected) { return CaseResult { cu: 0, - error: Some(format!("step {} (key={}) exp invariant: {}", i, step.key, e)), + error: Some(format!( + "step {} (key={}) exp invariant: {}", + i, step.key, e + )), }; } @@ -1363,8 +1372,9 @@ fn run_multi_insert(lang: ProgramLanguage, steps: &[MultiInsertStep]) -> CaseRes total_cu += result.compute_units_consumed; match &result.program_result { MolluskResult::Success => { - tree_account = - result.resulting_accounts[AccountIndex::Tree as usize].1.clone(); + tree_account = result.resulting_accounts[AccountIndex::Tree as usize] + .1 + .clone(); if let Err(e) = assert_tree_account(&tree_account.data, &step.expected) { return CaseResult { cu: total_cu, @@ -1441,239 +1451,254 @@ impl TestCase for MultiInsertCase { } fn run_balanced_3(lang: ProgramLanguage) -> CaseResult { - run_multi_insert(lang, &[ - MultiInsertStep { - key: 10, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + run_multi_insert( + lang, + &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiInsertStep { - key: 5, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 15, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)).val(1), - node(5, R, Some(0), None, None).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - ]) + ], + ) } fn run_left_skew(lang: ProgramLanguage) -> CaseResult { - run_multi_insert(lang, &[ - MultiInsertStep { - key: 10, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + run_multi_insert( + lang, + &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiInsertStep { - key: 5, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 1, - expected: TreeSpec { - root: Some(1), - top: None, - nodes: &[ - node(10, R, Some(1), None, None).val(1), - node(5, B, None, Some(2), Some(0)).val(1), - node(1, R, Some(1), None, None).val(1), - ], + MultiInsertStep { + key: 1, + expected: TreeSpec { + root: Some(1), + top: None, + nodes: &[ + node(10, R, Some(1), None, None).val(1), + node(5, B, None, Some(2), Some(0)).val(1), + node(1, R, Some(1), None, None).val(1), + ], + }, }, - }, - ]) + ], + ) } fn run_right_skew(lang: ProgramLanguage) -> CaseResult { - run_multi_insert(lang, &[ - MultiInsertStep { - key: 10, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + run_multi_insert( + lang, + &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiInsertStep { - key: 15, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, None, Some(1)).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, None, Some(1)).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 20, - expected: TreeSpec { - root: Some(1), - top: None, - nodes: &[ - node(10, R, Some(1), None, None).val(1), - node(15, B, None, Some(0), Some(2)).val(1), - node(20, R, Some(1), None, None).val(1), - ], + MultiInsertStep { + key: 20, + expected: TreeSpec { + root: Some(1), + top: None, + nodes: &[ + node(10, R, Some(1), None, None).val(1), + node(15, B, None, Some(0), Some(2)).val(1), + node(20, R, Some(1), None, None).val(1), + ], + }, }, - }, - ]) + ], + ) } fn run_zigzag(lang: ProgramLanguage) -> CaseResult { - run_multi_insert(lang, &[ - MultiInsertStep { - key: 10, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + run_multi_insert( + lang, + &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiInsertStep { - key: 5, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 7, - expected: TreeSpec { - root: Some(2), - top: None, - nodes: &[ - node(10, R, Some(2), None, None).val(1), - node(5, R, Some(2), None, None).val(1), - node(7, B, None, Some(1), Some(0)).val(1), - ], + MultiInsertStep { + key: 7, + expected: TreeSpec { + root: Some(2), + top: None, + nodes: &[ + node(10, R, Some(2), None, None).val(1), + node(5, R, Some(2), None, None).val(1), + node(7, B, None, Some(1), Some(0)).val(1), + ], + }, }, - }, - ]) + ], + ) } fn run_full_7(lang: ProgramLanguage) -> CaseResult { - run_multi_insert(lang, &[ - MultiInsertStep { - key: 10, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + run_multi_insert( + lang, + &[ + MultiInsertStep { + key: 10, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiInsertStep { - key: 5, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 5, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 15, - expected: TreeSpec { - root: Some(0), - top: Some(3), - nodes: &[ - node(10, B, None, Some(1), Some(2)).val(1), - node(5, R, Some(0), None, None).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiInsertStep { + key: 15, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 3, - expected: TreeSpec { - root: Some(0), - top: Some(4), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), None).val(1), - node(15, B, Some(0), None, None).val(1), - node(3, R, Some(1), None, None).val(1), - ], + MultiInsertStep { + key: 3, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 7, - expected: TreeSpec { - root: Some(0), - top: Some(5), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), None, None).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - ], + MultiInsertStep { + key: 7, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 12, - expected: TreeSpec { - root: Some(0), - top: Some(6), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), Some(5), None).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - ], + MultiInsertStep { + key: 12, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + ], + }, }, - }, - MultiInsertStep { - key: 20, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), Some(5), Some(6)).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - node(20, R, Some(2), None, None).val(1), - ], + MultiInsertStep { + key: 20, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, }, - }, - ]) + ], + ) } diff --git a/examples/tree/src/tests/remove.rs b/examples/tree/src/tests/remove.rs index 50315928..4ea11633 100644 --- a/examples/tree/src/tests/remove.rs +++ b/examples/tree/src/tests/remove.rs @@ -1,8 +1,9 @@ +// cspell:word reparented use super::common::*; use super::*; use tree_interface::{ - input_buffer, InsertInstruction, Instruction as TreeInstruction, - InstructionHeader, RemoveInstruction, StackNode, TreeHeader, TreeNode, + input_buffer, InsertInstruction, Instruction as TreeInstruction, InstructionHeader, + RemoveInstruction, StackNode, TreeHeader, TreeNode, }; // --------------------------------------------------------------------------- @@ -48,9 +49,7 @@ fn remove_setup( } /// A minimal two-account setup for input check tests. -fn remove_input_setup( - lang: ProgramLanguage, -) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { +fn remove_input_setup(lang: ProgramLanguage) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { let desc = TreeSpec { root: Some(0), top: None, @@ -74,10 +73,16 @@ fn run_remove_success( expected: &TreeSpec, ) -> CaseResult { if let Err(e) = assert_invariants(desc) { - return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("desc invariant: {}", e)), + }; } if let Err(e) = assert_invariants(expected) { - return CaseResult { cu: 0, error: Some(format!("exp invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("exp invariant: {}", e)), + }; } let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); let result = setup.mollusk.process_instruction(&instruction, &accounts); @@ -105,13 +110,12 @@ fn run_remove_success( } /// Execute a remove and verify KEY_DOES_NOT_EXIST error. -fn run_remove_not_found( - lang: ProgramLanguage, - desc: &TreeSpec, - remove_key: u16, -) -> CaseResult { +fn run_remove_not_found(lang: ProgramLanguage, desc: &TreeSpec, remove_key: u16) -> CaseResult { if let Err(e) = assert_invariants(desc) { - return CaseResult { cu: 0, error: Some(format!("desc invariant: {}", e)) }; + return CaseResult { + cu: 0, + error: Some(format!("desc invariant: {}", e)), + }; } let (setup, instruction, accounts) = remove_setup(lang, desc, remove_key); check_error( @@ -214,7 +218,9 @@ fn run_multi_step(lang: ProgramLanguage, n_slots: usize, steps: &[MultiStepCase] }; } - tree_account = result.resulting_accounts[AccountIndex::Tree as usize].1.clone(); + tree_account = result.resulting_accounts[AccountIndex::Tree as usize] + .1 + .clone(); if let Err(e) = assert_tree_account(&tree_account.data, &step.expected) { let step_desc = match &step.step { MultiStep::Insert { key, .. } => format!("insert key={}", key), @@ -460,7 +466,6 @@ impl TestCase for RemoveCase { } // ----- Search errors ----- - Self::SearchEmptyTree => { let desc = TreeSpec { root: None, @@ -528,10 +533,7 @@ impl TestCase for RemoveCase { let exp = TreeSpec { root: Some(0), top: Some(1), - nodes: &[ - node(10, B, None, None, None), - node(5, R, None, None, None), - ], + nodes: &[node(10, B, None, None, None), node(5, R, None, None, None)], }; run_remove_success(lang, &desc, 5, &exp) } @@ -549,10 +551,7 @@ impl TestCase for RemoveCase { let exp = TreeSpec { root: Some(0), top: Some(1), - nodes: &[ - node(10, B, None, None, None), - node(15, R, None, None, None), - ], + nodes: &[node(10, B, None, None, None), node(15, R, None, None, None)], }; run_remove_success(lang, &desc, 15, &exp) } @@ -570,10 +569,7 @@ impl TestCase for RemoveCase { let exp = TreeSpec { root: Some(1), top: Some(0), - nodes: &[ - node(10, B, None, None, None), - node(15, B, None, None, None), - ], + nodes: &[node(10, B, None, None, None), node(15, B, None, None, None)], }; run_remove_success(lang, &desc, 10, &exp) } @@ -591,10 +587,7 @@ impl TestCase for RemoveCase { let exp = TreeSpec { root: Some(1), top: Some(0), - nodes: &[ - node(10, B, None, None, None), - node(5, B, None, None, None), - ], + nodes: &[node(10, B, None, None, None), node(5, B, None, None, None)], }; run_remove_success(lang, &desc, 10, &exp) } @@ -1464,11 +1457,7 @@ pub(super) enum MultiRemoveCase { } impl MultiRemoveCase { - pub(super) const CASES: &'static [Self] = &[ - Self::Minimal, - Self::FullCycle, - Self::Recycle, - ]; + pub(super) const CASES: &'static [Self] = &[Self::Minimal, Self::FullCycle, Self::Recycle]; } impl TestCase for MultiRemoveCase { @@ -1482,321 +1471,333 @@ impl TestCase for MultiRemoveCase { fn run(&self, lang: ProgramLanguage) -> CaseResult { match self { - Self::Minimal => run_multi_step(lang, 3, &[ - MultiStepCase { - step: MultiStep::Insert { key: 10, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + Self::Minimal => run_multi_step( + lang, + 3, + &[ + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 5, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 15, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)).val(1), - node(5, R, Some(0), None, None).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 5 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[ - node(10, B, None, None, Some(2)).val(1), - // Freed node: key/value/color retained, children nulled, - // parent (= StackNode.next) = null (stack was empty). - node(5, R, None, None, None).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)).val(1), + // Freed node: key/value/color retained, children nulled, + // parent (= StackNode.next) = null (stack was empty). + node(5, R, None, None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - ]), - - Self::FullCycle => run_multi_step(lang, 7, &[ - // Insert 10,5,15,3,7,12,20. - MultiStepCase { - step: MultiStep::Insert { key: 10, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None).val(1)], + ], + ), + + Self::FullCycle => run_multi_step( + lang, + 7, + &[ + // Insert 10,5,15,3,7,12,20. + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None).val(1)], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 5, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None).val(1), - node(5, R, Some(0), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None).val(1), + node(5, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 15, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(3), - nodes: &[ - node(10, B, None, Some(1), Some(2)).val(1), - node(5, R, Some(0), None, None).val(1), - node(15, R, Some(0), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, B, None, Some(1), Some(2)).val(1), + node(5, R, Some(0), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 3, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(4), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), None).val(1), - node(15, B, Some(0), None, None).val(1), - node(3, R, Some(1), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 3, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 7, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(5), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), None, None).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 7, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 12, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: Some(6), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), Some(5), None).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 12, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 20, value: 1 }, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), Some(3), Some(4)).val(1), - node(15, B, Some(0), Some(5), Some(6)).val(1), - node(3, R, Some(1), None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - node(20, R, Some(2), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Insert { key: 20, value: 1 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), Some(3), Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, Some(1), None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, }, - }, - // Remove all: 3, 20, 7, 12, 5, 15, 10. - // Removing leaves first to simplify expected states. - MultiStepCase { - step: MultiStep::Remove { key: 3 }, - expected: TreeSpec { - root: Some(0), - top: Some(3), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), None, Some(4)).val(1), - node(15, B, Some(0), Some(5), Some(6)).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - node(20, R, Some(2), None, None).val(1), - ], + // Remove all: 3, 20, 7, 12, 5, 15, 10. + // Removing leaves first to simplify expected states. + MultiStepCase { + step: MultiStep::Remove { key: 3 }, + expected: TreeSpec { + root: Some(0), + top: Some(3), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, Some(4)).val(1), + node(15, B, Some(0), Some(5), Some(6)).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(2), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 20 }, - expected: TreeSpec { - root: Some(0), - top: Some(6), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), None, Some(4)).val(1), - node(15, B, Some(0), Some(5), None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(1), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 20 }, + expected: TreeSpec { + root: Some(0), + top: Some(6), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, Some(4)).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(1), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 7 }, - expected: TreeSpec { - root: Some(0), - top: Some(4), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), None, None).val(1), - node(15, B, Some(0), Some(5), None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(6), None, None).val(1), - node(12, R, Some(2), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 7 }, + expected: TreeSpec { + root: Some(0), + top: Some(4), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, None).val(1), + node(15, B, Some(0), Some(5), None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(2), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 12 }, - expected: TreeSpec { - root: Some(0), - top: Some(5), - nodes: &[ - node(10, R, None, Some(1), Some(2)).val(1), - node(5, B, Some(0), None, None).val(1), - node(15, B, Some(0), None, None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(6), None, None).val(1), - node(12, R, Some(4), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 12 }, + expected: TreeSpec { + root: Some(0), + top: Some(5), + nodes: &[ + node(10, R, None, Some(1), Some(2)).val(1), + node(5, B, Some(0), None, None).val(1), + node(15, B, Some(0), None, None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 5 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[ - node(10, B, None, None, Some(2)).val(1), - node(5, B, Some(5), None, None).val(1), - node(15, R, Some(0), None, None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(6), None, None).val(1), - node(12, R, Some(4), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(0), None, None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 15 }, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, None, None).val(1), - node(5, B, Some(5), None, None).val(1), - node(15, R, Some(1), None, None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(6), None, None).val(1), - node(12, R, Some(4), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 15 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, None, None).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(1), None, None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Remove { key: 10 }, - expected: TreeSpec { - root: None, - top: Some(0), - nodes: &[ - node(10, B, Some(2), None, None).val(1), - node(5, B, Some(5), None, None).val(1), - node(15, R, Some(1), None, None).val(1), - node(3, R, None, None, None).val(1), - node(7, R, Some(6), None, None).val(1), - node(12, R, Some(4), None, None).val(1), - node(20, R, Some(3), None, None).val(1), - ], + MultiStepCase { + step: MultiStep::Remove { key: 10 }, + expected: TreeSpec { + root: None, + top: Some(0), + nodes: &[ + node(10, B, Some(2), None, None).val(1), + node(5, B, Some(5), None, None).val(1), + node(15, R, Some(1), None, None).val(1), + node(3, R, None, None, None).val(1), + node(7, R, Some(6), None, None).val(1), + node(12, R, Some(4), None, None).val(1), + node(20, R, Some(3), None, None).val(1), + ], + }, }, - }, - ]), - - Self::Recycle => run_multi_step(lang, 3, &[ - // Insert 10,5,15. - MultiStepCase { - step: MultiStep::Insert { key: 10, value: 10 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[node(10, R, None, None, None)], + ], + ), + + Self::Recycle => run_multi_step( + lang, + 3, + &[ + // Insert 10,5,15. + MultiStepCase { + step: MultiStep::Insert { key: 10, value: 10 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[node(10, R, None, None, None)], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 5, value: 5 }, - expected: TreeSpec { - root: Some(0), - top: Some(2), - nodes: &[ - node(10, B, None, Some(1), None), - node(5, R, Some(0), None, None), - ], + MultiStepCase { + step: MultiStep::Insert { key: 5, value: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(2), + nodes: &[ + node(10, B, None, Some(1), None), + node(5, R, Some(0), None, None), + ], + }, }, - }, - MultiStepCase { - step: MultiStep::Insert { key: 15, value: 15 }, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(5, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], + MultiStepCase { + step: MultiStep::Insert { key: 15, value: 15 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(5, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }, }, - }, - // Remove 5: red leaf removal, N1 freed onto stack. - MultiStepCase { - step: MultiStep::Remove { key: 5 }, - expected: TreeSpec { - root: Some(0), - top: Some(1), - nodes: &[ - node(10, B, None, None, Some(2)), - node(5, R, None, None, None), - node(15, R, Some(0), None, None), - ], + // Remove 5: red leaf removal, N1 freed onto stack. + MultiStepCase { + step: MultiStep::Remove { key: 5 }, + expected: TreeSpec { + root: Some(0), + top: Some(1), + nodes: &[ + node(10, B, None, None, Some(2)), + node(5, R, None, None, None), + node(15, R, Some(0), None, None), + ], + }, }, - }, - // Insert 7: pops N1 from stack, reuses slot. - MultiStepCase { - step: MultiStep::Insert { key: 7, value: 7 }, - expected: TreeSpec { - root: Some(0), - top: None, - nodes: &[ - node(10, B, None, Some(1), Some(2)), - node(7, R, Some(0), None, None), - node(15, R, Some(0), None, None), - ], + // Insert 7: pops N1 from stack, reuses slot. + MultiStepCase { + step: MultiStep::Insert { key: 7, value: 7 }, + expected: TreeSpec { + root: Some(0), + top: None, + nodes: &[ + node(10, B, None, Some(1), Some(2)), + node(7, R, Some(0), None, None), + node(15, R, Some(0), None, None), + ], + }, }, - }, - ]), + ], + ), } } } From 9ecbff42f54e2d69f3b7b6fcd2881911b6ebf9a1 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:12:06 -0800 Subject: [PATCH 259/263] Fix quick-lint --- .claude/commands/build-example.md | 2 ++ .claude/commands/disassemble-example.md | 6 ++++-- .claude/commands/test-example.md | 2 ++ cfg/dictionary.txt | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.claude/commands/build-example.md b/.claude/commands/build-example.md index d7d93ae8..f83af5b6 100644 --- a/.claude/commands/build-example.md +++ b/.claude/commands/build-example.md @@ -1,3 +1,5 @@ +# Build example + Run the full build-examples pipeline that builds, dumps, disassembles, tests, and verifies artifacts. diff --git a/.claude/commands/disassemble-example.md b/.claude/commands/disassemble-example.md index acc056c1..5106f5d6 100644 --- a/.claude/commands/disassemble-example.md +++ b/.claude/commands/disassemble-example.md @@ -1,3 +1,5 @@ +# Disassemble example + Quick compile and disassemble cycle for a specific example program. Run the following commands sequentially from the example directory at @@ -9,13 +11,13 @@ Run the following commands sequentially from the example directory at rm -f ../target/deploy/${ARGUMENTS//-/_}.so ``` -2. Build for the disassembly architecture: +1. Build for the disassembly architecture: ```sh cargo build-sbf --arch v2 --tools-version 1.52 ``` -3. Disassemble and write output: +1. Disassemble and write output: ```sh sbpf disassemble ../target/deploy/${ARGUMENTS//-/_}.so \ diff --git a/.claude/commands/test-example.md b/.claude/commands/test-example.md index bd329b7b..e0fb2ecf 100644 --- a/.claude/commands/test-example.md +++ b/.claude/commands/test-example.md @@ -1,3 +1,5 @@ +# Test example + Quick build and test cycle for a specific example program. Run the following commands sequentially from the example directory at diff --git a/cfg/dictionary.txt b/cfg/dictionary.txt index 1505fc8e..7568247e 100644 --- a/cfg/dictionary.txt +++ b/cfg/dictionary.txt @@ -16,6 +16,7 @@ lamports lddw ldxb ldxdw +ldxh ldxw markdownlint mathjax From e2d826608da055d3e63932254606f5e274959be5 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:17:58 -0800 Subject: [PATCH 260/263] Add emoji headings --- docs/src/examples/tree.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/src/examples/tree.md b/docs/src/examples/tree.md index 2f857bfc..eed2f4ef 100644 --- a/docs/src/examples/tree.md +++ b/docs/src/examples/tree.md @@ -2,7 +2,7 @@ -## Background +## :bulb: Background This example implements a [red-black tree][wikipedia tree page] in both [SBPF assembly](../index.md) and Rust. Both implementations are compared @@ -23,7 +23,7 @@ exercise to the reader. Note that these data structures rely on direct addressing, which may be broken by [ABI v2]. -## Build support +## :building_construction: Build support Constants, error codes, and C bindings are derived in a shared interface using macros, then automatically inserted into the assembly program file at build @@ -53,7 +53,7 @@ time. ::: -## Entrypoint branching +## :twisted_rightwards_arrows: Entrypoint branching The Rust implementation does not use [`pinocchio`] for the entrypoint. Instead, it uses C-style bindings with the [`SIMD-0321`] `r2` pointer. Note that the Rust @@ -78,13 +78,13 @@ greedy [tail call optimizations][tail call]. ::: -## Initialize +## :rocket: Initialize The initialize operation creates a tree [PDA] for the entire program, then invokes a [`CreateAccount` CPI](counter#cpi-construction), with the same [fixed costs as in the counter example](counter#compute-unit-analysis). -### Input checks +### :shield: Input checks ::: details Implementations @@ -106,7 +106,7 @@ invokes a [`CreateAccount` CPI](counter#cpi-construction), with the same -### PDA checks +### :mag: PDA checks ::: details Implementations @@ -128,7 +128,7 @@ invokes a [`CreateAccount` CPI](counter#cpi-construction), with the same -### Create account +### :hammer_and_wrench: Create account The assembly implementation includes pointer walkthrough optimizations that are not available in Rust, since the compiler enforces @@ -154,9 +154,9 @@ not available in Rust, since the compiler enforces -## Insert +## :heavy_plus_sign: Insert -### Input checks +### :shield: Input checks ::: details Implementations @@ -178,7 +178,7 @@ not available in Rust, since the compiler enforces -### Allocate +### :package: Allocate See [`AccountView::resize_unchecked`] for reference implementation. @@ -204,7 +204,7 @@ See [`AccountView::resize_unchecked`] for reference implementation. -### Search +### :mag_right: Search ::: details Implementations @@ -226,7 +226,7 @@ See [`AccountView::resize_unchecked`] for reference implementation. -### Insert fixup +### :wrench: Insert fixup @@ -290,9 +290,9 @@ See [`AccountView::resize_unchecked`] for reference implementation. -## Remove +## :scissors: Remove -### Input checks +### :shield: Input checks ::: details Implementations @@ -314,7 +314,7 @@ See [`AccountView::resize_unchecked`] for reference implementation. -### Search +### :mag_right: Search ::: details Implementations @@ -336,7 +336,7 @@ See [`AccountView::resize_unchecked`] for reference implementation. -### Simple cases +### :bookmark_tabs: Simple cases From be5cf8107eee9260e9c69a231f3b022a73c52607 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:21:14 -0800 Subject: [PATCH 261/263] Link opcodes --- docs/src/indices/opcodes.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/src/indices/opcodes.md b/docs/src/indices/opcodes.md index 87557174..a973ec41 100644 --- a/docs/src/indices/opcodes.md +++ b/docs/src/indices/opcodes.md @@ -9,17 +9,23 @@ example from this guide where it is used, as well as its corresponding | Opcode hex | Opcode name | Assembler mnemonic | Select example | | ---------- | ------------- | ---------------------------------- | -------------- | +| [`0x05`] | [`JA`] | [`ja off`][`0x05`] | [Tree] | | [`0x07`] | [`ADD64_IMM`] | [`add64 dst, imm`][`0x07`] | [Memo] | | [`0x14`] | [`SUB32_IMM`] | [`sub32 dst, imm`][`0x14`] | [Fibonacci] | | [`0x15`] | [`JEQ_IMM`] | [`jeq dst, imm, off`][`0x15`] | [Counter] | | [`0x17`] | [`SUB64_IMM`] | [`sub64 dst, imm`][`0x17`] | [Transfer] | | [`0x18`] | [`LD_DW_IMM`] | [`lddw dst, imm`][`0x18`] | [Quickstart] | +| [`0x1d`] | [`JEQ_REG`] | [`jeq dst, src, off`][`0x1d`] | [Tree] | | [`0x25`] | [`JGT_IMM`] | [`jgt dst, imm, off`][`0x25`] | [Fibonacci] | | [`0x27`] | [`MUL64_IMM`] | [`mul64 dst, imm`][`0x27`] | [Counter] | +| [`0x2d`] | [`JGT_REG`] | [`jgt dst, src, off`][`0x2d`] | [Tree] | | [`0x55`] | [`JNE_IMM`] | [`jne dst, imm, off`][`0x55`] | [Transfer] | | [`0x57`] | [`AND64_IMM`] | [`and64 dst, imm`][`0x57`] | [Counter] | | [`0x5d`] | [`JNE_REG`] | [`jne dst, src, off`][`0x5d`] | [Memo] | +| [`0x61`] | [`LD_W_REG`] | [`ldxw dst, [src + off]`][`0x61`] | [Tree] | +| [`0x62`] | [`ST_W_IMM`] | [`stw [dst + off], imm`][`0x62`] | [Tree] | | [`0x63`] | [`ST_W_REG`] | [`stxw [dst + off], src`][`0x63`] | [Transfer] | +| [`0x69`] | [`LD_H_REG`] | [`ldxh dst, [src + off]`][`0x69`] | [Tree] | | [`0x6a`] | [`ST_H_IMM`] | [`sth [dst + off], imm`][`0x6a`] | [Counter] | | [`0x71`] | [`LD_B_REG`] | [`ldxb dst, [src + off]`][`0x71`] | [Fibonacci] | | [`0x72`] | [`ST_B_IMM`] | [`stb [dst + off], imm`][`0x72`] | [Transfer] | @@ -29,6 +35,7 @@ example from this guide where it is used, as well as its corresponding | [`0x7b`] | [`ST_DW_REG`] | [`stxdw [dst + off], src`][`0x7b`] | [Transfer] | | [`0x85`] | [`CALL_IMM`] | [`call imm`][`0x85`] | [Quickstart] | | [`0x95`] | [`EXIT`] | [`exit`][`0x95`] | [Quickstart] | +| [`0xa5`] | [`JLT_IMM`] | [`jlt dst, imm, off`][`0xa5`] | [Tree] | | [`0xad`] | [`JLT_REG`] | [`jlt dst, src, off`][`0xad`] | [Transfer] | | [`0xb4`] | [`MOV32_IMM`] | [`mov32 dst, imm`][`0xb4`] | [Fibonacci] | | [`0xb7`] | [`MOV64_IMM`] | [`mov64 dst, imm`][`0xb7`] | [Fibonacci] | @@ -44,17 +51,24 @@ example from this guide where it is used, as well as its corresponding [rust implementation constant name]: https://docs.rs/solana-sbpf/latest/solana_sbpf/ebpf/index.html [sbpf bytecode isa]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md [transfer]: ../examples/transfer +[tree]: ../examples/tree +[`0x05`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L274 [`0x07`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L130 [`0x14`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L87 [`0x15`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L276 [`0x17`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L132 [`0x18`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L222 +[`0x1d`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L277 [`0x25`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L278 [`0x27`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L135 +[`0x2d`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L279 [`0x55`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L284 [`0x57`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L145 [`0x5d`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L285 +[`0x61`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L228 +[`0x62`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L237 [`0x63`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L246 +[`0x69`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L229 [`0x6a`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L238 [`0x71`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L230 [`0x72`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L239 @@ -64,6 +78,7 @@ example from this guide where it is used, as well as its corresponding [`0x7b`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L249 [`0x85`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L290 [`0x95`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L294 +[`0xa5`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L298 [`0xad`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L299 [`0xb4`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L117 [`0xb7`]: https://github.com/anza-xyz/sbpf/blob/v0.13.1/doc/bytecode.md?plain=1#L161 @@ -72,14 +87,20 @@ example from this guide where it is used, as well as its corresponding [`and64_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.AND64_IMM.html [`call_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.CALL_IMM.html [`exit`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.EXIT.html +[`ja`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JA.html [`jeq_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JEQ_IMM.html +[`jeq_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JEQ_REG.html [`jgt_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JGT_IMM.html +[`jgt_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JGT_REG.html +[`jlt_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JLT_IMM.html [`jlt_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JLT_REG.html [`jne_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JNE_IMM.html [`jne_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.JNE_REG.html [`ld_b_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.LD_B_REG.html [`ld_dw_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.LD_DW_IMM.html [`ld_dw_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.LD_DW_REG.html +[`ld_h_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.LD_H_REG.html +[`ld_w_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.LD_W_REG.html [`mov32_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.MOV32_IMM.html [`mov64_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.MOV64_IMM.html [`mov64_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.MOV64_REG.html @@ -89,6 +110,7 @@ example from this guide where it is used, as well as its corresponding [`st_dw_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.ST_DW_IMM.html [`st_dw_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.ST_DW_REG.html [`st_h_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.ST_H_IMM.html +[`st_w_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.ST_W_IMM.html [`st_w_reg`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.ST_W_REG.html [`sub32_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.SUB32_IMM.html [`sub64_imm`]: https://docs.rs/solana-sbpf/0.13.1/solana_sbpf/ebpf/constant.SUB64_IMM.html From 5df1b8e635e958f4a05eeb31e47367bf23d055ea Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:37:00 -0800 Subject: [PATCH 262/263] Fix some clippy --- examples/tree/interface/src/common.rs | 1 - examples/tree/src/program.rs | 22 ++++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/examples/tree/interface/src/common.rs b/examples/tree/interface/src/common.rs index 36796dda..d1564466 100644 --- a/examples/tree/interface/src/common.rs +++ b/examples/tree/interface/src/common.rs @@ -1,5 +1,4 @@ use core::mem::size_of; -use error_codes::error; use macros::{array_fields, constant_group, error_codes}; use pinocchio::{ account::{RuntimeAccount as RuntimeAccountHeader, MAX_PERMITTED_DATA_INCREASE}, diff --git a/examples/tree/src/program.rs b/examples/tree/src/program.rs index 34155b43..0dd9f439 100644 --- a/examples/tree/src/program.rs +++ b/examples/tree/src/program.rs @@ -188,6 +188,7 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8, instruction_data: *mut u8) - // ANCHOR_END: entrypoint-branching // ANCHOR: insert-input-checks +#[allow(unused_assignments)] #[inline(always)] unsafe fn insert( input: *mut u8, @@ -204,7 +205,7 @@ unsafe fn insert( ); // Error if user has data. - let user = user_account!(input); + let _user = user_account!(input); // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); @@ -742,7 +743,7 @@ unsafe fn remove( #[inline(always)] unsafe fn initialize( input: *mut u8, - instruction_data: *mut u8, + _instruction_data: *mut u8, instruction_data_len: u64, n_accounts: u64, ) -> u64 { @@ -755,7 +756,7 @@ unsafe fn initialize( ); // Error if user has data. - let user = user_account!(input); + let _user = user_account!(input); // Error if tree is duplicate or has data. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); @@ -898,21 +899,6 @@ unsafe fn direction(node: *const TreeNode) -> usize { (node == (*(*node).parent).child[tree::DIR_R]) as usize } -#[inline(always)] -unsafe fn search(tree_header: *const TreeHeader, key: u16) -> *mut TreeNode { - let mut node = (*tree_header).root; - loop { - if node.is_null() { - break; - } - if (*node).key == key { - break; - } - node = (*node).child[(key > (*node).key) as usize]; - } - node -} - /// Rotate the subtree rooted at `subtree` in the given direction, returning new root of subtree. #[inline(always)] unsafe fn rotate_subtree( From d5ade29dfaef956fba9c3f106dc1661b7cd71b60 Mon Sep 17 00:00:00 2001 From: Alex Kahn <43892045+alnoki@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:46:13 -0800 Subject: [PATCH 263/263] Re-build examples --- examples/hello-dasmac/artifacts/dumps/asm.txt | 2 +- examples/tree/artifacts/dumps/asm.txt | 212 +++-- examples/tree/artifacts/dumps/rs.txt | 787 +++++++++++------- examples/tree/artifacts/rs-disassembly.s | 647 +++++++++----- .../snippets/rs/initialize-input-checks.txt | 4 +- .../snippets/rs/insert-input-checks.txt | 3 +- .../artifacts/tests/remove_simple/result.txt | 48 +- examples/tree/src/tests.rs | 1 + examples/tree/src/tests/init.rs | 4 +- examples/tree/src/tests/insert.rs | 4 +- 10 files changed, 1119 insertions(+), 593 deletions(-) diff --git a/examples/hello-dasmac/artifacts/dumps/asm.txt b/examples/hello-dasmac/artifacts/dumps/asm.txt index ef3ca6f7..754cdaca 100644 --- a/examples/hello-dasmac/artifacts/dumps/asm.txt +++ b/examples/hello-dasmac/artifacts/dumps/asm.txt @@ -43,7 +43,7 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x00003e 0x00003e R E 0x1000 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000040 0x000040 R E 0x1000 LOAD 0x0001d8 0x00000000000001d8 0x00000000000001d8 0x000080 0x000080 R 0x1000 DYNAMIC 0x000128 0x0000000000000128 0x0000000000000128 0x0000b0 0x0000b0 RW 0x8 diff --git a/examples/tree/artifacts/dumps/asm.txt b/examples/tree/artifacts/dumps/asm.txt index 508111c9..aecdf65a 100644 --- a/examples/tree/artifacts/dumps/asm.txt +++ b/examples/tree/artifacts/dumps/asm.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0xE8 Start of program headers 64 (bytes into file) - Start of section headers 4232 (bytes into file) + Start of section headers 4680 (bytes into file) Flags 0x0 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,17 +19,17 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 7 Section header string table index 6 -There are 7 section headers, starting at offset 0x1088 +There are 7 section headers, starting at offset 0x1248 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 00000000000000e8 0000e8 000e00 00 AX 0 0 4 - [ 2] .dynamic DYNAMIC 0000000000000ee8 000ee8 0000a0 10 WA 4 0 8 - [ 3] .dynsym DYNSYM 0000000000000f88 000f88 000060 18 A 4 1 8 - [ 4] .dynstr STRTAB 0000000000000fe8 000fe8 000040 00 A 0 0 1 - [ 5] .rel.dyn REL 0000000000001028 001028 000030 10 A 3 0 8 - [ 6] .s STRTAB 0000000000000000 001058 00002c 00 0 0 1 + [ 1] .text PROGBITS 00000000000000e8 0000e8 000fc0 00 AX 0 0 4 + [ 2] .dynamic DYNAMIC 00000000000010a8 0010a8 0000a0 10 WA 4 0 8 + [ 3] .dynsym DYNSYM 0000000000001148 001148 000060 18 A 4 1 8 + [ 4] .dynstr STRTAB 00000000000011a8 0011a8 000040 00 A 0 0 1 + [ 5] .rel.dyn REL 00000000000011e8 0011e8 000030 10 A 3 0 8 + [ 6] .s STRTAB 0000000000000000 001218 00002c 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -42,9 +42,9 @@ There are 3 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000e00 0x000e00 R E 0x1000 - LOAD 0x000f88 0x0000000000000f88 0x0000000000000f88 0x0000d0 0x0000d0 R 0x1000 - DYNAMIC 0x000ee8 0x0000000000000ee8 0x0000000000000ee8 0x0000a0 0x0000a0 RW 0x8 + LOAD 0x0000e8 0x00000000000000e8 0x00000000000000e8 0x000fc0 0x000fc0 R E 0x1000 + LOAD 0x001148 0x0000000000001148 0x0000000000001148 0x0000d0 0x0000d0 R 0x1000 + DYNAMIC 0x0010a8 0x00000000000010a8 0x00000000000010a8 0x0000a0 0x0000a0 RW 0x8 Section to Segment mapping Segment Sections... @@ -52,20 +52,20 @@ Program Headers 01 .dynsym .dynstr .rel.dyn 02 .dynamic None .s -Dynamic section at offset 0xee8 contains 10 entries +Dynamic section at offset 0x10a8 contains 10 entries Tag Type Name/Value 0x000000000000001e (FLAGS) TEXTREL - 0x0000000000000011 (REL) 0x1028 + 0x0000000000000011 (REL) 0x11e8 0x0000000000000012 (RELSZ) 48 (bytes) 0x0000000000000013 (RELENT) 16 (bytes) - 0x0000000000000006 (SYMTAB) 0xf88 + 0x0000000000000006 (SYMTAB) 0x1148 0x000000000000000b (SYMENT) 24 (bytes) - 0x0000000000000005 (STRTAB) 0xfe8 + 0x0000000000000005 (STRTAB) 0x11a8 0x000000000000000a (STRSZ) 64 (bytes) 0x0000000000000016 (TEXTREL) 0x0 0x0000000000000000 (NULL) 0x0 -Relocation section '.rel.dyn' at offset 0x1028 contains 3 entries +Relocation section '.rel.dyn' at offset 0x11e8 contains 3 entries Offset Info Type Symbol's Value Symbol's Name 0000000000000248 000000030000000a R_BPF_64_32 0000000000000000 sol_try_find_program_address 0000000000000468 000000020000000a R_BPF_64_32 0000000000000000 sol_invoke_signed_c @@ -92,32 +92,32 @@ Disassembly of section .text 34 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 35 b7 00 00 00 0b 00 00 00 r0 = 0xb 36 95 00 00 00 00 00 00 00 exit - 37 55 09 a1 01 01 00 00 00 if r9 != 0x1 goto +0x1a1 - 38 55 08 a2 01 04 00 00 00 if r8 != 0x4 goto +0x1a2 + 37 55 09 d9 01 01 00 00 00 if r9 != 0x1 goto +0x1d9 + 38 55 08 da 01 04 00 00 00 if r8 != 0x4 goto +0x1da 39 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 40 55 09 b2 01 00 00 00 00 if r9 != 0x0 goto +0x1b2 + 40 55 09 ea 01 00 00 00 00 if r9 != 0x0 goto +0x1ea 41 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 42 55 09 ae 01 ff 00 00 00 if r9 != 0xff goto +0x1ae + 42 55 09 e6 01 ff 00 00 00 if r9 != 0xff goto +0x1e6 43 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) - 44 55 09 aa 01 00 00 00 00 if r9 != 0x0 goto +0x1aa + 44 55 09 e2 01 00 00 00 00 if r9 != 0x0 goto +0x1e2 45 71 19 c8 50 00 00 00 00 r9 = *(u8 *)(r1 + 0x50c8) - 46 55 09 a6 01 ff 00 00 00 if r9 != 0xff goto +0x1a6 + 46 55 09 de 01 ff 00 00 00 if r9 != 0xff goto +0x1de 47 79 19 18 51 00 00 00 00 r9 = *(u64 *)(r1 + 0x5118) - 48 55 09 a2 01 0e 00 00 00 if r9 != 0xe goto +0x1a2 + 48 55 09 da 01 0e 00 00 00 if r9 != 0xe goto +0x1da 49 71 19 38 79 00 00 00 00 r9 = *(u8 *)(r1 + 0x7938) - 50 55 09 9e 01 ff 00 00 00 if r9 != 0xff goto +0x19e + 50 55 09 d6 01 ff 00 00 00 if r9 != 0xff goto +0x1d6 51 79 19 40 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7940) 52 18 08 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r8 = 0x515c2c1917d5a706 ll - 54 5d 89 98 01 00 00 00 00 if r9 != r8 goto +0x198 + 54 5d 89 d0 01 00 00 00 00 if r9 != r8 goto +0x1d0 55 79 19 48 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7948) 56 18 08 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r8 = 0x7ff14a3d4cc98c21 ll - 58 5d 89 94 01 00 00 00 00 if r9 != r8 goto +0x194 + 58 5d 89 cc 01 00 00 00 00 if r9 != r8 goto +0x1cc 59 79 19 50 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7950) 60 18 08 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r8 = 0x44fda19b08eeda58 ll - 62 5d 89 90 01 00 00 00 00 if r9 != r8 goto +0x190 + 62 5d 89 c8 01 00 00 00 00 if r9 != r8 goto +0x1c8 63 79 19 58 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7958) 64 b4 08 00 00 e3 db d9 8a w8 = -0x7526241d - 65 5d 89 8d 01 00 00 00 00 if r9 != r8 goto +0x18d + 65 5d 89 c5 01 00 00 00 00 if r9 != r8 goto +0x1c5 66 b7 02 00 00 00 00 00 00 r2 = 0x0 67 bf 13 00 00 00 00 00 00 r3 = r1 68 07 03 00 00 b9 a1 00 00 r3 += 0xa1b9 @@ -128,16 +128,16 @@ Disassembly of section .text 73 85 10 00 00 ff ff ff ff call -0x1 74 79 19 70 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2870) 75 79 48 00 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x0) - 76 5d 89 80 01 00 00 00 00 if r9 != r8 goto +0x180 + 76 5d 89 b8 01 00 00 00 00 if r9 != r8 goto +0x1b8 77 79 19 78 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2878) 78 79 48 08 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x8) - 79 5d 89 7d 01 00 00 00 00 if r9 != r8 goto +0x17d + 79 5d 89 b5 01 00 00 00 00 if r9 != r8 goto +0x1b5 80 79 19 80 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2880) 81 79 48 10 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x10) - 82 5d 89 7a 01 00 00 00 00 if r9 != r8 goto +0x17a + 82 5d 89 b2 01 00 00 00 00 if r9 != r8 goto +0x1b2 83 79 19 88 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x2888) 84 79 48 18 00 00 00 00 00 r8 = *(u64 *)(r4 + 0x18) - 85 5d 89 77 01 00 00 00 00 if r9 != r8 goto +0x177 + 85 5d 89 af 01 00 00 00 00 if r9 != r8 goto +0x1af 86 7a 0a e8 fe 02 00 00 00 *(u64 *)(r10 - 0x118) = 0x2 87 7a 0a f8 fe 34 00 00 00 *(u64 *)(r10 - 0x108) = 0x34 88 79 19 90 79 00 00 00 00 r9 = *(u64 *)(r1 + 0x7990) @@ -198,15 +198,15 @@ Disassembly of section .text 143 07 07 00 00 18 00 00 00 r7 += 0x18 144 7b 76 10 00 00 00 00 00 *(u64 *)(r6 + 0x10) = r7 145 95 00 00 00 00 00 00 00 exit - 146 55 09 34 01 05 00 00 00 if r9 != 0x5 goto +0x134 - 147 a5 08 35 01 02 00 00 00 if r8 < 0x2 goto +0x135 + 146 55 09 6c 01 05 00 00 00 if r9 != 0x5 goto +0x16c + 147 a5 08 6d 01 02 00 00 00 if r8 < 0x2 goto +0x16d 148 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 149 55 09 45 01 00 00 00 00 if r9 != 0x0 goto +0x145 + 149 55 09 7d 01 00 00 00 00 if r9 != 0x0 goto +0x17d 150 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 151 55 09 41 01 ff 00 00 00 if r9 != 0xff goto +0x141 + 151 55 09 79 01 ff 00 00 00 if r9 != 0xff goto +0x179 152 79 19 c8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28c8) 153 55 09 51 00 00 00 00 00 if r9 != 0x0 goto +0x51 - 154 55 08 30 01 04 00 00 00 if r8 != 0x4 goto +0x130 + 154 55 08 68 01 04 00 00 00 if r8 != 0x4 goto +0x168 155 79 19 b8 28 00 00 00 00 r9 = *(u64 *)(r1 + 0x28b8) 156 7b 9a 68 ff 00 00 00 00 *(u64 *)(r10 - 0x98) = r9 157 bf 97 00 00 00 00 00 00 r7 = r9 @@ -214,23 +214,23 @@ Disassembly of section .text 159 57 09 00 00 f8 ff ff ff r9 &= -0x8 160 0f 19 00 00 00 00 00 00 r9 += r1 161 71 98 c8 50 00 00 00 00 r8 = *(u8 *)(r9 + 0x50c8) - 162 55 08 32 01 ff 00 00 00 if r8 != 0xff goto +0x132 + 162 55 08 6a 01 ff 00 00 00 if r8 != 0xff goto +0x16a 163 79 98 18 51 00 00 00 00 r8 = *(u64 *)(r9 + 0x5118) - 164 55 08 2e 01 0e 00 00 00 if r8 != 0xe goto +0x12e + 164 55 08 66 01 0e 00 00 00 if r8 != 0xe goto +0x166 165 71 98 38 79 00 00 00 00 r8 = *(u8 *)(r9 + 0x7938) - 166 55 08 2a 01 ff 00 00 00 if r8 != 0xff goto +0x12a + 166 55 08 62 01 ff 00 00 00 if r8 != 0xff goto +0x162 167 79 98 40 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7940) 168 18 04 00 00 06 a7 d5 17 00 00 00 00 19 2c 5c 51 r4 = 0x515c2c1917d5a706 ll - 170 5d 48 24 01 00 00 00 00 if r8 != r4 goto +0x124 + 170 5d 48 5c 01 00 00 00 00 if r8 != r4 goto +0x15c 171 79 98 48 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7948) 172 18 04 00 00 21 8c c9 4c 00 00 00 00 3d 4a f1 7f r4 = 0x7ff14a3d4cc98c21 ll - 174 5d 48 20 01 00 00 00 00 if r8 != r4 goto +0x120 + 174 5d 48 58 01 00 00 00 00 if r8 != r4 goto +0x158 175 79 98 50 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7950) 176 18 04 00 00 58 da ee 08 00 00 00 00 9b a1 fd 44 r4 = 0x44fda19b08eeda58 ll - 178 5d 48 1c 01 00 00 00 00 if r8 != r4 goto +0x11c + 178 5d 48 54 01 00 00 00 00 if r8 != r4 goto +0x154 179 79 98 58 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7958) 180 b4 04 00 00 e3 db d9 8a w4 = -0x7526241d - 181 5d 48 19 01 00 00 00 00 if r8 != r4 goto +0x119 + 181 5d 48 51 01 00 00 00 00 if r8 != r4 goto +0x151 182 79 98 90 79 00 00 00 00 r8 = *(u64 *)(r9 + 0x7990) 183 27 08 00 00 1d 00 00 00 r8 *= 0x1d 184 62 0a a1 fe 02 00 00 00 *(u32 *)(r10 - 0x15f) = 0x2 @@ -409,12 +409,12 @@ Disassembly of section .text 357 79 92 00 00 00 00 00 00 r2 = *(u64 *)(r9 + 0x0) 358 55 02 a3 ff 00 00 00 00 if r2 != 0x0 goto -0x5d 359 95 00 00 00 00 00 00 00 exit - 360 55 09 5e 00 03 00 00 00 if r9 != 0x3 goto +0x5e - 361 a5 08 5f 00 02 00 00 00 if r8 < 0x2 goto +0x5f + 360 55 09 96 00 03 00 00 00 if r9 != 0x3 goto +0x96 + 361 a5 08 97 00 02 00 00 00 if r8 < 0x2 goto +0x97 362 79 19 58 00 00 00 00 00 r9 = *(u64 *)(r1 + 0x58) - 363 55 09 6f 00 00 00 00 00 if r9 != 0x0 goto +0x6f + 363 55 09 a7 00 00 00 00 00 if r9 != 0x0 goto +0xa7 364 71 19 68 28 00 00 00 00 r9 = *(u8 *)(r1 + 0x2868) - 365 55 09 6b 00 ff 00 00 00 if r9 != 0xff goto +0x6b + 365 55 09 a3 00 ff 00 00 00 if r9 != 0xff goto +0xa3 366 79 13 c0 28 00 00 00 00 r3 = *(u64 *)(r1 + 0x28c0) 367 15 03 0a 00 00 00 00 00 if r3 == 0x0 goto +0xa 368 69 24 01 00 00 00 00 00 r4 = *(u16 *)(r2 + 0x1) @@ -496,33 +496,89 @@ Disassembly of section .text 444 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 445 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 446 95 00 00 00 00 00 00 00 exit - 447 7a 03 08 00 00 00 00 00 *(u64 *)(r3 + 0x8) = 0x0 - 448 7a 03 10 00 00 00 00 00 *(u64 *)(r3 + 0x10) = 0x0 - 449 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) - 450 7b 43 00 00 00 00 00 00 *(u64 *)(r3 + 0x0) = r4 - 451 7b 31 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r3 - 452 95 00 00 00 00 00 00 00 exit - 453 b7 00 00 00 09 00 00 00 r0 = 0x9 - 454 95 00 00 00 00 00 00 00 exit - 455 b7 00 00 00 0c 00 00 00 r0 = 0xc - 456 95 00 00 00 00 00 00 00 exit - 457 b7 00 00 00 01 00 00 00 r0 = 0x1 - 458 95 00 00 00 00 00 00 00 exit - 459 b7 00 00 00 0d 00 00 00 r0 = 0xd - 460 95 00 00 00 00 00 00 00 exit - 461 b7 00 00 00 0a 00 00 00 r0 = 0xa - 462 95 00 00 00 00 00 00 00 exit - 463 b7 00 00 00 08 00 00 00 r0 = 0x8 - 464 95 00 00 00 00 00 00 00 exit - 465 b7 00 00 00 07 00 00 00 r0 = 0x7 - 466 95 00 00 00 00 00 00 00 exit - 467 b7 00 00 00 04 00 00 00 r0 = 0x4 - 468 95 00 00 00 00 00 00 00 exit - 469 b7 00 00 00 06 00 00 00 r0 = 0x6 - 470 95 00 00 00 00 00 00 00 exit - 471 b7 00 00 00 03 00 00 00 r0 = 0x3 - 472 95 00 00 00 00 00 00 00 exit - 473 b7 00 00 00 05 00 00 00 r0 = 0x5 - 474 95 00 00 00 00 00 00 00 exit - 475 b7 00 00 00 02 00 00 00 r0 = 0x2 - 476 95 00 00 00 00 00 00 00 exit \ No newline at end of file + 447 bf 32 00 00 00 00 00 00 r2 = r3 + 448 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 449 79 54 08 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x8) + 450 5d 43 02 00 00 00 00 00 if r3 != r4 goto +0x2 + 451 7a 05 08 00 00 00 00 00 *(u64 *)(r5 + 0x8) = 0x0 + 452 05 00 32 00 00 00 00 00 goto +0x32 + 453 7a 05 10 00 00 00 00 00 *(u64 *)(r5 + 0x10) = 0x0 + 454 79 56 08 00 00 00 00 00 r6 = *(u64 *)(r5 + 0x8) + 455 79 67 08 00 00 00 00 00 r7 = *(u64 *)(r6 + 0x8) + 456 79 68 10 00 00 00 00 00 r8 = *(u64 *)(r6 + 0x10) + 457 71 69 1c 00 00 00 00 00 r9 = *(u8 *)(r6 + 0x1c) + 458 15 09 1c 00 01 00 00 00 if r9 == 0x1 goto +0x1c + 459 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 460 71 79 1c 00 00 00 00 00 r9 = *(u8 *)(r7 + 0x1c) + 461 15 09 14 00 01 00 00 00 if r9 == 0x1 goto +0x14 + 462 15 08 02 00 00 00 00 00 if r8 == 0x0 goto +0x2 + 463 71 89 1c 00 00 00 00 00 r9 = *(u8 *)(r8 + 0x1c) + 464 15 09 0d 00 01 00 00 00 if r9 == 0x1 goto +0xd + 465 15 05 25 00 00 00 00 00 if r5 == 0x0 goto +0x25 + 466 71 59 1c 00 00 00 00 00 r9 = *(u8 *)(r5 + 0x1c) + 467 55 09 03 00 01 00 00 00 if r9 != 0x1 goto +0x3 + 468 72 06 1c 00 01 00 00 00 *(u8 *)(r6 + 0x1c) = 0x1 + 469 72 05 1c 00 00 00 00 00 *(u8 *)(r5 + 0x1c) = 0x0 + 470 05 00 20 00 00 00 00 00 goto +0x20 + 471 72 06 1c 00 01 00 00 00 *(u8 *)(r6 + 0x1c) = 0x1 + 472 bf 53 00 00 00 00 00 00 r3 = r5 + 473 79 35 00 00 00 00 00 00 r5 = *(u64 *)(r3 + 0x0) + 474 15 05 03 00 00 00 00 00 if r5 == 0x0 goto +0x3 + 475 79 54 08 00 00 00 00 00 r4 = *(u64 *)(r5 + 0x8) + 476 1d 43 1a 00 00 00 00 00 if r3 == r4 goto +0x1a + 477 05 00 e8 ff 00 00 00 00 goto -0x18 + 478 72 06 1c 00 01 00 00 00 *(u8 *)(r6 + 0x1c) = 0x1 + 479 72 08 1c 00 00 00 00 00 *(u8 *)(r8 + 0x1c) = 0x0 + 480 bf 67 00 00 00 00 00 00 r7 = r6 + 481 bf 86 00 00 00 00 00 00 r6 = r8 + 482 71 54 1c 00 00 00 00 00 r4 = *(u8 *)(r5 + 0x1c) + 483 73 46 1c 00 00 00 00 00 *(u8 *)(r6 + 0x1c) = r4 + 484 72 05 1c 00 00 00 00 00 *(u8 *)(r5 + 0x1c) = 0x0 + 485 72 07 1c 00 00 00 00 00 *(u8 *)(r7 + 0x1c) = 0x0 + 486 05 00 10 00 00 00 00 00 goto +0x10 + 487 72 05 1c 00 01 00 00 00 *(u8 *)(r5 + 0x1c) = 0x1 + 488 72 06 1c 00 00 00 00 00 *(u8 *)(r6 + 0x1c) = 0x0 + 489 bf 86 00 00 00 00 00 00 r6 = r8 + 490 79 64 08 00 00 00 00 00 r4 = *(u64 *)(r6 + 0x8) + 491 bf 47 00 00 00 00 00 00 r7 = r4 + 492 15 07 02 00 00 00 00 00 if r7 == 0x0 goto +0x2 + 493 71 74 1c 00 00 00 00 00 r4 = *(u8 *)(r7 + 0x1c) + 494 15 04 f3 ff 01 00 00 00 if r4 == 0x1 goto -0xd + 495 79 64 10 00 00 00 00 00 r4 = *(u64 *)(r6 + 0x10) + 496 bf 48 00 00 00 00 00 00 r8 = r4 + 497 15 08 02 00 00 00 00 00 if r8 == 0x0 goto +0x2 + 498 71 84 1c 00 00 00 00 00 r4 = *(u8 *)(r8 + 0x1c) + 499 15 04 ea ff 01 00 00 00 if r4 == 0x1 goto -0x16 + 500 72 06 1c 00 01 00 00 00 *(u8 *)(r6 + 0x1c) = 0x1 + 501 72 05 1c 00 00 00 00 00 *(u8 *)(r5 + 0x1c) = 0x0 + 502 05 00 00 00 00 00 00 00 goto +0x0 + 503 7a 02 08 00 00 00 00 00 *(u64 *)(r2 + 0x8) = 0x0 + 504 7a 02 10 00 00 00 00 00 *(u64 *)(r2 + 0x10) = 0x0 + 505 79 14 c8 28 00 00 00 00 r4 = *(u64 *)(r1 + 0x28c8) + 506 7b 42 00 00 00 00 00 00 *(u64 *)(r2 + 0x0) = r4 + 507 7b 21 c8 28 00 00 00 00 *(u64 *)(r1 + 0x28c8) = r2 + 508 95 00 00 00 00 00 00 00 exit + 509 b7 00 00 00 09 00 00 00 r0 = 0x9 + 510 95 00 00 00 00 00 00 00 exit + 511 b7 00 00 00 0c 00 00 00 r0 = 0xc + 512 95 00 00 00 00 00 00 00 exit + 513 b7 00 00 00 01 00 00 00 r0 = 0x1 + 514 95 00 00 00 00 00 00 00 exit + 515 b7 00 00 00 0d 00 00 00 r0 = 0xd + 516 95 00 00 00 00 00 00 00 exit + 517 b7 00 00 00 0a 00 00 00 r0 = 0xa + 518 95 00 00 00 00 00 00 00 exit + 519 b7 00 00 00 08 00 00 00 r0 = 0x8 + 520 95 00 00 00 00 00 00 00 exit + 521 b7 00 00 00 07 00 00 00 r0 = 0x7 + 522 95 00 00 00 00 00 00 00 exit + 523 b7 00 00 00 04 00 00 00 r0 = 0x4 + 524 95 00 00 00 00 00 00 00 exit + 525 b7 00 00 00 06 00 00 00 r0 = 0x6 + 526 95 00 00 00 00 00 00 00 exit + 527 b7 00 00 00 03 00 00 00 r0 = 0x3 + 528 95 00 00 00 00 00 00 00 exit + 529 b7 00 00 00 05 00 00 00 r0 = 0x5 + 530 95 00 00 00 00 00 00 00 exit + 531 b7 00 00 00 02 00 00 00 r0 = 0x2 + 532 95 00 00 00 00 00 00 00 exit \ No newline at end of file diff --git a/examples/tree/artifacts/dumps/rs.txt b/examples/tree/artifacts/dumps/rs.txt index e158bb4d..079d0390 100644 --- a/examples/tree/artifacts/dumps/rs.txt +++ b/examples/tree/artifacts/dumps/rs.txt @@ -11,7 +11,7 @@ ELF Header Version 0x1 Entry point address 0x0 Start of program headers 64 (bytes into file) - Start of section headers 6536 (bytes into file) + Start of section headers 8128 (bytes into file) Flags 0x4 Size of this header 64 (bytes) Size of program headers 56 (bytes) @@ -19,18 +19,18 @@ ELF Header Size of section headers 64 (bytes) Number of section headers 8 Section header string table index 6 -There are 8 section headers, starting at offset 0x1988 +There are 8 section headers, starting at offset 0x1fc0 Section Headers [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .text PROGBITS 0000000000000000 000120 000f78 00 AX 0 0 8 - [ 2] .rodata PROGBITS 0000000100000000 001098 000008 00 A 0 0 1 - [ 3] .bss.stack NOBITS 0000000200000000 0010a0 001000 00 A 0 0 1 - [ 4] .bss.heap NOBITS 0000000300000000 0010a0 001000 00 A 0 0 1 - [ 5] .symtab SYMTAB 0000000000000000 0010a0 000378 18 7 36 8 - [ 6] .shstrtab STRTAB 0000000000000000 001418 00003e 00 0 0 1 - [ 7] .strtab STRTAB 0000000000000000 001456 000532 00 0 0 1 + [ 1] .text PROGBITS 0000000000000000 000120 0015b0 00 AX 0 0 8 + [ 2] .rodata PROGBITS 0000000100000000 0016d0 000008 00 A 0 0 1 + [ 3] .bss.stack NOBITS 0000000200000000 0016d8 001000 00 A 0 0 1 + [ 4] .bss.heap NOBITS 0000000300000000 0016d8 001000 00 A 0 0 1 + [ 5] .symtab SYMTAB 0000000000000000 0016d8 000378 18 7 36 8 + [ 6] .shstrtab STRTAB 0000000000000000 001a50 00003e 00 0 0 1 + [ 7] .strtab STRTAB 0000000000000000 001a8e 000532 00 0 0 1 Key to Flags W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), @@ -43,10 +43,10 @@ There are 4 program headers, starting at offset 64 Program Headers Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x000f78 0x000f78 E 0x8 - LOAD 0x001098 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 - LOAD 0x0010a0 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 - LOAD 0x0010a0 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 + LOAD 0x000120 0x0000000000000000 0x0000000000000000 0x0015b0 0x0015b0 E 0x8 + LOAD 0x0016d0 0x0000000100000000 0x0000000100000000 0x000008 0x000008 R 0x8 + LOAD 0x0016d8 0x0000000200000000 0x0000000200000000 0x000000 0x001000 RW 0x8 + LOAD 0x0016d8 0x0000000300000000 0x0000000300000000 0x000000 0x001000 RW 0x8 Section to Segment mapping Segment Sections... @@ -96,7 +96,7 @@ Symbol table '.symtab' contains 37 entries 33 0000000200001000 0 NOTYPE LOCAL DEFAULT 3 _stack_end 34 0000000300000000 0 NOTYPE LOCAL DEFAULT 4 _heap_start 35 0000000300001000 0 NOTYPE LOCAL DEFAULT 4 _heap_end - 36 0000000000000000 3960 FUNC GLOBAL DEFAULT 1 entrypoint + 36 0000000000000000 5552 FUNC GLOBAL DEFAULT 1 entrypoint There are no section groups in this file. tree.so file format elf64-sbf @@ -104,17 +104,17 @@ tree.so file format elf64-sbf Disassembly of section .text 0000000000000000 - 0 07 0a 00 00 c0 fe ff ff add64 r10, -0x140 + 0 07 0a 00 00 80 fe ff ff add64 r10, -0x180 8 9c 14 00 00 00 00 00 00 ldxdw r4, [r1 + 0x0] 10 9c 23 f8 ff 00 00 00 00 ldxdw r3, [r2 - 0x8] 18 2c 25 00 00 00 00 00 00 ldxb w5, [r2 + 0x0] 20 55 05 ed 00 01 00 00 00 jne r5, 0x1, +0xed - 28 55 03 d3 01 05 00 00 00 jne r3, 0x5, +0x1d3 - 30 a5 04 d4 01 02 00 00 00 jlt r4, 0x2, +0x1d4 + 28 55 03 96 02 05 00 00 00 jne r3, 0x5, +0x296 + 30 a5 04 97 02 02 00 00 00 jlt r4, 0x2, +0x297 38 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 40 55 03 d4 01 00 00 00 00 jne r3, 0x0, +0x1d4 + 40 55 03 97 02 00 00 00 00 jne r3, 0x0, +0x297 48 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 50 55 03 d4 01 ff 00 00 00 jne r3, 0xff, +0x1d4 + 50 55 03 97 02 ff 00 00 00 jne r3, 0xff, +0x297 58 bf 16 00 00 00 00 00 00 mov64 r6, r1 60 07 06 00 00 c0 28 00 00 add64 r6, 0x28c0 68 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] @@ -133,7 +133,7 @@ Disassembly of section .text d0 9c 24 10 00 00 00 00 00 ldxdw r4, [r2 + 0x10] d8 55 04 fa ff 00 00 00 00 jne r4, 0x0, -0x6 e0 05 00 09 00 00 00 00 00 ja +0x9 - e8 3d 45 2c 01 00 00 00 00 jge r5, r4, +0x12c + e8 3d 45 83 01 00 00 00 00 jge r5, r4, +0x183 f0 9c 24 08 00 00 00 00 00 ldxdw r4, [r2 + 0x8] f8 55 04 f6 ff 00 00 00 00 jne r4, 0x0, -0xa 100 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 @@ -193,11 +193,11 @@ Disassembly of section .text 2b0 bf 14 00 00 00 00 00 00 mov64 r4, r1 2b8 0f 54 00 00 00 00 00 00 add64 r4, r5 2c0 2c 45 c8 50 00 00 00 00 ldxb w5, [r4 + 0x50c8] - 2c8 55 05 87 01 ff 00 00 00 jne r5, 0xff, +0x187 + 2c8 55 05 4a 02 ff 00 00 00 jne r5, 0xff, +0x24a 2d0 9c 45 18 51 00 00 00 00 ldxdw r5, [r4 + 0x5118] - 2d8 55 05 87 01 0e 00 00 00 jne r5, 0xe, +0x187 + 2d8 55 05 4a 02 0e 00 00 00 jne r5, 0xe, +0x24a 2e0 2c 45 38 79 00 00 00 00 ldxb w5, [r4 + 0x7938] - 2e8 55 05 87 01 ff 00 00 00 jne r5, 0xff, +0x187 + 2e8 55 05 4a 02 ff 00 00 00 jne r5, 0xff, +0x24a 2f0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 2f8 b4 05 00 00 06 a7 d5 17 mov32 w5, 0x17d5a706 300 f7 05 00 00 19 2c 5c 51 hor64 r5, 0x515c2c19 @@ -217,65 +217,65 @@ Disassembly of section .text 370 5d 52 68 00 00 00 00 00 jne r2, r5, +0x68 378 9c 42 90 79 00 00 00 00 ldxdw r2, [r4 + 0x7990] 380 96 02 00 00 1d 00 00 00 lmul64 r2, 0x1d - 388 9f 2a 34 01 00 00 00 00 stxdw [r10 + 0x134], r2 - 390 87 0a 30 01 02 00 00 00 stw [r10 + 0x130], 0x2 + 388 9f 2a 74 01 00 00 00 00 stxdw [r10 + 0x174], r2 + 390 87 0a 70 01 02 00 00 00 stw [r10 + 0x170], 0x2 398 bf 14 00 00 00 00 00 00 mov64 r4, r1 3a0 07 04 00 00 70 28 00 00 add64 r4, 0x2870 - 3a8 9f 4a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r4 + 3a8 9f 4a 28 01 00 00 00 00 stxdw [r10 + 0x128], r4 3b0 bf 12 00 00 00 00 00 00 mov64 r2, r1 3b8 07 02 00 00 10 00 00 00 add64 r2, 0x10 - 3c0 9f 2a d8 00 00 00 00 00 stxdw [r10 + 0xd8], r2 - 3c8 37 0a f0 00 01 00 00 00 sth [r10 + 0xf0], 0x1 - 3d0 37 0a e0 00 01 01 00 00 sth [r10 + 0xe0], 0x101 + 3c0 9f 2a 18 01 00 00 00 00 stxdw [r10 + 0x118], r2 + 3c8 37 0a 30 01 01 00 00 00 sth [r10 + 0x130], 0x1 + 3d0 37 0a 20 01 01 01 00 00 sth [r10 + 0x120], 0x101 3d8 bf 15 00 00 00 00 00 00 mov64 r5, r1 3e0 07 05 00 00 90 28 00 00 add64 r5, 0x2890 - 3e8 9f 5a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r5 - 3f0 9f 6a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r6 - 3f8 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 3e8 9f 5a 00 01 00 00 00 00 stxdw [r10 + 0x100], r5 + 3f0 9f 6a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r6 + 3f8 9f 3a f0 00 00 00 00 00 stxdw [r10 + 0xf0], r3 400 bf 13 00 00 00 00 00 00 mov64 r3, r1 408 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - 410 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - 418 9f 4a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r4 + 410 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + 418 9f 4a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r4 420 bf 13 00 00 00 00 00 00 mov64 r3, r1 428 07 03 00 00 30 00 00 00 add64 r3, 0x30 - 430 9f 3a 88 00 00 00 00 00 stxdw [r10 + 0x88], r3 + 430 9f 3a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r3 438 bf 13 00 00 00 00 00 00 mov64 r3, r1 440 07 03 00 00 60 00 00 00 add64 r3, 0x60 - 448 9f 3a 80 00 00 00 00 00 stxdw [r10 + 0x80], r3 + 448 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 450 bf 13 00 00 00 00 00 00 mov64 r3, r1 458 07 03 00 00 50 00 00 00 add64 r3, 0x50 - 460 9f 3a 70 00 00 00 00 00 stxdw [r10 + 0x70], r3 - 468 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - 470 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - 478 37 0a d0 00 00 01 00 00 sth [r10 + 0xd0], 0x100 - 480 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - 488 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - 490 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - 498 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - 4a0 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - 4a8 97 0a 10 01 00 00 00 00 stdw [r10 + 0x110], 0x0 - 4b0 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 - 4b8 97 0a 00 01 00 00 00 00 stdw [r10 + 0x100], 0x0 - 4c0 97 0a f8 00 00 00 00 00 stdw [r10 + 0xf8], 0x0 + 460 9f 3a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r3 + 468 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + 470 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + 478 37 0a 10 01 00 01 00 00 sth [r10 + 0x110], 0x100 + 480 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 488 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + 490 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + 498 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + 4a0 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + 4a8 97 0a 50 01 00 00 00 00 stdw [r10 + 0x150], 0x0 + 4b0 97 0a 48 01 00 00 00 00 stdw [r10 + 0x148], 0x0 + 4b8 97 0a 40 01 00 00 00 00 stdw [r10 + 0x140], 0x0 + 4c0 97 0a 38 01 00 00 00 00 stdw [r10 + 0x138], 0x0 4c8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4d0 07 02 00 00 30 01 00 00 add64 r2, 0x130 - 4d8 9f 2a 28 00 00 00 00 00 stxdw [r10 + 0x28], r2 + 4d0 07 02 00 00 70 01 00 00 add64 r2, 0x170 + 4d8 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 4e0 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 4e8 07 02 00 00 d8 00 00 00 add64 r2, 0xd8 - 4f0 9f 2a 18 00 00 00 00 00 stxdw [r10 + 0x18], r2 + 4e8 07 02 00 00 18 01 00 00 add64 r2, 0x118 + 4f0 9f 2a 58 00 00 00 00 00 stxdw [r10 + 0x58], r2 4f8 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 500 07 02 00 00 f8 00 00 00 add64 r2, 0xf8 - 508 9f 2a 10 00 00 00 00 00 stxdw [r10 + 0x10], r2 - 510 97 0a 30 00 0c 00 00 00 stdw [r10 + 0x30], 0xc - 518 97 0a 20 00 02 00 00 00 stdw [r10 + 0x20], 0x2 - 520 97 0a 50 00 00 00 00 00 stdw [r10 + 0x50], 0x0 - 528 97 0a 48 00 00 00 00 00 stdw [r10 + 0x48], 0x0 + 500 07 02 00 00 38 01 00 00 add64 r2, 0x138 + 508 9f 2a 50 00 00 00 00 00 stxdw [r10 + 0x50], r2 + 510 97 0a 70 00 0c 00 00 00 stdw [r10 + 0x70], 0xc + 518 97 0a 60 00 02 00 00 00 stdw [r10 + 0x60], 0x2 + 520 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 + 528 97 0a 88 00 00 00 00 00 stdw [r10 + 0x88], 0x0 530 bf a3 00 00 00 00 00 00 mov64 r3, r10 - 538 07 03 00 00 10 00 00 00 add64 r3, 0x10 + 538 07 03 00 00 50 00 00 00 add64 r3, 0x50 540 bf a2 00 00 00 00 00 00 mov64 r2, r10 - 548 07 02 00 00 68 00 00 00 add64 r2, 0x68 + 548 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 550 bf a4 00 00 00 00 00 00 mov64 r4, r10 - 558 07 04 00 00 48 00 00 00 add64 r4, 0x48 + 558 07 04 00 00 88 00 00 00 add64 r4, 0x88 560 bf 18 00 00 00 00 00 00 mov64 r8, r1 568 bf 31 00 00 00 00 00 00 mov64 r1, r3 570 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 @@ -346,13 +346,13 @@ Disassembly of section .text 778 9c 12 00 00 00 00 00 00 ldxdw r2, [r1 + 0x0] 780 55 03 57 ff 00 00 00 00 jne r3, 0x0, -0xa9 788 05 00 57 ff 00 00 00 00 ja -0xa9 - 790 55 05 59 00 02 00 00 00 jne r5, 0x2, +0x59 - 798 55 03 e5 00 03 00 00 00 jne r3, 0x3, +0xe5 - 7a0 a5 04 e6 00 02 00 00 00 jlt r4, 0x2, +0xe6 + 790 55 05 1c 01 02 00 00 00 jne r5, 0x2, +0x11c + 798 55 03 a8 01 03 00 00 00 jne r3, 0x3, +0x1a8 + 7a0 a5 04 a9 01 02 00 00 00 jlt r4, 0x2, +0x1a9 7a8 9c 13 58 00 00 00 00 00 ldxdw r3, [r1 + 0x58] - 7b0 55 03 e6 00 00 00 00 00 jne r3, 0x0, +0xe6 + 7b0 55 03 a9 01 00 00 00 00 jne r3, 0x0, +0x1a9 7b8 2c 13 68 28 00 00 00 00 ldxb w3, [r1 + 0x2868] - 7c0 55 03 e6 00 ff 00 00 00 jne r3, 0xff, +0xe6 + 7c0 55 03 a9 01 ff 00 00 00 jne r3, 0xff, +0x1a9 7c8 b7 00 00 00 0f 00 00 00 mov64 r0, 0xf 7d0 9c 14 c0 28 00 00 00 00 ldxdw r4, [r1 + 0x28c0] 7d8 15 04 db ff 00 00 00 00 jeq r4, 0x0, -0x25 @@ -372,230 +372,429 @@ Disassembly of section .text 848 05 00 cd ff 00 00 00 00 ja -0x33 850 b7 00 00 00 0d 00 00 00 mov64 r0, 0xd 858 05 00 cb ff 00 00 00 00 ja -0x35 - 860 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 - 868 9c 45 10 00 00 00 00 00 ldxdw r5, [r4 + 0x10] - 870 15 05 1d 00 00 00 00 00 jeq r5, 0x0, +0x1d - 878 bf 52 00 00 00 00 00 00 mov64 r2, r5 - 880 9c 25 08 00 00 00 00 00 ldxdw r5, [r2 + 0x8] - 888 55 05 fd ff 00 00 00 00 jne r5, 0x0, -0x3 - 890 8c 25 18 00 00 00 00 00 ldxw w5, [r2 + 0x18] - 898 8f 54 18 00 00 00 00 00 stxw [r4 + 0x18], w5 - 8a0 05 00 01 00 00 00 00 00 ja +0x1 - 8a8 bf 42 00 00 00 00 00 00 mov64 r2, r4 - 8b0 9c 25 00 00 00 00 00 00 ldxdw r5, [r2 + 0x0] - 8b8 bf 24 00 00 00 00 00 00 mov64 r4, r2 - 8c0 07 04 00 00 08 00 00 00 add64 r4, 0x8 - 8c8 9c 20 10 00 00 00 00 00 ldxdw r0, [r2 + 0x10] - 8d0 15 00 07 00 00 00 00 00 jeq r0, 0x0, +0x7 - 8d8 9f 50 00 00 00 00 00 00 stxdw [r0 + 0x0], r5 - 8e0 27 00 1c 00 00 00 00 00 stb [r0 + 0x1c], 0x0 - 8e8 15 05 1a 00 00 00 00 00 jeq r5, 0x0, +0x1a - 8f0 9c 53 10 00 00 00 00 00 ldxdw r3, [r5 + 0x10] - 8f8 1d 32 16 00 00 00 00 00 jeq r2, r3, +0x16 - 900 07 05 00 00 08 00 00 00 add64 r5, 0x8 - 908 05 00 15 00 00 00 00 00 ja +0x15 - 910 15 05 c4 00 00 00 00 00 jeq r5, 0x0, +0xc4 - 918 2c 23 1c 00 00 00 00 00 ldxb w3, [r2 + 0x1c] - 920 55 03 14 00 01 00 00 00 jne r3, 0x1, +0x14 - 928 9c 50 10 00 00 00 00 00 ldxdw r0, [r5 + 0x10] - 930 b7 03 00 00 10 00 00 00 mov64 r3, 0x10 - 938 1d 02 01 00 00 00 00 00 jeq r2, r0, +0x1 - 940 b7 03 00 00 08 00 00 00 mov64 r3, 0x8 - 948 0f 35 00 00 00 00 00 00 add64 r5, r3 - 950 97 05 00 00 00 00 00 00 stdw [r5 + 0x0], 0x0 - 958 05 00 0d 00 00 00 00 00 ja +0xd - 960 bf 45 00 00 00 00 00 00 mov64 r5, r4 - 968 07 05 00 00 08 00 00 00 add64 r5, 0x8 - 970 9c 40 00 00 00 00 00 00 ldxdw r0, [r4 + 0x0] - 978 9f 02 00 00 00 00 00 00 stxdw [r2 + 0x0], r0 - 980 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 - 988 15 00 10 00 00 00 00 00 jeq r0, 0x0, +0x10 - 990 9c 03 10 00 00 00 00 00 ldxdw r3, [r0 + 0x10] - 998 1d 34 0c 00 00 00 00 00 jeq r4, r3, +0xc - 9a0 07 00 00 00 08 00 00 00 add64 r0, 0x8 - 9a8 05 00 0b 00 00 00 00 00 ja +0xb - 9b0 07 05 00 00 10 00 00 00 add64 r5, 0x10 - 9b8 bf 53 00 00 00 00 00 00 mov64 r3, r5 - 9c0 9f 03 00 00 00 00 00 00 stxdw [r3 + 0x0], r0 - 9c8 97 04 08 00 00 00 00 00 stdw [r4 + 0x8], 0x0 - 9d0 97 04 00 00 00 00 00 00 stdw [r4 + 0x0], 0x0 - 9d8 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] - 9e0 9f 32 00 00 00 00 00 00 stxdw [r2 + 0x0], r3 - 9e8 9f 21 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r2 - 9f0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - 9f8 05 00 97 ff 00 00 00 00 ja -0x69 - a00 07 00 00 00 10 00 00 00 add64 r0, 0x10 - a08 bf 03 00 00 00 00 00 00 mov64 r3, r0 - a10 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 - a18 97 05 08 00 00 00 00 00 stdw [r5 + 0x8], 0x0 - a20 97 05 00 00 00 00 00 00 stdw [r5 + 0x0], 0x0 - a28 9c 12 c8 28 00 00 00 00 ldxdw r2, [r1 + 0x28c8] - a30 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 - a38 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 - a40 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - a48 05 00 8d ff 00 00 00 00 ja -0x73 - a50 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe - a58 05 00 8b ff 00 00 00 00 ja -0x75 - a60 bf 18 00 00 00 00 00 00 mov64 r8, r1 - a68 55 05 9f 00 00 00 00 00 jne r5, 0x0, +0x9f - a70 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a - a78 55 04 8b 00 04 00 00 00 jne r4, 0x4, +0x8b - a80 9c 81 58 00 00 00 00 00 ldxdw r1, [r8 + 0x58] - a88 55 01 8b 00 00 00 00 00 jne r1, 0x0, +0x8b - a90 2c 81 68 28 00 00 00 00 ldxb w1, [r8 + 0x2868] - a98 55 01 8b 00 ff 00 00 00 jne r1, 0xff, +0x8b - aa0 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] - aa8 55 01 95 00 00 00 00 00 jne r1, 0x0, +0x95 - ab0 2c 81 c8 50 00 00 00 00 ldxb w1, [r8 + 0x50c8] - ab8 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 - ac0 9c 81 18 51 00 00 00 00 ldxdw r1, [r8 + 0x5118] - ac8 55 01 89 00 0e 00 00 00 jne r1, 0xe, +0x89 - ad0 2c 81 38 79 00 00 00 00 ldxb w1, [r8 + 0x7938] - ad8 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 - ae0 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 - ae8 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 - af0 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 - af8 9c 82 40 79 00 00 00 00 ldxdw r2, [r8 + 0x7940] - b00 5d 12 76 ff 00 00 00 00 jne r2, r1, -0x8a - b08 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 - b10 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d - b18 9c 82 48 79 00 00 00 00 ldxdw r2, [r8 + 0x7948] - b20 5d 12 72 ff 00 00 00 00 jne r2, r1, -0x8e - b28 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 - b30 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b - b38 9c 82 50 79 00 00 00 00 ldxdw r2, [r8 + 0x7950] - b40 5d 12 6e ff 00 00 00 00 jne r2, r1, -0x92 - b48 bf 87 00 00 00 00 00 00 mov64 r7, r8 - b50 9c 71 58 79 00 00 00 00 ldxdw r1, [r7 + 0x7958] - b58 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d - b60 5d 21 6a ff 00 00 00 00 jne r1, r2, -0x96 - b68 bf 76 00 00 00 00 00 00 mov64 r6, r7 - b70 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 - b78 bf a4 00 00 00 00 00 00 mov64 r4, r10 - b80 07 04 00 00 68 00 00 00 add64 r4, 0x68 - b88 bf a5 00 00 00 00 00 00 mov64 r5, r10 - b90 07 05 00 00 0f 00 00 00 add64 r5, 0xf - b98 bf 71 00 00 00 00 00 00 mov64 r1, r7 - ba0 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 - ba8 bf 63 00 00 00 00 00 00 mov64 r3, r6 - bb0 95 00 00 00 38 4a 50 48 syscall 0x48504a38 - bb8 9c a1 68 00 00 00 00 00 ldxdw r1, [r10 + 0x68] - bc0 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] - bc8 5d 21 6f 00 00 00 00 00 jne r1, r2, +0x6f - bd0 9c a1 70 00 00 00 00 00 ldxdw r1, [r10 + 0x70] - bd8 9c 82 78 28 00 00 00 00 ldxdw r2, [r8 + 0x2878] - be0 5d 21 6c 00 00 00 00 00 jne r1, r2, +0x6c - be8 9c a1 78 00 00 00 00 00 ldxdw r1, [r10 + 0x78] - bf0 9c 82 80 28 00 00 00 00 ldxdw r2, [r8 + 0x2880] - bf8 5d 21 69 00 00 00 00 00 jne r1, r2, +0x69 - c00 9c a1 80 00 00 00 00 00 ldxdw r1, [r10 + 0x80] - c08 9c 82 88 28 00 00 00 00 ldxdw r2, [r8 + 0x2888] - c10 5d 21 66 00 00 00 00 00 jne r1, r2, +0x66 - c18 bf 81 00 00 00 00 00 00 mov64 r1, r8 - c20 07 01 00 00 70 28 00 00 add64 r1, 0x2870 - c28 9c 82 90 79 00 00 00 00 ldxdw r2, [r8 + 0x7990] - c30 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] - c38 9f 3a 3c 00 00 00 00 00 stxdw [r10 + 0x3c], r3 - c40 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] - c48 9f 3a 34 00 00 00 00 00 stxdw [r10 + 0x34], r3 - c50 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] - c58 9f 3a 2c 00 00 00 00 00 stxdw [r10 + 0x2c], r3 - c60 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] - c68 9f 3a 24 00 00 00 00 00 stxdw [r10 + 0x24], r3 - c70 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 - c78 9f 2a 14 00 00 00 00 00 stxdw [r10 + 0x14], r2 - c80 97 0a 1c 00 18 00 00 00 stdw [r10 + 0x1c], 0x18 - c88 87 0a 10 00 00 00 00 00 stw [r10 + 0x10], 0x0 - c90 9f 1a 58 00 00 00 00 00 stxdw [r10 + 0x58], r1 - c98 bf 82 00 00 00 00 00 00 mov64 r2, r8 - ca0 07 02 00 00 10 00 00 00 add64 r2, 0x10 - ca8 9f 2a 48 00 00 00 00 00 stxdw [r10 + 0x48], r2 - cb0 37 0a 60 00 01 01 00 00 sth [r10 + 0x60], 0x101 - cb8 37 0a 50 00 01 01 00 00 sth [r10 + 0x50], 0x101 - cc0 bf 83 00 00 00 00 00 00 mov64 r3, r8 - cc8 07 03 00 00 90 28 00 00 add64 r3, 0x2890 - cd0 9f 3a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r3 - cd8 bf 83 00 00 00 00 00 00 mov64 r3, r8 - ce0 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 - ce8 9f 3a b8 00 00 00 00 00 stxdw [r10 + 0xb8], r3 - cf0 bf 83 00 00 00 00 00 00 mov64 r3, r8 - cf8 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 - d00 9f 3a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r3 - d08 9f 1a a0 00 00 00 00 00 stxdw [r10 + 0xa0], r1 - d10 bf 81 00 00 00 00 00 00 mov64 r1, r8 - d18 07 01 00 00 30 00 00 00 add64 r1, 0x30 - d20 9f 1a 88 00 00 00 00 00 stxdw [r10 + 0x88], r1 - d28 bf 81 00 00 00 00 00 00 mov64 r1, r8 - d30 07 01 00 00 60 00 00 00 add64 r1, 0x60 - d38 9f 1a 80 00 00 00 00 00 stxdw [r10 + 0x80], r1 - d40 bf 81 00 00 00 00 00 00 mov64 r1, r8 - d48 07 01 00 00 50 00 00 00 add64 r1, 0x50 - d50 9f 1a 70 00 00 00 00 00 stxdw [r10 + 0x70], r1 - d58 9f 2a 68 00 00 00 00 00 stxdw [r10 + 0x68], r2 - d60 27 0a d2 00 00 00 00 00 stb [r10 + 0xd2], 0x0 - d68 37 0a d0 00 01 01 00 00 sth [r10 + 0xd0], 0x101 - d70 97 0a c8 00 00 00 00 00 stdw [r10 + 0xc8], 0x0 - d78 97 0a b0 00 00 00 00 00 stdw [r10 + 0xb0], 0x0 - d80 27 0a 9a 00 00 00 00 00 stb [r10 + 0x9a], 0x0 - d88 37 0a 98 00 01 01 00 00 sth [r10 + 0x98], 0x101 - d90 97 0a 90 00 00 00 00 00 stdw [r10 + 0x90], 0x0 - d98 97 0a 78 00 00 00 00 00 stdw [r10 + 0x78], 0x0 - da0 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 - da8 97 0a e8 00 00 00 00 00 stdw [r10 + 0xe8], 0x0 - db0 97 0a e0 00 00 00 00 00 stdw [r10 + 0xe0], 0x0 - db8 97 0a d8 00 00 00 00 00 stdw [r10 + 0xd8], 0x0 - dc0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - dc8 07 01 00 00 10 00 00 00 add64 r1, 0x10 - dd0 9f 1a 10 01 00 00 00 00 stxdw [r10 + 0x110], r1 - dd8 bf a1 00 00 00 00 00 00 mov64 r1, r10 - de0 07 01 00 00 48 00 00 00 add64 r1, 0x48 - de8 9f 1a 00 01 00 00 00 00 stxdw [r10 + 0x100], r1 - df0 bf a1 00 00 00 00 00 00 mov64 r1, r10 - df8 07 01 00 00 d8 00 00 00 add64 r1, 0xd8 - e00 9f 1a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r1 - e08 97 0a 18 01 34 00 00 00 stdw [r10 + 0x118], 0x34 - e10 97 0a 08 01 02 00 00 00 stdw [r10 + 0x108], 0x2 - e18 bf a1 00 00 00 00 00 00 mov64 r1, r10 - e20 07 01 00 00 0f 00 00 00 add64 r1, 0xf - e28 9f 1a 20 01 00 00 00 00 stxdw [r10 + 0x120], r1 - e30 97 0a 28 01 01 00 00 00 stdw [r10 + 0x128], 0x1 - e38 bf a1 00 00 00 00 00 00 mov64 r1, r10 - e40 07 01 00 00 20 01 00 00 add64 r1, 0x120 - e48 9f 1a 30 01 00 00 00 00 stxdw [r10 + 0x130], r1 - e50 97 0a 38 01 01 00 00 00 stdw [r10 + 0x138], 0x1 - e58 bf a1 00 00 00 00 00 00 mov64 r1, r10 - e60 07 01 00 00 f8 00 00 00 add64 r1, 0xf8 - e68 bf a2 00 00 00 00 00 00 mov64 r2, r10 - e70 07 02 00 00 68 00 00 00 add64 r2, 0x68 - e78 bf a4 00 00 00 00 00 00 mov64 r4, r10 - e80 07 04 00 00 30 01 00 00 add64 r4, 0x130 - e88 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 - e90 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 - e98 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b - ea0 bf 81 00 00 00 00 00 00 mov64 r1, r8 - ea8 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 - eb0 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 - eb8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 - ec0 05 00 fe fe 00 00 00 00 ja -0x102 - ec8 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc - ed0 05 00 fc fe 00 00 00 00 ja -0x104 - ed8 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 - ee0 05 00 fa fe 00 00 00 00 ja -0x106 - ee8 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 - ef0 05 00 f8 fe 00 00 00 00 ja -0x108 - ef8 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 - f00 05 00 f6 fe 00 00 00 00 ja -0x10a - f08 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 - f10 05 00 f4 fe 00 00 00 00 ja -0x10c - f18 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 - f20 05 00 f2 fe 00 00 00 00 ja -0x10e - f28 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 - f30 05 00 f0 fe 00 00 00 00 ja -0x110 - f38 97 01 c0 28 00 00 00 00 stdw [r1 + 0x28c0], 0x0 - f40 05 00 50 ff 00 00 00 00 ja -0xb0 - f48 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa - f50 05 00 ec fe 00 00 00 00 ja -0x114 - f58 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 - f60 05 00 ea fe 00 00 00 00 ja -0x116 - f68 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb - f70 05 00 e8 fe 00 00 00 00 ja -0x118 \ No newline at end of file + 860 9f 1a 40 00 00 00 00 00 stxdw [r10 + 0x40], r1 + 868 15 02 08 00 00 00 00 00 jeq r2, 0x0, +0x8 + 870 9c 41 10 00 00 00 00 00 ldxdw r1, [r4 + 0x10] + 878 15 01 1e 00 00 00 00 00 jeq r1, 0x0, +0x1e + 880 bf 12 00 00 00 00 00 00 mov64 r2, r1 + 888 9c 21 08 00 00 00 00 00 ldxdw r1, [r2 + 0x8] + 890 55 01 fd ff 00 00 00 00 jne r1, 0x0, -0x3 + 898 8c 21 18 00 00 00 00 00 ldxw w1, [r2 + 0x18] + 8a0 8f 14 18 00 00 00 00 00 stxw [r4 + 0x18], w1 + 8a8 05 00 01 00 00 00 00 00 ja +0x1 + 8b0 bf 42 00 00 00 00 00 00 mov64 r2, r4 + 8b8 9c 26 00 00 00 00 00 00 ldxdw r6, [r2 + 0x0] + 8c0 bf 21 00 00 00 00 00 00 mov64 r1, r2 + 8c8 07 01 00 00 08 00 00 00 add64 r1, 0x8 + 8d0 9f 1a 38 00 00 00 00 00 stxdw [r10 + 0x38], r1 + 8d8 9c 21 10 00 00 00 00 00 ldxdw r1, [r2 + 0x10] + 8e0 15 01 07 00 00 00 00 00 jeq r1, 0x0, +0x7 + 8e8 9f 61 00 00 00 00 00 00 stxdw [r1 + 0x0], r6 + 8f0 27 01 1c 00 00 00 00 00 stb [r1 + 0x1c], 0x0 + 8f8 15 06 4c 00 00 00 00 00 jeq r6, 0x0, +0x4c + 900 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 908 1d 32 48 00 00 00 00 00 jeq r2, r3, +0x48 + 910 07 06 00 00 08 00 00 00 add64 r6, 0x8 + 918 05 00 47 00 00 00 00 00 ja +0x47 + 920 15 06 85 01 00 00 00 00 jeq r6, 0x0, +0x185 + 928 9c 61 10 00 00 00 00 00 ldxdw r1, [r6 + 0x10] + 930 2c 24 1c 00 00 00 00 00 ldxb w4, [r2 + 0x1c] + 938 55 04 10 00 01 00 00 00 jne r4, 0x1, +0x10 + 940 b7 03 00 00 10 00 00 00 mov64 r3, 0x10 + 948 1d 12 01 00 00 00 00 00 jeq r2, r1, +0x1 + 950 b7 03 00 00 08 00 00 00 mov64 r3, 0x8 + 958 0f 36 00 00 00 00 00 00 add64 r6, r3 + 960 97 06 00 00 00 00 00 00 stdw [r6 + 0x0], 0x0 + 968 05 00 d8 00 00 00 00 00 ja +0xd8 + 970 bf 41 00 00 00 00 00 00 mov64 r1, r4 + 978 07 01 00 00 08 00 00 00 add64 r1, 0x8 + 980 9c 45 00 00 00 00 00 00 ldxdw r5, [r4 + 0x0] + 988 9f 52 00 00 00 00 00 00 stxdw [r2 + 0x0], r5 + 990 27 02 1c 00 00 00 00 00 stb [r2 + 0x1c], 0x0 + 998 15 05 64 00 00 00 00 00 jeq r5, 0x0, +0x64 + 9a0 9c 53 10 00 00 00 00 00 ldxdw r3, [r5 + 0x10] + 9a8 1d 34 60 00 00 00 00 00 jeq r4, r3, +0x60 + 9b0 07 05 00 00 08 00 00 00 add64 r5, 0x8 + 9b8 05 00 5f 00 00 00 00 00 ja +0x5f + 9c0 b4 04 00 00 01 00 00 00 mov32 w4, 0x1 + 9c8 9f 4a 30 00 00 00 00 00 stxdw [r10 + 0x30], r4 + 9d0 1d 12 02 00 00 00 00 00 jeq r2, r1, +0x2 + 9d8 b4 01 00 00 00 00 00 00 mov32 w1, 0x0 + 9e0 9f 1a 30 00 00 00 00 00 stxdw [r10 + 0x30], r1 + 9e8 bf 61 00 00 00 00 00 00 mov64 r1, r6 + 9f0 07 01 00 00 08 00 00 00 add64 r1, 0x8 + 9f8 9c a7 30 00 00 00 00 00 ldxdw r7, [r10 + 0x30] + a00 bf 75 00 00 00 00 00 00 mov64 r5, r7 + a08 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + a10 bf 14 00 00 00 00 00 00 mov64 r4, r1 + a18 0f 54 00 00 00 00 00 00 add64 r4, r5 + a20 97 04 00 00 00 00 00 00 stdw [r4 + 0x0], 0x0 + a28 a7 07 00 00 01 00 00 00 xor64 r7, 0x1 + a30 bf 74 00 00 00 00 00 00 mov64 r4, r7 + a38 67 04 00 00 03 00 00 00 lsh64 r4, 0x3 + a40 0f 41 00 00 00 00 00 00 add64 r1, r4 + a48 9c 18 00 00 00 00 00 00 ldxdw r8, [r1 + 0x0] + a50 bf 89 00 00 00 00 00 00 mov64 r9, r8 + a58 07 09 00 00 1c 00 00 00 add64 r9, 0x1c + a60 bf 80 00 00 00 00 00 00 mov64 r0, r8 + a68 07 00 00 00 08 00 00 00 add64 r0, 0x8 + a70 bf 01 00 00 00 00 00 00 mov64 r1, r0 + a78 0f 51 00 00 00 00 00 00 add64 r1, r5 + a80 9c 11 00 00 00 00 00 00 ldxdw r1, [r1 + 0x0] + a88 2c 85 1c 00 00 00 00 00 ldxb w5, [r8 + 0x1c] + a90 15 05 1b 00 00 00 00 00 jeq r5, 0x0, +0x1b + a98 bf 64 00 00 00 00 00 00 mov64 r4, r6 + aa0 bf 75 00 00 00 00 00 00 mov64 r5, r7 + aa8 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + ab0 bf 46 00 00 00 00 00 00 mov64 r6, r4 + ab8 0f 56 00 00 00 00 00 00 add64 r6, r5 + ac0 9c 40 00 00 00 00 00 00 ldxdw r0, [r4 + 0x0] + ac8 9f 16 08 00 00 00 00 00 stxdw [r6 + 0x8], r1 + ad0 9c a5 30 00 00 00 00 00 ldxdw r5, [r10 + 0x30] + ad8 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + ae0 bf 86 00 00 00 00 00 00 mov64 r6, r8 + ae8 0f 56 00 00 00 00 00 00 add64 r6, r5 + af0 07 06 00 00 08 00 00 00 add64 r6, 0x8 + af8 15 01 01 00 00 00 00 00 jeq r1, 0x0, +0x1 + b00 9f 41 00 00 00 00 00 00 stxdw [r1 + 0x0], r4 + b08 9f 46 00 00 00 00 00 00 stxdw [r6 + 0x0], r4 + b10 9f 08 00 00 00 00 00 00 stxdw [r8 + 0x0], r0 + b18 9f 84 00 00 00 00 00 00 stxdw [r4 + 0x0], r8 + b20 bf 36 00 00 00 00 00 00 mov64 r6, r3 + b28 15 00 3f 00 00 00 00 00 jeq r0, 0x0, +0x3f + b30 9c 05 10 00 00 00 00 00 ldxdw r5, [r0 + 0x10] + b38 1d 45 3b 00 00 00 00 00 jeq r5, r4, +0x3b + b40 07 00 00 00 08 00 00 00 add64 r0, 0x8 + b48 05 00 3a 00 00 00 00 00 ja +0x3a + b50 07 06 00 00 10 00 00 00 add64 r6, 0x10 + b58 bf 63 00 00 00 00 00 00 mov64 r3, r6 + b60 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + b68 05 00 98 00 00 00 00 00 ja +0x98 + b70 0f 40 00 00 00 00 00 00 add64 r0, r4 + b78 05 00 15 00 00 00 00 00 ja +0x15 + b80 bf 97 00 00 00 00 00 00 mov64 r7, r9 + b88 a7 07 00 00 01 00 00 00 xor64 r7, 0x1 + b90 bf 71 00 00 00 00 00 00 mov64 r1, r7 + b98 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + ba0 bf 45 00 00 00 00 00 00 mov64 r5, r4 + ba8 0f 15 00 00 00 00 00 00 add64 r5, r1 + bb0 9c 58 08 00 00 00 00 00 ldxdw r8, [r5 + 0x8] + bb8 bf 85 00 00 00 00 00 00 mov64 r5, r8 + bc0 07 05 00 00 08 00 00 00 add64 r5, 0x8 + bc8 bf 50 00 00 00 00 00 00 mov64 r0, r5 + bd0 0f 10 00 00 00 00 00 00 add64 r0, r1 + bd8 9f 9a 30 00 00 00 00 00 stxdw [r10 + 0x30], r9 + be0 bf 91 00 00 00 00 00 00 mov64 r1, r9 + be8 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + bf0 0f 15 00 00 00 00 00 00 add64 r5, r1 + bf8 bf 89 00 00 00 00 00 00 mov64 r9, r8 + c00 07 09 00 00 1c 00 00 00 add64 r9, 0x1c + c08 9c 51 00 00 00 00 00 00 ldxdw r1, [r5 + 0x0] + c10 2c 85 1c 00 00 00 00 00 ldxb w5, [r8 + 0x1c] + c18 bf 46 00 00 00 00 00 00 mov64 r6, r4 + c20 55 05 cf ff 00 00 00 00 jne r5, 0x0, -0x31 + c28 9c 04 00 00 00 00 00 00 ldxdw r4, [r0 + 0x0] + c30 15 04 02 00 00 00 00 00 jeq r4, 0x0, +0x2 + c38 2c 45 1c 00 00 00 00 00 ldxb w5, [r4 + 0x1c] + c40 55 05 3d 00 00 00 00 00 jne r5, 0x0, +0x3d + c48 15 01 02 00 00 00 00 00 jeq r1, 0x0, +0x2 + c50 2c 14 1c 00 00 00 00 00 ldxb w4, [r1 + 0x1c] + c58 55 04 3c 00 00 00 00 00 jne r4, 0x0, +0x3c + c60 2c 61 1c 00 00 00 00 00 ldxb w1, [r6 + 0x1c] + c68 27 09 00 00 01 00 00 00 stb [r9 + 0x0], 0x1 + c70 15 01 34 00 01 00 00 00 jeq r1, 0x1, +0x34 + c78 9c 64 00 00 00 00 00 00 ldxdw r4, [r6 + 0x0] + c80 15 04 75 00 00 00 00 00 jeq r4, 0x0, +0x75 + c88 9c 41 10 00 00 00 00 00 ldxdw r1, [r4 + 0x10] + c90 b4 09 00 00 01 00 00 00 mov32 w9, 0x1 + c98 1d 16 dc ff 00 00 00 00 jeq r6, r1, -0x24 + ca0 b4 09 00 00 00 00 00 00 mov32 w9, 0x0 + ca8 05 00 da ff 00 00 00 00 ja -0x26 + cb0 07 05 00 00 10 00 00 00 add64 r5, 0x10 + cb8 bf 53 00 00 00 00 00 00 mov64 r3, r5 + cc0 9f 23 00 00 00 00 00 00 stxdw [r3 + 0x0], r2 + cc8 97 01 08 00 00 00 00 00 stdw [r1 + 0x8], 0x0 + cd0 97 01 00 00 00 00 00 00 stdw [r1 + 0x0], 0x0 + cd8 9c a1 40 00 00 00 00 00 ldxdw r1, [r10 + 0x40] + ce0 9c 12 c8 28 00 00 00 00 ldxdw r2, [r1 + 0x28c8] + ce8 9f 24 00 00 00 00 00 00 stxdw [r4 + 0x0], r2 + cf0 9f 41 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r4 + cf8 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + d00 05 00 36 ff 00 00 00 00 ja -0xca + d08 b7 00 00 00 0e 00 00 00 mov64 r0, 0xe + d10 05 00 34 ff 00 00 00 00 ja -0xcc + d18 07 00 00 00 10 00 00 00 add64 r0, 0x10 + d20 bf 06 00 00 00 00 00 00 mov64 r6, r0 + d28 9f 86 00 00 00 00 00 00 stxdw [r6 + 0x0], r8 + d30 27 04 1c 00 01 00 00 00 stb [r4 + 0x1c], 0x1 + d38 27 09 00 00 00 00 00 00 stb [r9 + 0x0], 0x0 + d40 bf 75 00 00 00 00 00 00 mov64 r5, r7 + d48 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + d50 bf 10 00 00 00 00 00 00 mov64 r0, r1 + d58 07 00 00 00 08 00 00 00 add64 r0, 0x8 + d60 bf 06 00 00 00 00 00 00 mov64 r6, r0 + d68 0f 56 00 00 00 00 00 00 add64 r6, r5 + d70 9c 68 00 00 00 00 00 00 ldxdw r8, [r6 + 0x0] + d78 15 08 06 00 00 00 00 00 jeq r8, 0x0, +0x6 + d80 2c 85 1c 00 00 00 00 00 ldxb w5, [r8 + 0x1c] + d88 15 05 04 00 00 00 00 00 jeq r5, 0x0, +0x4 + d90 bf 46 00 00 00 00 00 00 mov64 r6, r4 + d98 bf 19 00 00 00 00 00 00 mov64 r9, r1 + da0 bf 84 00 00 00 00 00 00 mov64 r4, r8 + da8 05 00 2f 00 00 00 00 00 ja +0x2f + db0 9c a5 30 00 00 00 00 00 ldxdw r5, [r10 + 0x30] + db8 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + dc0 0f 50 00 00 00 00 00 00 add64 r0, r5 + dc8 9c 09 00 00 00 00 00 00 ldxdw r9, [r0 + 0x0] + dd0 15 09 05 00 00 00 00 00 jeq r9, 0x0, +0x5 + dd8 2c 95 1c 00 00 00 00 00 ldxb w5, [r9 + 0x1c] + de0 15 05 03 00 00 00 00 00 jeq r5, 0x0, +0x3 + de8 bf 46 00 00 00 00 00 00 mov64 r6, r4 + df0 bf 14 00 00 00 00 00 00 mov64 r4, r1 + df8 05 00 0a 00 00 00 00 00 ja +0xa + e00 07 04 00 00 1c 00 00 00 add64 r4, 0x1c + e08 27 01 1c 00 01 00 00 00 stb [r1 + 0x1c], 0x1 + e10 05 00 42 00 00 00 00 00 ja +0x42 + e18 07 06 00 00 1c 00 00 00 add64 r6, 0x1c + e20 bf 64 00 00 00 00 00 00 mov64 r4, r6 + e28 05 00 3f 00 00 00 00 00 ja +0x3f + e30 bf 89 00 00 00 00 00 00 mov64 r9, r8 + e38 05 00 1d 00 00 00 00 00 ja +0x1d + e40 bf 19 00 00 00 00 00 00 mov64 r9, r1 + e48 bf 84 00 00 00 00 00 00 mov64 r4, r8 + e50 67 07 00 00 03 00 00 00 lsh64 r7, 0x3 + e58 bf 90 00 00 00 00 00 00 mov64 r0, r9 + e60 0f 70 00 00 00 00 00 00 add64 r0, r7 + e68 9c a1 30 00 00 00 00 00 ldxdw r1, [r10 + 0x30] + e70 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + e78 bf 45 00 00 00 00 00 00 mov64 r5, r4 + e80 0f 15 00 00 00 00 00 00 add64 r5, r1 + e88 9c 41 00 00 00 00 00 00 ldxdw r1, [r4 + 0x0] + e90 9c 07 08 00 00 00 00 00 ldxdw r7, [r0 + 0x8] + e98 9f 75 08 00 00 00 00 00 stxdw [r5 + 0x8], r7 + ea0 07 00 00 00 08 00 00 00 add64 r0, 0x8 + ea8 15 07 01 00 00 00 00 00 jeq r7, 0x0, +0x1 + eb0 9f 47 00 00 00 00 00 00 stxdw [r7 + 0x0], r4 + eb8 9f 40 00 00 00 00 00 00 stxdw [r0 + 0x0], r4 + ec0 9f 19 00 00 00 00 00 00 stxdw [r9 + 0x0], r1 + ec8 9f 94 00 00 00 00 00 00 stxdw [r4 + 0x0], r9 + ed0 bf 30 00 00 00 00 00 00 mov64 r0, r3 + ed8 15 01 06 00 00 00 00 00 jeq r1, 0x0, +0x6 + ee0 9c 15 10 00 00 00 00 00 ldxdw r5, [r1 + 0x10] + ee8 1d 45 02 00 00 00 00 00 jeq r5, r4, +0x2 + ef0 07 01 00 00 08 00 00 00 add64 r1, 0x8 + ef8 05 00 01 00 00 00 00 00 ja +0x1 + f00 07 01 00 00 10 00 00 00 add64 r1, 0x10 + f08 bf 10 00 00 00 00 00 00 mov64 r0, r1 + f10 9f 90 00 00 00 00 00 00 stxdw [r0 + 0x0], r9 + f18 27 04 1c 00 01 00 00 00 stb [r4 + 0x1c], 0x1 + f20 27 09 1c 00 00 00 00 00 stb [r9 + 0x1c], 0x0 + f28 9c a5 30 00 00 00 00 00 ldxdw r5, [r10 + 0x30] + f30 bf 51 00 00 00 00 00 00 mov64 r1, r5 + f38 a7 01 00 00 01 00 00 00 xor64 r1, 0x1 + f40 67 01 00 00 03 00 00 00 lsh64 r1, 0x3 + f48 bf 68 00 00 00 00 00 00 mov64 r8, r6 + f50 0f 18 00 00 00 00 00 00 add64 r8, r1 + f58 67 05 00 00 03 00 00 00 lsh64 r5, 0x3 + f60 9c 81 08 00 00 00 00 00 ldxdw r1, [r8 + 0x8] + f68 bf 10 00 00 00 00 00 00 mov64 r0, r1 + f70 0f 50 00 00 00 00 00 00 add64 r0, r5 + f78 9c 65 00 00 00 00 00 00 ldxdw r5, [r6 + 0x0] + f80 9c 07 08 00 00 00 00 00 ldxdw r7, [r0 + 0x8] + f88 9f 78 08 00 00 00 00 00 stxdw [r8 + 0x8], r7 + f90 07 00 00 00 08 00 00 00 add64 r0, 0x8 + f98 15 07 01 00 00 00 00 00 jeq r7, 0x0, +0x1 + fa0 9f 67 00 00 00 00 00 00 stxdw [r7 + 0x0], r6 + fa8 9f 60 00 00 00 00 00 00 stxdw [r0 + 0x0], r6 + fb0 9f 51 00 00 00 00 00 00 stxdw [r1 + 0x0], r5 + fb8 9f 16 00 00 00 00 00 00 stxdw [r6 + 0x0], r1 + fc0 15 05 06 00 00 00 00 00 jeq r5, 0x0, +0x6 + fc8 9c 53 10 00 00 00 00 00 ldxdw r3, [r5 + 0x10] + fd0 1d 63 02 00 00 00 00 00 jeq r3, r6, +0x2 + fd8 07 05 00 00 08 00 00 00 add64 r5, 0x8 + fe0 05 00 01 00 00 00 00 00 ja +0x1 + fe8 07 05 00 00 10 00 00 00 add64 r5, 0x10 + ff0 bf 53 00 00 00 00 00 00 mov64 r3, r5 + ff8 9f 13 00 00 00 00 00 00 stxdw [r3 + 0x0], r1 + 1000 2c 61 1c 00 00 00 00 00 ldxb w1, [r6 + 0x1c] + 1008 54 01 00 00 01 00 00 00 and32 w1, 0x1 + 1010 2f 19 1c 00 00 00 00 00 stxb [r9 + 0x1c], w1 + 1018 27 06 1c 00 00 00 00 00 stb [r6 + 0x1c], 0x0 + 1020 07 04 00 00 1c 00 00 00 add64 r4, 0x1c + 1028 27 04 00 00 00 00 00 00 stb [r4 + 0x0], 0x0 + 1030 9c a1 38 00 00 00 00 00 ldxdw r1, [r10 + 0x38] + 1038 97 01 08 00 00 00 00 00 stdw [r1 + 0x8], 0x0 + 1040 97 01 00 00 00 00 00 00 stdw [r1 + 0x0], 0x0 + 1048 9c a1 40 00 00 00 00 00 ldxdw r1, [r10 + 0x40] + 1050 9c 13 c8 28 00 00 00 00 ldxdw r3, [r1 + 0x28c8] + 1058 9f 32 00 00 00 00 00 00 stxdw [r2 + 0x0], r3 + 1060 9f 21 c8 28 00 00 00 00 stxdw [r1 + 0x28c8], r2 + 1068 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 1070 05 00 c8 fe 00 00 00 00 ja -0x138 + 1078 bf 18 00 00 00 00 00 00 mov64 r8, r1 + 1080 55 05 a3 00 00 00 00 00 jne r5, 0x0, +0xa3 + 1088 55 03 8a 00 01 00 00 00 jne r3, 0x1, +0x8a + 1090 55 04 8b 00 04 00 00 00 jne r4, 0x4, +0x8b + 1098 9c 81 58 00 00 00 00 00 ldxdw r1, [r8 + 0x58] + 10a0 55 01 8b 00 00 00 00 00 jne r1, 0x0, +0x8b + 10a8 2c 81 68 28 00 00 00 00 ldxb w1, [r8 + 0x2868] + 10b0 55 01 8b 00 ff 00 00 00 jne r1, 0xff, +0x8b + 10b8 9c 81 b8 28 00 00 00 00 ldxdw r1, [r8 + 0x28b8] + 10c0 55 01 99 00 00 00 00 00 jne r1, 0x0, +0x99 + 10c8 2c 81 c8 50 00 00 00 00 ldxb w1, [r8 + 0x50c8] + 10d0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + 10d8 9c 81 18 51 00 00 00 00 ldxdw r1, [r8 + 0x5118] + 10e0 55 01 89 00 0e 00 00 00 jne r1, 0xe, +0x89 + 10e8 2c 81 38 79 00 00 00 00 ldxb w1, [r8 + 0x7938] + 10f0 55 01 89 00 ff 00 00 00 jne r1, 0xff, +0x89 + 10f8 b7 00 00 00 08 00 00 00 mov64 r0, 0x8 + 1100 b4 01 00 00 06 a7 d5 17 mov32 w1, 0x17d5a706 + 1108 f7 01 00 00 19 2c 5c 51 hor64 r1, 0x515c2c19 + 1110 9c 82 40 79 00 00 00 00 ldxdw r2, [r8 + 0x7940] + 1118 5d 12 b3 fe 00 00 00 00 jne r2, r1, -0x14d + 1120 b4 01 00 00 21 8c c9 4c mov32 w1, 0x4cc98c21 + 1128 f7 01 00 00 3d 4a f1 7f hor64 r1, 0x7ff14a3d + 1130 9c 82 48 79 00 00 00 00 ldxdw r2, [r8 + 0x7948] + 1138 5d 12 af fe 00 00 00 00 jne r2, r1, -0x151 + 1140 b4 01 00 00 58 da ee 08 mov32 w1, 0x8eeda58 + 1148 f7 01 00 00 9b a1 fd 44 hor64 r1, 0x44fda19b + 1150 9c 82 50 79 00 00 00 00 ldxdw r2, [r8 + 0x7950] + 1158 5d 12 ab fe 00 00 00 00 jne r2, r1, -0x155 + 1160 bf 87 00 00 00 00 00 00 mov64 r7, r8 + 1168 9c 71 58 79 00 00 00 00 ldxdw r1, [r7 + 0x7958] + 1170 b4 02 00 00 e3 db d9 8a mov32 w2, -0x7526241d + 1178 5d 21 a7 fe 00 00 00 00 jne r1, r2, -0x159 + 1180 bf 76 00 00 00 00 00 00 mov64 r6, r7 + 1188 07 06 00 00 b9 a1 00 00 add64 r6, 0xa1b9 + 1190 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 1198 07 04 00 00 a8 00 00 00 add64 r4, 0xa8 + 11a0 bf a5 00 00 00 00 00 00 mov64 r5, r10 + 11a8 07 05 00 00 4f 00 00 00 add64 r5, 0x4f + 11b0 bf 71 00 00 00 00 00 00 mov64 r1, r7 + 11b8 b7 02 00 00 00 00 00 00 mov64 r2, 0x0 + 11c0 bf 63 00 00 00 00 00 00 mov64 r3, r6 + 11c8 95 00 00 00 38 4a 50 48 syscall 0x48504a38 + 11d0 9c a1 a8 00 00 00 00 00 ldxdw r1, [r10 + 0xa8] + 11d8 9c 72 70 28 00 00 00 00 ldxdw r2, [r7 + 0x2870] + 11e0 5d 21 73 00 00 00 00 00 jne r1, r2, +0x73 + 11e8 9c a1 b0 00 00 00 00 00 ldxdw r1, [r10 + 0xb0] + 11f0 9c 82 78 28 00 00 00 00 ldxdw r2, [r8 + 0x2878] + 11f8 5d 21 70 00 00 00 00 00 jne r1, r2, +0x70 + 1200 9c a1 b8 00 00 00 00 00 ldxdw r1, [r10 + 0xb8] + 1208 9c 82 80 28 00 00 00 00 ldxdw r2, [r8 + 0x2880] + 1210 5d 21 6d 00 00 00 00 00 jne r1, r2, +0x6d + 1218 9c a1 c0 00 00 00 00 00 ldxdw r1, [r10 + 0xc0] + 1220 9c 82 88 28 00 00 00 00 ldxdw r2, [r8 + 0x2888] + 1228 5d 21 6a 00 00 00 00 00 jne r1, r2, +0x6a + 1230 bf 81 00 00 00 00 00 00 mov64 r1, r8 + 1238 07 01 00 00 70 28 00 00 add64 r1, 0x2870 + 1240 9c 82 90 79 00 00 00 00 ldxdw r2, [r8 + 0x7990] + 1248 9c 63 18 00 00 00 00 00 ldxdw r3, [r6 + 0x18] + 1250 9f 3a 7c 00 00 00 00 00 stxdw [r10 + 0x7c], r3 + 1258 9c 63 10 00 00 00 00 00 ldxdw r3, [r6 + 0x10] + 1260 9f 3a 74 00 00 00 00 00 stxdw [r10 + 0x74], r3 + 1268 9c 63 08 00 00 00 00 00 ldxdw r3, [r6 + 0x8] + 1270 9f 3a 6c 00 00 00 00 00 stxdw [r10 + 0x6c], r3 + 1278 9c 63 00 00 00 00 00 00 ldxdw r3, [r6 + 0x0] + 1280 9f 3a 64 00 00 00 00 00 stxdw [r10 + 0x64], r3 + 1288 96 02 00 00 98 00 00 00 lmul64 r2, 0x98 + 1290 9f 2a 54 00 00 00 00 00 stxdw [r10 + 0x54], r2 + 1298 97 0a 5c 00 18 00 00 00 stdw [r10 + 0x5c], 0x18 + 12a0 87 0a 50 00 00 00 00 00 stw [r10 + 0x50], 0x0 + 12a8 9f 1a 98 00 00 00 00 00 stxdw [r10 + 0x98], r1 + 12b0 bf 82 00 00 00 00 00 00 mov64 r2, r8 + 12b8 07 02 00 00 10 00 00 00 add64 r2, 0x10 + 12c0 9f 2a 88 00 00 00 00 00 stxdw [r10 + 0x88], r2 + 12c8 37 0a a0 00 01 01 00 00 sth [r10 + 0xa0], 0x101 + 12d0 37 0a 90 00 01 01 00 00 sth [r10 + 0x90], 0x101 + 12d8 bf 83 00 00 00 00 00 00 mov64 r3, r8 + 12e0 07 03 00 00 90 28 00 00 add64 r3, 0x2890 + 12e8 9f 3a 00 01 00 00 00 00 stxdw [r10 + 0x100], r3 + 12f0 bf 83 00 00 00 00 00 00 mov64 r3, r8 + 12f8 07 03 00 00 c0 28 00 00 add64 r3, 0x28c0 + 1300 9f 3a f8 00 00 00 00 00 stxdw [r10 + 0xf8], r3 + 1308 bf 83 00 00 00 00 00 00 mov64 r3, r8 + 1310 07 03 00 00 b0 28 00 00 add64 r3, 0x28b0 + 1318 9f 3a e8 00 00 00 00 00 stxdw [r10 + 0xe8], r3 + 1320 9f 1a e0 00 00 00 00 00 stxdw [r10 + 0xe0], r1 + 1328 bf 81 00 00 00 00 00 00 mov64 r1, r8 + 1330 07 01 00 00 30 00 00 00 add64 r1, 0x30 + 1338 9f 1a c8 00 00 00 00 00 stxdw [r10 + 0xc8], r1 + 1340 bf 81 00 00 00 00 00 00 mov64 r1, r8 + 1348 07 01 00 00 60 00 00 00 add64 r1, 0x60 + 1350 9f 1a c0 00 00 00 00 00 stxdw [r10 + 0xc0], r1 + 1358 bf 81 00 00 00 00 00 00 mov64 r1, r8 + 1360 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 1368 9f 1a b0 00 00 00 00 00 stxdw [r10 + 0xb0], r1 + 1370 9f 2a a8 00 00 00 00 00 stxdw [r10 + 0xa8], r2 + 1378 27 0a 12 01 00 00 00 00 stb [r10 + 0x112], 0x0 + 1380 37 0a 10 01 01 01 00 00 sth [r10 + 0x110], 0x101 + 1388 97 0a 08 01 00 00 00 00 stdw [r10 + 0x108], 0x0 + 1390 97 0a f0 00 00 00 00 00 stdw [r10 + 0xf0], 0x0 + 1398 27 0a da 00 00 00 00 00 stb [r10 + 0xda], 0x0 + 13a0 37 0a d8 00 01 01 00 00 sth [r10 + 0xd8], 0x101 + 13a8 97 0a d0 00 00 00 00 00 stdw [r10 + 0xd0], 0x0 + 13b0 97 0a b8 00 00 00 00 00 stdw [r10 + 0xb8], 0x0 + 13b8 97 0a 30 01 00 00 00 00 stdw [r10 + 0x130], 0x0 + 13c0 97 0a 28 01 00 00 00 00 stdw [r10 + 0x128], 0x0 + 13c8 97 0a 20 01 00 00 00 00 stdw [r10 + 0x120], 0x0 + 13d0 97 0a 18 01 00 00 00 00 stdw [r10 + 0x118], 0x0 + 13d8 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 13e0 07 01 00 00 50 00 00 00 add64 r1, 0x50 + 13e8 9f 1a 50 01 00 00 00 00 stxdw [r10 + 0x150], r1 + 13f0 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 13f8 07 01 00 00 88 00 00 00 add64 r1, 0x88 + 1400 9f 1a 40 01 00 00 00 00 stxdw [r10 + 0x140], r1 + 1408 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 1410 07 01 00 00 18 01 00 00 add64 r1, 0x118 + 1418 9f 1a 38 01 00 00 00 00 stxdw [r10 + 0x138], r1 + 1420 97 0a 58 01 34 00 00 00 stdw [r10 + 0x158], 0x34 + 1428 97 0a 48 01 02 00 00 00 stdw [r10 + 0x148], 0x2 + 1430 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 1438 07 01 00 00 4f 00 00 00 add64 r1, 0x4f + 1440 9f 1a 60 01 00 00 00 00 stxdw [r10 + 0x160], r1 + 1448 97 0a 68 01 01 00 00 00 stdw [r10 + 0x168], 0x1 + 1450 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 1458 07 01 00 00 60 01 00 00 add64 r1, 0x160 + 1460 9f 1a 70 01 00 00 00 00 stxdw [r10 + 0x170], r1 + 1468 97 0a 78 01 01 00 00 00 stdw [r10 + 0x178], 0x1 + 1470 bf a1 00 00 00 00 00 00 mov64 r1, r10 + 1478 07 01 00 00 38 01 00 00 add64 r1, 0x138 + 1480 bf a2 00 00 00 00 00 00 mov64 r2, r10 + 1488 07 02 00 00 a8 00 00 00 add64 r2, 0xa8 + 1490 bf a4 00 00 00 00 00 00 mov64 r4, r10 + 1498 07 04 00 00 70 01 00 00 add64 r4, 0x170 + 14a0 b7 03 00 00 02 00 00 00 mov64 r3, 0x2 + 14a8 b7 05 00 00 01 00 00 00 mov64 r5, 0x1 + 14b0 95 00 00 00 85 9c 2b a2 syscall -0x5dd4637b + 14b8 bf 81 00 00 00 00 00 00 mov64 r1, r8 + 14c0 07 01 00 00 d8 28 00 00 add64 r1, 0x28d8 + 14c8 9f 18 d0 28 00 00 00 00 stxdw [r8 + 0x28d0], r1 + 14d0 b7 00 00 00 00 00 00 00 mov64 r0, 0x0 + 14d8 05 00 3b fe 00 00 00 00 ja -0x1c5 + 14e0 b7 00 00 00 0c 00 00 00 mov64 r0, 0xc + 14e8 05 00 39 fe 00 00 00 00 ja -0x1c7 + 14f0 b7 00 00 00 01 00 00 00 mov64 r0, 0x1 + 14f8 05 00 37 fe 00 00 00 00 ja -0x1c9 + 1500 b7 00 00 00 02 00 00 00 mov64 r0, 0x2 + 1508 05 00 35 fe 00 00 00 00 ja -0x1cb + 1510 b7 00 00 00 05 00 00 00 mov64 r0, 0x5 + 1518 05 00 33 fe 00 00 00 00 ja -0x1cd + 1520 b7 00 00 00 06 00 00 00 mov64 r0, 0x6 + 1528 05 00 31 fe 00 00 00 00 ja -0x1cf + 1530 b7 00 00 00 04 00 00 00 mov64 r0, 0x4 + 1538 05 00 2f fe 00 00 00 00 ja -0x1d1 + 1540 b7 00 00 00 07 00 00 00 mov64 r0, 0x7 + 1548 05 00 2d fe 00 00 00 00 ja -0x1d3 + 1550 9c a1 40 00 00 00 00 00 ldxdw r1, [r10 + 0x40] + 1558 97 01 c0 28 00 00 00 00 stdw [r1 + 0x28c0], 0x0 + 1560 9c a3 38 00 00 00 00 00 ldxdw r3, [r10 + 0x38] + 1568 97 03 08 00 00 00 00 00 stdw [r3 + 0x8], 0x0 + 1570 97 03 00 00 00 00 00 00 stdw [r3 + 0x0], 0x0 + 1578 05 00 5a ff 00 00 00 00 ja -0xa6 + 1580 b7 00 00 00 0a 00 00 00 mov64 r0, 0xa + 1588 05 00 25 fe 00 00 00 00 ja -0x1db + 1590 b7 00 00 00 03 00 00 00 mov64 r0, 0x3 + 1598 05 00 23 fe 00 00 00 00 ja -0x1dd + 15a0 b7 00 00 00 0b 00 00 00 mov64 r0, 0xb + 15a8 05 00 21 fe 00 00 00 00 ja -0x1df \ No newline at end of file diff --git a/examples/tree/artifacts/rs-disassembly.s b/examples/tree/artifacts/rs-disassembly.s index 1eab8172..62f98877 100644 --- a/examples/tree/artifacts/rs-disassembly.s +++ b/examples/tree/artifacts/rs-disassembly.s @@ -1,17 +1,17 @@ .globl entrypoint entrypoint: - add64 r10, -320 + add64 r10, -384 ldxdw r4, [r1+0] ldxdw r3, [r2-8] ldxb r5, [r2+0] jne r5, 1, jmp_0780 - jne r3, 5, jmp_0e90 - jlt r4, 2, jmp_0ea0 + jne r3, 5, jmp_1518 + jlt r4, 2, jmp_1528 ldxdw r3, [r1+88] - jne r3, 0, jmp_0eb0 + jne r3, 0, jmp_1538 ldxb r3, [r1+10344] - jne r3, 255, jmp_0ec0 + jne r3, 255, jmp_1548 mov64 r6, r1 add64 r6, 10432 ldxdw r3, [r1+10440] @@ -36,7 +36,7 @@ jmp_00b0: ja jmp_0120 jmp_00e8: - jge r5, r4, jmp_0a18 + jge r5, r4, jmp_0ce0 ldxdw r4, [r2+8] jne r4, 0, jmp_00b0 stxdw [r3+0], r2 @@ -114,11 +114,11 @@ jmp_0278: mov64 r4, r1 add64 r4, r5 ldxb r5, [r4+20680] - jne r5, 255, jmp_0ed0 + jne r5, 255, jmp_1558 ldxdw r5, [r4+20760] - jne r5, 14, jmp_0ee0 + jne r5, 14, jmp_1568 ldxb r5, [r4+31032] - jne r5, 255, jmp_0ef0 + jne r5, 255, jmp_1578 mov64 r0, 8 mov32 r5, 399877894 hor64 r5, 1364995097 @@ -138,65 +138,65 @@ jmp_0278: jne r2, r5, jmp_06a8 ldxdw r2, [r4+31120] lmul64 r2, 29 - stxdw [r10+308], r2 - stw [r10+304], 2 + stxdw [r10+372], r2 + stw [r10+368], 2 mov64 r4, r1 add64 r4, 10352 - stxdw [r10+232], r4 + stxdw [r10+296], r4 mov64 r2, r1 add64 r2, 16 - stxdw [r10+216], r2 - sth [r10+240], 1 - sth [r10+224], 257 + stxdw [r10+280], r2 + sth [r10+304], 1 + sth [r10+288], 257 mov64 r5, r1 add64 r5, 10384 - stxdw [r10+192], r5 - stxdw [r10+184], r6 - stxdw [r10+176], r3 + stxdw [r10+256], r5 + stxdw [r10+248], r6 + stxdw [r10+240], r3 mov64 r3, r1 add64 r3, 10416 - stxdw [r10+168], r3 - stxdw [r10+160], r4 + stxdw [r10+232], r3 + stxdw [r10+224], r4 mov64 r3, r1 add64 r3, 48 - stxdw [r10+136], r3 + stxdw [r10+200], r3 mov64 r3, r1 add64 r3, 96 - stxdw [r10+128], r3 + stxdw [r10+192], r3 mov64 r3, r1 add64 r3, 80 - stxdw [r10+112], r3 - stxdw [r10+104], r2 - stb [r10+210], 0 - sth [r10+208], 256 - stdw [r10+200], 0 - stb [r10+154], 0 - sth [r10+152], 257 - stdw [r10+144], 0 - stdw [r10+120], 0 - stdw [r10+272], 0 + stxdw [r10+176], r3 + stxdw [r10+168], r2 + stb [r10+274], 0 + sth [r10+272], 256 stdw [r10+264], 0 - stdw [r10+256], 0 - stdw [r10+248], 0 + stb [r10+218], 0 + sth [r10+216], 257 + stdw [r10+208], 0 + stdw [r10+184], 0 + stdw [r10+336], 0 + stdw [r10+328], 0 + stdw [r10+320], 0 + stdw [r10+312], 0 mov64 r2, r10 - add64 r2, 304 - stxdw [r10+40], r2 + add64 r2, 368 + stxdw [r10+104], r2 mov64 r2, r10 - add64 r2, 216 - stxdw [r10+24], r2 + add64 r2, 280 + stxdw [r10+88], r2 mov64 r2, r10 - add64 r2, 248 - stxdw [r10+16], r2 - stdw [r10+48], 12 - stdw [r10+32], 2 - stdw [r10+80], 0 - stdw [r10+72], 0 + add64 r2, 312 + stxdw [r10+80], r2 + stdw [r10+112], 12 + stdw [r10+96], 2 + stdw [r10+144], 0 + stdw [r10+136], 0 mov64 r3, r10 - add64 r3, 16 + add64 r3, 80 mov64 r2, r10 - add64 r2, 104 + add64 r2, 168 mov64 r4, r10 - add64 r4, 72 + add64 r4, 136 mov64 r8, r1 mov64 r1, r3 mov64 r3, 2 @@ -297,13 +297,13 @@ jmp_0738: ja jmp_0238 jmp_0780: - jne r5, 2, jmp_0a28 - jne r3, 3, jmp_0e90 - jlt r4, 2, jmp_0ea0 + jne r5, 2, jmp_10b0 + jne r3, 3, jmp_1518 + jlt r4, 2, jmp_1528 ldxdw r3, [r1+88] - jne r3, 0, jmp_0eb0 + jne r3, 0, jmp_1538 ldxb r3, [r1+10344] - jne r3, 255, jmp_0ec0 + jne r3, 255, jmp_1548 mov64 r0, 15 ldxdw r3, [r1+10432] jeq r3, 0, jmp_06a8 @@ -329,111 +329,376 @@ jmp_0830: ja jmp_06a8 jmp_0840: - jeq r2, 0, jmp_0888 - ldxdw r4, [r3+16] - jeq r4, 0, jmp_0928 + stxdw [r10+64], r1 + jeq r2, 0, jmp_0890 + ldxdw r1, [r3+16] + jeq r1, 0, jmp_0938 -jmp_0858: - mov64 r2, r4 - ldxdw r4, [r2+8] - jne r4, 0, jmp_0858 - ldxw r4, [r2+24] - stxw [r3+24], r4 - ja jmp_0890 +jmp_0860: + mov64 r2, r1 + ldxdw r1, [r2+8] + jne r1, 0, jmp_0860 + ldxw r1, [r2+24] + stxw [r3+24], r1 + ja jmp_0898 -jmp_0888: +jmp_0890: mov64 r2, r3 -jmp_0890: +jmp_0898: ldxdw r4, [r2+0] - mov64 r3, r2 - add64 r3, 8 - ldxdw r5, [r2+16] - jeq r5, 0, jmp_08f0 - stxdw [r5+0], r4 - stb [r5+28], 0 - jeq r4, 0, jmp_0978 - ldxdw r0, [r4+16] - jeq r2, r0, jmp_0988 - stxdw [r4+8], r5 - ja jmp_09e8 - -jmp_08f0: - jeq r4, 0, jmp_0f00 - ldxb r5, [r2+28] - jne r5, 1, jmp_09e8 - ldxdw r5, [r4+16] - jeq r2, r5, jmp_09e0 + mov64 r1, r2 + add64 r1, 8 + stxdw [r10+48], r1 + ldxdw r1, [r2+16] + jeq r1, 0, jmp_0900 + stxdw [r1+0], r4 + stb [r1+28], 0 + jeq r4, 0, jmp_0988 + ldxdw r3, [r4+16] + jeq r2, r3, jmp_0b10 + stxdw [r4+8], r1 + ja jmp_1070 + +jmp_0900: + jeq r4, 0, jmp_1588 + ldxdw r1, [r4+16] + ldxb r3, [r2+28] + jne r3, 1, jmp_09a0 + jeq r2, r1, jmp_0cd0 stdw [r4+8], 0 - ja jmp_09e8 + ja jmp_1070 -jmp_0928: - mov64 r4, r3 - add64 r4, 8 - ldxdw r5, [r3+0] - stxdw [r2+0], r5 +jmp_0938: + mov64 r1, r3 + add64 r1, 8 + ldxdw r4, [r3+0] + stxdw [r2+0], r4 stb [r2+28], 0 - jeq r5, 0, jmp_0998 - ldxdw r0, [r5+16] - jeq r3, r0, jmp_09a8 - stxdw [r5+8], r2 - ja jmp_09b0 - -jmp_0978: - stxdw [r1+10432], r5 - ja jmp_09e8 + jeq r4, 0, jmp_0b20 + ldxdw r5, [r4+16] + jeq r3, r5, jmp_0c90 + stxdw [r4+8], r2 + ja jmp_0c98 jmp_0988: - stxdw [r4+16], r5 - ja jmp_09e8 + ldxdw r3, [r10+64] + stxdw [r3+10432], r1 + ja jmp_1070 + +jmp_09a0: + mov32 r3, 1 + stxdw [r10+32], r3 + jeq r2, r1, jmp_09c8 + mov32 r1, 0 + stxdw [r10+32], r1 + +jmp_09c8: + mov64 r8, r4 + add64 r8, 8 + ldxdw r5, [r10+32] + mov64 r6, r5 + lsh64 r6, 3 + mov64 r1, r8 + add64 r1, r6 + stdw [r1+0], 0 + xor64 r5, 1 + mov64 r9, r5 + lsh64 r9, 3 + add64 r8, r9 + ldxdw r3, [r8+0] + mov64 r7, r3 + add64 r7, 28 + mov64 r1, r3 + add64 r1, 8 + mov64 r0, r1 + add64 r0, r6 + ldxdw r6, [r0+0] + stxdw [r10+56], r6 + stxdw [r10+40], r3 + ldxb r6, [r3+28] + jeq r6, 0, jmp_0b38 + mov64 r6, r4 + ldxdw r1, [r6+0] + ldxdw r3, [r10+56] + stxdw [r8+0], r3 + jeq r3, 0, jmp_0ac0 + +jmp_0ab0: + ldxdw r3, [r10+56] + stxdw [r3+0], r6 + +jmp_0ac0: + stxdw [r0+0], r6 + ldxdw r3, [r10+40] + stxdw [r3+0], r1 + stxdw [r6+0], r3 + jeq r1, 0, jmp_0cf0 + ldxdw r4, [r1+16] + jeq r6, r4, jmp_0d10 + ldxdw r3, [r10+40] + stxdw [r1+8], r3 + ja jmp_0d20 -jmp_0998: - stxdw [r1+10432], r2 - ja jmp_09b0 +jmp_0b10: + stxdw [r4+16], r1 + ja jmp_1070 -jmp_09a8: - stxdw [r5+16], r2 +jmp_0b20: + ldxdw r4, [r10+64] + stxdw [r4+10432], r2 + ja jmp_0c98 -jmp_09b0: - stdw [r4+8], 0 - stdw [r4+0], 0 +jmp_0b38: + add64 r1, r9 + ja jmp_0c00 + +jmp_0b48: + mov64 r5, r3 + xor64 r5, 1 + mov64 r4, r5 + lsh64 r4, 3 + mov64 r8, r6 + add64 r8, r4 + ldxdw r9, [r8+8] + mov64 r0, r9 + add64 r0, 8 + mov64 r1, r0 + add64 r1, r4 + stxdw [r10+32], r3 + mov64 r4, r3 + lsh64 r4, 3 + add64 r0, r4 + mov64 r7, r9 + add64 r7, 28 + ldxdw r3, [r0+0] + stxdw [r10+56], r3 + stxdw [r10+40], r9 + ldxb r3, [r9+28] + mov64 r4, r6 + jne r3, 0, jmp_0ef8 + +jmp_0c00: + ldxdw r1, [r1+0] + jeq r1, 0, jmp_0c20 + ldxb r0, [r1+28] + jne r0, 0, jmp_0f40 + +jmp_0c20: + ldxdw r9, [r10+56] + jeq r9, 0, jmp_0c40 + ldxb r1, [r9+28] + jne r1, 0, jmp_0df8 + +jmp_0c40: + ldxb r1, [r4+28] + stb [r7+0], 1 + jeq r1, 1, jmp_0ee8 + ldxdw r6, [r4+0] + jeq r6, 0, jmp_1070 + ldxdw r1, [r6+16] + mov32 r3, 1 + jeq r4, r1, jmp_0b48 + mov32 r3, 0 + ja jmp_0b48 + +jmp_0c90: + stxdw [r4+16], r2 + +jmp_0c98: + stdw [r1+8], 0 + stdw [r1+0], 0 + ldxdw r1, [r10+64] ldxdw r2, [r1+10440] stxdw [r3+0], r2 stxdw [r1+10440], r3 ja jmp_05f0 -jmp_09e0: +jmp_0cd0: stdw [r4+16], 0 + ja jmp_1070 -jmp_09e8: - stdw [r3+8], 0 - stdw [r3+0], 0 +jmp_0ce0: + mov64 r0, 14 + ja jmp_06a8 + +jmp_0cf0: + ldxdw r1, [r10+64] + ldxdw r3, [r10+40] + stxdw [r1+10432], r3 + ja jmp_0d20 + +jmp_0d10: + ldxdw r3, [r10+40] + stxdw [r1+16], r3 + +jmp_0d20: + stb [r6+28], 1 + stb [r7+0], 0 + mov64 r3, r5 + lsh64 r3, 3 + ldxdw r1, [r10+56] + add64 r1, 8 + mov64 r4, r1 + add64 r4, r3 + ldxdw r3, [r4+0] + stxdw [r10+40], r3 + jeq r3, 0, jmp_0da8 + ldxdw r3, [r10+40] + ldxb r4, [r3+28] + jeq r4, 0, jmp_0da8 + mov64 r4, r6 + ldxdw r9, [r10+56] + ja jmp_0f78 + +jmp_0da8: + ldxdw r3, [r10+32] + lsh64 r3, 3 + add64 r1, r3 + ldxdw r9, [r1+0] + jeq r9, 0, jmp_0ec8 + ldxb r1, [r9+28] + jeq r1, 0, jmp_0ec8 + mov64 r4, r6 + ldxdw r1, [r10+56] + stxdw [r10+40], r1 + +jmp_0df8: + mov64 r1, r5 + lsh64 r1, 3 + mov64 r0, r9 + add64 r0, r1 + ldxdw r1, [r10+32] + lsh64 r1, 3 + ldxdw r6, [r10+40] + mov64 r3, r6 + add64 r3, r1 + ldxdw r1, [r6+0] + ldxdw r6, [r0+8] + stxdw [r3+8], r6 + add64 r0, 8 + jeq r6, 0, jmp_0e78 + ldxdw r3, [r10+40] + stxdw [r6+0], r3 + +jmp_0e78: + ldxdw r3, [r10+40] + stxdw [r0+0], r3 + stxdw [r9+0], r1 + stxdw [r3+0], r9 + jeq r1, 0, jmp_0f28 + ldxdw r3, [r1+16] + ldxdw r0, [r10+40] + jeq r0, r3, jmp_0f58 + stxdw [r1+8], r9 + ja jmp_0f60 + +jmp_0ec8: + ldxdw r1, [r10+56] + stb [r1+28], 1 + stb [r6+28], 0 + ja jmp_1070 + +jmp_0ee8: + stb [r4+28], 0 + ja jmp_1070 + +jmp_0ef8: + add64 r8, 8 + ldxdw r1, [r6+0] + ldxdw r3, [r10+56] + stxdw [r8+0], r3 + jne r3, 0, jmp_0ab0 + ja jmp_0ac0 + +jmp_0f28: + ldxdw r1, [r10+64] + stxdw [r1+10432], r9 + ja jmp_0f60 + +jmp_0f40: + ldxdw r9, [r10+40] + stxdw [r10+40], r1 + ja jmp_0f78 + +jmp_0f58: + stxdw [r1+16], r9 + +jmp_0f60: + ldxdw r1, [r10+40] + stb [r1+28], 1 + stb [r9+28], 0 + +jmp_0f78: + lsh64 r5, 3 + mov64 r3, r4 + add64 r3, r5 + ldxdw r5, [r10+32] + lsh64 r5, 3 + ldxdw r1, [r3+8] + mov64 r0, r1 + add64 r0, r5 + ldxdw r5, [r4+0] + ldxdw r6, [r0+8] + stxdw [r3+8], r6 + add64 r0, 8 + jeq r6, 0, jmp_0fe8 + stxdw [r6+0], r4 + +jmp_0fe8: + stxdw [r0+0], r4 + stxdw [r1+0], r5 + stxdw [r4+0], r1 + jeq r5, 0, jmp_1028 + ldxdw r3, [r5+16] + jeq r4, r3, jmp_1040 + stxdw [r5+8], r1 + ja jmp_1048 + +jmp_1028: + ldxdw r5, [r10+64] + stxdw [r5+10432], r1 + ja jmp_1048 + +jmp_1040: + stxdw [r5+16], r1 + +jmp_1048: + ldxb r1, [r4+28] + stxb [r9+28], r1 + stb [r4+28], 0 + ldxdw r1, [r10+40] + stb [r1+28], 0 + +jmp_1070: + ldxdw r1, [r10+48] + stdw [r1+8], 0 + stdw [r1+0], 0 + ldxdw r1, [r10+64] + +jmp_1090: ldxdw r3, [r1+10440] stxdw [r2+0], r3 stxdw [r1+10440], r2 ja jmp_05f0 -jmp_0a18: - mov64 r0, 14 - ja jmp_06a8 - -jmp_0a28: +jmp_10b0: mov64 r8, r1 - jne r5, 0, jmp_0f20 - jne r3, 1, jmp_0e90 - jne r4, 4, jmp_0ea0 + jne r5, 0, jmp_15c8 + jne r3, 1, jmp_1518 + jne r4, 4, jmp_1528 ldxdw r1, [r8+88] - jne r1, 0, jmp_0eb0 + jne r1, 0, jmp_1538 ldxb r1, [r8+10344] - jne r1, 255, jmp_0ec0 + jne r1, 255, jmp_1548 ldxdw r1, [r8+10424] - jne r1, 0, jmp_0f10 + jne r1, 0, jmp_15b8 ldxb r1, [r8+20680] - jne r1, 255, jmp_0ed0 + jne r1, 255, jmp_1558 ldxdw r1, [r8+20760] - jne r1, 14, jmp_0ee0 + jne r1, 14, jmp_1568 ldxb r1, [r8+31032] - jne r1, 255, jmp_0ef0 + jne r1, 255, jmp_1578 mov64 r0, 8 mov32 r1, 399877894 hor64 r1, 1364995097 @@ -454,104 +719,104 @@ jmp_0a28: mov64 r6, r7 add64 r6, 41401 mov64 r4, r10 - add64 r4, 104 + add64 r4, 168 mov64 r5, r10 - add64 r5, 15 + add64 r5, 79 mov64 r1, r7 mov64 r2, 0 mov64 r3, r6 call sol_try_find_program_address mov64 r0, 10 - ldxdw r1, [r10+104] + ldxdw r1, [r10+168] ldxdw r2, [r7+10352] jne r1, r2, jmp_06a8 - ldxdw r1, [r10+112] + ldxdw r1, [r10+176] ldxdw r2, [r8+10360] jne r1, r2, jmp_06a8 - ldxdw r1, [r10+120] + ldxdw r1, [r10+184] ldxdw r2, [r8+10368] jne r1, r2, jmp_06a8 - ldxdw r1, [r10+128] + ldxdw r1, [r10+192] ldxdw r2, [r8+10376] jne r1, r2, jmp_06a8 mov64 r1, r8 add64 r1, 10352 ldxdw r2, [r8+31120] ldxdw r3, [r6+24] - stxdw [r10+60], r3 + stxdw [r10+124], r3 ldxdw r3, [r6+16] - stxdw [r10+52], r3 + stxdw [r10+116], r3 ldxdw r3, [r6+8] - stxdw [r10+44], r3 + stxdw [r10+108], r3 ldxdw r3, [r6+0] - stxdw [r10+36], r3 + stxdw [r10+100], r3 lmul64 r2, 152 - stxdw [r10+20], r2 - stdw [r10+28], 24 - stw [r10+16], 0 - stxdw [r10+88], r1 + stxdw [r10+84], r2 + stdw [r10+92], 24 + stw [r10+80], 0 + stxdw [r10+152], r1 mov64 r2, r8 add64 r2, 16 - stxdw [r10+72], r2 - sth [r10+96], 257 - sth [r10+80], 257 + stxdw [r10+136], r2 + sth [r10+160], 257 + sth [r10+144], 257 mov64 r3, r8 add64 r3, 10384 - stxdw [r10+192], r3 + stxdw [r10+256], r3 mov64 r3, r8 add64 r3, 10432 - stxdw [r10+184], r3 + stxdw [r10+248], r3 mov64 r3, r8 add64 r3, 10416 - stxdw [r10+168], r3 - stxdw [r10+160], r1 + stxdw [r10+232], r3 + stxdw [r10+224], r1 mov64 r1, r8 add64 r1, 48 - stxdw [r10+136], r1 + stxdw [r10+200], r1 mov64 r1, r8 add64 r1, 96 - stxdw [r10+128], r1 + stxdw [r10+192], r1 mov64 r1, r8 add64 r1, 80 - stxdw [r10+112], r1 - stxdw [r10+104], r2 - stb [r10+210], 0 - sth [r10+208], 257 - stdw [r10+200], 0 - stdw [r10+176], 0 - stb [r10+154], 0 - sth [r10+152], 257 - stdw [r10+144], 0 - stdw [r10+120], 0 + stxdw [r10+176], r1 + stxdw [r10+168], r2 + stb [r10+274], 0 + sth [r10+272], 257 + stdw [r10+264], 0 stdw [r10+240], 0 - stdw [r10+232], 0 - stdw [r10+224], 0 - stdw [r10+216], 0 + stb [r10+218], 0 + sth [r10+216], 257 + stdw [r10+208], 0 + stdw [r10+184], 0 + stdw [r10+304], 0 + stdw [r10+296], 0 + stdw [r10+288], 0 + stdw [r10+280], 0 mov64 r1, r10 - add64 r1, 16 - stxdw [r10+272], r1 + add64 r1, 80 + stxdw [r10+336], r1 mov64 r1, r10 - add64 r1, 72 - stxdw [r10+256], r1 + add64 r1, 136 + stxdw [r10+320], r1 mov64 r1, r10 - add64 r1, 216 - stxdw [r10+248], r1 - stdw [r10+280], 52 - stdw [r10+264], 2 + add64 r1, 280 + stxdw [r10+312], r1 + stdw [r10+344], 52 + stdw [r10+328], 2 mov64 r1, r10 - add64 r1, 15 - stxdw [r10+288], r1 - stdw [r10+296], 1 + add64 r1, 79 + stxdw [r10+352], r1 + stdw [r10+360], 1 mov64 r1, r10 - add64 r1, 288 - stxdw [r10+304], r1 - stdw [r10+312], 1 + add64 r1, 352 + stxdw [r10+368], r1 + stdw [r10+376], 1 mov64 r1, r10 - add64 r1, 248 + add64 r1, 312 mov64 r2, r10 - add64 r2, 104 + add64 r2, 168 mov64 r4, r10 - add64 r4, 304 + add64 r4, 368 mov64 r3, 2 mov64 r5, 1 call sol_invoke_signed_c @@ -560,42 +825,46 @@ jmp_0a28: stxdw [r8+10448], r1 ja jmp_05f0 -jmp_0e90: +jmp_1518: mov64 r0, 12 ja jmp_06a8 -jmp_0ea0: +jmp_1528: mov64 r0, 1 ja jmp_06a8 -jmp_0eb0: +jmp_1538: mov64 r0, 2 ja jmp_06a8 -jmp_0ec0: +jmp_1548: mov64 r0, 5 ja jmp_06a8 -jmp_0ed0: +jmp_1558: mov64 r0, 6 ja jmp_06a8 -jmp_0ee0: +jmp_1568: mov64 r0, 4 ja jmp_06a8 -jmp_0ef0: +jmp_1578: mov64 r0, 7 ja jmp_06a8 -jmp_0f00: +jmp_1588: + ldxdw r1, [r10+64] stdw [r1+10432], 0 - ja jmp_09e8 + ldxdw r3, [r10+48] + stdw [r3+8], 0 + stdw [r3+0], 0 + ja jmp_1090 -jmp_0f10: +jmp_15b8: mov64 r0, 3 ja jmp_06a8 -jmp_0f20: +jmp_15c8: mov64 r0, 11 ja jmp_06a8 diff --git a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt index ee9aeb59..e4744660 100644 --- a/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/initialize-input-checks.txt @@ -1,7 +1,7 @@ #[inline(always)] unsafe fn initialize( input: *mut u8, - instruction_data: *mut u8, + _instruction_data: *mut u8, instruction_data_len: u64, n_accounts: u64, ) -> u64 { @@ -14,7 +14,7 @@ unsafe fn initialize( ); // Error if user has data. - let user = user_account!(input); + let _user = user_account!(input); // Error if tree is duplicate or has data. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); diff --git a/examples/tree/artifacts/snippets/rs/insert-input-checks.txt b/examples/tree/artifacts/snippets/rs/insert-input-checks.txt index 48969685..440102e4 100644 --- a/examples/tree/artifacts/snippets/rs/insert-input-checks.txt +++ b/examples/tree/artifacts/snippets/rs/insert-input-checks.txt @@ -1,3 +1,4 @@ +#[allow(unused_assignments)] #[inline(always)] unsafe fn insert( input: *mut u8, @@ -14,7 +15,7 @@ unsafe fn insert( ); // Error if user has data. - let user = user_account!(input); + let _user = user_account!(input); // Error if tree is duplicate. let tree = account_non_dup!(input, input_buffer::TREE_ACCOUNT_OFF, error::TREE_DUPLICATE); \ No newline at end of file diff --git a/examples/tree/artifacts/tests/remove_simple/result.txt b/examples/tree/artifacts/tests/remove_simple/result.txt index 81647402..6998b83b 100644 --- a/examples/tree/artifacts/tests/remove_simple/result.txt +++ b/examples/tree/artifacts/tests/remove_simple/result.txt @@ -1,87 +1,87 @@ | Test case | ASM (CUs) | Rust (CUs) | Overhead | Overhead % | |-----------|-----------|------------|----------|------------| -| Successor immediate R (SC 1) | 40 | 55 | +15 | +37.5% | -| Successor deep L descent (SC 1) | 44 | 59 | +15 | +34.1% | -| Successor with R child (SC 1) | 40 | 54 | +14 | +35.0% | -| One child root R (SC 2) | 31 | 43 | +12 | +38.7% | -| One child root L (SC 2) | 31 | 42 | +11 | +35.5% | -| One child non-root R,R (SC 2) | 38 | 52 | +14 | +36.8% | -| One child non-root L,L (SC 2) | 38 | 54 | +16 | +42.1% | -| One child non-root R,L (SC 2) | 38 | 55 | +17 | +44.7% | -| One child non-root L,R (SC 2) | 38 | 51 | +13 | +34.2% | -| Root leaf (SC 3) | 29 | 42 | +13 | +44.8% | -| Red leaf L (SC 4) | 38 | 56 | +18 | +47.4% | -| Red leaf R (SC 4) | 38 | 53 | +15 | +39.5% | +| Successor immediate R (SC 1) | 40 | 59 | +19 | +47.5% | +| Successor deep L descent (SC 1) | 44 | 63 | +19 | +43.2% | +| Successor with R child (SC 1) | 40 | 59 | +19 | +47.5% | +| One child root R (SC 2) | 31 | 48 | +17 | +54.8% | +| One child root L (SC 2) | 31 | 44 | +13 | +41.9% | +| One child non-root R,R (SC 2) | 38 | 57 | +19 | +50.0% | +| One child non-root L,L (SC 2) | 38 | 56 | +18 | +47.4% | +| One child non-root R,L (SC 2) | 38 | 60 | +22 | +57.9% | +| One child non-root L,R (SC 2) | 38 | 53 | +15 | +39.5% | +| Root leaf (SC 3) | 29 | 46 | +17 | +58.6% | +| Red leaf L (SC 4) | 38 | 60 | +22 | +57.9% | +| Red leaf R (SC 4) | 38 | 57 | +19 | +50.0% | test tests::test_remove_simple ... ok [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 40 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 59 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 48 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 31 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 44 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 52 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 54 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 55 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 51 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 29 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 42 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 46 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 56 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 60 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] [ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success [ ... DEBUG ... ] Program DASMAC... invoke [1] -[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units +[ ... DEBUG ... ] Program DASMAC... consumed 57 of 1400000 compute units [ ... DEBUG ... ] Program DASMAC... success \ No newline at end of file diff --git a/examples/tree/src/tests.rs b/examples/tree/src/tests.rs index bbfcc014..2f580728 100644 --- a/examples/tree/src/tests.rs +++ b/examples/tree/src/tests.rs @@ -2,6 +2,7 @@ mod common; mod entrypoint; mod init; mod insert; +#[allow(dead_code, unused_imports)] mod remove; use mollusk_svm::program; diff --git a/examples/tree/src/tests/init.rs b/examples/tree/src/tests/init.rs index 602da474..6e40de9f 100644 --- a/examples/tree/src/tests/init.rs +++ b/examples/tree/src/tests/init.rs @@ -1,5 +1,5 @@ use super::*; -use tree_interface::{input_buffer, tree, Instruction as TreeInstruction, TreeHeader}; +use tree_interface::{input_buffer, Instruction as TreeInstruction, TreeHeader}; fn init_setup( program_language: ProgramLanguage, @@ -40,7 +40,7 @@ fn init_setup( fn pda_init_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let mut setup = setup_test_with_rent(program_language); + let setup = setup_test_with_rent(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) = diff --git a/examples/tree/src/tests/insert.rs b/examples/tree/src/tests/insert.rs index 0c8b15a7..035e9a58 100644 --- a/examples/tree/src/tests/insert.rs +++ b/examples/tree/src/tests/insert.rs @@ -23,7 +23,7 @@ fn insert_instruction_data() -> InsertInstruction { fn insert_setup( program_language: ProgramLanguage, ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { - let mut setup = setup_test_with_rent(program_language); + let setup = setup_test_with_rent(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) = @@ -137,7 +137,7 @@ fn insert_max_data_setup( ) -> (TestSetup, Instruction, Vec<(Pubkey, Account)>) { const MAX_PERMITTED_DATA_LENGTH: usize = 10 * 1024 * 1024; - let mut setup = setup_test_with_rent(program_language); + let setup = setup_test_with_rent(program_language); let (system_program_pubkey, system_program_account) = program::keyed_account_for_system_program(); let (rent_sysvar_pubkey, rent_sysvar_account) =