@@ -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>
@@ -256,6 +257,118 @@ static void infer_opaque_type_fields(
256
257
}
257
258
}
258
259
260
+ // / Create if necessary, then return the constant global java.lang.Class symbol
261
+ // / for a given class id
262
+ // / \param class_id: class identifier
263
+ // / \param symbol_table: global symbol table; a symbol may be added
264
+ // / \return java.lang.Class typed symbol expression
265
+ static symbol_exprt get_or_create_class_literal_symbol (
266
+ const irep_idt &class_id, symbol_tablet &symbol_table)
267
+ {
268
+ symbol_typet java_lang_Class (" java::java.lang.Class" );
269
+ symbol_exprt symbol_expr (
270
+ id2string (class_id)+" @class_model" ,
271
+ java_lang_Class);
272
+ if (!symbol_table.has_symbol (symbol_expr.get_identifier ()))
273
+ {
274
+ symbolt new_class_symbol;
275
+ new_class_symbol.name = symbol_expr.get_identifier ();
276
+ new_class_symbol.type = symbol_expr.type ();
277
+ INVARIANT (
278
+ has_prefix (id2string (new_class_symbol.name ), " java::" ),
279
+ " class identifier should have 'java::' prefix" );
280
+ new_class_symbol.base_name =
281
+ id2string (new_class_symbol.name ).substr (6 );
282
+ new_class_symbol.mode = ID_java;
283
+ new_class_symbol.is_lvalue = true ;
284
+ new_class_symbol.is_state_var = true ;
285
+ new_class_symbol.is_static_lifetime = true ;
286
+ symbol_table.add (new_class_symbol);
287
+ }
288
+
289
+ return symbol_expr;
290
+ }
291
+
292
+ // / Get result of a Java load-constant (ldc) instruction.
293
+ // / Possible cases:
294
+ // / 1) Pushing a String causes a reference to a java.lang.String object
295
+ // / to be constructed and pushed onto the operand stack.
296
+ // / 2) Pushing an int or a float causes a primitive value to be pushed
297
+ // / onto the stack.
298
+ // / 3) Pushing a Class constant causes a reference to a java.lang.Class
299
+ // / to be pushed onto the operand stack
300
+ // / \param ldc_arg0: raw operand to the ldc opcode
301
+ // / \param symbol_table: global symbol table. If the argument `ldc_arg0` is a
302
+ // / String or Class constant then a new constant global may be added.
303
+ // / \param string_refinement_enabled: true if --refine-strings is enabled, which
304
+ // / influences how String literals are structured.
305
+ // / \return ldc result
306
+ static exprt get_ldc_result (
307
+ const exprt &ldc_arg0,
308
+ symbol_tablet &symbol_table,
309
+ bool string_refinement_enabled)
310
+ {
311
+ if (ldc_arg0.id () == ID_type)
312
+ {
313
+ const irep_idt &class_id = ldc_arg0.type ().get (ID_identifier);
314
+ return
315
+ address_of_exprt (
316
+ get_or_create_class_literal_symbol (class_id, symbol_table));
317
+ }
318
+ else if (ldc_arg0.id () == ID_java_string_literal)
319
+ {
320
+ return
321
+ address_of_exprt (
322
+ get_or_create_string_literal_symbol (
323
+ ldc_arg0, symbol_table, string_refinement_enabled));
324
+ }
325
+ else
326
+ {
327
+ INVARIANT (
328
+ ldc_arg0.id () == ID_constant,
329
+ " ldc argument should be constant, string literal or class literal" );
330
+ return ldc_arg0;
331
+ }
332
+ }
333
+
334
+ // / Creates global variables for constants mentioned in a given method. These
335
+ // / are either string literals, or class literals (the java.lang.Class instance
336
+ // / returned by `(some_reference_typed_expression).class`). The method parse
337
+ // / tree is rewritten to directly reference these globals.
338
+ // / \param parse_tree: parse tree to search for constant global references
339
+ // / \param symbol_table: global symbol table, to which constant globals will be
340
+ // / added.
341
+ // / \param string_refinement_enabled: true if `--refine-stings` is active,
342
+ // / which changes how string literals are structured.
343
+ static void generate_constant_global_variables (
344
+ java_bytecode_parse_treet &parse_tree,
345
+ symbol_tablet &symbol_table,
346
+ bool string_refinement_enabled)
347
+ {
348
+ for (auto &method : parse_tree.parsed_class .methods )
349
+ {
350
+ for (auto &instruction : method.instructions )
351
+ {
352
+ // ldc* instructions are Java bytecode "load constant" ops, which can
353
+ // retrieve a numeric constant, String literal, or Class literal.
354
+ if (instruction.statement == " ldc" ||
355
+ instruction.statement == " ldc2" ||
356
+ instruction.statement == " ldc_w" ||
357
+ instruction.statement == " ldc2_w" )
358
+ {
359
+ INVARIANT (
360
+ instruction.args .size () != 0 ,
361
+ " ldc instructions should have an argument" );
362
+ instruction.args [0 ] =
363
+ get_ldc_result (
364
+ instruction.args [0 ],
365
+ symbol_table,
366
+ string_refinement_enabled);
367
+ }
368
+ }
369
+ }
370
+ }
371
+
259
372
bool java_bytecode_languaget::typecheck (
260
373
symbol_tablet &symbol_table,
261
374
const std::string &module )
@@ -317,6 +430,23 @@ bool java_bytecode_languaget::typecheck(
317
430
infer_opaque_type_fields (c.second , symbol_table);
318
431
}
319
432
433
+ // Create global variables for constants (String and Class literals) up front.
434
+ // This means that when running with lazy loading, we will be aware of these
435
+ // literal globals' existence when __CPROVER_initialize is generated in
436
+ // `generate_support_functions`.
437
+ const std::size_t before_constant_globals_size = symbol_table.symbols .size ();
438
+ for (auto &c : java_class_loader.class_map )
439
+ {
440
+ generate_constant_global_variables (
441
+ c.second ,
442
+ symbol_table,
443
+ string_refinement_enabled);
444
+ }
445
+ status () << " Java: added "
446
+ << (symbol_table.symbols .size () - before_constant_globals_size)
447
+ << " String or Class constant symbols"
448
+ << messaget::eom;
449
+
320
450
// Now incrementally elaborate methods
321
451
// that are reachable from this entry point.
322
452
if (lazy_methods_mode==LAZY_METHODS_MODE_CONTEXT_INSENSITIVE)
0 commit comments