Skip to content

Commit 6ecf4f9

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 6c84caa commit 6ecf4f9

File tree

1 file changed

+90
-52
lines changed

1 file changed

+90
-52
lines changed

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 90 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -394,65 +394,103 @@ void java_object_factoryt::gen_pointer_target_init(
394394
update_in_placet update_in_place,
395395
const source_locationt &location)
396396
{
397-
PRECONDITION(expr.type().id()==ID_pointer);
398-
PRECONDITION(update_in_place!=update_in_placet::MAY_UPDATE_IN_PLACE);
397+
PRECONDITION(expr.type().id() == ID_pointer);
398+
PRECONDITION(update_in_place != update_in_placet::MAY_UPDATE_IN_PLACE);
399399

400-
if(target_type.id()==ID_struct &&
401-
has_prefix(
402-
id2string(to_struct_type(target_type).get_tag()),
403-
"java::array["))
404-
{
405-
gen_nondet_array_init(
406-
assignments, expr, depth + 1, update_in_place, location);
407-
}
408-
else
400+
if(target_type.id() == ID_struct)
409401
{
410-
// obtain a target pointer to initialize; if in MUST_UPDATE_IN_PLACE mode we
411-
// initialize the fields of the object pointed by `expr`; if in
412-
// NO_UPDATE_IN_PLACE then we allocate a new object, get a pointer to it
413-
// (return value of `allocate_object`), emit a statement of the form
414-
// `<expr> := address-of(<new-object>)` and recursively initialize such new
415-
// object.
416-
exprt target;
417-
if(update_in_place==update_in_placet::NO_UPDATE_IN_PLACE)
402+
const auto &target_class_type = to_java_class_type(target_type);
403+
if(has_prefix(id2string(target_class_type.get_tag()), "java::array["))
418404
{
419-
target=allocate_object(
420-
assignments,
421-
expr,
422-
target_type,
423-
alloc_type);
424-
INVARIANT(
425-
target.type().id()==ID_pointer,
426-
"Pointer-typed expression expected");
405+
gen_nondet_array_init(
406+
assignments, expr, depth + 1, update_in_place, location);
407+
return;
427408
}
428-
else
409+
if(target_class_type.get_base("java::java.lang.Enum"))
429410
{
430-
target=expr;
431-
}
411+
// We nondet-initialize enums to be equal to one of the constants defined
412+
// for their type:
413+
// int i = nondet(int)
414+
// assume(0 < = i < $VALUES.length)
415+
// expr = $VALUES[i]
416+
// where $VALUES is a variable generated by the Java compiler that stores
417+
// the array that is returned by Enum.values().
418+
419+
const irep_idt &class_name = target_class_type.get_name();
420+
const irep_idt values_name = id2string(class_name) + ".$VALUES";
421+
INVARIANT(
422+
ns.get_symbol_table().has_symbol(values_name),
423+
"The $VALUES array (populated by clinit_wrapper) should be in the "
424+
"symbol table");
425+
const symbolt &values = ns.lookup(values_name);
426+
427+
// Access members (length and data) of $VALUES array
428+
dereference_exprt deref_expr(values.symbol_expr());
429+
const auto &deref_struct_type =
430+
to_struct_type(ns.follow(deref_expr.type()));
431+
PRECONDITION(is_valid_java_array(deref_struct_type));
432+
const auto &comps = deref_struct_type.components();
433+
const member_exprt length_expr(deref_expr, "length", comps[1].type());
434+
const member_exprt enum_array_expr =
435+
member_exprt(deref_expr, "data", comps[2].type());
436+
437+
const symbol_exprt &index_expr = gen_nondet_int_init(
438+
assignments,
439+
"enum_index_init",
440+
from_integer(0, java_int_type()),
441+
minus_exprt(length_expr, from_integer(1, java_int_type())),
442+
location);
432443

433-
// we dereference the pointer and initialize the resulting object using a
434-
// recursive call
435-
exprt init_expr;
436-
if(target.id()==ID_address_of)
437-
init_expr=target.op0();
438-
else
439-
{
440-
init_expr=
441-
dereference_exprt(target, target.type().subtype());
444+
// Generate statement using pointer arithmetic to access array element:
445+
// expr = (expr.type())*(enum_array_expr + index_expr);
446+
plus_exprt plus(enum_array_expr, index_expr);
447+
const dereference_exprt arraycellref(
448+
plus, enum_array_expr.type().subtype());
449+
code_assignt enum_assign(expr, typecast_exprt(arraycellref, expr.type()));
450+
assignments.add(enum_assign);
451+
return;
442452
}
443-
gen_nondet_init(
444-
assignments,
445-
init_expr,
446-
false, // is_sub
447-
"", // class_identifier
448-
false, // skip_classid
449-
alloc_type,
450-
false,
451-
typet(),
452-
depth + 1,
453-
update_in_place,
454-
location);
455453
}
454+
455+
// obtain a target pointer to initialize; if in MUST_UPDATE_IN_PLACE mode we
456+
// initialize the fields of the object pointed by `expr`; if in
457+
// NO_UPDATE_IN_PLACE then we allocate a new object, get a pointer to it
458+
// (return value of `allocate_object`), emit a statement of the form
459+
// `<expr> := address-of(<new-object>)` and recursively initialize such new
460+
// object.
461+
exprt target;
462+
if(update_in_place == update_in_placet::NO_UPDATE_IN_PLACE)
463+
{
464+
target = allocate_object(assignments, expr, target_type, alloc_type);
465+
INVARIANT(
466+
target.type().id() == ID_pointer, "Pointer-typed expression expected");
467+
}
468+
else
469+
{
470+
target = expr;
471+
}
472+
473+
// we dereference the pointer and initialize the resulting object using a
474+
// recursive call
475+
exprt init_expr;
476+
if(target.id() == ID_address_of)
477+
init_expr = target.op0();
478+
else
479+
{
480+
init_expr = dereference_exprt(target, target.type().subtype());
481+
}
482+
gen_nondet_init(
483+
assignments,
484+
init_expr,
485+
false, // is_sub
486+
"", // class_identifier
487+
false, // skip_classid
488+
alloc_type,
489+
false, // override
490+
typet(), // override type immaterial
491+
depth + 1,
492+
update_in_place,
493+
location);
456494
}
457495

458496
/// Recursion-set entry owner class. If a recursion-set entry is added
@@ -1258,7 +1296,7 @@ const symbol_exprt java_object_factoryt::gen_nondet_int_init(
12581296
gen_nondet_init(
12591297
assignments,
12601298
int_symbol_expr,
1261-
false, // is_sub
1299+
false, // is_sub
12621300
irep_idt(),
12631301
false, // skip_classid
12641302
allocation_typet::LOCAL, // immaterial, type is primitive

0 commit comments

Comments
 (0)