@@ -30,6 +30,7 @@ Author: Daniel Kroening, kroening@kroening.com
30
30
#include " java_entry_point.h"
31
31
#include " java_bytecode_parser.h"
32
32
#include " java_class_loader.h"
33
+ #include " java_string_literals.h"
33
34
#include " java_utils.h"
34
35
#include < java_bytecode/ci_lazy_methods.h>
35
36
#include < java_bytecode/generate_java_generic_type.h>
@@ -267,6 +268,118 @@ static void infer_opaque_type_fields(
267
268
}
268
269
}
269
270
271
+ // / Create if necessary, then return the constant global java.lang.Class symbol
272
+ // / for a given class id
273
+ // / \param class_id: class identifier
274
+ // / \param symbol_table: global symbol table; a symbol may be added
275
+ // / \return java.lang.Class typed symbol expression
276
+ static symbol_exprt get_or_create_class_literal_symbol (
277
+ const irep_idt &class_id, symbol_tablet &symbol_table)
278
+ {
279
+ symbol_typet java_lang_Class (" java::java.lang.Class" );
280
+ symbol_exprt symbol_expr (
281
+ id2string (class_id)+" @class_model" ,
282
+ java_lang_Class);
283
+ if (!symbol_table.has_symbol (symbol_expr.get_identifier ()))
284
+ {
285
+ symbolt new_class_symbol;
286
+ new_class_symbol.name = symbol_expr.get_identifier ();
287
+ new_class_symbol.type = symbol_expr.type ();
288
+ INVARIANT (
289
+ has_prefix (id2string (new_class_symbol.name ), " java::" ),
290
+ " class identifier should have 'java::' prefix" );
291
+ new_class_symbol.base_name =
292
+ id2string (new_class_symbol.name ).substr (6 );
293
+ new_class_symbol.mode = ID_java;
294
+ new_class_symbol.is_lvalue = true ;
295
+ new_class_symbol.is_state_var = true ;
296
+ new_class_symbol.is_static_lifetime = true ;
297
+ symbol_table.add (new_class_symbol);
298
+ }
299
+
300
+ return symbol_expr;
301
+ }
302
+
303
+ // / Get result of a Java load-constant (ldc) instruction.
304
+ // / Possible cases:
305
+ // / 1) Pushing a String causes a reference to a java.lang.String object
306
+ // / to be constructed and pushed onto the operand stack.
307
+ // / 2) Pushing an int or a float causes a primitive value to be pushed
308
+ // / onto the stack.
309
+ // / 3) Pushing a Class constant causes a reference to a java.lang.Class
310
+ // / to be pushed onto the operand stack
311
+ // / \param ldc_arg0: raw operand to the ldc opcode
312
+ // / \param symbol_table: global symbol table. If the argument `ldc_arg0` is a
313
+ // / String or Class constant then a new constant global may be added.
314
+ // / \param string_refinement_enabled: true if --refine-strings is enabled, which
315
+ // / influences how String literals are structured.
316
+ // / \return ldc result
317
+ static exprt get_ldc_result (
318
+ const exprt &ldc_arg0,
319
+ symbol_tablet &symbol_table,
320
+ bool string_refinement_enabled)
321
+ {
322
+ if (ldc_arg0.id () == ID_type)
323
+ {
324
+ const irep_idt &class_id = ldc_arg0.type ().get (ID_identifier);
325
+ return
326
+ address_of_exprt (
327
+ get_or_create_class_literal_symbol (class_id, symbol_table));
328
+ }
329
+ else if (ldc_arg0.id () == ID_java_string_literal)
330
+ {
331
+ return
332
+ address_of_exprt (
333
+ get_or_create_string_literal_symbol (
334
+ ldc_arg0, symbol_table, string_refinement_enabled));
335
+ }
336
+ else
337
+ {
338
+ INVARIANT (
339
+ ldc_arg0.id () == ID_constant,
340
+ " ldc argument should be constant, string literal or class literal" );
341
+ return ldc_arg0;
342
+ }
343
+ }
344
+
345
+ // / Creates global variables for constants mentioned in a given method. These
346
+ // / are either string literals, or class literals (the java.lang.Class instance
347
+ // / returned by `(some_reference_typed_expression).class`). The method parse
348
+ // / tree is rewritten to directly reference these globals.
349
+ // / \param parse_tree: parse tree to search for constant global references
350
+ // / \param symbol_table: global symbol table, to which constant globals will be
351
+ // / added.
352
+ // / \param string_refinement_enabled: true if `--refine-stings` is active,
353
+ // / which changes how string literals are structured.
354
+ static void generate_constant_global_variables (
355
+ java_bytecode_parse_treet &parse_tree,
356
+ symbol_tablet &symbol_table,
357
+ bool string_refinement_enabled)
358
+ {
359
+ for (auto &method : parse_tree.parsed_class .methods )
360
+ {
361
+ for (auto &instruction : method.instructions )
362
+ {
363
+ // ldc* instructions are Java bytecode "load constant" ops, which can
364
+ // retrieve a numeric constant, String literal, or Class literal.
365
+ if (instruction.statement == " ldc" ||
366
+ instruction.statement == " ldc2" ||
367
+ instruction.statement == " ldc_w" ||
368
+ instruction.statement == " ldc2_w" )
369
+ {
370
+ INVARIANT (
371
+ instruction.args .size () != 0 ,
372
+ " ldc instructions should have an argument" );
373
+ instruction.args [0 ] =
374
+ get_ldc_result (
375
+ instruction.args [0 ],
376
+ symbol_table,
377
+ string_refinement_enabled);
378
+ }
379
+ }
380
+ }
381
+ }
382
+
270
383
bool java_bytecode_languaget::typecheck (
271
384
symbol_tablet &symbol_table,
272
385
const std::string &module )
@@ -346,6 +459,23 @@ bool java_bytecode_languaget::typecheck(
346
459
infer_opaque_type_fields (c.second , symbol_table);
347
460
}
348
461
462
+ // Create global variables for constants (String and Class literals) up front.
463
+ // This means that when running with lazy loading, we will be aware of these
464
+ // literal globals' existence when __CPROVER_initialize is generated in
465
+ // `generate_support_functions`.
466
+ const std::size_t before_constant_globals_size = symbol_table.symbols .size ();
467
+ for (auto &c : java_class_loader.class_map )
468
+ {
469
+ generate_constant_global_variables (
470
+ c.second ,
471
+ symbol_table,
472
+ string_refinement_enabled);
473
+ }
474
+ status () << " Java: added "
475
+ << (symbol_table.symbols .size () - before_constant_globals_size)
476
+ << " String or Class constant symbols"
477
+ << messaget::eom;
478
+
349
479
// Now incrementally elaborate methods
350
480
// that are reachable from this entry point.
351
481
if (lazy_methods_mode==LAZY_METHODS_MODE_CONTEXT_INSENSITIVE)
0 commit comments