Skip to content

Commit 75caefa

Browse files
Merge pull request diffblue#2116 from peterschrammel/java-new-pass
Move java new side-effect removal into separate pass
2 parents 6c90b35 + a61d03f commit 75caefa

File tree

10 files changed

+524
-235
lines changed

10 files changed

+524
-235
lines changed

src/clobber/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ target_link_libraries(clobber-lib
2525
)
2626

2727
add_if_library(clobber-lib bv_refinement)
28-
add_if_library(clobber-lib java_bytecode)
2928
add_if_library(clobber-lib specc)
3029
add_if_library(clobber-lib php)
3130

src/clobber/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
SRC = clobber_main.cpp \
22
clobber_parse_options.cpp \
33
# Empty last line
4+
45
OBJ += ../ansi-c/ansi-c$(LIBEXT) \
56
../cpp/cpp$(LIBEXT) \
6-
../java_bytecode/java_bytecode$(LIBEXT) \
77
../linking/linking$(LIBEXT) \
88
../big-int/big-int$(LIBEXT) \
99
../goto-programs/goto-programs$(LIBEXT) \

src/goto-cc/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ target_link_libraries(goto-cc-lib
1919
langapi
2020
)
2121

22-
add_if_library(goto-cc-lib java_bytecode)
2322
add_if_library(goto-cc-lib jsil)
2423

2524
# Executable

src/goto-programs/builtin_functions.cpp

-210
Original file line numberDiff line numberDiff line change
@@ -539,216 +539,6 @@ void goto_convertt::do_cpp_new(
539539
dest.destructive_append(tmp_initializer);
540540
}
541541

542-
void goto_convertt::do_java_new(
543-
const exprt &lhs,
544-
const side_effect_exprt &rhs,
545-
goto_programt &dest)
546-
{
547-
PRECONDITION(!lhs.is_nil());
548-
PRECONDITION(rhs.operands().empty());
549-
PRECONDITION(rhs.type().id() == ID_pointer);
550-
source_locationt location=rhs.source_location();
551-
typet object_type=rhs.type().subtype();
552-
553-
// build size expression
554-
exprt object_size=size_of_expr(object_type, ns);
555-
CHECK_RETURN(object_size.is_not_nil());
556-
557-
// we produce a malloc side-effect, which stays
558-
side_effect_exprt malloc_expr(ID_allocate, rhs.type());
559-
malloc_expr.copy_to_operands(object_size);
560-
// could use true and get rid of the code below
561-
malloc_expr.copy_to_operands(false_exprt());
562-
563-
goto_programt::targett t_n=dest.add_instruction(ASSIGN);
564-
t_n->code=code_assignt(lhs, malloc_expr);
565-
t_n->source_location=location;
566-
567-
// zero-initialize the object
568-
dereference_exprt deref(lhs, object_type);
569-
exprt zero_object=
570-
zero_initializer(object_type, location, ns, get_message_handler());
571-
set_class_identifier(
572-
to_struct_expr(zero_object), ns, to_symbol_type(object_type));
573-
goto_programt::targett t_i=dest.add_instruction(ASSIGN);
574-
t_i->code=code_assignt(deref, zero_object);
575-
t_i->source_location=location;
576-
}
577-
578-
void goto_convertt::do_java_new_array(
579-
const exprt &lhs,
580-
const side_effect_exprt &rhs,
581-
goto_programt &dest)
582-
{
583-
PRECONDITION(!lhs.is_nil()); // do_java_new_array without lhs not implemented
584-
PRECONDITION(rhs.operands().size() >= 1); // one per dimension
585-
PRECONDITION(rhs.type().id() == ID_pointer);
586-
587-
source_locationt location=rhs.source_location();
588-
typet object_type=rhs.type().subtype();
589-
PRECONDITION(ns.follow(object_type).id() == ID_struct);
590-
591-
// build size expression
592-
exprt object_size=size_of_expr(object_type, ns);
593-
594-
CHECK_RETURN(!object_size.is_nil());
595-
596-
// we produce a malloc side-effect, which stays
597-
side_effect_exprt malloc_expr(ID_allocate, rhs.type());
598-
malloc_expr.copy_to_operands(object_size);
599-
// code use true and get rid of the code below
600-
malloc_expr.copy_to_operands(false_exprt());
601-
602-
goto_programt::targett t_n=dest.add_instruction(ASSIGN);
603-
t_n->code=code_assignt(lhs, malloc_expr);
604-
t_n->source_location=location;
605-
606-
const struct_typet &struct_type=to_struct_type(ns.follow(object_type));
607-
608-
// Ideally we would have a check for `is_valid_java_array(struct_type)` but
609-
// `is_valid_java_array is part of the java_bytecode module and we cannot
610-
// introduce such dependencies. We do this simple check instead:
611-
PRECONDITION(struct_type.components().size()==3);
612-
613-
// Init base class:
614-
dereference_exprt deref(lhs, object_type);
615-
exprt zero_object=
616-
zero_initializer(object_type, location, ns, get_message_handler());
617-
set_class_identifier(
618-
to_struct_expr(zero_object), ns, to_symbol_type(object_type));
619-
goto_programt::targett t_i=dest.add_instruction(ASSIGN);
620-
t_i->code=code_assignt(deref, zero_object);
621-
t_i->source_location=location;
622-
623-
// if it's an array, we need to set the length field
624-
member_exprt length(
625-
deref,
626-
struct_type.components()[1].get_name(),
627-
struct_type.components()[1].type());
628-
goto_programt::targett t_s=dest.add_instruction(ASSIGN);
629-
t_s->code=code_assignt(length, rhs.op0());
630-
t_s->source_location=location;
631-
632-
// we also need to allocate space for the data
633-
member_exprt data(
634-
deref,
635-
struct_type.components()[2].get_name(),
636-
struct_type.components()[2].type());
637-
638-
// Allocate a (struct realtype**) instead of a (void**) if possible.
639-
const irept &given_element_type=object_type.find(ID_C_element_type);
640-
typet allocate_data_type;
641-
if(given_element_type.is_not_nil())
642-
{
643-
allocate_data_type=
644-
pointer_type(static_cast<const typet &>(given_element_type));
645-
}
646-
else
647-
allocate_data_type=data.type();
648-
649-
side_effect_exprt data_java_new_expr(
650-
ID_java_new_array_data, allocate_data_type);
651-
652-
// The instruction may specify a (hopefully small) upper bound on the
653-
// array size, in which case we allocate a fixed-length array that may
654-
// be larger than the `length` member rather than use a true variable-
655-
// length array, which produces a more complex formula in the current
656-
// backend.
657-
const irept size_bound=rhs.find(ID_length_upper_bound);
658-
if(size_bound.is_nil())
659-
data_java_new_expr.set(ID_size, rhs.op0());
660-
else
661-
data_java_new_expr.set(ID_size, size_bound);
662-
663-
// Must directly assign the new array to a temporary
664-
// because goto-symex will notice `x=side_effect_exprt` but not
665-
// `x=typecast_exprt(side_effect_exprt(...))`
666-
symbol_exprt new_array_data_symbol =
667-
new_tmp_symbol(
668-
data_java_new_expr.type(), "new_array_data", dest, location, ID_java)
669-
.symbol_expr();
670-
goto_programt::targett t_p2=dest.add_instruction(ASSIGN);
671-
t_p2->code=code_assignt(new_array_data_symbol, data_java_new_expr);
672-
t_p2->source_location=location;
673-
674-
goto_programt::targett t_p=dest.add_instruction(ASSIGN);
675-
exprt cast_java_new=new_array_data_symbol;
676-
if(cast_java_new.type()!=data.type())
677-
cast_java_new=typecast_exprt(cast_java_new, data.type());
678-
t_p->code=code_assignt(data, cast_java_new);
679-
t_p->source_location=location;
680-
681-
// zero-initialize the data
682-
if(!rhs.get_bool(ID_skip_initialize))
683-
{
684-
exprt zero_element=
685-
zero_initializer(
686-
data.type().subtype(),
687-
location,
688-
ns,
689-
get_message_handler());
690-
codet array_set(ID_array_set);
691-
array_set.copy_to_operands(new_array_data_symbol, zero_element);
692-
goto_programt::targett t_d=dest.add_instruction(OTHER);
693-
t_d->code=array_set;
694-
t_d->source_location=location;
695-
}
696-
697-
// multi-dimensional?
698-
699-
if(rhs.operands().size()>=2)
700-
{
701-
// produce
702-
// for(int i=0; i<size; i++) tmp[i]=java_new(dim-1);
703-
// This will be converted recursively.
704-
705-
goto_programt tmp;
706-
707-
symbol_exprt tmp_i =
708-
new_tmp_symbol(length.type(), "index", tmp, location, ID_java)
709-
.symbol_expr();
710-
711-
code_fort for_loop;
712-
713-
side_effect_exprt sub_java_new=rhs;
714-
sub_java_new.operands().erase(sub_java_new.operands().begin());
715-
716-
assert(rhs.type().id()==ID_pointer);
717-
typet sub_type=
718-
static_cast<const typet &>(rhs.type().subtype().find("#element_type"));
719-
assert(sub_type.id()==ID_pointer);
720-
sub_java_new.type()=sub_type;
721-
722-
side_effect_exprt inc(ID_assign);
723-
inc.operands().resize(2);
724-
inc.op0()=tmp_i;
725-
inc.op1()=plus_exprt(tmp_i, from_integer(1, tmp_i.type()));
726-
727-
dereference_exprt deref_expr(
728-
plus_exprt(data, tmp_i), data.type().subtype());
729-
730-
code_blockt for_body;
731-
symbol_exprt init_sym =
732-
new_tmp_symbol(sub_type, "subarray_init", tmp, location, ID_java)
733-
.symbol_expr();
734-
735-
code_assignt init_subarray(init_sym, sub_java_new);
736-
code_assignt assign_subarray(
737-
deref_expr,
738-
typecast_exprt(init_sym, deref_expr.type()));
739-
for_body.move_to_operands(init_subarray);
740-
for_body.move_to_operands(assign_subarray);
741-
742-
for_loop.init()=code_assignt(tmp_i, from_integer(0, tmp_i.type()));
743-
for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0());
744-
for_loop.iter()=inc;
745-
for_loop.body()=for_body;
746-
747-
convert(for_loop, tmp);
748-
dest.destructive_append(tmp);
749-
}
750-
}
751-
752542
/// builds a goto program for object initialization after new
753543
void goto_convertt::cpp_new_initializer(
754544
const exprt &lhs,

src/goto-programs/goto_convert.cpp

+31-17
Original file line numberDiff line numberDiff line change
@@ -753,30 +753,43 @@ void goto_convertt::convert_assign(
753753
Forall_operands(it, rhs)
754754
clean_expr(*it, dest);
755755

756+
// TODO: This should be done in a separate pass
756757
do_cpp_new(lhs, to_side_effect_expr(rhs), dest);
757758
}
758-
else if(rhs.id()==ID_side_effect &&
759-
rhs.get(ID_statement)==ID_java_new)
759+
else if(
760+
rhs.id() == ID_side_effect &&
761+
(rhs.get(ID_statement) == ID_assign ||
762+
rhs.get(ID_statement) == ID_postincrement ||
763+
rhs.get(ID_statement) == ID_preincrement ||
764+
rhs.get(ID_statement) == ID_statement_expression))
760765
{
761-
Forall_operands(it, rhs)
762-
clean_expr(*it, dest);
766+
// handle above side effects
767+
clean_expr(rhs, dest);
763768

764-
do_java_new(lhs, to_side_effect_expr(rhs), dest);
765-
}
766-
else if(rhs.id()==ID_side_effect &&
767-
rhs.get(ID_statement)==ID_java_new_array)
768-
{
769-
Forall_operands(it, rhs)
770-
clean_expr(*it, dest);
769+
if(lhs.id() == ID_typecast)
770+
{
771+
DATA_INVARIANT(
772+
lhs.operands().size() == 1, "Typecast must have one operand");
771773

772-
do_java_new_array(lhs, to_side_effect_expr(rhs), dest);
774+
// add a typecast to the rhs
775+
exprt new_rhs = rhs;
776+
rhs.make_typecast(lhs.op0().type());
777+
778+
// remove typecast from lhs
779+
exprt tmp = lhs.op0();
780+
lhs.swap(tmp);
781+
}
782+
783+
code_assignt new_assign(code);
784+
new_assign.lhs() = lhs;
785+
new_assign.rhs() = rhs;
786+
787+
copy(new_assign, ASSIGN, dest);
773788
}
774-
else if(
775-
rhs.id() == ID_side_effect &&
776-
(rhs.get(ID_statement) == ID_allocate ||
777-
rhs.get(ID_statement) == ID_java_new_array_data))
789+
else if(rhs.id() == ID_side_effect)
778790
{
779-
// just preserve
791+
// preserve side effects that will be handled at later stages,
792+
// such as allocate, new operators of other languages, e.g. java, etc
780793
Forall_operands(it, rhs)
781794
clean_expr(*it, dest);
782795

@@ -788,6 +801,7 @@ void goto_convertt::convert_assign(
788801
}
789802
else
790803
{
804+
// do everything else
791805
clean_expr(rhs, dest);
792806

793807
if(lhs.id()==ID_typecast)

src/java_bytecode/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ SRC = bytecode_info.cpp \
3131
java_types.cpp \
3232
java_utils.cpp \
3333
mz_zip_archive.cpp \
34-
replace_java_nondet.cpp \
3534
remove_exceptions.cpp \
3635
remove_instanceof.cpp \
36+
remove_java_new.cpp \
37+
replace_java_nondet.cpp \
3738
select_pointer_type.cpp \
3839
# Empty last line
3940

0 commit comments

Comments
 (0)