1616#include " java_bytecode_convert_method.h"
1717#include " java_bytecode_convert_method_class.h"
1818#include " bytecode_info.h"
19+ #include " java_static_initializers.h"
1920#include " java_string_library_preprocess.h"
2021#include " java_types.h"
2122#include " java_utils.h"
@@ -930,156 +931,6 @@ void java_bytecode_convert_methodt::check_static_field_stub(
930931 }
931932}
932933
933- // / Determine whether a `new` or static access against `classname` should be
934- // / prefixed with a static initialization check.
935- // / \param classname: Class name
936- // / \return Returns true if the given class or one of its parents has a static
937- // / initializer
938- bool java_bytecode_convert_methodt::class_needs_clinit (
939- const irep_idt &classname)
940- {
941- auto findit_any=any_superclass_has_clinit_method.insert ({classname, false });
942- if (!findit_any.second )
943- return findit_any.first ->second ;
944-
945- auto findit_here=class_has_clinit_method.insert ({classname, false });
946- if (findit_here.second )
947- {
948- const irep_idt &clinit_name=id2string (classname)+" .<clinit>:()V" ;
949- findit_here.first ->second =symbol_table.symbols .count (clinit_name);
950- }
951- if (findit_here.first ->second )
952- {
953- findit_any.first ->second =true ;
954- return true ;
955- }
956- const auto maybe_symbol=symbol_table.lookup (classname);
957- // Stub class?
958- if (!maybe_symbol)
959- {
960- warning () << " SKIPPED: " << classname << eom;
961- return false ;
962- }
963- const symbolt &class_symbol=*maybe_symbol;
964- for (const auto &base : to_class_type (class_symbol.type ).bases ())
965- {
966- if (class_needs_clinit (to_symbol_type (base.type ()).get_identifier ()))
967- {
968- findit_any.first ->second =true ;
969- return true ;
970- }
971- }
972- return false ;
973- }
974-
975- // / Create a ::clinit_wrapper the first time a static initializer might be
976- // / called. The wrapper method checks whether static init has already taken
977- // / place, calls the actual <clinit> method if not, and initializes super-
978- // / classes and interfaces.
979- // / \param classname: Class name
980- // / \return Returns a symbol_exprt pointing to the given class' clinit wrapper
981- // / if one is required, or nil otherwise.
982- exprt java_bytecode_convert_methodt::get_or_create_clinit_wrapper (
983- const irep_idt &classname)
984- {
985- if (!class_needs_clinit (classname))
986- return static_cast <const exprt &>(get_nil_irep ());
987-
988- // if the symbol table already contains the clinit_wrapper() function, return
989- // it
990- const irep_idt &clinit_wrapper_name=
991- id2string (classname)+" ::clinit_wrapper" ;
992- auto findit=symbol_table.symbols .find (clinit_wrapper_name);
993- if (findit!=symbol_table.symbols .end ())
994- return findit->second .symbol_expr ();
995-
996- // Otherwise, assume that class C extends class C' and implements interfaces
997- // I1, ..., In. We now create the following function (possibly recursively
998- // creating the clinit_wrapper functions for C' and I1, ..., In):
999- //
1000- // java::C::clinit_wrapper()
1001- // {
1002- // if (java::C::clinit_already_run == false)
1003- // {
1004- // java::C::clinit_already_run = true; // before recursive calls!
1005- //
1006- // java::C'::clinit_wrapper();
1007- // java::I1::clinit_wrapper();
1008- // java::I2::clinit_wrapper();
1009- // // ...
1010- // java::In::clinit_wrapper();
1011- //
1012- // java::C::<clinit>();
1013- // }
1014- // }
1015- const irep_idt &already_run_name=
1016- id2string (classname)+" ::clinit_already_run" ;
1017- symbolt already_run_symbol;
1018- already_run_symbol.name =already_run_name;
1019- already_run_symbol.pretty_name =already_run_name;
1020- already_run_symbol.base_name =" clinit_already_run" ;
1021- already_run_symbol.type =bool_typet ();
1022- already_run_symbol.value =false_exprt ();
1023- already_run_symbol.is_lvalue =true ;
1024- already_run_symbol.is_state_var =true ;
1025- already_run_symbol.is_static_lifetime =true ;
1026- already_run_symbol.mode =ID_java;
1027- symbol_table.add (already_run_symbol);
1028-
1029- equal_exprt check_already_run (
1030- already_run_symbol.symbol_expr (),
1031- false_exprt ());
1032-
1033- // the entire body of the function is an if-then-else
1034- code_ifthenelset wrapper_body;
1035-
1036- // add the condition to the if
1037- wrapper_body.cond ()=check_already_run;
1038-
1039- // add the "already-run = false" statement
1040- code_blockt init_body;
1041- code_assignt set_already_run (already_run_symbol.symbol_expr (), true_exprt ());
1042- init_body.move_to_operands (set_already_run);
1043-
1044- // iterate through the base types and add recursive calls to the
1045- // clinit_wrapper()
1046- const symbolt &class_symbol=*symbol_table.lookup (classname);
1047- for (const auto &base : to_class_type (class_symbol.type ).bases ())
1048- {
1049- const auto base_name=to_symbol_type (base.type ()).get_identifier ();
1050- exprt base_init_routine=get_or_create_clinit_wrapper (base_name);
1051- if (base_init_routine.is_nil ())
1052- continue ;
1053- code_function_callt call_base;
1054- call_base.function ()=base_init_routine;
1055- init_body.move_to_operands (call_base);
1056- }
1057-
1058- // call java::C::<clinit>(), if the class has one static initializer
1059- const irep_idt &real_clinit_name=id2string (classname)+" .<clinit>:()V" ;
1060- auto find_sym_it=symbol_table.symbols .find (real_clinit_name);
1061- if (find_sym_it!=symbol_table.symbols .end ())
1062- {
1063- code_function_callt call_real_init;
1064- call_real_init.function ()=find_sym_it->second .symbol_expr ();
1065- init_body.move_to_operands (call_real_init);
1066- }
1067- wrapper_body.then_case ()=init_body;
1068-
1069- // insert symbol in the symbol table
1070- symbolt wrapper_method_symbol;
1071- code_typet wrapper_method_type;
1072- wrapper_method_type.return_type ()=void_typet ();
1073- wrapper_method_symbol.name =clinit_wrapper_name;
1074- wrapper_method_symbol.pretty_name =clinit_wrapper_name;
1075- wrapper_method_symbol.base_name =" clinit_wrapper" ;
1076- wrapper_method_symbol.type =wrapper_method_type;
1077- wrapper_method_symbol.value =wrapper_body;
1078- wrapper_method_symbol.mode =ID_java;
1079- symbol_table.add (wrapper_method_symbol);
1080- return wrapper_method_symbol.symbol_expr ();
1081- }
1082-
1083934// / Each static access to classname should be prefixed with a check for
1084935// / necessary static init; this returns a call implementing that check.
1085936// / \param classname: Class name
@@ -1088,12 +939,17 @@ exprt java_bytecode_convert_methodt::get_or_create_clinit_wrapper(
1088939codet java_bytecode_convert_methodt::get_clinit_call (
1089940 const irep_idt &classname)
1090941{
1091- exprt callee= get_or_create_clinit_wrapper ( classname);
1092- if (callee. is_nil ())
942+ auto findit = symbol_table. symbols . find ( clinit_wrapper_name ( classname) );
943+ if (findit == symbol_table. symbols . end ())
1093944 return code_skipt ();
1094- code_function_callt ret;
1095- ret.function ()=callee;
1096- return ret;
945+ else
946+ {
947+ code_function_callt ret;
948+ ret.function () = findit->second .symbol_expr ();
949+ if (needed_lazy_methods)
950+ needed_lazy_methods->add_needed_method (findit->second .name );
951+ return ret;
952+ }
1097953}
1098954
1099955static unsigned get_bytecode_type_width (const typet &ty)
0 commit comments