@@ -248,9 +248,179 @@ for(tmp_index = 0; tmp_index < dim_size; ++tmp_index)
248248
249249` remove_java_new ` is then recursively applied to the new ` subarray ` .
250250
251- \section java-bytecode-remove-exceptions remove_exceptions
251+ \section java-bytecode-remove-exceptions Remove exceptions
252252
253- To be documented.
253+ When \ref remove_exceptions is called on the \ref goto_modelt, the
254+ goto model contains complex instructions (\ref goto_program_instruction_typet)
255+ such as ` CATCH-POP ` , ` CATCH-PUSH ` and ` THROW ` . In order to analyze the goto
256+ model, the instructions must be simplified to use more basic instructions - this
257+ is called "lowering". This class lowers the ` CATCH ` and ` THROW ` instructions.
258+
259+ ` THROW ` instructions are replaced by assigning to ` @inflight_exception ` and a
260+ goto to end of the function. ` CATCH ` instructions are replaced by a check of
261+ the ` @inflight_exception ` and setting it to null.
262+
263+ \subsection throw THROW
264+
265+ Consider a simple method ` testException(I)V ` :
266+
267+ ``` java
268+ public class TestExceptions {
269+ int field;
270+ public void testException (int i ) throws Exception {
271+ if (i < 0 ) {
272+ throw new Exception ();
273+ }
274+ field = i;
275+ }
276+ }
277+ ```
278+
279+ The goto for ` testException(I)V ` before ` remove_exceptions ` (removing comments
280+ and replacing irrelevant parts with ` ... ` ) is:
281+
282+ ```
283+ TestExceptions.testException(int) /* java::TestExceptions.testException:(I)V */
284+ IF i >= 0 THEN GOTO 3
285+ struct java.lang.Exception *new_tmp0;
286+ new_tmp0 = new struct java.lang.Exception;
287+ IF !(new_tmp0 == null) THEN GOTO 1
288+
289+ ...
290+
291+ 1: SKIP
292+ new_tmp0 . java.lang.Exception.<init>:()V();
293+
294+ ...
295+
296+ 2: SKIP
297+ THROW: throw(new_tmp0)
298+ dead new_tmp0;
299+
300+ ...
301+
302+ ```
303+ where there is a ` THROW ` instruction to be replaced.
304+
305+ After passing the goto model through ` remove_exceptions ` , it is:
306+
307+ ```
308+ TestExceptions.testException(int) /* java::TestExceptions.testException:(I)V */
309+ IF i >= 0 THEN GOTO 4
310+ struct java.lang.Exception *new_tmp0;
311+ new_tmp0 = new struct java.lang.Exception;
312+ IF !(new_tmp0 == null) THEN GOTO 1
313+
314+ ...
315+
316+ 1: new_tmp0 . java.lang.Exception.<init>:()V();
317+ IF @inflight_exception == null THEN GOTO 2 // it is because we've not used it yet
318+
319+ ...
320+
321+ 2: IF !(new_tmp0 == null) THEN GOTO 3
322+
323+ ...
324+
325+ 3: @inflight_exception = (void *)new_tmp0;
326+ dead new_tmp0;
327+
328+ ...
329+
330+ ```
331+ where now instead of the instruction ` THROW ` , the global variable
332+ ` @inflight_exception ` holds the thrown exception in a separate goto statement.
333+
334+ \subsection catch CATCH-PUSH, CATCH-POP and EXCEPTION LANDING PAD
335+
336+ Consider the method ` catchSomething(I)V ` that tries the above method
337+ ` testException(I)V ` and catches the exception:
338+
339+ ``` java
340+ public class TestExceptions {
341+ int field;
342+ public void testException (int i ) throws Exception {
343+ if (i < 0 ) {
344+ throw new Exception ();
345+ }
346+ field = i;
347+ }
348+ public void catchSomething (int i ) {
349+ try {
350+ testException(i);
351+ } catch (Exception e) {
352+ }
353+ }
354+ }
355+ ```
356+
357+ The goto model before ` remove_exceptions ` is:
358+ ```
359+ TestExceptions.catchSomething(int) /* java::TestExceptions.catchSomething:(I)V */
360+
361+ ...
362+
363+ CATCH-PUSH ->2
364+
365+ ...
366+
367+ 1: SKIP
368+ this . com.diffblue.regression.TestExceptions.testException:(I)V(i);
369+ CATCH-POP
370+ GOTO 3
371+ 2: void *anonlocal::2a;
372+ struct java.lang.Exception *caught_exception_tmp0;
373+ EXCEPTION LANDING PAD (struct java.lang.Exception * caught_exception_tmp0)
374+ anonlocal::2a = (void *)caught_exception_tmp0;
375+ dead caught_exception_tmp0;
376+ dead anonlocal::2a;
377+
378+ ...
379+
380+ ```
381+ The ` CATCH-PUSH ` instruction signifies the start of the try block, the
382+ ` CATCH-POP ` instruction signifies the end of the try block, and the `EXCEPTION
383+ LANDING PAD` signifies beginning of the catch block.
384+
385+ After ` remove_exceptions ` the goto model is:
386+
387+ ```
388+ TestExceptions.catchSomething(int) /* java::TestExceptions.catchSomething:(I)V */
389+
390+ ...
391+
392+ this . com.diffblue.regression.TestExceptions.testException:(I)V(i);
393+ IF @inflight_exception == null THEN GOTO 3 // true if testException does not throw, method terminates normally
394+ IF !(@inflight_exception == null) THEN GOTO 1 // true if testException throws, enters catch block
395+
396+ ...
397+
398+ 1: __CPROVER_string class_identifier_tmp;
399+ class_identifier_tmp = ((struct java.lang.Object *)@inflight_exception)->@class_identifier;
400+ instanceof_result_tmp = class_identifier_tmp == "java::java.lang.Exception" || ... ; // TRUE
401+ dead class_identifier_tmp;
402+ 2: IF instanceof_result_tmp THEN GOTO 4
403+
404+ ...
405+
406+ 3: ASSERT false // block 3
407+ GOTO 5
408+ 4: void *anonlocal::2a; // The catch block
409+ struct java.lang.Exception *caught_exception_tmp0;
410+ ASSERT false // block 4
411+ caught_exception_tmp0 = (struct java.lang.Exception *)@inflight_exception;
412+ @inflight_exception = null;
413+ anonlocal::2a = (void *)caught_exception_tmp0;
414+ dead caught_exception_tmp0;
415+ dead anonlocal::2a;
416+ 5: ASSERT false // block 5
417+ 6: END_FUNCTION
418+ ```
419+ where the ` CATCH-PUSH ` has been replaced by a check on the ` @inflight_exception `
420+ variable and goto statements, the ` CATCH-POP ` replaced by a check on the class
421+ of the exception and a goto statement, and the ` EXCEPTION LANDING PAD ` replaced
422+ by a section that assigns the exception to a local variable and sets the
423+ ` @inflight_exception ` back to null.
254424
255425\section java-bytecode-remove-instanceof Remove instanceof
256426
0 commit comments