rexglue-skate3/resources/templates/codegen/_indirect_call.inja
2026-05-18 22:41:13 +01:00

38 lines
2.4 KiB
Text

//=============================================================================
// Indirect Call Dispatch
//
// REX_LOOKUP_FUNC indexes into the per-module dispatch table at
// IMAGE_BASE + IMAGE_SIZE. REX_CALL_INDIRECT_FUNC bounds-checks the target
// against the caller's [REX_CODE_BASE, REX_CODE_BASE + REX_CODE_SIZE +
// REX_THUNK_RESERVE_SIZE) range; out-of-bounds targets and in-bounds
// unregistered slots fall back to rex::runtime::ResolveIndirectFunction,
// which queries the global FunctionDispatcher across every loaded module.
//=============================================================================
#ifdef REXGLUE_ENABLE_PROFILING
#include <rex/perf/counter.h>
#define REX_PROFILE_INDIRECT_DISPATCH() PROFILE_FUNCTION_DISPATCHED()
#else
#define REX_PROFILE_INDIRECT_DISPATCH()
#endif
#define REX_LOOKUP_FUNC(x, y) \
(*(PPCFunc**)(x + REX_IMAGE_BASE + REX_IMAGE_SIZE + (u64(u32(y) - REX_CODE_BASE) * 2)))
#define REX_CALL_INDIRECT_FUNC(x) \
do { \
REX_PROFILE_INDIRECT_DISPATCH(); \
uint32_t rex_indirect_target_ = (uint32_t)(x); \
PPCFunc* rex_indirect_func_; \
if ((uint32_t)(rex_indirect_target_ - REX_CODE_BASE) < \
REX_CODE_SIZE + REX_THUNK_RESERVE_SIZE) [[likely]] { \
rex_indirect_func_ = REX_LOOKUP_FUNC(base, rex_indirect_target_); \
} else { \
rex_indirect_func_ = nullptr; \
} \
if (!rex_indirect_func_) [[unlikely]] { \
ctx.last_indirect_target = rex_indirect_target_; \
rex_indirect_func_ = rex::runtime::ResolveIndirectFunction(rex_indirect_target_); \
} \
rex_indirect_func_(ctx, base); \
} while (0)