@@ -911,6 +911,174 @@ void java_bytecode_convert_methodt::check_static_field_stub(
911
911
912
912
/* ******************************************************************\
913
913
914
+ Function: java_bytecode_convert_methodt::class_needs_clinit
915
+
916
+ Inputs: classname: Class name
917
+
918
+ Outputs: Returns true if the given class or one of its parents
919
+ has a static initializer
920
+
921
+ Purpose: Determine whether a `new` or static access against `classname`
922
+ should be prefixed with a static initialization check.
923
+
924
+ \*******************************************************************/
925
+
926
+ bool java_bytecode_convert_methodt::class_needs_clinit (
927
+ const irep_idt &classname)
928
+ {
929
+ auto findit_any=any_superclass_has_clinit_method.insert ({classname, false });
930
+ if (!findit_any.second )
931
+ return findit_any.first ->second ;
932
+
933
+ auto findit_here=class_has_clinit_method.insert ({classname, false });
934
+ if (findit_here.second )
935
+ {
936
+ const irep_idt &clinit_name=id2string (classname)+" .<clinit>:()V" ;
937
+ findit_here.first ->second =symbol_table.symbols .count (clinit_name);
938
+ }
939
+ if (findit_here.first ->second )
940
+ {
941
+ findit_any.first ->second =true ;
942
+ return true ;
943
+ }
944
+ auto findit_symbol=symbol_table.symbols .find (classname);
945
+ // Stub class?
946
+ if (findit_symbol==symbol_table.symbols .end ())
947
+ {
948
+ warning () << " SKIPPED: " << classname << eom;
949
+ return false ;
950
+ }
951
+ const symbolt &class_symbol=symbol_table.lookup (classname);
952
+ for (const auto &base : to_class_type (class_symbol.type ).bases ())
953
+ {
954
+ if (class_needs_clinit (to_symbol_type (base.type ()).get_identifier ()))
955
+ {
956
+ findit_any.first ->second =true ;
957
+ return true ;
958
+ }
959
+ }
960
+ return false ;
961
+ }
962
+
963
+ /* ******************************************************************\
964
+
965
+ Function: java_bytecode_convert_methodt::get_or_create_clinit_wrapper
966
+
967
+ Inputs: classname: Class name
968
+
969
+ Outputs: Returns a symbol_exprt pointing to the given class' clinit
970
+ wrapper if one is required, or nil otherwise.
971
+
972
+ Purpose: Create a ::clinit_wrapper the first time a static initializer
973
+ might be called. The wrapper method checks whether static init
974
+ has already taken place, calls the actual <clinit> method if
975
+ not, and initializes super-classes and interfaces.
976
+
977
+ \*******************************************************************/
978
+
979
+ exprt java_bytecode_convert_methodt::get_or_create_clinit_wrapper (
980
+ const irep_idt &classname)
981
+ {
982
+ if (!class_needs_clinit (classname))
983
+ return static_cast <const exprt &>(get_nil_irep ());
984
+
985
+ const irep_idt &clinit_wrapper_name=
986
+ id2string (classname)+" ::clinit_wrapper" ;
987
+ auto findit=symbol_table.symbols .find (clinit_wrapper_name);
988
+ if (findit!=symbol_table.symbols .end ())
989
+ return findit->second .symbol_expr ();
990
+
991
+ // Create the wrapper now:
992
+ const irep_idt &already_run_name=
993
+ id2string (classname)+" ::clinit_already_run" ;
994
+ symbolt already_run_symbol;
995
+ already_run_symbol.name =already_run_name;
996
+ already_run_symbol.pretty_name =already_run_name;
997
+ already_run_symbol.base_name =" clinit_already_run" ;
998
+ already_run_symbol.type =bool_typet ();
999
+ already_run_symbol.value =false_exprt ();
1000
+ already_run_symbol.is_lvalue =true ;
1001
+ already_run_symbol.is_state_var =true ;
1002
+ already_run_symbol.is_static_lifetime =true ;
1003
+ already_run_symbol.mode =ID_java;
1004
+ symbol_table.add (already_run_symbol);
1005
+
1006
+ equal_exprt check_already_run (
1007
+ already_run_symbol.symbol_expr (),
1008
+ false_exprt ());
1009
+
1010
+ code_ifthenelset wrapper_body;
1011
+ wrapper_body.cond ()=check_already_run;
1012
+ code_blockt init_body;
1013
+ // Note already-run is set *before* calling clinit, in order to prevent
1014
+ // recursion in clinit methods.
1015
+ code_assignt set_already_run (already_run_symbol.symbol_expr (), true_exprt ());
1016
+ init_body.move_to_operands (set_already_run);
1017
+ const irep_idt &real_clinit_name=id2string (classname)+" .<clinit>:()V" ;
1018
+ const symbolt &class_symbol=symbol_table.lookup (classname);
1019
+
1020
+ auto findsymit=symbol_table.symbols .find (real_clinit_name);
1021
+ if (findsymit!=symbol_table.symbols .end ())
1022
+ {
1023
+ code_function_callt call_real_init;
1024
+ call_real_init.function ()=findsymit->second .symbol_expr ();
1025
+ init_body.move_to_operands (call_real_init);
1026
+ }
1027
+
1028
+ for (const auto &base : to_class_type (class_symbol.type ).bases ())
1029
+ {
1030
+ const auto base_name=to_symbol_type (base.type ()).get_identifier ();
1031
+ exprt base_init_routine=get_or_create_clinit_wrapper (base_name);
1032
+ if (base_init_routine.is_nil ())
1033
+ continue ;
1034
+ code_function_callt call_base;
1035
+ call_base.function ()=base_init_routine;
1036
+ init_body.move_to_operands (call_base);
1037
+ }
1038
+
1039
+ wrapper_body.then_case ()=init_body;
1040
+
1041
+ symbolt wrapper_method_symbol;
1042
+ code_typet wrapper_method_type;
1043
+ wrapper_method_type.return_type ()=void_typet ();
1044
+ wrapper_method_symbol.name =clinit_wrapper_name;
1045
+ wrapper_method_symbol.pretty_name =clinit_wrapper_name;
1046
+ wrapper_method_symbol.base_name =" clinit_wrapper" ;
1047
+ wrapper_method_symbol.type =wrapper_method_type;
1048
+ wrapper_method_symbol.value =wrapper_body;
1049
+ wrapper_method_symbol.mode =ID_java;
1050
+ symbol_table.add (wrapper_method_symbol);
1051
+ return wrapper_method_symbol.symbol_expr ();
1052
+ }
1053
+
1054
+ /* ******************************************************************\
1055
+
1056
+ Function: java_bytecode_convert_methodt::get_clinit_call
1057
+
1058
+ Inputs: classname: Class name
1059
+
1060
+ Outputs: Returns a function call to the given class' static initializer
1061
+ wrapper if one is needed, or a skip instruction otherwise.
1062
+
1063
+ Purpose: Each static access to classname should be prefixed with a check
1064
+ for necessary static init; this returns a call implementing
1065
+ that check.
1066
+
1067
+ \*******************************************************************/
1068
+
1069
+ codet java_bytecode_convert_methodt::get_clinit_call (
1070
+ const irep_idt &classname)
1071
+ {
1072
+ exprt callee=get_or_create_clinit_wrapper (classname);
1073
+ if (callee.is_nil ())
1074
+ return code_skipt ();
1075
+ code_function_callt ret;
1076
+ ret.function ()=callee;
1077
+ return ret;
1078
+ }
1079
+
1080
+ /* ******************************************************************\
1081
+
914
1082
Function: java_bytecode_convert_methodt::convert_instructions
915
1083
916
1084
Inputs:
@@ -1378,6 +1546,18 @@ codet java_bytecode_convert_methodt::convert_instructions(
1378
1546
1379
1547
call.function ().add_source_location ()=loc;
1380
1548
c=call;
1549
+
1550
+ if (!use_this)
1551
+ {
1552
+ codet clinit_call=get_clinit_call (arg0.get (ID_C_class));
1553
+ if (clinit_call.get_statement ()!=ID_skip)
1554
+ {
1555
+ code_blockt ret_block;
1556
+ ret_block.move_to_operands (clinit_call);
1557
+ ret_block.move_to_operands (c);
1558
+ c=std::move (ret_block);
1559
+ }
1560
+ }
1381
1561
}
1382
1562
else if (statement==" return" )
1383
1563
{
@@ -1916,9 +2096,14 @@ codet java_bytecode_convert_methodt::convert_instructions(
1916
2096
}
1917
2097
results[0 ]=java_bytecode_promotion (symbol_expr);
1918
2098
1919
- // set $assertionDisabled to false
1920
- if (field_name.find (" $assertionsDisabled" )!=std::string::npos)
2099
+ codet clinit_call=get_clinit_call (arg0.get_string (ID_class));
2100
+ if (clinit_call.get_statement ()!=ID_skip)
2101
+ c=clinit_call;
2102
+ else if (field_name.find (" $assertionsDisabled" )!=std::string::npos)
2103
+ {
2104
+ // set $assertionDisabled to false
1921
2105
c=code_assignt (symbol_expr, false_exprt ());
2106
+ }
1922
2107
}
1923
2108
else if (statement==" putfield" )
1924
2109
{
@@ -1937,6 +2122,14 @@ codet java_bytecode_convert_methodt::convert_instructions(
1937
2122
to_symbol_type (arg0.type ()).get_identifier ());
1938
2123
}
1939
2124
c=code_assignt (symbol_expr, op[0 ]);
2125
+ codet clinit_call=get_clinit_call (arg0.get_string (ID_class));
2126
+ if (clinit_call.get_statement ()!=ID_skip)
2127
+ {
2128
+ code_blockt ret_block;
2129
+ ret_block.move_to_operands (clinit_call);
2130
+ ret_block.move_to_operands (c);
2131
+ c=std::move (ret_block);
2132
+ }
1940
2133
}
1941
2134
else if (statement==patternt (" ?2?" )) // i2c etc.
1942
2135
{
@@ -1955,6 +2148,15 @@ codet java_bytecode_convert_methodt::convert_instructions(
1955
2148
1956
2149
const exprt tmp=tmp_variable (" new" , ref_type);
1957
2150
c=code_assignt (tmp, java_new_expr);
2151
+ codet clinit_call=
2152
+ get_clinit_call (to_symbol_type (arg0.type ()).get_identifier ());
2153
+ if (clinit_call.get_statement ()!=ID_skip)
2154
+ {
2155
+ code_blockt ret_block;
2156
+ ret_block.move_to_operands (clinit_call);
2157
+ ret_block.move_to_operands (c);
2158
+ c=std::move (ret_block);
2159
+ }
1958
2160
results[0 ]=tmp;
1959
2161
}
1960
2162
else if (statement==" newarray" ||
0 commit comments