@@ -46,7 +46,8 @@ struct IndexedMethodTable {
46
46
ctor_parameters : TokenStream ,
47
47
pre_init_code : TokenStream ,
48
48
fptr_type : TokenStream ,
49
- method_inits : Vec < MethodInit > ,
49
+ fetch_fptr_type : TokenStream ,
50
+ method_init_groups : Vec < MethodInitGroup > ,
50
51
lazy_key_type : TokenStream ,
51
52
lazy_method_init : TokenStream ,
52
53
named_accessors : Vec < AccessorMethod > ,
@@ -70,6 +71,38 @@ impl ToTokens for MethodInit {
70
71
71
72
// ----------------------------------------------------------------------------------------------------------------------------------------------
72
73
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
+
73
106
struct AccessorMethod {
74
107
name : Ident ,
75
108
index : usize ,
@@ -273,7 +306,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
273
306
ctor_parameters,
274
307
pre_init_code,
275
308
fptr_type,
276
- mut method_inits,
309
+ fetch_fptr_type,
310
+ method_init_groups,
277
311
lazy_key_type : _,
278
312
lazy_method_init : _,
279
313
named_accessors,
@@ -287,27 +321,59 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
287
321
288
322
// Make sure methods are complete and in order of index.
289
323
assert_eq ! (
290
- method_inits. len( ) ,
324
+ method_init_groups
325
+ . iter( )
326
+ . map( |group| group. method_inits. len( ) )
327
+ . sum:: <usize >( ) ,
291
328
method_count,
292
329
"number of methods does not match count"
293
330
) ;
294
- method_inits. sort_by_key ( |init| init. index ) ;
331
+ // method_inits.sort_by_key(|init| init.index);
295
332
296
- if let Some ( last) = method_inits . last ( ) {
333
+ if let Some ( last) = method_init_groups . last ( ) {
297
334
assert_eq ! (
298
- last. index,
335
+ last. method_inits . last ( ) . unwrap ( ) . index,
299
336
method_count - 1 ,
300
337
"last method should have highest index"
301
338
) ;
302
339
} else {
303
340
assert_eq ! ( method_count, 0 , "empty method table should have count 0" ) ;
304
341
}
305
342
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
+
306
370
// Assumes that inits already have a trailing comma.
307
371
// This is necessary because some generators emit multiple lines (statements) per element.
308
372
quote ! {
309
373
#imports
310
374
375
+ type FetchFn = <#fetch_fptr_type as crate :: Inner >:: FnPtr ;
376
+
311
377
pub struct #table_name {
312
378
function_pointers: Vec <#fptr_type>,
313
379
}
@@ -322,11 +388,10 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
322
388
) -> Self {
323
389
#pre_init_code
324
390
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 }
330
395
}
331
396
332
397
#[ inline( always) ]
@@ -339,6 +404,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
339
404
340
405
#named_method_api
341
406
}
407
+
408
+ #( #method_load_decls ) *
342
409
}
343
410
}
344
411
@@ -350,7 +417,8 @@ fn make_method_table(info: IndexedMethodTable) -> TokenStream {
350
417
ctor_parameters : _,
351
418
pre_init_code : _,
352
419
fptr_type,
353
- method_inits : _,
420
+ fetch_fptr_type : _,
421
+ method_init_groups : _,
354
422
lazy_key_type,
355
423
lazy_method_init,
356
424
named_accessors,
@@ -819,7 +887,8 @@ fn make_class_method_table(
819
887
} ,
820
888
pre_init_code : TokenStream :: new ( ) , // late-init, depends on class string names
821
889
fptr_type : quote ! { crate :: ClassMethodBind } ,
822
- method_inits : vec ! [ ] ,
890
+ fetch_fptr_type : quote ! { crate :: GDExtensionInterfaceClassdbGetMethodBind } ,
891
+ method_init_groups : vec ! [ ] ,
823
892
lazy_key_type : quote ! { crate :: lazy_keys:: ClassMethodKey } ,
824
893
lazy_method_init : quote ! {
825
894
let get_method_bind = crate :: interface_fn!( classdb_get_method_bind) ;
@@ -837,7 +906,6 @@ fn make_class_method_table(
837
906
method_count : 0 ,
838
907
} ;
839
908
840
- let mut class_sname_decls = Vec :: new ( ) ;
841
909
for class in api. classes . iter ( ) {
842
910
let class_ty = TyName :: from_godot ( & class. name ) ;
843
911
if special_cases:: is_class_deleted ( & class_ty)
@@ -847,25 +915,11 @@ fn make_class_method_table(
847
915
continue ;
848
916
}
849
917
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) ;
863
919
}
864
920
865
921
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" ) ;
869
923
} ;
870
924
871
925
make_method_table ( table)
@@ -916,16 +970,16 @@ fn make_builtin_method_table(
916
970
string_names: & mut crate :: StringCache ,
917
971
} ,
918
972
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" ) ;
921
974
} ,
922
975
fptr_type : quote ! { crate :: BuiltinMethodBind } ,
923
- method_inits : vec ! [ ] ,
976
+ fetch_fptr_type : quote ! { crate :: GDExtensionInterfaceVariantGetPtrBuiltinMethod } ,
977
+ method_init_groups : vec ! [ ] ,
924
978
lazy_key_type : quote ! { crate :: lazy_keys:: BuiltinMethodKey } ,
925
979
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) ;
927
981
crate :: load_builtin_method(
928
- get_builtin_method ,
982
+ fetch_fptr ,
929
983
& mut inner. string_cache,
930
984
key. variant_type. sys( ) ,
931
985
key. variant_type_str,
@@ -945,7 +999,6 @@ fn make_builtin_method_table(
945
999
} ;
946
1000
947
1001
populate_builtin_methods ( & mut table, builtin, & builtin_type. type_names , ctx) ;
948
- table. class_count += 1 ;
949
1002
}
950
1003
951
1004
make_method_table ( table)
@@ -955,9 +1008,11 @@ fn populate_class_methods(
955
1008
table : & mut IndexedMethodTable ,
956
1009
class : & Class ,
957
1010
class_ty : & TyName ,
958
- class_var : & Ident ,
959
1011
ctx : & mut Context ,
960
1012
) {
1013
+ let class_var = format_ident ! ( "sname_{}" , & class. name) ;
1014
+ let mut method_inits = vec ! [ ] ;
1015
+
961
1016
for method in option_as_slice ( & class. methods ) {
962
1017
if special_cases:: is_deleted ( class_ty, method, ctx) {
963
1018
continue ;
@@ -969,9 +1024,9 @@ fn populate_class_methods(
969
1024
class_ty : class_ty. clone ( ) ,
970
1025
method_name : method. name . clone ( ) ,
971
1026
} ) ;
972
- let method_init = make_class_method_init ( method, class_var, class_ty) ;
973
1027
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 } ) ;
975
1030
table. method_count += 1 ;
976
1031
977
1032
// If requested, add a named accessor for this method.
@@ -993,6 +1048,13 @@ fn populate_class_methods(
993
1048
} ) ;
994
1049
}
995
1050
}
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 ;
996
1058
}
997
1059
998
1060
fn populate_builtin_methods (
@@ -1001,6 +1063,9 @@ fn populate_builtin_methods(
1001
1063
builtin_name : & TypeNames ,
1002
1064
ctx : & mut Context ,
1003
1065
) {
1066
+ let class_var = format_ident ! ( "sname_{}" , & builtin_class. name) ;
1067
+ let mut method_inits = vec ! [ ] ;
1068
+
1004
1069
for method in option_as_slice ( & builtin_class. methods ) {
1005
1070
let builtin_ty = TyName :: from_godot ( & builtin_class. name ) ;
1006
1071
if special_cases:: is_builtin_deleted ( & builtin_ty, method) {
@@ -1013,8 +1078,7 @@ fn populate_builtin_methods(
1013
1078
} ) ;
1014
1079
1015
1080
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 } ) ;
1018
1082
table. method_count += 1 ;
1019
1083
1020
1084
// If requested, add a named accessor for this method.
@@ -1038,6 +1102,13 @@ fn populate_builtin_methods(
1038
1102
} ) ;
1039
1103
}
1040
1104
}
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 ;
1041
1112
}
1042
1113
1043
1114
fn make_class_method_init (
@@ -1057,7 +1128,14 @@ fn make_class_method_init(
1057
1128
1058
1129
// Could reuse lazy key, but less code like this -> faster parsing.
1059
1130
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
+ ) ,
1061
1139
}
1062
1140
}
1063
1141
@@ -1083,9 +1161,9 @@ fn make_builtin_method_init(
1083
1161
{
1084
1162
let _ = #index;
1085
1163
crate :: load_builtin_method(
1086
- get_builtin_method ,
1164
+ fetch_fptr ,
1087
1165
string_names,
1088
- sys :: #variant_type,
1166
+ crate :: #variant_type,
1089
1167
#variant_type_str,
1090
1168
#method_name_str,
1091
1169
#hash
0 commit comments