// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef EVAL_CORE_H #define EVAL_CORE_H //////////////////////////////// //~ rjf: Evaluation Key Type typedef struct E_Key E_Key; struct E_Key { U64 u64; }; //////////////////////////////// //~ rjf: Messages typedef enum E_MsgKind { E_MsgKind_Null, E_MsgKind_MalformedInput, E_MsgKind_MissingInfo, E_MsgKind_ResolutionFailure, E_MsgKind_InterpretationError, E_MsgKind_COUNT } E_MsgKind; typedef struct E_Msg E_Msg; struct E_Msg { E_Msg *next; E_MsgKind kind; Rng1U64 range; String8 text; }; typedef struct E_MsgList E_MsgList; struct E_MsgList { E_Msg *first; E_Msg *last; E_MsgKind max_kind; U64 count; }; //////////////////////////////// //~ rjf: Register-Sized Value Type typedef union E_Value E_Value; union E_Value { U512 u512; U256 u256; U128 u128; U64 u64; U32 u32; U16 u16; U8 u8; S64 s64; S32 s32; S16 s16; S8 s8; F64 f64; F32 f32; }; //////////////////////////////// //~ rjf: Bytecode Operation Types enum { E_IRExtKind_Bytecode = RDI_EvalOp_COUNT, E_IRExtKind_SetSpace, E_IRExtKind_COUNT }; typedef struct E_Op E_Op; struct E_Op { E_Op *next; RDI_EvalOp opcode; E_Value value; String8 string; }; typedef struct E_OpList E_OpList; struct E_OpList { E_Op *first; E_Op *last; U64 op_count; U64 encoded_size; }; //////////////////////////////// //~ rjf: Operator Info typedef enum E_OpKind { E_OpKind_Null, E_OpKind_UnaryPrefix, E_OpKind_Binary, } E_OpKind; typedef struct E_OpInfo E_OpInfo; struct E_OpInfo { E_OpKind kind; S64 precedence; String8 pre; String8 sep; String8 post; String8 chain; }; //////////////////////////////// //~ rjf: Evaluation Spaces // // NOTE(rjf): Evaluations occur within the context of a "space". Each "space" // refers to a different offset/address-space, but it's a bit looser of a // concept than just address space, since it can also refer to offsets into // a register block, and it is also used to refer to spaces of unique IDs for // key-value stores, e.g. for information in the debugger. // // Effectively, when considering the result of an evaluation, you use the // value for understanding a key *into* a space, e.g. 1+2 -> 3, in a null // space, or &foo, in the space of PID: 1234. typedef U64 E_SpaceKind; enum { E_SpaceKind_Null, E_SpaceKind_File, E_SpaceKind_FileSystem, E_SpaceKind_HashStoreKey, E_SpaceKind_FirstUserDefined, }; typedef struct E_Space E_Space; struct E_Space { E_SpaceKind kind; union { U64 u64s[3]; struct { U64 u64_0; U128 u128; }; }; }; //////////////////////////////// //~ rjf: Implicit Type Graph Key Types typedef enum E_TypeKeyKind { E_TypeKeyKind_Null, E_TypeKeyKind_Basic, E_TypeKeyKind_Ext, E_TypeKeyKind_Cons, E_TypeKeyKind_Reg, E_TypeKeyKind_RegAlias, } E_TypeKeyKind; typedef struct E_TypeKey E_TypeKey; struct E_TypeKey { E_TypeKeyKind kind; U32 u32[3]; // [0] -> E_TypeKind (Basic, Cons, Ext); Arch (Reg, RegAlias) // [1] -> Type Index In RDI (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) // [2] -> RDI Index (Ext) }; typedef struct E_TypeKeyNode E_TypeKeyNode; struct E_TypeKeyNode { E_TypeKeyNode *next; E_TypeKey v; }; typedef struct E_TypeKeyList E_TypeKeyList; struct E_TypeKeyList { E_TypeKeyNode *first; E_TypeKeyNode *last; U64 count; }; //////////////////////////////// //~ rjf: Generated Code #include "generated/eval.meta.h" //////////////////////////////// //~ rjf: Token Types typedef struct E_Token E_Token; struct E_Token { E_TokenKind kind; Rng1U64 range; }; typedef struct E_TokenChunkNode E_TokenChunkNode; struct E_TokenChunkNode { E_TokenChunkNode *next; E_Token *v; U64 count; U64 cap; }; typedef struct E_TokenChunkList E_TokenChunkList; struct E_TokenChunkList { E_TokenChunkNode *first; E_TokenChunkNode *last; U64 node_count; U64 total_count; }; typedef struct E_TokenArray E_TokenArray; struct E_TokenArray { E_Token *v; U64 count; }; //////////////////////////////// //~ rjf: Evaluation Modes typedef enum E_Mode { E_Mode_Null, E_Mode_Value, E_Mode_Offset, } E_Mode; //////////////////////////////// //~ rjf: Expression Tree Types typedef struct E_Expr E_Expr; struct E_Expr { E_Expr *first; E_Expr *last; E_Expr *next; E_Expr *prev; E_Expr *ref; Rng1U64 range; E_ExprKind kind; E_Mode mode; E_Space space; E_TypeKey type_key; E_Value value; String8 string; String8 qualifier; String8 bytecode; }; typedef struct E_ExprChain E_ExprChain; struct E_ExprChain { E_Expr *first; E_Expr *last; }; typedef struct E_ExprNode E_ExprNode; struct E_ExprNode { E_ExprNode *next; E_Expr *v; }; typedef struct E_ExprList E_ExprList; struct E_ExprList { E_ExprNode *first; E_ExprNode *last; U64 count; }; typedef struct E_Parse E_Parse; struct E_Parse { E_TokenArray tokens; E_Token *last_token; E_Expr *expr; E_Expr *last_expr; E_MsgList msgs; }; //////////////////////////////// //~ rjf: IR Tree Types typedef struct E_IRNode E_IRNode; struct E_IRNode { E_IRNode *first; E_IRNode *last; E_IRNode *next; RDI_EvalOp op; E_Space space; String8 string; E_Value value; }; typedef struct E_IRTreeAndType E_IRTreeAndType; struct E_IRTreeAndType { E_IRNode *root; E_TypeKey type_key; void *user_data; E_Mode mode; B32 auto_hook; E_MsgList msgs; E_IRTreeAndType *prev; }; //////////////////////////////// //~ rjf: Bytecode Interpretation Types typedef struct E_Interpretation E_Interpretation; struct E_Interpretation { E_Value value; E_Space space; E_InterpretationCode code; }; //////////////////////////////// //~ rjf: Evaluation Artifact Bundle typedef struct E_Eval E_Eval; struct E_Eval { E_Key key; E_Key parent_key; String8 string; E_Expr *expr; E_IRTreeAndType irtree; String8 bytecode; E_InterpretationCode code; E_Value value; E_Space space; E_MsgList msgs; }; //////////////////////////////// //~ rjf: Full Extracted Type Information Types typedef enum E_MemberKind { E_MemberKind_Null, E_MemberKind_DataField, E_MemberKind_StaticData, E_MemberKind_Method, E_MemberKind_StaticMethod, E_MemberKind_VirtualMethod, E_MemberKind_VTablePtr, E_MemberKind_Base, E_MemberKind_VirtualBase, E_MemberKind_NestedType, E_MemberKind_Padding, E_MemberKind_COUNT } E_MemberKind; typedef U32 E_TypeFlags; enum { E_TypeFlag_Const = (1<<0), E_TypeFlag_Volatile = (1<<1), E_TypeFlag_Restrict = (1<<2), E_TypeFlag_IsPlainText = (1<<3), E_TypeFlag_IsCodeText = (1<<4), E_TypeFlag_IsPathText = (1<<5), E_TypeFlag_IsNotText = (1<<6), E_TypeFlag_EditableChildren = (1<<7), E_TypeFlag_InheritedByMembers = (1<<8), E_TypeFlag_InheritedByElements = (1<<9), E_TypeFlag_ArrayLikeExpansion = (1<<10), E_TypeFlag_StubSingleLineExpansion = (1<<11), }; typedef struct E_Member E_Member; struct E_Member { E_MemberKind kind; E_TypeKey type_key; String8 name; U64 off; E_TypeKeyList inheritance_key_chain; }; typedef struct E_MemberNode E_MemberNode; struct E_MemberNode { E_MemberNode *next; E_Member v; }; typedef struct E_MemberList E_MemberList; struct E_MemberList { E_MemberNode *first; E_MemberNode *last; U64 count; }; typedef struct E_MemberArray E_MemberArray; struct E_MemberArray { E_Member *v; U64 count; }; typedef struct E_EnumVal E_EnumVal; struct E_EnumVal { String8 name; U64 val; }; typedef struct E_EnumValNode E_EnumValNode; struct E_EnumValNode { E_EnumValNode *next; E_EnumVal v; }; typedef struct E_EnumValList E_EnumValList; struct E_EnumValList { E_EnumValNode *first; E_EnumValNode *last; U64 count; }; typedef struct E_EnumValArray E_EnumValArray; struct E_EnumValArray { E_EnumVal *v; U64 count; }; typedef struct E_IRExt E_IRExt; struct E_IRExt { void *user_data; }; typedef struct E_TypeExpandInfo E_TypeExpandInfo; struct E_TypeExpandInfo { void *user_data; U64 expr_count; }; #define E_TYPE_IREXT_FUNCTION_SIG(name) E_IRExt name(Arena *arena, E_Expr *expr, E_IRTreeAndType *irtree) #define E_TYPE_IREXT_FUNCTION_NAME(name) e_type_irext__##name #define E_TYPE_IREXT_FUNCTION_DEF(name) internal E_TYPE_IREXT_FUNCTION_SIG(E_TYPE_IREXT_FUNCTION_NAME(name)) typedef E_TYPE_IREXT_FUNCTION_SIG(E_TypeIRExtFunctionType); #define E_TYPE_ACCESS_FUNCTION_SIG(name) E_IRTreeAndType name(Arena *arena, E_IRTreeAndType *overridden, E_Expr *expr, E_IRTreeAndType *lhs_irtree) #define E_TYPE_ACCESS_FUNCTION_NAME(name) e_type_access__##name #define E_TYPE_ACCESS_FUNCTION_DEF(name) internal E_TYPE_ACCESS_FUNCTION_SIG(E_TYPE_ACCESS_FUNCTION_NAME(name)) typedef E_TYPE_ACCESS_FUNCTION_SIG(E_TypeAccessFunctionType); #define E_TYPE_EXPAND_INFO_FUNCTION_SIG(name) E_TypeExpandInfo name(Arena *arena, E_Eval eval, String8 filter) #define E_TYPE_EXPAND_INFO_FUNCTION_NAME(name) e_type_expand_info__##name #define E_TYPE_EXPAND_INFO_FUNCTION_DEF(name) internal E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TYPE_EXPAND_INFO_FUNCTION_NAME(name)) typedef E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TypeExpandInfoFunctionType); #define E_TYPE_EXPAND_RANGE_FUNCTION_SIG(name) void name(Arena *arena, void *user_data, E_Eval eval, String8 filter, Rng1U64 idx_range, E_Eval *evals_out) #define E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name) e_type_expand_range__##name #define E_TYPE_EXPAND_RANGE_FUNCTION_DEF(name) internal E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)) typedef E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TypeExpandRangeFunctionType); #define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(name) U64 name(void *user_data, U64 num) #define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name) e_type_expand_id_from_num__##name #define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(name) internal E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name)) typedef E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TypeExpandIDFromNumFunctionType); #define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(name) U64 name(void *user_data, U64 id) #define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name) e_type_expand_num_from_id__##name #define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(name) internal E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name)) typedef E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TypeExpandNumFromIDFunctionType); typedef struct E_TypeExpandRule E_TypeExpandRule; struct E_TypeExpandRule { E_TypeExpandInfoFunctionType *info; E_TypeExpandRangeFunctionType *range; E_TypeExpandIDFromNumFunctionType *id_from_num; E_TypeExpandNumFromIDFunctionType *num_from_id; }; typedef struct E_Type E_Type; struct E_Type { E_TypeKind kind; E_TypeFlags flags; String8 name; U64 byte_size; U64 count; U64 depth; U32 off; Arch arch; E_TypeKey direct_type_key; E_TypeKey owner_type_key; E_TypeKey *param_type_keys; E_Member *members; E_EnumVal *enum_vals; E_Expr **args; E_TypeIRExtFunctionType *irext; E_TypeAccessFunctionType *access; E_TypeExpandRule expand; }; //////////////////////////////// //~ rjf: Constructed Type Types typedef struct E_ConsTypeParams E_ConsTypeParams; struct E_ConsTypeParams { Arch arch; E_TypeKind kind; E_TypeFlags flags; String8 name; E_TypeKey direct_key; U64 count; U64 depth; E_Member *members; E_EnumVal *enum_vals; E_Expr **args; E_TypeIRExtFunctionType *irext; E_TypeAccessFunctionType *access; E_TypeExpandRule expand; }; typedef struct E_ConsTypeNode E_ConsTypeNode; struct E_ConsTypeNode { E_ConsTypeNode *key_next; E_ConsTypeNode *content_next; E_TypeKey key; E_ConsTypeParams params; U64 byte_size; }; typedef struct E_ConsTypeSlot E_ConsTypeSlot; struct E_ConsTypeSlot { E_ConsTypeNode *first; E_ConsTypeNode *last; }; //////////////////////////////// //~ rjf: Modules typedef struct E_Module E_Module; struct E_Module { DI_Key dbgi_key; RDI_Parsed *rdi; Rng1U64 vaddr_range; Arch arch; E_Space space; }; //////////////////////////////// //~ rjf: String -> Num typedef struct E_String2NumMapNode E_String2NumMapNode; struct E_String2NumMapNode { E_String2NumMapNode *order_next; E_String2NumMapNode *hash_next; String8 string; U64 num; }; typedef struct E_String2NumMapNodeArray E_String2NumMapNodeArray; struct E_String2NumMapNodeArray { E_String2NumMapNode **v; U64 count; }; typedef struct E_String2NumMapSlot E_String2NumMapSlot; struct E_String2NumMapSlot { E_String2NumMapNode *first; E_String2NumMapNode *last; }; typedef struct E_String2NumMap E_String2NumMap; struct E_String2NumMap { U64 slots_count; U64 node_count; E_String2NumMapSlot *slots; E_String2NumMapNode *first; E_String2NumMapNode *last; }; //////////////////////////////// //~ rjf: String -> Expr typedef struct E_String2ExprMapNode E_String2ExprMapNode; struct E_String2ExprMapNode { E_String2ExprMapNode *hash_next; String8 string; E_Expr *expr; U64 poison_count; }; typedef struct E_String2ExprMapSlot E_String2ExprMapSlot; struct E_String2ExprMapSlot { E_String2ExprMapNode *first; E_String2ExprMapNode *last; }; typedef struct E_String2ExprMap E_String2ExprMap; struct E_String2ExprMap { U64 slots_count; E_String2ExprMapSlot *slots; }; //////////////////////////////// //~ rjf: String -> Type Key Map Data Structure typedef struct E_String2TypeKeyNode E_String2TypeKeyNode; struct E_String2TypeKeyNode { E_String2TypeKeyNode *next; String8 string; E_TypeKey key; }; typedef struct E_String2TypeKeySlot E_String2TypeKeySlot; struct E_String2TypeKeySlot { E_String2TypeKeyNode *first; E_String2TypeKeyNode *last; }; typedef struct E_String2TypeKeyMap E_String2TypeKeyMap; struct E_String2TypeKeyMap { U64 slots_count; E_String2TypeKeySlot *slots; }; //////////////////////////////// //~ rjf: Type Pattern -> Hook Key Data Structure (Type Views) typedef struct E_PatternPart E_PatternPart; struct E_PatternPart { E_PatternPart *next; String8 string; String8List wildcard_inst_names; }; typedef struct E_Pattern E_Pattern; struct E_Pattern { E_PatternPart *first_part; E_PatternPart *last_part; U64 count; }; typedef struct E_AutoHookWildcardInst E_AutoHookWildcardInst; struct E_AutoHookWildcardInst { E_AutoHookWildcardInst *next; String8 name; E_Expr *inst_expr; }; typedef struct E_AutoHookMatch E_AutoHookMatch; struct E_AutoHookMatch { E_AutoHookMatch *next; E_Expr *expr; E_AutoHookWildcardInst *first_wildcard_inst; E_AutoHookWildcardInst *last_wildcard_inst; }; typedef struct E_AutoHookMatchList E_AutoHookMatchList; struct E_AutoHookMatchList { E_AutoHookMatch *first; E_AutoHookMatch *last; U64 count; }; typedef struct E_AutoHookNode E_AutoHookNode; struct E_AutoHookNode { E_AutoHookNode *hash_next; E_AutoHookNode *pattern_order_next; String8 type_string; E_Pattern type_pattern; String8 expr_string; }; typedef struct E_AutoHookSlot E_AutoHookSlot; struct E_AutoHookSlot { E_AutoHookNode *first; E_AutoHookNode *last; }; typedef struct E_AutoHookMap E_AutoHookMap; struct E_AutoHookMap { U64 slots_count; E_AutoHookSlot *slots; E_AutoHookNode *first_pattern; E_AutoHookNode *last_pattern; }; typedef struct E_AutoHookParams E_AutoHookParams; struct E_AutoHookParams { E_TypeKey type_key; String8 type_pattern; String8 tag_expr_string; }; //////////////////////////////// //~ rjf: Evaluation Context typedef U64 E_SpaceGenFunction(E_Space space); typedef B32 E_SpaceRWFunction(E_Space space, void *out, Rng1U64 offset_range); //- rjf: base context typedef struct E_BaseCtx E_BaseCtx; struct E_BaseCtx { // rjf: instruction pointer info U64 thread_ip_vaddr; U64 thread_ip_voff; E_Space thread_reg_space; Arch thread_arch; U64 thread_unwind_count; // rjf: modules E_Module *modules; U64 modules_count; E_Module *primary_module; // rjf: space hooks E_SpaceGenFunction *space_gen; E_SpaceRWFunction *space_read; E_SpaceRWFunction *space_write; }; //- rjf: ir generation context typedef struct E_IRCtx E_IRCtx; struct E_IRCtx { E_String2NumMap *regs_map; E_String2NumMap *reg_alias_map; E_String2NumMap *locals_map; // (within `primary_module`) E_String2NumMap *member_map; // (within `primary_module`) E_String2ExprMap *macro_map; E_AutoHookMap *auto_hook_map; }; //////////////////////////////// //~ rjf: Core Evaluation Cache Types //- rjf: unpacked type cache typedef struct E_TypeCacheNode E_TypeCacheNode; struct E_TypeCacheNode { E_TypeCacheNode *next; E_TypeKey key; E_Type *type; }; typedef struct E_TypeCacheSlot E_TypeCacheSlot; struct E_TypeCacheSlot { E_TypeCacheNode *first; E_TypeCacheNode *last; }; //- rjf: member lookup cache types typedef struct E_MemberHashNode E_MemberHashNode; struct E_MemberHashNode { E_MemberHashNode *next; U64 member_idx; }; typedef struct E_MemberHashSlot E_MemberHashSlot; struct E_MemberHashSlot { E_MemberHashNode *first; E_MemberHashNode *last; }; typedef struct E_MemberFilterNode E_MemberFilterNode; struct E_MemberFilterNode { E_MemberFilterNode *next; String8 filter; E_MemberArray members_filtered; }; typedef struct E_MemberFilterSlot E_MemberFilterSlot; struct E_MemberFilterSlot { E_MemberFilterNode *first; E_MemberFilterNode *last; }; typedef struct E_MemberCacheNode E_MemberCacheNode; struct E_MemberCacheNode { E_MemberCacheNode *next; E_TypeKey key; E_MemberArray members; U64 member_hash_slots_count; E_MemberHashSlot *member_hash_slots; U64 member_filter_slots_count; E_MemberFilterSlot *member_filter_slots; }; typedef struct E_MemberCacheSlot E_MemberCacheSlot; struct E_MemberCacheSlot { E_MemberCacheNode *first; E_MemberCacheNode *last; }; //- rjf: enum val lookup cache types typedef struct E_EnumValHashNode E_EnumValHashNode; struct E_EnumValHashNode { E_EnumValHashNode *next; U64 val_idx; }; typedef struct E_EnumValHashSlot E_EnumValHashSlot; struct E_EnumValHashSlot { E_EnumValHashNode *first; E_EnumValHashNode *last; }; typedef struct E_EnumValFilterNode E_EnumValFilterNode; struct E_EnumValFilterNode { E_EnumValFilterNode *next; String8 filter; E_EnumValArray vals_filtered; }; typedef struct E_EnumValFilterSlot E_EnumValFilterSlot; struct E_EnumValFilterSlot { E_EnumValFilterNode *first; E_EnumValFilterNode *last; }; typedef struct E_EnumValCacheNode E_EnumValCacheNode; struct E_EnumValCacheNode { E_EnumValCacheNode *next; E_TypeKey key; U64 val_hash_slots_count; E_EnumValHashSlot *val_hash_slots; U64 val_filter_slots_count; E_EnumValFilterSlot *val_filter_slots; }; typedef struct E_EnumValCacheSlot E_EnumValCacheSlot; struct E_EnumValCacheSlot { E_EnumValCacheNode *first; E_EnumValCacheNode *last; }; //- rjf: used expression map typedef struct E_UsedExprNode E_UsedExprNode; struct E_UsedExprNode { E_UsedExprNode *next; E_UsedExprNode *prev; E_Expr *expr; }; typedef struct E_UsedExprSlot E_UsedExprSlot; struct E_UsedExprSlot { E_UsedExprNode *first; E_UsedExprNode *last; }; typedef struct E_UsedExprMap E_UsedExprMap; struct E_UsedExprMap { U64 slots_count; E_UsedExprSlot *slots; }; //- rjf: type key -> auto hook expression list cache typedef struct E_TypeAutoHookCacheNode E_TypeAutoHookCacheNode; struct E_TypeAutoHookCacheNode { E_TypeAutoHookCacheNode *next; E_TypeKey key; E_AutoHookMatchList matches; }; typedef struct E_TypeAutoHookCacheSlot E_TypeAutoHookCacheSlot; struct E_TypeAutoHookCacheSlot { E_TypeAutoHookCacheNode *first; E_TypeAutoHookCacheNode *last; }; typedef struct E_TypeAutoHookCacheMap E_TypeAutoHookCacheMap; struct E_TypeAutoHookCacheMap { U64 slots_count; E_TypeAutoHookCacheSlot *slots; }; //- rjf: string ID cache typedef struct E_StringIDNode E_StringIDNode; struct E_StringIDNode { E_StringIDNode *hash_next; E_StringIDNode *id_next; U64 id; String8 string; }; typedef struct E_StringIDSlot E_StringIDSlot; struct E_StringIDSlot { E_StringIDNode *first; E_StringIDNode *last; }; typedef struct E_StringIDMap E_StringIDMap; struct E_StringIDMap { U64 id_slots_count; E_StringIDSlot *id_slots; U64 hash_slots_count; E_StringIDSlot *hash_slots; }; //- rjf: cache evaluation bundles typedef U32 E_CacheBundleFlags; enum { E_CacheBundleFlag_Parse = (1<<0), E_CacheBundleFlag_IRTree = (1<<1), E_CacheBundleFlag_Bytecode = (1<<2), E_CacheBundleFlag_Interpret = (1<<3), }; typedef struct E_CacheBundle E_CacheBundle; struct E_CacheBundle { E_CacheBundleFlags flags; E_Key key; E_Key parent_key; String8 string; E_Parse parse; E_IRTreeAndType irtree; String8 bytecode; E_Interpretation interpretation; U64 space_gen; E_MsgList msgs; }; typedef struct E_CacheNode E_CacheNode; struct E_CacheNode { E_CacheNode *string_next; E_CacheNode *key_next; E_CacheBundle bundle; }; typedef struct E_CacheLookup E_CacheLookup; struct E_CacheLookup { E_CacheNode *node; U64 hash; }; typedef struct E_CacheSlot E_CacheSlot; struct E_CacheSlot { E_CacheNode *first; E_CacheNode *last; }; //- rjf: parent stack typedef struct E_CacheParentNode E_CacheParentNode; struct E_CacheParentNode { E_CacheParentNode *next; E_Key key; }; //- rjf: main cache state type typedef struct E_Cache E_Cache; struct E_Cache { //- rjf: root arena Arena *arena; U64 arena_eval_start_pos; //- rjf: key ID generation counter U64 key_id_gen; //- rjf: key -> bundle, string -> bundle tables U64 key_slots_count; E_CacheSlot *key_slots; U64 string_slots_count; E_CacheSlot *string_slots; //- rjf: parent stack E_CacheParentNode *top_parent_node; E_CacheParentNode *free_parent_node; //- rjf: unpacked context RDI_Procedure *thread_ip_procedure; //- rjf: [types] JIT-constructed types tables U64 cons_id_gen; U64 cons_content_slots_count; U64 cons_key_slots_count; E_ConsTypeSlot *cons_content_slots; E_ConsTypeSlot *cons_key_slots; //- rjf: [types] build-in constructed type keys E_TypeKey file_type_key; E_TypeKey folder_type_key; //- rjf: [types] member cache table U64 member_cache_slots_count; E_MemberCacheSlot *member_cache_slots; //- rjf: [types] enum val cache table U64 enum_val_cache_slots_count; E_EnumValCacheSlot *enum_val_cache_slots; //- rjf: [types] unpacked type cache U64 type_cache_slots_count; E_TypeCacheSlot *type_cache_slots; //- rjf: [ir] ir gen options B32 disallow_autohooks; B32 disallow_chained_fastpaths; E_AutoHookWildcardInst *first_wildcard_inst; E_AutoHookWildcardInst *last_wildcard_inst; //- rjf: [ir] ir caches E_UsedExprMap *used_expr_map; E_TypeAutoHookCacheMap *type_auto_hook_cache_map; //- rjf: [ir] string ID cache U64 string_id_gen; E_StringIDMap *string_id_map; }; //////////////////////////////// //~ rjf: Generated Code #include "eval/generated/eval.meta.h" //////////////////////////////// //~ rjf: Globals read_only global E_String2NumMap e_string2num_map_nil = {0}; read_only global E_String2ExprMap e_string2expr_map_nil = {0}; read_only global E_Expr e_expr_nil = {&e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil}; read_only global E_IRNode e_irnode_nil = {&e_irnode_nil, &e_irnode_nil, &e_irnode_nil}; read_only global E_Eval e_eval_nil = {{0}, {0}, {0}, &e_expr_nil, {&e_irnode_nil}}; read_only global E_Module e_module_nil = {{0}, &rdi_parsed_nil}; read_only global E_CacheBundle e_cache_bundle_nil = {0, {0}, {0}, {0}, {{0}, 0, &e_expr_nil, &e_expr_nil}, {&e_irnode_nil}}; thread_static E_BaseCtx *e_base_ctx = 0; thread_static E_IRCtx *e_ir_ctx = 0; thread_static E_Cache *e_cache = 0; //////////////////////////////// //~ rjf: Basic Helpers internal U64 e_hash_from_string(U64 seed, String8 string); #define e_value_u64(v) (E_Value){.u64 = (v)} //////////////////////////////// //~ rjf: Expr Kind Enum Functions internal RDI_EvalOp e_opcode_from_expr_kind(E_ExprKind kind); internal B32 e_expr_kind_is_comparison(E_ExprKind kind); //////////////////////////////// //~ rjf: Key Type Functions internal B32 e_key_match(E_Key a, E_Key b); internal E_Key e_key_zero(void); //////////////////////////////// //~ rjf: Type Key Type Functions internal void e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key); internal void e_type_key_list_push_front(Arena *arena, E_TypeKeyList *list, E_TypeKey key); internal E_TypeKeyList e_type_key_list_copy(Arena *arena, E_TypeKeyList *src); //////////////////////////////// //~ rjf: Message Functions internal void e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, String8 text); internal void e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, char *fmt, ...); internal void e_msg_list_concat_in_place(E_MsgList *dst, E_MsgList *to_push); internal E_MsgList e_msg_list_copy(Arena *arena, E_MsgList *src); //////////////////////////////// //~ rjf: Space Functions internal E_Space e_space_make(E_SpaceKind kind); internal B32 e_space_match(E_Space a, E_Space b); //////////////////////////////// //~ rjf: Map Functions //- rjf: string -> num internal E_String2NumMap e_string2num_map_make(Arena *arena, U64 slot_count); internal void e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num); internal U64 e_num_from_string(E_String2NumMap *map, String8 string); internal E_String2NumMapNodeArray e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map); internal int e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b); internal void e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array); //- rjf: string -> expr internal E_String2ExprMap e_string2expr_map_make(Arena *arena, U64 slot_count); internal void e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr); internal void e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string); internal void e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string); internal E_Expr *e_string2expr_map_lookup(E_String2ExprMap *map, String8 string); //- rjf: string -> type-key internal E_String2TypeKeyMap e_string2typekey_map_make(Arena *arena, U64 slots_count); internal void e_string2typekey_map_insert(Arena *arena, E_String2TypeKeyMap *map, String8 string, E_TypeKey key); internal E_TypeKey e_string2typekey_map_lookup(E_String2TypeKeyMap *map, String8 string); //- rjf: auto hooks internal E_AutoHookMap e_auto_hook_map_make(Arena *arena, U64 slots_count); internal void e_auto_hook_map_insert_new_(Arena *arena, E_AutoHookMap *map, E_AutoHookParams *params); #define e_auto_hook_map_insert_new(arena, map, ...) e_auto_hook_map_insert_new_((arena), (map), &(E_AutoHookParams){.type_key = zero_struct, __VA_ARGS__}) //////////////////////////////// //~ rjf: Debug-Info-Driven Map Building Functions internal E_String2NumMap *e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); internal E_String2NumMap *e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); //////////////////////////////// //~ rjf: Cache Creation & Selection internal E_Cache *e_cache_alloc(void); internal void e_cache_release(E_Cache *cache); internal void e_select_cache(E_Cache *cache); //////////////////////////////// //~ rjf: Evaluation Phase Markers internal void e_select_base_ctx(E_BaseCtx *ctx); internal void e_select_ir_ctx(E_IRCtx *ctx); //////////////////////////////// //~ rjf: Base Cache Accessing Functions // // The cache uses a unique keying mechanism to refer to some evaluation at // many layers of analysis. // // key // ________________________________________________ // / / | \ // text -> expression -> ir tree and type -> interpretation result // // Each one of these calls refers to one stage in this pipeline. The cache will // only compute what is needed on-demand. If you ask for the full evaluation, // which is a bundle of artifacts at all layers of analysis, then all stages // will be computed. // // One wrinkle here is that the IR tree generation stage is implicitly // parameterized by the "overridden" IR tree - this is to enable "parent // expressions", e.g. `$.x`, or simply `x` assuming `foo` has such a member, // in the context of some struct `foo` evaluates to the same thing as `foo.x`. // So even though the primary API shape is based around singular keys, the // "parent key stack" also implicitly parameterizes all of these (partly // because it is not relevant in 99% of cases). //- rjf: parent key stack internal E_Key e_parent_key_push(E_Key key); internal E_Key e_parent_key_pop(void); #define E_ParentKey(key) DeferLoop(e_parent_key_push(key), e_parent_key_pop()) //- rjf: key construction internal E_Key e_key_from_string(String8 string); internal E_Key e_key_from_stringf(char *fmt, ...); internal E_Key e_key_from_expr(E_Expr *expr); //- rjf: base key -> bundle helper internal E_CacheBundle *e_cache_bundle_from_key(E_Key key); //- rjf: bundle -> pipeline stage outputs internal E_Parse e_parse_from_bundle(E_CacheBundle *bundle); internal E_IRTreeAndType e_irtree_from_bundle(E_CacheBundle *bundle); internal String8 e_bytecode_from_bundle(E_CacheBundle *bundle); internal E_Interpretation e_interpretation_from_bundle(E_CacheBundle *bundle); #define e_parse_from_key(key) e_parse_from_bundle(e_cache_bundle_from_key(key)) #define e_irtree_from_key(key) e_irtree_from_bundle(e_cache_bundle_from_key(key)) #define e_bytecode_from_key(key) e_bytecode_from_bundle(e_cache_bundle_from_key(key)) #define e_interpretation_from_key(key) e_interpretation_from_bundle(e_cache_bundle_from_key(key)) //- rjf: key -> full expression string internal String8 e_full_expr_string_from_key(Arena *arena, E_Key key); //- rjf: comprehensive bundle internal E_Eval e_eval_from_bundle(E_CacheBundle *bundle); internal E_Eval e_value_eval_from_eval(E_Eval eval); #define e_eval_from_key(key) e_eval_from_bundle(e_cache_bundle_from_key(key)) #define e_value_from_key(key) (e_value_eval_from_eval(e_eval_from_key(key)).value) //- rjf: string-based helpers #define e_parse_from_string(string) e_parse_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) #define e_irtree_from_string(string) e_irtree_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) #define e_bytecode_from_string(string) e_bytecode_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) #define e_interpretation_from_string(string) e_interpretation_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) #define e_eval_from_string(string) e_eval_from_key(e_key_from_string(string)) #define e_eval_from_stringf(...) e_eval_from_key(e_key_from_stringf(__VA_ARGS__)) #define e_value_from_string(string) e_value_eval_from_eval(e_eval_from_string(string)).value #define e_value_from_stringf(...) e_value_eval_from_eval(e_eval_from_stringf(__VA_ARGS__)).value //- rjf: expr-based helpers #define e_eval_from_expr(expr) e_eval_from_key(e_key_from_expr(expr)) #define e_value_from_expr(expr) e_value_eval_from_eval(e_eval_from_expr(expr)).value //- rjf: type key -> auto hooks internal E_AutoHookMatchList e_push_auto_hook_matches_from_type_key(Arena *arena, E_TypeKey type_key); internal E_AutoHookMatchList e_auto_hook_matches_from_type_key(E_TypeKey type_key); //- rjf: string IDs internal U64 e_id_from_string(String8 string); internal String8 e_string_from_id(U64 id); //////////////////////////////// //~ rjf: Key Extension Functions internal E_Key e_key_wrap(E_Key key, String8 string); internal E_Key e_key_wrapf(E_Key key, char *fmt, ...); //- rjf: eval-based helpers #define e_eval_wrap(eval, string) e_eval_from_key(e_key_wrap((eval).key, (string))) #define e_eval_wrapf(eval, ...) e_eval_from_key(e_key_wrapf((eval).key, __VA_ARGS__)) //////////////////////////////// //~ rjf: Eval Info Extraction internal Rng1U64 e_range_from_eval(E_Eval eval); //////////////////////////////// //~ rjf: Debug Functions internal String8 e_debug_log_from_expr_string(Arena *arena, String8 string); #endif // EVAL_CORE_H