@@ -198,7 +198,7 @@ def emit_line() -> None:
198
198
generate_dealloc_for_class (cl , dealloc_name , clear_name , emitter )
199
199
emit_line ()
200
200
generate_native_getters_and_setters (cl , emitter )
201
- vtable_name = generate_vtables (cl , vtable_name , emitter )
201
+ vtable_name = generate_vtables (cl , vtable_setup_name , vtable_name , emitter )
202
202
emit_line ()
203
203
if needs_getseters :
204
204
generate_getseter_declarations (cl , emitter )
@@ -222,7 +222,6 @@ def emit_line() -> None:
222
222
t = emitter .type_struct_name (cl )))
223
223
224
224
emitter .emit_line ()
225
- generate_trait_vtable_setup (cl , vtable_setup_name , vtable_name , emitter )
226
225
if generate_full :
227
226
generate_setup_for_class (cl , setup_name , defaults_fn , vtable_name , emitter )
228
227
emitter .emit_line ()
@@ -307,39 +306,63 @@ def generate_native_getters_and_setters(cl: ClassIR,
307
306
308
307
309
308
def generate_vtables (base : ClassIR ,
309
+ vtable_setup_name : str ,
310
310
vtable_name : str ,
311
311
emitter : Emitter ) -> str :
312
- """Emit the vtables for a class.
312
+ """Emit the vtables and vtable setup functions for a class.
313
313
314
314
This includes both the primary vtable and any trait implementation vtables.
315
315
316
+ To account for both dynamic loading and dynamic class creation,
317
+ vtables are populated dynamically at class creation time, so we
318
+ emit empty array definitions to store the vtables and a function to
319
+ populate them.
320
+
316
321
Returns the expression to use to refer to the vtable, which might be
317
- different than the name, if there are trait vtables."""
322
+ different than the name, if there are trait vtables.
323
+ """
324
+
325
+ def trait_vtable_name (trait : ClassIR ) -> str :
326
+ return '{}_{}_trait_vtable' .format (
327
+ base .name_prefix (emitter .names ), trait .name_prefix (emitter .names ))
328
+
329
+ # Emit array definitions with enough space for all the entries
330
+ emitter .emit_line ('static CPyVTableItem {}[{}];' .format (
331
+ vtable_name ,
332
+ max (1 , len (base .vtable_entries ) + 2 * len (base .trait_vtables ))))
333
+ for trait , vtable in base .trait_vtables .items ():
334
+ emitter .emit_line ('static CPyVTableItem {}[{}];' .format (
335
+ trait_vtable_name (trait ),
336
+ max (1 , len (vtable ))))
337
+
338
+ # Emit vtable setup function
339
+ emitter .emit_line ('static bool' )
340
+ emitter .emit_line ('{}{}(void)' .format (NATIVE_PREFIX , vtable_setup_name ))
341
+ emitter .emit_line ('{' )
318
342
319
343
subtables = []
320
344
for trait , vtable in base .trait_vtables .items ():
321
- name = '{}_{}_trait_vtable' .format (
322
- base .name_prefix (emitter .names ), trait .name_prefix (emitter .names ))
345
+ name = trait_vtable_name (trait )
323
346
generate_vtable (vtable , name , emitter , [])
324
347
subtables .append ((trait , name ))
325
348
326
349
generate_vtable (base .vtable_entries , vtable_name , emitter , subtables )
327
350
351
+ emitter .emit_line ('return 1;' )
352
+ emitter .emit_line ('}' )
353
+
328
354
return vtable_name if not subtables else "{} + {}" .format (vtable_name , len (subtables ) * 2 )
329
355
330
356
331
357
def generate_vtable (entries : VTableEntries ,
332
358
vtable_name : str ,
333
359
emitter : Emitter ,
334
360
subtables : List [Tuple [ClassIR , str ]]) -> None :
335
- emitter .emit_line ('static CPyVTableItem {}[] = {{' .format (vtable_name ))
361
+ emitter .emit_line ('CPyVTableItem {}_scratch [] = {{' .format (vtable_name ))
336
362
if subtables :
337
363
emitter .emit_line ('/* Array of trait vtables */' )
338
364
for trait , table in subtables :
339
- # N.B: C only lets us store constant values. We do a nasty hack of
340
- # storing a pointer to the location, which we will then dynamically
341
- # patch up on module load in CPy_FixupTraitVtable.
342
- emitter .emit_line ('(CPyVTableItem)&{}, (CPyVTableItem){},' .format (
365
+ emitter .emit_line ('(CPyVTableItem){}, (CPyVTableItem){},' .format (
343
366
emitter .type_struct_name (trait ), table ))
344
367
emitter .emit_line ('/* Start of real vtable */' )
345
368
@@ -355,24 +378,7 @@ def generate_vtable(entries: VTableEntries,
355
378
if not entries :
356
379
emitter .emit_line ('NULL' )
357
380
emitter .emit_line ('};' )
358
-
359
-
360
- def generate_trait_vtable_setup (cl : ClassIR ,
361
- vtable_setup_name : str ,
362
- vtable_name : str ,
363
- emitter : Emitter ) -> None :
364
- """Generate a native function that fixes up the trait vtables of a class.
365
-
366
- This needs to be called before a class is used.
367
- """
368
- emitter .emit_line ('static bool' )
369
- emitter .emit_line ('{}{}(void)' .format (NATIVE_PREFIX , vtable_setup_name ))
370
- emitter .emit_line ('{' )
371
- if cl .trait_vtables and not cl .is_trait :
372
- emitter .emit_lines ('CPy_FixupTraitVtable({}_vtable, {});' .format (
373
- cl .name_prefix (emitter .names ), len (cl .trait_vtables )))
374
- emitter .emit_line ('return 1;' )
375
- emitter .emit_line ('}' )
381
+ emitter .emit_line ('memcpy({name}, {name}_scratch, sizeof({name}));' .format (name = vtable_name ))
376
382
377
383
378
384
def generate_setup_for_class (cl : ClassIR ,
0 commit comments