Skip to content

Reduce direct RTTI to a single reflection - #81

Open
mingxwa wants to merge 1 commit into
ngcpp:feature/v5from
mingxwa:user/mingxwa/reduce-direct-rtti
Open

Reduce direct RTTI to a single reflection#81
mingxwa wants to merge 1 commit into
ngcpp:feature/v5from
mingxwa:user/mingxwa/reduce-direct-rtti

Conversation

@mingxwa

@mingxwa mingxwa commented Sep 7, 2026

Copy link
Copy Markdown
Member

skills::direct_rtti installed three conventions to carry proxy_cast, so every proxiable pointer paid three function pointers of metadata and every cast went through one of them. The typeid reflection that the same skill already installs records the contained type, and once that type is known to match the requested one the cast is a static_cast on the pointer storage, so the indirection buys nothing.

Changes

  • Reduced skills::direct_rtti to a single reflection, because the reflection it already installed is enough to identify the contained type.
  • Added direct_rtti_reflector, which inherits proxy_typeid_reflector for the type identity and reuses the accessor generated for proxy_cast_dispatch, so the five proxy_cast overloads and their qualifier mapping stay in one place.
  • Added a private invoke_cast to proxy_cast_accessor_impl, which tests the reflected type and then invokes the same dispatch through an erased context with the contained type known statically. The indirect path is unchanged and compiles to the same code as before.

Effect

Metadata for a facade built from direct_rtti alone drops from 40 bytes to 16. Measured on feature/v5 with g++-16 at -O2 on aarch64.

cast before after
lvalue 46 instructions, 1 indirect call 27 instructions, no indirect call
pointer 37 instructions, 1 indirect call 29 instructions, no indirect call
rvalue 66 instructions, 1 indirect call 34 instructions, 1 indirect call

The indirect call remaining in the rvalue form sits on the type mismatch branch, where the proxy is reset through the erased destructor. The success path has none.

The existing RTTI tests pass unchanged, so no test was added or modified.

direct_rtti added three conventions to carry proxy_cast, so every
proxiable pointer paid three function pointers of metadata and every cast
went through one of them. The typeid reflection that the same skill
installs already records the contained type, and once that type is known
to match the requested one the cast is a static_cast on the pointer
storage, so the indirection buys nothing.

direct_rtti now adds one reflection. direct_rtti_reflector inherits
proxy_typeid_reflector for the type identity and reuses the accessor
generated for proxy_cast_dispatch, so the five proxy_cast overloads and
their qualifier mapping stay in one place. proxy_cast_accessor_impl
gained a private invoke_cast that tests the reflected type and then
invokes the same dispatch through an erased context with the contained
type known statically. The indirect path keeps its conventions and
compiles to the same code as before.

The metadata of a facade built from direct_rtti alone drops from 40 bytes
to 16, and the lvalue, pointer and rvalue casts compile to 27, 29 and 34
instructions in place of 46, 37 and 66. No indirect call is left on the
success path. The rvalue form keeps one on the type mismatch branch,
where the proxy is reset through the erased destructor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant