Re: Try/Catch

new topic     » goto parent     » topic index » view thread      » older message » newer message

Woke up this morning with a head full of this stuff, in particular the "propagate" idea below, so here goes nuttin:

Draft Technical Spec

Some knowledge of the existing compiler internals is assumed. I have tried to keep this Phix/OpenEuphoria agnostic, and quite deliberately as simple as possible.

A new construct is to be added to the language:

try 
   <block> 
catch <e_name> 
   <block> 
end try 

In addition there will also be a new builtin, throw(atom code).

The call stack frame has a new machine-word-sized field, ehndlr. At startup, in the top-level frame ehndlr is set to 0 (likewise for new threads). Call statements propagate ehndlr as follows:

    ==0 -->  0 
    !=0 --> -1 

The try statement saves the old value then sets it to the machine address of the catch statement. Hopefully a bog-standard local unnamed temporary integer variable can be used for this purpose. That original value must be restored immediately on entry to the catch statement, and on any exit from the try block, including exit/break/continue etc. It is worth noting that a return statement pops the call stack and effectively discards the current ehndlr, thus avoiding the 'exit' issue, even for several nested try statements in the same routine. Obviously a throw statement within a try block should be caught by the immediately following catch statement and needs no ehndlr updates whatsoever. Otherwise, the restoration of ehndlr during normal execution stands out as the most fiddly task, in terms of updates to the compiler, and probably requires a new control flag(/var_id) that is saved/restored at many points during parsing. An exit that jumps out of more than one nested try statement may pose additional challenges, but nothing worse than the exit statement itself already does.

The catch statement traps any exception within the try block or any routines it invokes that is not first caught by another nested try/catch statement. Any exceptions that must be re-thrown must be done so manually. As shown next, on entry the value for <e_name> will be in e/rax.

The existing final exception handler needs something like the following new code added to it:

if ehndlr!=0 then 
    <create content for e_name, ref left in e/rax> 
  ::unwind 
    if ehndlr==-1 then 
        retaddr := unwind 
        return (ie standard dealloc, frame discard, etc) 
    end if 
    mov e_e/rax,e/rax 
    mov e_e/rip,ehndlr 
    mov e/rax,EXCEPTION_CONTINUE_EXECUTION  -- (at catch statement) 
    ret 
end if 
<existing code to generate ex.err> 

Sorry, but I have no idea what the equivalent C/Linux code would be like. Obviously, the ability to resume execution depends on the severity of the fault. For example, if the stack is toast, so is your app.

The exception variable is automatically declared (as a sequence) and is most likely to be just 'e' in actual code. Unlike "for i", there is no reason to have e available after the catch, as should no exception occur it would be unassigned anyway.

At a bare minimum, the sequence e contains an exception code and address, but could also hold a routine number/name, and source code line number. The content may differ between interpreted and compiled applications, and the catch code block should be written to cope accordingly.

The throw routine can be trivially implemented as a fatal error, the only technical difficulty would be getting the code parameter into e instead of #80000003 or whatever.

A new error code is required should throw() be invoked when there is no active handler in the current call stack.

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu