Skip to content

Commit f65f0fd

Browse files
authored
Merge pull request #1764 from smowton/smowton/feature/java-infer-opaque-type-fields-earlier
Java: infer opaque type fields before method conversion
2 parents 58d5980 + e86e2a0 commit f65f0fd

File tree

2 files changed

+69
-15
lines changed

2 files changed

+69
-15
lines changed

src/java_bytecode/java_bytecode_language.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,67 @@ bool java_bytecode_languaget::parse(
195195
return false;
196196
}
197197

198+
/// Infer fields that must exist on opaque types from field accesses against
199+
/// them. Note that we don't yet try to infer inheritence between opaque types
200+
/// here, so we may introduce the same field onto a type and its ancestor
201+
/// without realising that is in fact the same field, inherited from that
202+
/// ancestor. This can lead to incorrect results when opaque types are cast
203+
/// to other opaque types and their fields do not alias as intended.
204+
/// \param parse_tree: class parse tree
205+
/// \param symbol_table: global symbol table
206+
static void infer_opaque_type_fields(
207+
const java_bytecode_parse_treet &parse_tree,
208+
symbol_tablet &symbol_table)
209+
{
210+
namespacet ns(symbol_table);
211+
for(const auto &method : parse_tree.parsed_class.methods)
212+
{
213+
for(const auto &instruction : method.instructions)
214+
{
215+
if(instruction.statement == "getfield" ||
216+
instruction.statement == "putfield")
217+
{
218+
const exprt &fieldref = instruction.args[0];
219+
const symbolt *class_symbol =
220+
symbol_table.lookup(fieldref.get(ID_class));
221+
INVARIANT(
222+
class_symbol != nullptr, "all field types should have been loaded");
223+
224+
const class_typet *class_type = &to_class_type(class_symbol->type);
225+
irep_idt class_symbol_id = fieldref.get(ID_class);
226+
const irep_idt &component_name = fieldref.get(ID_component_name);
227+
while(!class_type->has_component(component_name))
228+
{
229+
if(class_type->get_bool(ID_incomplete_class))
230+
{
231+
// Accessing a field of an incomplete (opaque) type.
232+
symbolt &writable_class_symbol =
233+
symbol_table.get_writeable_ref(class_symbol_id);
234+
auto &add_to_components =
235+
to_struct_type(writable_class_symbol.type).components();
236+
add_to_components.push_back(
237+
struct_typet::componentt(component_name, fieldref.type()));
238+
add_to_components.back().set_base_name(component_name);
239+
add_to_components.back().set_pretty_name(component_name);
240+
break;
241+
}
242+
else
243+
{
244+
// Not present here: check the superclass.
245+
INVARIANT(
246+
class_type->bases().size() != 0,
247+
"class missing an expected field should have a superclass");
248+
const symbol_typet &superclass_type =
249+
to_symbol_type(class_type->bases()[0].type());
250+
class_symbol_id = superclass_type.get_identifier();
251+
class_type = &to_class_type(ns.follow(superclass_type));
252+
}
253+
}
254+
}
255+
}
256+
}
257+
}
258+
198259
bool java_bytecode_languaget::typecheck(
199260
symbol_tablet &symbol_table,
200261
const std::string &module)
@@ -248,6 +309,14 @@ bool java_bytecode_languaget::typecheck(
248309
}
249310
}
250311

312+
// Infer fields on opaque types based on the method instructions just loaded.
313+
// For example, if we don't have bytecode for field x of class A, but we can
314+
// see an int-typed getfield instruction referring to it, add that field now.
315+
for(const auto &c : java_class_loader.class_map)
316+
{
317+
infer_opaque_type_fields(c.second, symbol_table);
318+
}
319+
251320
// Now incrementally elaborate methods
252321
// that are reachable from this entry point.
253322
if(lazy_methods_mode==LAZY_METHODS_MODE_CONTEXT_INSENSITIVE)

src/java_bytecode/java_bytecode_typecheck_expr.cpp

-15
Original file line numberDiff line numberDiff line change
@@ -307,21 +307,6 @@ void java_bytecode_typecheckt::typecheck_expr_member(member_exprt &expr)
307307
struct_typet::componentst &components=
308308
struct_type.components();
309309

310-
if(struct_type.get_bool(ID_incomplete_class))
311-
{
312-
// member doesn't exist. In this case struct_type should be an opaque
313-
// stub, and we'll add the member to it.
314-
symbolt &symbol_table_type=symbol_table.get_writeable_ref(
315-
"java::"+id2string(struct_type.get_tag()));
316-
auto &add_to_components=
317-
to_struct_type(symbol_table_type.type).components();
318-
add_to_components
319-
.push_back(struct_typet::componentt(component_name, expr.type()));
320-
add_to_components.back().set_base_name(component_name);
321-
add_to_components.back().set_pretty_name(component_name);
322-
return;
323-
}
324-
325310
if(components.empty())
326311
break;
327312

0 commit comments

Comments
 (0)