void goto_convertt::convert_try_catch( const codet &code, goto_programt &dest) { assert(code.operands().size()>=2); // add the CATCH-push instruction to 'dest' goto_programt::targett catch_push_instruction=dest.add_instruction(); catch_push_instruction->make_catch(); catch_push_instruction->code.set_statement(ID_catch); catch_push_instruction->source_location=code.source_location(); // the CATCH-push instruction is annotated with a list of IDs, // one per target irept::subt &exception_list= catch_push_instruction->code.add(ID_exception_list).get_sub(); // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); // the first operand is the 'try' block convert(to_code(code.op0()), dest); // add the CATCH-pop to the end of the 'try' block goto_programt::targett catch_pop_instruction=dest.add_instruction(); catch_pop_instruction->make_catch(); catch_pop_instruction->code.set_statement(ID_catch); // add a goto to the end of the 'try' block dest.add_instruction()->make_goto(end_target); for(unsigned i=1; i<code.operands().size(); i++) { const codet &block=to_code(code.operands()[i]); // grab the ID and add to CATCH instruction exception_list.push_back(irept(block.get(ID_exception_id))); goto_programt tmp; convert(block, tmp); catch_push_instruction->targets.push_back(tmp.instructions.begin()); dest.destructive_append(tmp); // add a goto to the end of the 'catch' block dest.add_instruction()->make_goto(end_target); } // add the end-target dest.destructive_append(end); }
void goto_convertt::read(exprt &expr, goto_programt &dest) { if(expr.is_constant()) return; if(expr.id()=="symbol") { // see if we already renamed it } symbolt &new_symbol=new_tmp_symbol(expr.type()); codet assignment("assign"); assignment.reserve_operands(2); assignment.copy_to_operands(symbol_expr(new_symbol)); assignment.move_to_operands(expr); goto_programt tmp_program; convert(assignment, tmp_program); dest.destructive_append(tmp_program); expr=symbol_expr(new_symbol); }
void goto_convertt::convert_CPROVER_try_catch( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { err_location(code); throw "CPROVER_try_catch expects two arguments"; } // this is where we go after 'throw' goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); // set 'throw' target throw_targett throw_target(targets); targets.set_throw(tmp.instructions.begin()); // now put 'catch' code onto destructor stack code_ifthenelset catch_code; catch_code.cond()=exception_flag(); catch_code.add_source_location()=code.source_location(); catch_code.then_case()=to_code(code.op1()); targets.destructor_stack.push_back(catch_code); // now convert 'try' code convert(to_code(code.op0()), dest); // pop 'catch' code off stack targets.destructor_stack.pop_back(); // add 'throw' target dest.destructive_append(tmp); }
void goto_convertt::convert_java_try_catch( const codet &code, goto_programt &dest) { assert(!code.operands().empty()); // add the CATCH instruction to 'dest' goto_programt::targett catch_instruction=dest.add_instruction(); catch_instruction->make_catch(); catch_instruction->code.set_statement(ID_catch); catch_instruction->source_location=code.source_location(); catch_instruction->function=code.source_location().get_function(); // the CATCH instruction is annotated with a list of exception IDs const irept exceptions=code.op0().find(ID_exception_list); if(exceptions.is_not_nil()) { irept::subt exceptions_sub=exceptions.get_sub(); irept::subt &exception_list= catch_instruction->code.add(ID_exception_list).get_sub(); exception_list.resize(exceptions_sub.size()); for(size_t i=0; i<exceptions_sub.size(); ++i) exception_list[i].id(exceptions_sub[i].id()); } // the CATCH instruction is also annotated with a list of handle labels const irept handlers=code.op0().find(ID_label); if(handlers.is_not_nil()) { irept::subt handlers_sub=handlers.get_sub(); irept::subt &handlers_list= catch_instruction->code.add(ID_label).get_sub(); handlers_list.resize(handlers_sub.size()); for(size_t i=0; i<handlers_sub.size(); ++i) handlers_list[i].id(handlers_sub[i].id()); } // the CATCH instruction may also signal a handler if(code.op0().has_operands()) { catch_instruction->code.get_sub().resize(1); catch_instruction->code.get_sub()[0]=code.op0().op0(); } // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); end_target->source_location=code.source_location(); end_target->function=code.source_location().get_function(); // add the end-target dest.destructive_append(end); }
void goto_convertt::convert_msc_try_finally( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { error().source_location=code.find_source_location(); error() << "msc_try_finally expects two arguments" << eom; throw 0; } goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); { // save 'leave' target leave_targett leave_target(targets); targets.set_leave(tmp.instructions.begin()); // first put 'finally' code onto destructor stack targets.destructor_stack.push_back(to_code(code.op1())); // do 'try' code convert(to_code(code.op0()), dest); // pop 'finally' from destructor stack targets.destructor_stack.pop_back(); // 'leave' target gets restored here } // now add 'finally' code convert(to_code(code.op1()), dest); // this is the target for 'leave' dest.destructive_append(tmp); }
void goto_convertt::do_java_new_array( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new_array without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().size()>=1); // one per dimension if(rhs.type().id()!=ID_pointer) throw "do_java_new_array returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new_array got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // multi-dimensional? assert(ns.follow(object_type).id()==ID_struct); const struct_typet &struct_type=to_struct_type(ns.follow(object_type)); assert(struct_type.components().size()==3); // if it's an array, we need to set the length field dereference_exprt deref(lhs, object_type); member_exprt length(deref, struct_type.components()[1].get_name(), struct_type.components()[1].type()); goto_programt::targett t_s=dest.add_instruction(ASSIGN); t_s->code=code_assignt(length, rhs.op0()); t_s->source_location=location; // we also need to allocate space for the data member_exprt data(deref, struct_type.components()[2].get_name(), struct_type.components()[2].type()); side_effect_exprt data_cpp_new_expr(ID_cpp_new_array, data.type()); data_cpp_new_expr.set(ID_size, rhs.op0()); goto_programt::targett t_p=dest.add_instruction(ASSIGN); t_p->code=code_assignt(data, data_cpp_new_expr); t_p->source_location=location; // zero-initialize the data exprt zero_element=gen_zero(data.type().subtype()); codet array_set(ID_array_set); array_set.copy_to_operands(data, zero_element); goto_programt::targett t_d=dest.add_instruction(OTHER); t_d->code=array_set; t_d->source_location=location; if(rhs.operands().size()>=2) { // produce // for(int i=0; i<size; i++) tmp[i]=java_new(dim-1); // This will be converted recursively. goto_programt tmp; symbol_exprt tmp_i= new_tmp_symbol(index_type(), "index", tmp, location).symbol_expr(); code_fort for_loop; side_effect_exprt sub_java_new=rhs; sub_java_new.operands().erase(sub_java_new.operands().begin()); side_effect_exprt inc(ID_assign); inc.operands().resize(2); inc.op0()=tmp_i; inc.op1()=plus_exprt(tmp_i, gen_one(tmp_i.type())); dereference_exprt deref_expr(plus_exprt(data, tmp_i), data.type().subtype()); for_loop.init()=code_assignt(tmp_i, gen_zero(tmp_i.type())); for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); for_loop.iter()=inc; for_loop.body()=code_skipt(); for_loop.body()=code_assignt(deref_expr, sub_java_new); convert(for_loop, tmp); dest.destructive_append(tmp); } }
void goto_convertt::do_cpp_new( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_cpp_new without lhs is yet to be implemented"; // build size expression exprt object_size= static_cast<const exprt &>(rhs.find(ID_sizeof)); bool new_array=rhs.get(ID_statement)==ID_cpp_new_array; exprt count; if(new_array) { count=static_cast<const exprt &>(rhs.find(ID_size)); if(count.type()!=object_size.type()) count.make_typecast(object_size.type()); // might have side-effect clean_expr(count, dest); } exprt tmp_symbol_expr; // is this a placement new? if(rhs.operands().empty()) // no, "regular" one { // call __new or __new_array exprt new_symbol= ns.lookup(new_array?"__new_array":"__new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type= code_type.return_type(); assert(code_type.parameters().size()==1 || code_type.parameters().size()==2); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); convert(new_call, dest); } else if(rhs.operands().size()==1) { // call __placement_new exprt new_symbol= ns.lookup(new_array?"__placement_new_array":"__placement_new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type=code_type.return_type(); assert(code_type.parameters().size()==2 || code_type.parameters().size()==3); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.arguments().push_back(rhs.op0()); // memory location new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); for(unsigned i=0; i<code_type.parameters().size(); i++) if(new_call.arguments()[i].type()!=code_type.parameters()[i].type()) new_call.arguments()[i].make_typecast(code_type.parameters()[i].type()); convert(new_call, dest); } else throw "cpp_new expected to have 0 or 1 operands"; goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt( lhs, typecast_exprt(tmp_symbol_expr, lhs.type())); t_n->source_location=rhs.find_source_location(); // grab initializer goto_programt tmp_initializer; cpp_new_initializer(lhs, rhs, tmp_initializer); dest.destructive_append(tmp_initializer); }
void goto_convertt::do_function_call_if( const exprt &lhs, const if_exprt &function, const exprt::operandst &arguments, goto_programt &dest) { // case split // c?f():g() //-------------------- // v: if(!c) goto y; // w: f(); // x: goto z; // y: g(); // z: ; // do the v label goto_programt tmp_v; goto_programt::targett v=tmp_v.add_instruction(); // do the x label goto_programt tmp_x; goto_programt::targett x=tmp_x.add_instruction(); // do the z label goto_programt tmp_z; goto_programt::targett z=tmp_z.add_instruction(); z->make_skip(); // y: g(); goto_programt tmp_y; goto_programt::targett y; do_function_call(lhs, function.false_case(), arguments, tmp_y); if(tmp_y.instructions.empty()) y=tmp_y.add_instruction(SKIP); else y=tmp_y.instructions.begin(); // v: if(!c) goto y; v->make_goto(y); v->guard=function.cond(); v->guard.make_not(); v->source_location=function.cond().source_location(); // w: f(); goto_programt tmp_w; do_function_call(lhs, function.true_case(), arguments, tmp_w); if(tmp_w.instructions.empty()) tmp_w.add_instruction(SKIP); // x: goto z; x->make_goto(z); dest.destructive_append(tmp_v); dest.destructive_append(tmp_w); dest.destructive_append(tmp_x); dest.destructive_append(tmp_y); dest.destructive_append(tmp_z); }