8484 not_local_var_cache map [string ]bool // per-function negative cache for get_local_var_c_type
8585 resolved_module_names map [string ]string // per-function cache for resolve_module_name
8686 cached_env_scopes map [string ]voidptr // cache of env_scope results (avoids repeated locking)
87+ struct_field_lookup_cache map [string ]string
88+ struct_field_lookup_miss map [string ]bool
89+ struct_type_lookup_cache map [string ]types.Struct
90+ struct_type_lookup_miss map [string ]bool
91+ struct_decl_info_cache map [string ]StructDeclInfo
92+ struct_decl_info_miss map [string ]bool
93+ alias_base_lookup_cache map [string ]string
94+ alias_base_lookup_miss map [string ]bool
8795
8896 const_exprs map [string ]string // const name → C expression string (for inlining)
8997 const_types map [string ]string // const name → C type string
@@ -217,16 +225,24 @@ pub fn Gen.new_with_env(files []ast.File, env &types.Environment) &Gen {
217225
218226pub fn Gen .new_with_env_and_pref (files []ast.File, env & types.Environment, p & pref.Preferences) & Gen {
219227 return & Gen{
220- files: files
221- env: unsafe { env }
222- pref: unsafe { p }
223- sb: strings.new_builder (10_000 )
224- fn_param_is_ptr: map [string ][]bool {}
225- fn_param_types: map [string ][]string {}
226- fn_return_types: map [string ]string {}
227- runtime_local_types: map [string ]string {}
228- cur_fn_returned_idents: map [string ]bool {}
229- active_generic_types: map [string ]types.Type{}
228+ files: files
229+ env: unsafe { env }
230+ pref: unsafe { p }
231+ sb: strings.new_builder (10_000 )
232+ fn_param_is_ptr: map [string ][]bool {}
233+ fn_param_types: map [string ][]string {}
234+ fn_return_types: map [string ]string {}
235+ runtime_local_types: map [string ]string {}
236+ cur_fn_returned_idents: map [string ]bool {}
237+ active_generic_types: map [string ]types.Type{}
238+ struct_field_lookup_cache: map [string ]string {}
239+ struct_field_lookup_miss: map [string ]bool {}
240+ struct_type_lookup_cache: map [string ]types.Struct{}
241+ struct_type_lookup_miss: map [string ]bool {}
242+ struct_decl_info_cache: map [string ]StructDeclInfo{}
243+ struct_decl_info_miss: map [string ]bool {}
244+ alias_base_lookup_cache: map [string ]string {}
245+ alias_base_lookup_miss: map [string ]bool {}
230246
231247 fixed_array_fields: map [string ]bool {}
232248 fixed_array_field_elem: map [string ]string {}
@@ -1080,6 +1096,11 @@ fn (g &Gen) should_skip_plain_v_fallback_fn(fn_key string) bool {
10801096
10811097// gen_finalize runs post-pass-5 finalization and returns the complete C source string.
10821098pub fn (mut g Gen) gen_finalize () string {
1099+ stats_enabled := g.cgen_stats_enabled ()
1100+ stats_scope := g.cgen_stats_scope_label ()
1101+ mut stats_sw := time.new_stopwatch ()
1102+ mut stage_start := stats_sw.elapsed ()
1103+
10831104 // Generate test runner main if this is a test file (has test_ functions but no main)
10841105 // Skip when generating cached module sources (cache_bundle_name is set) - main belongs only in the main module source
10851106 if ! g.has_main && g.test_fn_names.len > 0 && g.cache_bundle_name.len == 0 {
@@ -1126,11 +1147,15 @@ pub fn (mut g Gen) gen_finalize() string {
11261147 g.sb.writeln ('\t return 0;' )
11271148 g.sb.writeln ('}' )
11281149 }
1150+ stage_start = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start,
1151+ 'finalize test main' )
11291152
11301153 g.emit_missing_array_contains_fallbacks ()
11311154 g.emit_missing_runtime_fallbacks ()
11321155 g.emit_cached_module_init_function ()
11331156 g.emit_exported_const_symbols ()
1157+ stage_start = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start,
1158+ 'finalize fallbacks' )
11341159
11351160 mut out := ''
11361161 // Emit deferred str macros for late-discovered generic struct instances.
@@ -1142,9 +1167,13 @@ pub fn (mut g Gen) gen_finalize() string {
11421167 g.late_struct_defs << '#define ${inst_name} __str(v) ((string){.str = "${label} ", .len = ${label.len} , .is_lit = 1})\n #define ${inst_name} _str(v) ${inst_name} __str(v)\n '
11431168 }
11441169 }
1170+ stage_start = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start,
1171+ 'finalize late str macros' )
11451172 if g.anon_fn_defs.len > 0 || g.spawn_wrapper_defs.len > 0 || g.trampoline_defs.len > 0
11461173 || g.late_struct_defs.len > 0 || g.pending_late_body_keys.len > 0 {
11471174 full := g.sb.str ()
1175+ stage_start = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start,
1176+ 'finalize snapshot' )
11481177 mut out_sb := strings.new_builder (full.len + 4096 )
11491178 unsafe { out_sb.write_ptr (full.str, g.pass5_ start_pos) }
11501179 // Late-discovered generic struct definitions (discovered during setup/pass 4 codegen)
@@ -1183,12 +1212,20 @@ pub fn (mut g Gen) gen_finalize() string {
11831212 } else {
11841213 out = g.sb.str ()
11851214 }
1215+ _ = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start, 'finalize output' )
11861216 return out
11871217}
11881218
11891219// gen_pass5 generates Pass 5 (function bodies, globals, etc.) sequentially.
11901220fn (mut g Gen) gen_pass5 () {
1221+ stats_enabled := g.cgen_stats_enabled ()
1222+ stats_scope := g.cgen_stats_scope_label ()
1223+ mut stats_sw := time.new_stopwatch ()
1224+ mut stage_start := stats_sw.elapsed ()
1225+
11911226 g.pass5_start_pos = g.sb.len
1227+ g.struct_field_lookup_cache = map [string ]string {}
1228+ g.struct_field_lookup_miss = map [string ]bool {}
11921229 g.collect_force_emit_str_fns ()
11931230 // Pre-pass: emit extern forward declarations for all globals across all modules
11941231 for file in g.files {
@@ -1203,13 +1240,18 @@ fn (mut g Gen) gen_pass5() {
12031240 }
12041241 g.gen_file (file)
12051242 }
1243+ stage_start = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start,
1244+ 'pass 5 files' )
12061245 g.gen_pass5_post ()
1246+ _ = g.mark_cgen_step (stats_enabled, stats_scope, mut stats_sw, stage_start, 'pass 5 post' )
12071247}
12081248
12091249// gen_pass5_pre runs Pass 5 sequential pre-work: extern globals and extern consts
12101250// for non-emitted modules. Returns the list of file indices that need gen_file().
12111251pub fn (mut g Gen) gen_pass5_pre () []int {
12121252 g.pass5_start_pos = g.sb.len
1253+ g.struct_field_lookup_cache = map [string ]string {}
1254+ g.struct_field_lookup_miss = map [string ]bool {}
12131255 g.collect_force_emit_str_fns ()
12141256 for file in g.files {
12151257 g.set_file_module (file)
@@ -1353,6 +1395,14 @@ pub fn (g &Gen) new_pass5_worker(file_indices []int, worker_id int) &Gen {
13531395 resolved_module_names: map [string ]string {}
13541396 cur_fn_mut_params: map [string ]bool {}
13551397 cached_env_scopes: map [string ]voidptr {}
1398+ struct_field_lookup_cache: map [string ]string {}
1399+ struct_field_lookup_miss: map [string ]bool {}
1400+ struct_type_lookup_cache: map [string ]types.Struct{}
1401+ struct_type_lookup_miss: map [string ]bool {}
1402+ struct_decl_info_cache: map [string ]StructDeclInfo{}
1403+ struct_decl_info_miss: map [string ]bool {}
1404+ alias_base_lookup_cache: map [string ]string {}
1405+ alias_base_lookup_miss: map [string ]bool {}
13561406 needed_interface_wrappers: map [string ]bool {}
13571407 needed_ierror_wrapper_bases: map [string ]bool {}
13581408 spawned_fns: map [string ]bool {}
0 commit comments