More instructions with abnormal control flow
Created by: wks
There are a few instructions that may not always be executed successfully.
- TRAP, WATCHPOINT, SWAPSTACK, CALL/INVOKE, ICALL/IINVOKE: Some instructions expect exceptions. We already have multiple versions of instructions for those with or without exceptions.
- BinOp: division-by-zero and floating-point exceptions are generated by the hardware, but many programming languages have defined behaviour on those cases (e.g. Java throws language-level exceptions). Some (e.g. FP exceptions) cannot be prevented easily by checking before doing operation
- NEW/NEWHYBRID/ALLOCA/ALLOCAHYBRID: out-of-memory error
- Function calls and the NEWSTACK instruction may call declared but undefined functions.
- Function calls may result in out-of-memory errors.
- LOAD/STORE/CMPXCHG/ATOMICRMW: they may access invalid memory locations, including the
NULL
reference and invalid addresses introduced by array element addressing. The hardware cannot cover all illegal cases, but it may be possible to let the hardware handle common errors (likeNULL
reference dereferencing). See Issue #6 - All intrinsic functions that may have exceptions (covered by the IINVOKE instruction).
The proposal
Change the grammar so that all such instructions take an optional "exception clause". This generalises the handling of many instructions. Existing instruction pairs that distinguish the awareness of exceptions (CALL/INVOKE, ICALL/IINVOKE) can be merged. The identification of "basic block terminator" instructions now depends on the presence of such clause, not just by the opcode.
Example:
Do not handle exception locally:
%entry:
%rv = CALL <@sig> @func (%arg) // continue with the next instruction, or unwind the current frame
%b = ADD <@i64> %rv 1
...
Handle exception locally:
%entry:
%rv = CALL <@sig> @func (%arg) EXC(%nor %exc) // terminates the current basic block.
%nor:
... // normal destination
%exc:
%e = LANDINGPAD // exceptional destination
...
Even simple divisions may go wrong:
%entry:
%result = SDIV <@i64> %a %b EXC(%nor %exc)
%nor:
... // continue normally
%exc:
THROW @DivisionByZeroException
NOTE: The µVM will not create new exceptions for the client. If the exceptional case is not because of an exception being thrown from a function or another stack (by swap-stack), then it is an error. Errors are undefined behaviours. The following code is fatal when %b
is zero:
%entry:
%result = SDIV <@i64> %a %b // undefined behaviour if %b is zero.
About factored CFG
Factored CFG is used by the JikesRVM. It allows a basic block to have multiple exceptional side-exits, breaking the single-entry single-exit property. Although that will reduce the number of exceptional branches, the traditional CFG is better-understood and is still capable to express all control flows with additional verbosity.