@@ -248,9 +248,179 @@ for(tmp_index = 0; tmp_index < dim_size; ++tmp_index)
248
248
249
249
` remove_java_new ` is then recursively applied to the new ` subarray ` .
250
250
251
- \section java-bytecode-remove-exceptions remove_exceptions
251
+ \section java-bytecode-remove-exceptions Remove exceptions
252
252
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.
254
424
255
425
\section java-bytecode-remove-instanceof Remove instanceof
256
426
0 commit comments