Skip to content

Commit 11dbf8a

Browse files
committed
Nondet-init enums by assigning them to a constant
Rather than nondet-initializing each field (String name and int ordinal) of an enum, we assign it to be equal to one of the constant values stored in the $VALUES array of the corresponding type.
1 parent b65a0d4 commit 11dbf8a

File tree

1 file changed

+95
-59
lines changed

1 file changed

+95
-59
lines changed

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 95 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ class java_object_factoryt
146146
code_blockt &assignments,
147147
const std::string &basename_prefix,
148148
const exprt &min_length_expr,
149-
const exprt &max_length_expr);
149+
const exprt &max_length_expr,
150+
bool include_max);
150151

151152
void gen_method_call(
152153
code_blockt &assignments,
@@ -384,67 +385,95 @@ void java_object_factoryt::gen_pointer_target_init(
384385
size_t depth,
385386
update_in_placet update_in_place)
386387
{
387-
PRECONDITION(expr.type().id()==ID_pointer);
388-
PRECONDITION(update_in_place!=update_in_placet::MAY_UPDATE_IN_PLACE);
388+
PRECONDITION(expr.type().id() == ID_pointer);
389+
PRECONDITION(update_in_place != update_in_placet::MAY_UPDATE_IN_PLACE);
389390

390-
if(target_type.id()==ID_struct &&
391-
has_prefix(
392-
id2string(to_struct_type(target_type).get_tag()),
393-
"java::array["))
394-
{
395-
gen_nondet_array_init(
396-
assignments,
397-
expr,
398-
depth+1,
399-
update_in_place);
400-
}
401-
else
391+
if(target_type.id() == ID_struct)
402392
{
403-
// obtain a target pointer to initialize; if in MUST_UPDATE_IN_PLACE mode we
404-
// initialize the fields of the object pointed by `expr`; if in
405-
// NO_UPDATE_IN_PLACE then we allocate a new object, get a pointer to it
406-
// (return value of `allocate_object`), emit a statement of the form
407-
// `<expr> := address-of(<new-object>)` and recursively initialize such new
408-
// object.
409-
exprt target;
410-
if(update_in_place==update_in_placet::NO_UPDATE_IN_PLACE)
393+
const auto &target_class_type = to_java_class_type(target_type);
394+
if(has_prefix(id2string(target_class_type.get_tag()), "java::array["))
411395
{
412-
target=allocate_object(
413-
assignments,
414-
expr,
415-
target_type,
416-
alloc_type);
417-
INVARIANT(
418-
target.type().id()==ID_pointer,
419-
"Pointer-typed expression expected");
396+
gen_nondet_array_init(assignments, expr, depth + 1, update_in_place);
397+
return;
420398
}
421-
else
399+
if(target_class_type.get_base("java::java.lang.Enum"))
422400
{
423-
target=expr;
401+
// We nondet-initialize enums to be equal to one of the constants defined
402+
// for their type:
403+
// int i = nondet(int)
404+
// assume(0 < = i < $VALUES.length)
405+
// expr = $VALUES[i]
406+
// where $VALUES is a variable generated by the Java compiler that stores
407+
// the array that is returned by Enum.values().
408+
409+
const irep_idt &class_name = target_class_type.get_name();
410+
const symbolt &values = ns.lookup(id2string(class_name) + ".$VALUES");
411+
412+
// Access members (length and data) of $VALUES array
413+
dereference_exprt deref_expr(values.symbol_expr());
414+
const auto &deref_struct_type =
415+
to_struct_type(ns.follow(deref_expr.type()));
416+
const auto &comps = deref_struct_type.components();
417+
const member_exprt length_expr(deref_expr, "length", comps[1].type());
418+
const member_exprt enum_array_expr =
419+
member_exprt(deref_expr, "data", comps[2].type());
420+
421+
const symbol_exprt &index_expr = gen_nondet_int_init(
422+
assignments,
423+
"enum_index_init",
424+
from_integer(0, java_int_type()),
425+
length_expr,
426+
false);
427+
428+
// Index array using pointer arithmetic
429+
plus_exprt plus(enum_array_expr, index_expr, enum_array_expr.type());
430+
const dereference_exprt arraycellref(
431+
plus_exprt(enum_array_expr, index_expr, enum_array_expr.type()),
432+
enum_array_expr.type().subtype());
433+
code_assignt enum_assign(expr, typecast_exprt(arraycellref, expr.type()));
434+
assignments.add(enum_assign);
435+
return;
424436
}
437+
}
425438

426-
// we dereference the pointer and initialize the resulting object using a
427-
// recursive call
428-
exprt init_expr;
429-
if(target.id()==ID_address_of)
430-
init_expr=target.op0();
431-
else
432-
{
433-
init_expr=
434-
dereference_exprt(target, target.type().subtype());
435-
}
436-
gen_nondet_init(
437-
assignments,
438-
init_expr,
439-
false, // is_sub
440-
"", // class_identifier
441-
false, // skip_classid
442-
alloc_type,
443-
false, // override
444-
typet(), // override type immaterial
445-
depth+1,
446-
update_in_place);
439+
// obtain a target pointer to initialize; if in MUST_UPDATE_IN_PLACE mode we
440+
// initialize the fields of the object pointed by `expr`; if in
441+
// NO_UPDATE_IN_PLACE then we allocate a new object, get a pointer to it
442+
// (return value of `allocate_object`), emit a statement of the form
443+
// `<expr> := address-of(<new-object>)` and recursively initialize such new
444+
// object.
445+
exprt target;
446+
if(update_in_place == update_in_placet::NO_UPDATE_IN_PLACE)
447+
{
448+
target = allocate_object(assignments, expr, target_type, alloc_type);
449+
INVARIANT(
450+
target.type().id() == ID_pointer, "Pointer-typed expression expected");
451+
}
452+
else
453+
{
454+
target = expr;
455+
}
456+
457+
// we dereference the pointer and initialize the resulting object using a
458+
// recursive call
459+
exprt init_expr;
460+
if(target.id() == ID_address_of)
461+
init_expr = target.op0();
462+
else
463+
{
464+
init_expr = dereference_exprt(target, target.type().subtype());
447465
}
466+
gen_nondet_init(
467+
assignments,
468+
init_expr,
469+
false, // is_sub
470+
"", // class_identifier
471+
false, // skip_classid
472+
alloc_type,
473+
false, // override
474+
typet(), // override type immaterial
475+
depth + 1,
476+
update_in_place);
448477
}
449478

450479
/// Recursion-set entry owner class. If a recursion-set entry is added
@@ -1207,20 +1236,25 @@ void java_object_factoryt::gen_nondet_init(
12071236
}
12081237
}
12091238

1210-
/// Nondeterministically initializes an int i in the range min <= i <= max,
1239+
/// Nondeterministically initializes an int i in the range min <= i <= max (if
1240+
/// `include_max` is true) or min <= i < max (if `include_max` is false),
12111241
/// where min is the integer represented by `min_value_expr` and max is the
12121242
/// integer represented by `max_value_expr`.
12131243
/// \param [out] assignments: A code block that the initializing assignments
12141244
/// will be appended to.
12151245
/// \param basename_prefix: Used for naming the newly created symbol.
12161246
/// \param min_value_expr: Represents the minimum value for the integer.
12171247
/// \param max_value_expr: Represents the maximum value for the integer.
1248+
/// \param include_max: true if the maximum value should be included in the
1249+
/// range, false otherwise (i.e. if the maximum value for the integer is
1250+
/// max_value_expr - 1).
12181251
/// \return A symbol expression for the resulting integer.
12191252
const symbol_exprt java_object_factoryt::gen_nondet_int_init(
12201253
code_blockt &assignments,
12211254
const std::string &basename_prefix,
12221255
const exprt &min_value_expr,
1223-
const exprt &max_value_expr)
1256+
const exprt &max_value_expr,
1257+
bool include_max)
12241258
{
12251259
// Allocate a new symbol for the int
12261260
const symbolt &int_symbol = get_fresh_aux_symbol(
@@ -1237,7 +1271,7 @@ const symbol_exprt java_object_factoryt::gen_nondet_int_init(
12371271
gen_nondet_init(
12381272
assignments,
12391273
int_symbol_expr,
1240-
false, // is_sub
1274+
false, // is_sub
12411275
irep_idt(),
12421276
false, // skip_classid
12431277
allocation_typet::LOCAL, // immaterial, type is primitive
@@ -1250,7 +1284,8 @@ const symbol_exprt java_object_factoryt::gen_nondet_int_init(
12501284
const auto min_assume_expr =
12511285
binary_relation_exprt(int_symbol_expr, ID_ge, min_value_expr);
12521286
const auto max_assume_expr =
1253-
binary_relation_exprt(int_symbol_expr, ID_le, max_value_expr);
1287+
include_max ? binary_relation_exprt(int_symbol_expr, ID_le, max_value_expr)
1288+
: binary_relation_exprt(int_symbol_expr, ID_lt, max_value_expr);
12541289
assignments.add(code_assumet(min_assume_expr));
12551290
assignments.add(code_assumet(max_assume_expr));
12561291

@@ -1280,7 +1315,8 @@ void java_object_factoryt::allocate_nondet_length_array(
12801315
assignments,
12811316
"nondet_array_length",
12821317
from_integer(0, java_int_type()),
1283-
max_length_expr);
1318+
max_length_expr,
1319+
true);
12841320

12851321
side_effect_exprt java_new_array(ID_java_new_array, lhs.type());
12861322
java_new_array.copy_to_operands(length_sym_expr);

0 commit comments

Comments
 (0)