Skip to content

Commit 0f42a19

Browse files
davidpichardiefacebook-github-bot
authored andcommitted
[Java frontend] Fixing Java bytecode local variable table before Sawja transformation
Summary: The .class format contains a debug table to retrieve the source name of local variables. The table generated by the Kotlin compiler does not follow the same convention than the javac compiler. This patch is a quick fix. it is not fully correct because we don't check outgoing edge while going forward in the opcode array, but we expect the bacward iteration to be always safe (and short). Official JVM spec: https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.13 Reviewed By: ngorogiannis Differential Revision: D31431271 fbshipit-source-id: 0cc608039
1 parent 8f0596e commit 0f42a19

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

infer/src/java/jTrans.ml

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,68 @@ let get_bytecode cm =
277277
{bytecode with JCode.c_code}
278278

279279

280+
(* Sawja uses the .class local_variable table using `javac` conventions where each
281+
[start, start+length) interval in the table should start at the next valid
282+
instruction after a store (except for parameters).
283+
284+
Example :
285+
I i = (I) o;
286+
System.out.println("something");
287+
i.m();
288+
is compiled into
289+
0: aload_0
290+
1: checkcast #2
291+
4: astore_1
292+
5: getstatic #3
293+
8: ldc #4
294+
10: invokevirtual #5
295+
13: aload_1
296+
14: invokeinterface #6, 1
297+
19: return
298+
LocalVariableTable:
299+
Start Length Slot Name Signature
300+
0 20 0 o Ljava/lang/Object;
301+
5 15 1 i LI;
302+
303+
Here, the interval is [5, 5+15) and its starts just after slot#1 assignment.
304+
305+
With the Kotlin compilation chain, the generated table does not respect this
306+
convention. The interval starts a bit later. It would be [13, 13+7) here
307+
for example.
308+
309+
The following function fix this problem by traversing backward (from 13 to 4
310+
in our example) the opcode array. *)
311+
let fix_local_variable_table code table =
312+
let fix_table_entry entry =
313+
let start, length, name, sign, slot = entry in
314+
let rec loop current_pc last_pc =
315+
(* last_pc : the last program point we have seen with a valide opcode *)
316+
if current_pc < 0 then entry
317+
else
318+
match code.(current_pc) with
319+
(* in a standard table, this case will happen as soon
320+
as the first iteration *)
321+
| JCode.OpStore (_, s) when Int.equal s slot ->
322+
if Int.equal last_pc start then entry else (last_pc, length, name, sign, slot)
323+
| JCode.OpInvalid ->
324+
loop (current_pc - 1) last_pc
325+
| _ ->
326+
loop (current_pc - 1) current_pc
327+
in
328+
loop (start - 1) start
329+
in
330+
List.map table ~f:fix_table_entry
331+
332+
280333
let get_jbir_representation cm bytecode =
334+
let c_local_variable_table =
335+
Option.map
336+
~f:(fix_local_variable_table bytecode.JCode.c_code)
337+
bytecode.JCode.c_local_variable_table
338+
in
339+
let fixed_bytecode = {bytecode with JCode.c_local_variable_table} in
281340
JBir.transform ~bcv:false ~ch_link:false ~formula:false ~formula_cmd:[] ~almost_ssa:true cm
282-
bytecode
341+
fixed_bytecode
283342

284343

285344
let pp_jbir fmt jbir =

0 commit comments

Comments
 (0)