@@ -46,7 +46,8 @@ struct IndexedMethodTable {
4646 ctor_parameters : TokenStream ,
4747 pre_init_code : TokenStream ,
4848 fptr_type : TokenStream ,
49- method_inits : Vec < MethodInit > ,
49+ fetch_fptr_type : TokenStream ,
50+ method_init_groups : Vec < MethodInitGroup > ,
5051 lazy_key_type : TokenStream ,
5152 lazy_method_init : TokenStream ,
5253 named_accessors : Vec < AccessorMethod > ,
@@ -70,6 +71,38 @@ impl ToTokens for MethodInit {
7071
7172// ----------------------------------------------------------------------------------------------------------------------------------------------
7273
74+ #[ cfg_attr( feature = "codegen-lazy-fptrs" , allow( dead_code) ) ]
75+ struct MethodInitGroup {
76+ class_name : Ident ,
77+ class_var_init : Option < TokenStream > ,
78+ method_inits : Vec < MethodInit > ,
79+ }
80+
81+ impl MethodInitGroup {
82+ fn new ( class_godot_name : & str , class_var : Ident , method_inits : Vec < MethodInit > ) -> Self {
83+ Self {
84+ class_name : ident ( class_godot_name) ,
85+ // Only create class variable if any methods have been added.
86+ class_var_init : if method_inits. is_empty ( ) {
87+ None
88+ } else {
89+ let initializer_expr = util:: make_sname_ptr ( class_godot_name) ;
90+ Some ( quote ! {
91+ let #class_var = #initializer_expr;
92+ } )
93+ } ,
94+ method_inits,
95+ }
96+ }
97+
98+ #[ cfg( not( feature = "codegen-lazy-fptrs" ) ) ]
99+ fn function_name ( & self ) -> Ident {
100+ format_ident ! ( "load_{}_methods" , self . class_name)
101+ }
102+ }
103+
104+ // ----------------------------------------------------------------------------------------------------------------------------------------------
105+
73106struct AccessorMethod {
74107 name : Ident ,
75108 index : usize ,
@@ -273,7 +306,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
273306 ctor_parameters,
274307 pre_init_code,
275308 fptr_type,
276- mut method_inits,
309+ fetch_fptr_type,
310+ method_init_groups,
277311 lazy_key_type : _,
278312 lazy_method_init : _,
279313 named_accessors,
@@ -287,27 +321,59 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
287321
288322 // Make sure methods are complete and in order of index.
289323 assert_eq ! (
290- method_inits. len( ) ,
324+ method_init_groups
325+ . iter( )
326+ . map( |group| group. method_inits. len( ) )
327+ . sum:: <usize >( ) ,
291328 method_count,
292329 "number of methods does not match count"
293330 ) ;
294- method_inits. sort_by_key ( |init| init. index ) ;
331+ // method_inits.sort_by_key(|init| init.index);
295332
296- if let Some ( last) = method_inits . last ( ) {
333+ if let Some ( last) = method_init_groups . last ( ) {
297334 assert_eq ! (
298- last. index,
335+ last. method_inits . last ( ) . unwrap ( ) . index,
299336 method_count - 1 ,
300337 "last method should have highest index"
301338 ) ;
302339 } else {
303340 assert_eq ! ( method_count, 0 , "empty method table should have count 0" ) ;
304341 }
305342
343+ let method_load_inits = method_init_groups. iter ( ) . map ( |group| {
344+ let func = group. function_name ( ) ;
345+ quote ! {
346+ #func( & mut function_pointers, string_names, fetch_fptr) ;
347+ }
348+ } ) ;
349+
350+ let method_load_decls = method_init_groups. iter ( ) . map ( |group| {
351+ let func = group. function_name ( ) ;
352+ let method_inits = & group. method_inits ;
353+ let class_var_init = & group. class_var_init ;
354+
355+ quote ! {
356+ fn #func(
357+ function_pointers: & mut Vec <#fptr_type>,
358+ string_names: & mut crate :: StringCache ,
359+ fetch_fptr: FetchFn ,
360+ ) {
361+ #class_var_init
362+
363+ #(
364+ function_pointers. push( #method_inits) ;
365+ ) *
366+ }
367+ }
368+ } ) ;
369+
306370 // Assumes that inits already have a trailing comma.
307371 // This is necessary because some generators emit multiple lines (statements) per element.
308372 quote ! {
309373 #imports
310374
375+ type FetchFn = <#fetch_fptr_type as crate :: Inner >:: FnPtr ;
376+
311377 pub struct #table_name {
312378 function_pointers: Vec <#fptr_type>,
313379 }
@@ -322,11 +388,10 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
322388 ) -> Self {
323389 #pre_init_code
324390
325- Self {
326- function_pointers: vec![
327- #( #method_inits ) *
328- ]
329- }
391+ let mut function_pointers = Vec :: with_capacity( #method_count) ;
392+ #( #method_load_inits ) *
393+
394+ Self { function_pointers }
330395 }
331396
332397 #[ inline( always) ]
@@ -339,6 +404,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
339404
340405 #named_method_api
341406 }
407+
408+ #( #method_load_decls ) *
342409 }
343410}
344411
@@ -350,7 +417,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
350417 ctor_parameters : _,
351418 pre_init_code : _,
352419 fptr_type,
353- method_inits : _,
420+ fetch_fptr_type : _,
421+ method_init_groups : _,
354422 lazy_key_type,
355423 lazy_method_init,
356424 named_accessors,
@@ -819,7 +887,8 @@ fn make_class_method_table(
819887 } ,
820888 pre_init_code : TokenStream :: new ( ) , // late-init, depends on class string names
821889 fptr_type : quote ! { crate :: ClassMethodBind } ,
822- method_inits : vec ! [ ] ,
890+ fetch_fptr_type : quote ! { crate :: GDExtensionInterfaceClassdbGetMethodBind } ,
891+ method_init_groups : vec ! [ ] ,
823892 lazy_key_type : quote ! { crate :: lazy_keys:: ClassMethodKey } ,
824893 lazy_method_init : quote ! {
825894 let get_method_bind = crate :: interface_fn!( classdb_get_method_bind) ;
@@ -837,7 +906,6 @@ fn make_class_method_table(
837906 method_count : 0 ,
838907 } ;
839908
840- let mut class_sname_decls = Vec :: new ( ) ;
841909 for class in api. classes . iter ( ) {
842910 let class_ty = TyName :: from_godot ( & class. name ) ;
843911 if special_cases:: is_class_deleted ( & class_ty)
@@ -847,25 +915,11 @@ fn make_class_method_table(
847915 continue ;
848916 }
849917
850- let class_var = format_ident ! ( "sname_{}" , & class. name) ;
851- let initializer_expr = util:: make_sname_ptr ( & class. name ) ;
852-
853- let prev_method_count = table. method_count ;
854- populate_class_methods ( & mut table, class, & class_ty, & class_var, ctx) ;
855- if table. method_count > prev_method_count {
856- // Only create class variable if any methods have been added.
857- class_sname_decls. push ( quote ! {
858- let #class_var = #initializer_expr;
859- } ) ;
860- }
861-
862- table. class_count += 1 ;
918+ populate_class_methods ( & mut table, class, & class_ty, ctx) ;
863919 }
864920
865921 table. pre_init_code = quote ! {
866- let get_method_bind = interface. classdb_get_method_bind. expect( "classdb_get_method_bind absent" ) ;
867-
868- #( #class_sname_decls ) *
922+ let fetch_fptr = interface. classdb_get_method_bind. expect( "classdb_get_method_bind absent" ) ;
869923 } ;
870924
871925 make_method_table ( table)
@@ -916,16 +970,16 @@ fn make_builtin_method_table(
916970 string_names: & mut crate :: StringCache ,
917971 } ,
918972 pre_init_code : quote ! {
919- use crate as sys;
920- let get_builtin_method = interface. variant_get_ptr_builtin_method. expect( "variant_get_ptr_builtin_method absent" ) ;
973+ let fetch_fptr = interface. variant_get_ptr_builtin_method. expect( "variant_get_ptr_builtin_method absent" ) ;
921974 } ,
922975 fptr_type : quote ! { crate :: BuiltinMethodBind } ,
923- method_inits : vec ! [ ] ,
976+ fetch_fptr_type : quote ! { crate :: GDExtensionInterfaceVariantGetPtrBuiltinMethod } ,
977+ method_init_groups : vec ! [ ] ,
924978 lazy_key_type : quote ! { crate :: lazy_keys:: BuiltinMethodKey } ,
925979 lazy_method_init : quote ! {
926- let get_builtin_method = crate :: interface_fn!( variant_get_ptr_builtin_method) ;
980+ let fetch_fptr = crate :: interface_fn!( variant_get_ptr_builtin_method) ;
927981 crate :: load_builtin_method(
928- get_builtin_method ,
982+ fetch_fptr ,
929983 & mut inner. string_cache,
930984 key. variant_type. sys( ) ,
931985 key. variant_type_str,
@@ -945,7 +999,6 @@ fn make_builtin_method_table(
945999 } ;
9461000
9471001 populate_builtin_methods ( & mut table, builtin, & builtin_type. type_names , ctx) ;
948- table. class_count += 1 ;
9491002 }
9501003
9511004 make_method_table ( table)
@@ -955,9 +1008,11 @@ fn populate_class_methods(
9551008 table : & mut IndexedMethodTable ,
9561009 class : & Class ,
9571010 class_ty : & TyName ,
958- class_var : & Ident ,
9591011 ctx : & mut Context ,
9601012) {
1013+ let class_var = format_ident ! ( "sname_{}" , & class. name) ;
1014+ let mut method_inits = vec ! [ ] ;
1015+
9611016 for method in option_as_slice ( & class. methods ) {
9621017 if special_cases:: is_deleted ( class_ty, method, ctx) {
9631018 continue ;
@@ -969,9 +1024,9 @@ fn populate_class_methods(
9691024 class_ty : class_ty. clone ( ) ,
9701025 method_name : method. name . clone ( ) ,
9711026 } ) ;
972- let method_init = make_class_method_init ( method, class_var, class_ty) ;
9731027
974- table. method_inits . push ( MethodInit { method_init, index } ) ;
1028+ let method_init = make_class_method_init ( method, & class_var, class_ty) ;
1029+ method_inits. push ( MethodInit { method_init, index } ) ;
9751030 table. method_count += 1 ;
9761031
9771032 // If requested, add a named accessor for this method.
@@ -993,6 +1048,13 @@ fn populate_class_methods(
9931048 } ) ;
9941049 }
9951050 }
1051+
1052+ table. method_init_groups . push ( MethodInitGroup :: new (
1053+ & class_ty. godot_ty ,
1054+ class_var,
1055+ method_inits,
1056+ ) ) ;
1057+ table. class_count += 1 ;
9961058}
9971059
9981060fn populate_builtin_methods (
@@ -1001,6 +1063,9 @@ fn populate_builtin_methods(
10011063 builtin_name : & TypeNames ,
10021064 ctx : & mut Context ,
10031065) {
1066+ let class_var = format_ident ! ( "sname_{}" , & builtin_class. name) ;
1067+ let mut method_inits = vec ! [ ] ;
1068+
10041069 for method in option_as_slice ( & builtin_class. methods ) {
10051070 let builtin_ty = TyName :: from_godot ( & builtin_class. name ) ;
10061071 if special_cases:: is_builtin_deleted ( & builtin_ty, method) {
@@ -1013,8 +1078,7 @@ fn populate_builtin_methods(
10131078 } ) ;
10141079
10151080 let method_init = make_builtin_method_init ( method, builtin_name, index) ;
1016-
1017- table. method_inits . push ( MethodInit { method_init, index } ) ;
1081+ method_inits. push ( MethodInit { method_init, index } ) ;
10181082 table. method_count += 1 ;
10191083
10201084 // If requested, add a named accessor for this method.
@@ -1038,6 +1102,13 @@ fn populate_builtin_methods(
10381102 } ) ;
10391103 }
10401104 }
1105+
1106+ table. method_init_groups . push ( MethodInitGroup :: new (
1107+ & builtin_class. name ,
1108+ class_var,
1109+ method_inits,
1110+ ) ) ;
1111+ table. class_count += 1 ;
10411112}
10421113
10431114fn make_class_method_init (
@@ -1057,7 +1128,14 @@ fn make_class_method_init(
10571128
10581129 // Could reuse lazy key, but less code like this -> faster parsing.
10591130 quote ! {
1060- crate :: load_class_method( get_method_bind, string_names, Some ( #class_var) , #class_name_str, #method_name_str, #hash) ,
1131+ crate :: load_class_method(
1132+ fetch_fptr,
1133+ string_names,
1134+ Some ( #class_var) ,
1135+ #class_name_str,
1136+ #method_name_str,
1137+ #hash
1138+ ) ,
10611139 }
10621140}
10631141
@@ -1083,9 +1161,9 @@ fn make_builtin_method_init(
10831161 {
10841162 let _ = #index;
10851163 crate :: load_builtin_method(
1086- get_builtin_method ,
1164+ fetch_fptr ,
10871165 string_names,
1088- sys :: #variant_type,
1166+ crate :: #variant_type,
10891167 #variant_type_str,
10901168 #method_name_str,
10911169 #hash
0 commit comments