|
33 | 33 | #include <util/std_expr.h>
|
34 | 34 | #include <util/string2int.h>
|
35 | 35 | #include <util/string_constant.h>
|
| 36 | +#include <util/threeval.h> |
36 | 37 |
|
37 | 38 | #include <goto-programs/cfg.h>
|
38 | 39 | #include <goto-programs/class_hierarchy.h>
|
@@ -3176,44 +3177,90 @@ irep_idt java_bytecode_convert_methodt::get_static_field(
|
3176 | 3177 | return inherited_method.get_full_component_identifier();
|
3177 | 3178 | }
|
3178 | 3179 |
|
3179 |
| -/// create temporary variables if a write instruction can have undesired side- |
3180 |
| -/// effects |
| 3180 | +/// Create temporary variables if a write instruction can have undesired side- |
| 3181 | +/// effects. |
| 3182 | +/// \param tmp_var_prefix: The prefix string to use for new temporary variables |
| 3183 | +/// \param tmp_var_type: The type of the temporary variable. |
| 3184 | +/// \param[out] block: The code block the assignment is added to if required. |
| 3185 | +/// \param write_type: The enumeration type of the write instruction. |
| 3186 | +/// \param identifier: The identifier of the symbol in the write instruction. |
3181 | 3187 | void java_bytecode_convert_methodt::save_stack_entries(
|
3182 | 3188 | const std::string &tmp_var_prefix,
|
3183 | 3189 | const typet &tmp_var_type,
|
3184 | 3190 | code_blockt &block,
|
3185 | 3191 | const bytecode_write_typet write_type,
|
3186 | 3192 | const irep_idt &identifier)
|
3187 | 3193 | {
|
| 3194 | + const std::function<bool( |
| 3195 | + const std::function<tvt(const exprt &expr)>, const exprt &expr)> |
| 3196 | + entry_matches = [&entry_matches]( |
| 3197 | + const std::function<tvt(const exprt &expr)> predicate, |
| 3198 | + const exprt &expr) { |
| 3199 | + const tvt &tvres = predicate(expr); |
| 3200 | + if(tvres.is_unknown()) |
| 3201 | + { |
| 3202 | + return std::any_of( |
| 3203 | + expr.operands().begin(), |
| 3204 | + expr.operands().end(), |
| 3205 | + [&predicate, &entry_matches](const exprt &expr) { |
| 3206 | + return entry_matches(predicate, expr); |
| 3207 | + }); |
| 3208 | + } |
| 3209 | + else |
| 3210 | + { |
| 3211 | + return tvres.is_true(); |
| 3212 | + } |
| 3213 | + }; |
| 3214 | + |
| 3215 | + // Function that checks whether the expression accesses a member with the |
| 3216 | + // given identifier name. These accesses are created in the case of `iinc`, or |
| 3217 | + // non-array `?store` instructions. |
| 3218 | + const std::function<tvt(const exprt &expr)> has_member_entry = [&identifier]( |
| 3219 | + const exprt &expr) { |
| 3220 | + const auto member_expr = expr_try_dynamic_cast<member_exprt>(expr); |
| 3221 | + return !member_expr ? tvt::unknown() |
| 3222 | + : tvt(member_expr->get_component_name() == identifier); |
| 3223 | + }; |
| 3224 | + |
| 3225 | + // Function that checks whether the expression is a symbol with the given |
| 3226 | + // identifier name. These accesses are created in the case of `putstatic` or |
| 3227 | + // `putfield` instructions. |
| 3228 | + const std::function<tvt(const exprt &expr)> is_symbol_entry = |
| 3229 | + [&identifier](const exprt &expr) { |
| 3230 | + const auto symbol_expr = expr_try_dynamic_cast<symbol_exprt>(expr); |
| 3231 | + return !symbol_expr ? tvt::unknown() |
| 3232 | + : tvt(symbol_expr->get_identifier() == identifier); |
| 3233 | + }; |
| 3234 | + |
| 3235 | + // Function that checks whether the expression is a dereference |
| 3236 | + // expression. These accesses are created in `?astore` array write |
| 3237 | + // instructions. |
| 3238 | + const std::function<tvt(const exprt &expr)> is_dereference_entry = |
| 3239 | + [](const exprt &expr) { |
| 3240 | + const auto dereference_expr = |
| 3241 | + expr_try_dynamic_cast<dereference_exprt>(expr); |
| 3242 | + return !dereference_expr ? tvt::unknown() : tvt(true); |
| 3243 | + }; |
| 3244 | + |
3188 | 3245 | for(auto &stack_entry : stack)
|
3189 | 3246 | {
|
3190 |
| - // remove typecasts if existing |
3191 |
| - while(stack_entry.id()==ID_typecast) |
3192 |
| - stack_entry=to_typecast_expr(stack_entry).op(); |
3193 |
| - |
3194 |
| - // variables or static fields and symbol -> save symbols with same id |
3195 |
| - if((write_type==bytecode_write_typet::VARIABLE || |
3196 |
| - write_type==bytecode_write_typet::STATIC_FIELD) && |
3197 |
| - stack_entry.id()==ID_symbol) |
| 3247 | + bool replace = false; |
| 3248 | + switch(write_type) |
| 3249 | + { |
| 3250 | + case bytecode_write_typet::VARIABLE: |
| 3251 | + case bytecode_write_typet::STATIC_FIELD: |
| 3252 | + replace = entry_matches(is_symbol_entry, stack_entry); |
| 3253 | + break; |
| 3254 | + case bytecode_write_typet::ARRAY_REF: |
| 3255 | + replace = entry_matches(is_dereference_entry, stack_entry); |
| 3256 | + break; |
| 3257 | + case bytecode_write_typet::FIELD: |
| 3258 | + replace = entry_matches(has_member_entry, stack_entry); |
| 3259 | + break; |
| 3260 | + } |
| 3261 | + if(replace) |
3198 | 3262 | {
|
3199 |
| - const symbol_exprt &var=to_symbol_expr(stack_entry); |
3200 |
| - if(var.get_identifier()==identifier) |
3201 |
| - create_stack_tmp_var(tmp_var_prefix, tmp_var_type, block, stack_entry); |
3202 |
| - } |
3203 |
| - |
3204 |
| - // array reference and dereference -> save all references on the stack |
3205 |
| - else if(write_type==bytecode_write_typet::ARRAY_REF && |
3206 |
| - stack_entry.id()==ID_dereference) |
3207 | 3263 | create_stack_tmp_var(tmp_var_prefix, tmp_var_type, block, stack_entry);
|
3208 |
| - |
3209 |
| - // field and member access -> compare component name |
3210 |
| - else if(write_type==bytecode_write_typet::FIELD && |
3211 |
| - stack_entry.id()==ID_member) |
3212 |
| - { |
3213 |
| - const irep_idt &entry_id= |
3214 |
| - to_member_expr(stack_entry).get_component_name(); |
3215 |
| - if(entry_id==identifier) |
3216 |
| - create_stack_tmp_var(tmp_var_prefix, tmp_var_type, block, stack_entry); |
3217 | 3264 | }
|
3218 | 3265 | }
|
3219 | 3266 | }
|
|
0 commit comments