@@ -223,7 +223,8 @@ static void infer_opaque_type_fields(
223
223
namespacet ns (symbol_table);
224
224
for (const auto &method : parse_tree.parsed_class .methods )
225
225
{
226
- for (const auto &instruction : method.instructions )
226
+ for (const java_bytecode_parse_treet::instructiont &instruction :
227
+ method.instructions )
227
228
{
228
229
if (instruction.statement == " getfield" ||
229
230
instruction.statement == " putfield" )
@@ -359,7 +360,8 @@ static void generate_constant_global_variables(
359
360
{
360
361
for (auto &method : parse_tree.parsed_class .methods )
361
362
{
362
- for (auto &instruction : method.instructions )
363
+ for (java_bytecode_parse_treet::instructiont &instruction :
364
+ method.instructions )
363
365
{
364
366
// ldc* instructions are Java bytecode "load constant" ops, which can
365
367
// retrieve a numeric constant, String literal, or Class literal.
@@ -381,6 +383,87 @@ static void generate_constant_global_variables(
381
383
}
382
384
}
383
385
386
+ // / Add a stub global symbol to the symbol table, initialising pointer-typed
387
+ // / symbols with null and primitive-typed ones with an arbitrary (nondet) value.
388
+ // / \param symbol_table: table to add to
389
+ // / \param symbol_id: new symbol fully-qualified identifier
390
+ // / \param symbol_basename: new symbol basename
391
+ // / \param symbol_type: new symbol type
392
+ // / \param class_id: class id that directly encloses this static field
393
+ static void create_stub_global_symbol (
394
+ symbol_table_baset &symbol_table,
395
+ const irep_idt &symbol_id,
396
+ const irep_idt &symbol_basename,
397
+ const typet &symbol_type,
398
+ const irep_idt &class_id)
399
+ {
400
+ symbolt new_symbol;
401
+ new_symbol.is_static_lifetime = true ;
402
+ new_symbol.is_lvalue = true ;
403
+ new_symbol.is_state_var = true ;
404
+ new_symbol.name = symbol_id;
405
+ new_symbol.base_name = symbol_basename;
406
+ new_symbol.type = symbol_type;
407
+ new_symbol.type .set (ID_C_class, class_id);
408
+ new_symbol.pretty_name = new_symbol.name ;
409
+ new_symbol.mode = ID_java;
410
+ new_symbol.is_type = false ;
411
+ // If pointer-typed, initialise to null and a static initialiser will be
412
+ // created to initialise on first reference. If primitive-typed, specify
413
+ // nondeterministic initialisation by setting a nil value.
414
+ if (symbol_type.id () == ID_pointer)
415
+ new_symbol.value = null_pointer_exprt (to_pointer_type (symbol_type));
416
+ else
417
+ new_symbol.value .make_nil ();
418
+ bool add_failed = symbol_table.add (new_symbol);
419
+ INVARIANT (
420
+ !add_failed, " caller should have checked symbol not already in table" );
421
+ }
422
+
423
+ // / Search for getstatic and putstatic instructions in a class' bytecode and
424
+ // / create stub symbols for any static fields that aren't already in the symbol
425
+ // / table. The new symbols are null-initialised for reference-typed globals /
426
+ // / static fields, and nondet-initialised for primitives.
427
+ // / \param parse_tree: class bytecode
428
+ // / \param symbol_table: symbol table; may gain new symbols
429
+ static void create_stub_global_symbols (
430
+ const java_bytecode_parse_treet &parse_tree,
431
+ symbol_table_baset &symbol_table)
432
+ {
433
+ namespacet ns (symbol_table);
434
+ for (const auto &method : parse_tree.parsed_class .methods )
435
+ {
436
+ for (const java_bytecode_parse_treet::instructiont &instruction :
437
+ method.instructions )
438
+ {
439
+ if (instruction.statement == " getstatic" ||
440
+ instruction.statement == " putstatic" )
441
+ {
442
+ INVARIANT (
443
+ instruction.args .size () > 0 ,
444
+ " get/putstatic should have at least one argument" );
445
+ irep_idt component = instruction.args [0 ].get_string (ID_component_name);
446
+ INVARIANT (
447
+ !component.empty (), " get/putstatic should specify a component" );
448
+ irep_idt class_id = instruction.args [0 ].get_string (ID_class);
449
+ INVARIANT (
450
+ !class_id.empty (), " get/putstatic should specify a class" );
451
+ irep_idt identifier = id2string (class_id) + " ." + id2string (component);
452
+
453
+ if (!symbol_table.has_symbol (identifier))
454
+ {
455
+ create_stub_global_symbol (
456
+ symbol_table,
457
+ identifier,
458
+ component,
459
+ instruction.args [0 ].type (),
460
+ class_id);
461
+ }
462
+ }
463
+ }
464
+ }
465
+ }
466
+
384
467
bool java_bytecode_languaget::typecheck (
385
468
symbol_tablet &symbol_table,
386
469
const std::string &module)
@@ -477,10 +560,31 @@ bool java_bytecode_languaget::typecheck(
477
560
<< " String or Class constant symbols"
478
561
<< messaget::eom;
479
562
563
+ // For each reference to a stub global (that is, a global variable declared on
564
+ // a class we don't have bytecode for, and therefore don't know the static
565
+ // initialiser for), create a synthetic static initialiser (clinit method)
566
+ // to nondet initialise it.
567
+ // Note this must be done before making static initialiser wrappers below, as
568
+ // this makes a Classname.clinit method, then the next pass makes a wrapper
569
+ // that ensures it is only run once, and that static initialisation happens
570
+ // in class-graph topological order.
571
+
572
+ {
573
+ journalling_symbol_tablet symbol_table_journal =
574
+ journalling_symbol_tablet::wrap (symbol_table);
575
+ for (const auto &c : java_class_loader.class_map )
576
+ {
577
+ create_stub_global_symbols (c.second , symbol_table_journal);
578
+ }
579
+
580
+ stub_global_initializer_factory.create_stub_global_initializer_symbols (
581
+ symbol_table, symbol_table_journal.get_inserted (), synthetic_methods);
582
+ }
583
+
480
584
// For each class that will require a static initializer wrapper, create a
481
585
// function named package.classname::clinit_wrapper, and a corresponding
482
586
// global tracking whether it has run or not:
483
- create_static_initializer_wrappers (symbol_table);
587
+ create_static_initializer_wrappers (symbol_table, synthetic_methods );
484
588
485
589
// Now incrementally elaborate methods
486
590
// that are reachable from this entry point.
@@ -495,24 +599,12 @@ bool java_bytecode_languaget::typecheck(
495
599
journalling_symbol_tablet journalling_symbol_table =
496
600
journalling_symbol_tablet::wrap (symbol_table);
497
601
602
+ // Convert all synthetic methods:
603
+ for (const auto &function_id_and_type : synthetic_methods)
498
604
{
499
- // Convert all static initialisers:
500
- std::vector<irep_idt> static_initialisers;
501
-
502
- // Careful not to add symbols while iterating over the symbol table!
503
- for (const auto &symbol : symbol_table.symbols )
504
- {
505
- if (is_clinit_wrapper_function (symbol.second .name ))
506
- static_initialisers.push_back (symbol.second .name );
507
- }
508
-
509
- for (const auto &static_init_wrapper_name : static_initialisers)
510
- {
511
- convert_single_method (
512
- static_init_wrapper_name, journalling_symbol_table);
513
- }
605
+ convert_single_method (
606
+ function_id_and_type.first , journalling_symbol_table);
514
607
}
515
-
516
608
// Convert all methods for which we have bytecode now
517
609
for (const auto &method_sig : method_bytecode)
518
610
{
@@ -714,6 +806,8 @@ bool java_bytecode_languaget::convert_single_method(
714
806
// Get bytecode for specified function if we have it
715
807
method_bytecodet::opt_reft cmb = method_bytecode.get (function_id);
716
808
809
+ synthetic_methods_mapt::iterator synthetic_method_it;
810
+
717
811
// Check if have a string solver implementation
718
812
if (string_preprocess.implements_function (function_id))
719
813
{
@@ -735,11 +829,29 @@ bool java_bytecode_languaget::convert_single_method(
735
829
symbol.value = generated_code;
736
830
return false ;
737
831
}
738
- else if (is_clinit_wrapper_function (function_id))
832
+ else if (
833
+ (synthetic_method_it = synthetic_methods.find (function_id)) !=
834
+ synthetic_methods.end ())
739
835
{
836
+ // Synthetic method (i.e. one generated by the Java frontend and which
837
+ // doesn't occur in the source bytecode):
740
838
symbolt &symbol = symbol_table.get_writeable_ref (function_id);
741
- symbol.value = get_clinit_wrapper_body (function_id, symbol_table);
742
- // Notify lazy methods of other static init functions called:
839
+ switch (synthetic_method_it->second )
840
+ {
841
+ case synthetic_method_typet::STATIC_INITIALIZER_WRAPPER:
842
+ symbol.value = get_clinit_wrapper_body (function_id, symbol_table);
843
+ break ;
844
+ case synthetic_method_typet::STUB_CLASS_STATIC_INITIALIZER:
845
+ symbol.value =
846
+ stub_global_initializer_factory.get_stub_initializer_body (
847
+ function_id,
848
+ symbol_table,
849
+ object_factory_parameters,
850
+ get_pointer_type_selector ());
851
+ break ;
852
+ }
853
+ // Notify lazy methods of static calls made from the newly generated
854
+ // function:
743
855
notify_static_method_calls (symbol.value , needed_lazy_methods);
744
856
return false ;
745
857
}
0 commit comments