From eee7e781cd287f97912281312a3fa9f8098c0e7e Mon Sep 17 00:00:00 2001 From: blasty Date: Mon, 10 Aug 2026 00:25:10 +0200 Subject: remote_tools: item class by mask instead of is_code/is_data calls The listing walk asked ida_bytes.is_code/is_data ~6 times per head (the row's kind, plus twice more via _is_unknown_f from _advance and _rows_for). Each is a python wrapper around a C call; the mask compare is the same question with no call at all. Equivalence was proven, not assumed: checked against is_code/is_data over all four classes x 16,020 synthetic flag values, and over every distinct flag in a real database (125 across 207,191 heads). Zero mismatches. Output is byte-identical over 3003 rows spanning all five row kinds. (The digest DOES differ run to run, which looked alarming until it turned out the same unmodified code differs too: hash() is seed-randomised per process and the digest is documented as per-process. Cross-process digest comparison proves nothing.) Worth 5.6% on a skeleton page (3.37 -> 3.18ms) and 2.7% on a full one -- the ~5% the profile predicted, not the 1.5-2x I guessed out loud. End to end it does NOT move bash's boot (3117 -> 3140ms, noise), because at 455 x 3.18ms the backend is now only ~1.45s of a 3.14s boot: the other ~54% is transport, Head construction and model bookkeeping on the client. Only the two hot sites changed. The four in the operand-format paths are not per-head and read better as is_code/is_data. Full gate: 1050 passed. --- idatui/remote_tools.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'idatui/remote_tools.py') diff --git a/idatui/remote_tools.py b/idatui/remote_tools.py index 1f66193..d2cb02e 100644 --- a/idatui/remote_tools.py +++ b/idatui/remote_tools.py @@ -52,6 +52,21 @@ import ida_typeinf import ida_ua import idaapi +# Item-class bits, read once. +# +# ida_bytes.is_code/is_data are thin python wrappers around a C call, and the +# listing walk asks ~6 times per head (once each for the row's kind, twice more +# via _is_unknown_f from _advance and _rows_for). The mask compare is the same +# question with no call at all. +# +# Equivalence is not assumed: it was checked against is_code/is_data over all +# four classes x 16,020 synthetic flag values, and over every distinct flag +# value in a real database (125 of them across 207,191 heads). Zero mismatches. +# MS_CLS=0x600, FF_CODE=0x600, FF_DATA=0x400, FF_TAIL=0x200, FF_UNK=0x0. +_MS_CLS = ida_bytes.MS_CLS +_FF_CODE = ida_bytes.FF_CODE +_FF_DATA = ida_bytes.FF_DATA + from typing import Annotated # the extracted tool signatures still carry these @@ -119,9 +134,10 @@ def _idatui_head_row(ea, flags=None, text=True): """ f = ida_bytes.get_flags(ea) if flags is None else flags - if ida_bytes.is_code(f): + cls = f & _MS_CLS # == is_code(f) / is_data(f), without the calls + if cls == _FF_CODE: kind = "code" - elif ida_bytes.is_data(f): + elif cls == _FF_DATA: kind = "data" else: kind = "unknown" @@ -552,7 +568,9 @@ def heads( # end found in O(1) via next_head, which skips undefined) so a large .bss or # gap doesn't explode into millions of one-byte rows. def _is_unknown_f(f): - return not (ida_bytes.is_code(f) or ida_bytes.is_data(f)) + # Hot: twice per head. See _MS_CLS -- same test, no call. + cls = f & _MS_CLS + return cls != _FF_CODE and cls != _FF_DATA def _run_end(e): """End (exclusive) of the undefined run starting at ``e``.""" -- cgit v1.3.1-sl0p