void jsil_typecheckt::typecheck_expr_concatenation(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), string_typet(), true); make_type_compatible(expr.op1(), string_typet(), true); expr.type()=string_typet(); }
void jsil_typecheckt::typecheck_expr_ref(exprt &expr) { if(expr.operands().size()!=3) { err_location(expr); error() << "operator `" << expr.id() << "' expects three operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_value_type(), true); make_type_compatible(expr.op1(), string_typet(), true); exprt &operand3=expr.op2(); make_type_compatible(operand3, jsil_kind(), true); if(operand3.id()==ID_member) expr.type()=jsil_member_reference_type(); else if(operand3.id()=="variable") expr.type()=jsil_variable_reference_type(); else { err_location(expr); error() << "operator `" << expr.id() << "' expects reference type in the third parameter. Got:" << operand3.pretty() << eom; throw 0; } }
void java_root_class(symbolt &class_symbol) { struct_typet &struct_type=to_struct_type(class_symbol.type); struct_typet::componentst &components=struct_type.components(); { // for monitorenter/monitorexit struct_typet::componentt component; component.set_name("@lock"); component.set_pretty_name("@lock"); component.type()=java_boolean_type(); // add at the beginning components.insert(components.begin(), component); } { // the class identifier is used for stuff such as 'instanceof' struct_typet::componentt component; component.set_name("@class_identifier"); component.set_pretty_name("@class_identifier"); component.type()=string_typet(); // add at the beginning components.insert(components.begin(), component); } }
typet jsil_prim_type() { return jsil_union_typet({ floatbv_typet(), string_typet(), bool_typet() }); }
void jsil_typecheckt::typecheck_expr_unary_string(exprt &expr) { if(expr.operands().size()!=1) { err_location(expr); error() << "operator `" << expr.id() << "' expects one operand" << eom; throw 0; } make_type_compatible(expr.op0(), string_typet(), true); expr.type()=floatbv_typet(); }
void jsil_typecheckt::typecheck_expr_field(exprt &expr) { if(expr.operands().size()!=1) { err_location(expr); error() << "operator `" << expr.id() << "' expects single operand" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_reference_type(), true); expr.type()=string_typet(); }
void jsil_typecheckt::typecheck_expr_proto_field(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_object_type(), true); make_type_compatible(expr.op1(), string_typet(), true); expr.type()=jsil_value_or_empty_type(); }
void jsil_typecheckt::typecheck_expr_index(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_object_type(), true); make_type_compatible(expr.op1(), string_typet(), true); // special case for function identifiers if (expr.op1().id()=="fid" || expr.op1().id()=="constructid") expr.type()=code_typet(); else expr.type()=jsil_value_type(); }
void set_class_identifier( struct_exprt &expr, const namespacet &ns, const symbol_typet &class_type) { const struct_typet &struct_type= to_struct_type(ns.follow(expr.type())); const struct_typet::componentst &components=struct_type.components(); if(components.empty()) return; assert(!expr.operands().empty()); if(components.front().get_name()=="@class_identifier") { assert(expr.op0().id()==ID_constant); expr.op0()=constant_exprt(class_type.get_identifier(), string_typet()); } else { assert(expr.op0().id()==ID_struct); set_class_identifier(to_struct_expr(expr.op0()), ns, class_type); } }
void remove_virtual_functionst::remove_virtual_function( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const auto &vcall_source_loc=target->source_location; const exprt &function=code.function(); assert(function.id()==ID_virtual_function); assert(!code.arguments().empty()); functionst functions; get_functions(function, functions); if(functions.empty()) { target->make_skip(); return; // give up } // only one option? if(functions.size()==1) { assert(target->is_function_call()); if(functions.begin()->symbol_expr==symbol_exprt()) target->make_skip(); else to_code_function_call(target->code).function()= functions.begin()->symbol_expr; return; } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->source_location=vcall_source_loc; t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; exprt this_expr=code.arguments()[0]; // If necessary, cast to the last candidate function to // get the object's clsid. By the structure of get_functions, // this is the parent of all other classes under consideration. const auto &base_classid=functions.back().class_id; const auto &base_function_symbol=functions.back().symbol_expr; symbol_typet suggested_type(base_classid); exprt c_id2=get_class_identifier_field(this_expr, suggested_type, ns); std::map<irep_idt, goto_programt::targett> calls; // Note backwards iteration, to get the least-derived candidate first. for(auto it=functions.crbegin(), itend=functions.crend(); it!=itend; ++it) { const auto &fun=*it; auto insertit=calls.insert( {fun.symbol_expr.get_identifier(), goto_programt::targett()}); // Only create one call sequence per possible target: if(insertit.second) { goto_programt::targett t1=new_code_calls.add_instruction(); t1->source_location=vcall_source_loc; if(!fun.symbol_expr.get_identifier().empty()) { // call function t1->make_function_call(code); auto &newcall=to_code_function_call(t1->code); newcall.function()=fun.symbol_expr; pointer_typet need_type(symbol_typet(fun.symbol_expr.get(ID_C_class))); if(!type_eq(newcall.arguments()[0].type(), need_type, ns)) newcall.arguments()[0].make_typecast(need_type); } else { // No definition for this type; shouldn't be possible... t1->make_assertion(false_exprt()); } insertit.first->second=t1; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->source_location=vcall_source_loc; t3->make_goto(t_final, true_exprt()); } // If this calls the base function we just fall through. // Otherwise branch to the right call: if(fun.symbol_expr!=base_function_symbol) { exprt c_id1=constant_exprt(fun.class_id, string_typet()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->source_location=vcall_source_loc; t4->make_goto(insertit.first->second, equal_exprt(c_id1, c_id2)); } } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { const irep_idt property_class=it->source_location.get_property_class(); const irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); } goto_programt::targett next_target=target; next_target++; goto_program.destructive_insert(next_target, new_code); // finally, kill original invocation target->make_skip(); }
void remove_virtual_functionst::remove_virtual_function( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); assert(function.id()==ID_virtual_function); assert(!code.arguments().empty()); functionst functions; get_functions(function, functions); if(functions.empty()) { target->make_skip(); return; // give up } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(functionst::const_iterator it=functions.begin(); it!=functions.end(); it++) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=it->symbol_expr; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); exprt this_expr=code.arguments()[0]; if(this_expr.type().id()!=ID_pointer || this_expr.type().id()!=ID_struct) { symbol_typet symbol_type(it->class_id); this_expr=typecast_exprt(this_expr, pointer_typet(symbol_type)); } exprt deref=dereference_exprt(this_expr, this_expr.type().subtype()); exprt c_id1=constant_exprt(it->class_id, string_typet()); exprt c_id2=build_class_identifier(deref); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(c_id1, c_id2)); } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { irep_idt property_class=it->source_location.get_property_class(); irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); }
void jsil_typecheckt::typecheck_expr_main(exprt &expr) { if(expr.id()==ID_code) { err_location(expr); error() << "typecheck_expr_main got code: " << expr.pretty() << eom; throw 0; } else if(expr.id()==ID_symbol) typecheck_symbol_expr(to_symbol_expr (expr)); else if(expr.id()==ID_constant) { } else { // expressions are expected not to have type set just yet assert(expr.type().is_nil()||expr.type().id().empty()); if (expr.id()==ID_null || expr.id()=="undefined" || expr.id()==ID_empty) typecheck_expr_constant(expr); else if(expr.id()=="null_type" || expr.id()=="undefined_type" || expr.id()==ID_boolean || expr.id()==ID_string || expr.id()=="number" || expr.id()=="builtin_object" || expr.id()=="user_object" || expr.id()=="object" || expr.id()==ID_reference || expr.id()==ID_member || expr.id()=="variable") expr.type()=jsil_kind(); else if(expr.id()=="proto" || expr.id()=="fid" || expr.id()=="scope" || expr.id()=="constructid" || expr.id()=="primvalue" || expr.id()=="targetfunction" || expr.id()==ID_class) { // TODO: have a special type for builtin fields expr.type()=string_typet(); } else if(expr.id()==ID_not) typecheck_expr_unary_boolean(expr); else if(expr.id()=="string_to_num") typecheck_expr_unary_string(expr); else if(expr.id()==ID_unary_minus || expr.id()=="num_to_int32" || expr.id()=="num_to_uint32" || expr.id()==ID_bitnot) { typecheck_expr_unary_num(expr); expr.type()=floatbv_typet(); } else if(expr.id()=="num_to_string") { typecheck_expr_unary_num(expr); expr.type()=string_typet(); } else if(expr.id()==ID_equal) typecheck_exp_binary_equal(expr); else if(expr.id()==ID_lt || expr.id()==ID_le) typecheck_expr_binary_compare(expr); else if(expr.id()==ID_plus || expr.id()==ID_minus || expr.id()==ID_mult || expr.id()==ID_div || expr.id()==ID_mod || expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor || expr.id()==ID_shl || expr.id()==ID_shr || expr.id()==ID_lshr) typecheck_expr_binary_arith(expr); else if(expr.id()==ID_and || expr.id()==ID_or) typecheck_expr_binary_boolean(expr); else if(expr.id()=="subtype_of") typecheck_expr_subtype(expr); else if(expr.id()==ID_concatenation) typecheck_expr_concatenation(expr); else if(expr.id()=="ref") typecheck_expr_ref(expr); else if(expr.id()=="field") typecheck_expr_field(expr); else if(expr.id()==ID_base) typecheck_expr_base(expr); else if(expr.id()==ID_typeof) expr.type()=jsil_kind(); else if(expr.id()=="new") expr.type()=jsil_user_object_type(); else if(expr.id()=="hasField") typecheck_expr_has_field(expr); else if(expr.id()==ID_index) typecheck_expr_index(expr); else if(expr.id()=="delete") typecheck_expr_delete(expr); else if(expr.id()=="protoField") typecheck_expr_proto_field(expr); else if(expr.id()=="protoObj") typecheck_expr_proto_obj(expr); else if(expr.id()==ID_side_effect) typecheck_expr_side_effect_throw(to_side_effect_expr_throw(expr)); else { err_location(expr); error() << "unexpected expression: " << expr.pretty() << eom; throw 0; } } }