TransferOfControl

Overview

This section provides a design and implementation overview of the Transfer Of Control (TOC) events that occur within Lisp; specifically: Catch/Throw, Block/Return-from, Tagbody/Go, and Unwind-protect.

References

HyperSpec CLtL
Transfer of Control N/A
catch catch
throw throw
unwind-protect unwind-protect

Transfer of Control Exceptions

Class Diagram

ClassDiagramofTOCException.jpg

The fillInStackTrace() method will be overriden to return NULL for performance issues with our stack management.

Unwind-Protect Implementation

Static Diagram and Associated Descriptions

unwind-protectstatic.jpg

Attribute Additions to CLforJava

  • TOCMgmt - This is a runtime stack that manages all of the runtime transfer of control points. During compilation, all TOC types establish the code to manage the pushing and popping of TOCRecords to/from the stack. The push will always occur immediately in the code and the pop will always occur in the finally block of the corresponding TOC.

  • returnException - If the unwind-protect block is entered because an exception was thrown (ie...Go, Throw, or Return-from occured) and not from regular control flow returns, it must store and rethrow the corresponding exception after it has executed the cleanup form. This is the exception that will be rethrown at the end of the cleanup form (if one is going to be rethrown at all).

Method Additions to CLforJava

  • addTOCRecord - This method is a run-time registration mechanism for all of the TOC special operators. All TOC bodies (block, tagbody, and catch) immediataly call this method at runtime when thier scope is entered. They store thier type of TOC and what tag values or symbols they are authorized to process in the event a corresponding event (go, throw, return-from) occurs.

  • popTOCRecord - All of the TOC special operators will generate code in their finally block to call this method. This is necessary clearnup in order to ensure that the runtime TOC stack is correctly maintained. Since the TOCMgmt stack can have heterogeneous TOC types on the stack at any given time, the callers will pass the type and this method will find and remove the first instance of that corresponding type on the stack.

  • isMine - This method is only called if one of the TOC types actually caught an exception; otherwise, the finally block of the corresponding code will be executed and the TOCRecord will simply be removed from the TOCMgmt stack. If a handler does catch the exception, it will call this method with the corresponding TOC type and exception. This method will find the first instance of the corresponding type on the stack, verify that the Exception is of the correct type and if so compare the value with the value that this already on the stack (ie...what tags/symbols this exception is allowed to process) and return the result of the comparison. If the compare fails, the caller will remove himself from the stack and rethrow the exception; otherwise, they will remove themselves from the stack, handle the exception, and continue as normal.

  • disableExitPoints - Immediately after the finally block from the unwind-protect form begins execution, this method is called. This method will traverse up the TOCMgmt stack and disable every single TOCRecord until it finds the first instance of a TOCRecord that matches the current returnException value. All other methods (such as isMine) will always check the valid bit before validating an entry in the TOCMgmt stack. This will ensure that the cleanup form from unwind-protect is unable to transfer back into anything that was within scope during the protected form execution. If this does occur, when the exception handler from the protected form tries to handle the exception, it will get a false from isMine and therefore, throw the exception right back up the runtime stack.

  • setReturnException - This simply sets the returnException value in case the TOC occured because of an explicit control transfer. This value will be utilized later to throw back up after the TOC has executed finally code. If another control transfer occurs in the finally code, the value will be ignored and never used. It will get set back to null every time a processReturnException call is made.

  • processReturnException - If an exception was caught (and was not handled by the current TOC), it would have been stored as the returnException. If this was the case, once the finally code of the TOC is completed, this will be the last call made before going on to the continuation block. If there is a valid exception, it will simply be rethrown; otherwise, control will return to the current TOC, and they will proceed to their respective continuation block.

TOCRecord - This is simply a struct that holds the information about an instance of a control transfer that will be held on the TOCMgmt stack.

  • Type - This is an instance of an enumeration TOCType {Block, TagBody? , Catch, UnwindProtect? } and simply store the type of the TOC record on the stack.

  • Value - This is the tag or symbol that the corresponding type is allowed to process (for catch 'a, it would be 'a'; for block here, it would be 'here', and so forth). For tagbody, since it can have multiple labels, it will be a list of objects holding all of the corresponding label values. That is required so that CLforJava can effectively answer the isMine question.

  • Valid - This value is defaulted to true and is only set to false when an unwind-protect protected form is disabled after the cleanup form is entered.

Runtime TOC Sequence Example

Sequence Diagram of Use Case unwind-protectsequence.jpg

Sequence steps:

  1. The catch tag form of the catch Special Operator (SO) is evaluated at runtime and with the result of the evaluation, a new element is added to the TOCMgmt stack using the Catch enum value and the corresponding catch tag result.
  2. The block SO adds a new element to the TOCMgmt stack with the corresponding symbol of the block SO.
  3. The tagbody SO finds all of the labels within it's own internal structure (this could have been completed at compile time, but needs to be readily accessible at run-time) and adds a new element to the TOCMgmt stack with the Tagbody enum value and a list of all it's labels that it contains within its scope.
  4. Some of the non-TOC related statements are evaluated in the protected form, and when the protected form reaches the catch 'c element at runtime, the catch tag form is evaluated and the result of the eval is added to the TOCMgmt stack.
  5. When the throw 'a statement is executed, the catch tag form is evaluated and then the return value form is evaluated. The results of these evaluations are used to create a new ThrowException? exception.
  6. This new ThrowException? is then thrown to the JRE.
  7. Based on the compilation of the corresponding function, the JRE will find the catch 'c as the first valid exception handler in the exception table and pass the exception to the corresponding catch (java) block of the catch 'c.
  8. This block will retrieve the determine (using the isMine method) if it is able to catch this exception (basically if the first value of the first catch element TOCRecord on the TOCMgmt stack has a value that matches the value of the exception just caught).
  9. In this case, it will fail, and so the corresponding exception handler pop itself of the TOCMgmt stack and then simply rethrow the same exception.
  10. Had it not failed, the exception handler would have stopped the exception and gone on to its corresponding continuation code block.
  11. Based on the compilation of the unwind-protect block, it will have the next valid exception handler registered in the exception table.
  12. The catch block of unwind-protect will simply store the current exception that caused the protected form to be exited. Setting this value siginfies that the protected form was exited explicitely and not through a regular return.
  13. After this is completed, the catch block will go onto it's finally block.
  14. The finally block will immediately disable any TOC exit points up until it finds the place in the TOCMgmt stack where the current exception has a valid handler. This will ensure that if during the cleanup form, an explicit TOC is attempted, it will not be able to go back into an invalid exit point.
  15. The finally (java) block of the unwind-protect construct will then proceed to actually execute the contents of the cleanup form.
  16. In the cleanup form, when the 'go end' statement is executed, a new instance of GoException? will be created with the corresponding label (end) and it will be thrown to the JRE.
  17. The JRE will find the tagbody exception handler registered in the exception handler table and will pass control to the catch (java) block of the tagbody construct.
  18. At this point, the unwind-protect construct is completely out of scope and the ThrowException? previously thrown (that caused the exit of the protected form in the first place) is also disbanded.
  19. The catch (java) block of the tagbody contstruct will get a true back from the isMine method call and therefore process the exception and stop its traversal up the runtime stack.
  20. The code will follow a normal path from this point forward and in the normal path, as the scope is left for the outer tagbody, block b, and catch 'a blocks, the corresponding finally blocks for each of these constructs will be executed.
  21. As each finally block is called, the respective TOC constructs will remove thier corresponding TOCRecords from the TOCMgmt stack.
  22. Upon successful execution of the use case, the TOCMgmt stack will be empty and the end label of the tagbody will have been the last block of code to be executed (since the ThrowException? was disbanded when another TOC took place in the cleanup form that superceded the provious TOC).

Compilation Time TOC Sequences for Each TOC Type

  • catch
    1. Setup the runtime evaluation of the catch tag form
    2. Using the result of the catch tag evaluation, add a catch TOCRecord to the TOCMgmt stack with the result value of the catch tag.
    3. Start the try block
    4. Setup for the evaluation of the result form
    5. Setup a goto for the finally block
    6. Start the catch block
    7. Setup a runtime isMine call with the caught exception
    8. Setup a comparison of the result, and if true, goto the finally block
    9. If false, set the returnException value and then goto the finally block
    10. Setup a finally block
    11. In the finally block, remove the TOCRecord from the TOCMgmt stack, then processReturnException, then goto the continue block
    12. Setup the continue block label
    13. Register an exception handler for type Exception
  • block
    1. Using the constant symbol 'b', add a block TOCRecord to the TOCMgmt stack with the symbol.
    2. Start the try block
    3. Setup for the evaluation of the result form
    4. Setup a goto for the finally block
    5. Start the catch block
    6. Setup a runtime isMine call with the caught exception
    7. Setup a comparison of the result, and if true, goto the finally block
    8. If false, set the returnException value and then goto the finally block
    9. Setup a finally block
    10. In the finally block, remove the TOCRecord from the TOCMgmt stack, then processReturnException, then goto the continue block
    11. Setup the continue block label
    12. Register an exception handler for type Exception
  • tagbody
    1. Retrieve a list of all of the labels in the tagbody (done at compile time)
    2. Using that result, make a constant delim separated string that contains all of the labels
    3. Using that compile time generated constant value, add a tagbody TOCRecord to the TOCMgmt stack with the constant.
    4. Start the try block
    5. Perform same icg steps as previously implemented for the tagbody construct
    6. Start the catch block
    7. Setup a runtime isMine call with the caught exception
    8. Setup a comparison of the result, and if true, goto the finally block
    9. If false, set the returnException value and then goto the finally block
    10. Setup a finally block
    11. In the finally block, remove the TOCRecord from the TOCMgmt stack, then processReturnException, then goto the continue block
    12. Setup the continue block label
    13. Register an exception handler for type Exception
  • unwind-protect
    1. Start the try block
    2. Setup for the evaluation of the protected form
    3. Setup a goto for the finally block
    4. Start the catch block
    5. Using the exception, store the exception so that it can be rethrown after the cleanup form is executed
    6. Setup a finally block
    7. In the finally block, disable invalid TOC Exit Points
    8. Setup the evalution of the cleanup form
    9. Setup for a runtime call to process the return exception (if there was one, it will be rethrown automatically)
    10. Register an exception handler for type RuntimeException?
  • go/return-from/throw
    1. This code should remain unchanged from its current implementation

Catch/Throw Implementation

The throw and catch functionality in lisp has been implemented using a java try/catch construct. There is an abstract TransferOfControl exception (that derives from java.lang.RuntimeException). The ThrowException? exception class derives from the abstract TransferOfControl class. The ThrowException? contains the following methods:

  • public ThrowException? (Object catchTag, Object value) - This takes the post-evaluated catch tag name and the return value and creates a new exception instance
  • public boolean equals(Object obj) - This checks to see if the catch tag values match the current object's value with the object passed as a parameter
  • public Symbol getCatchTag() - This returns the current catch tag name
  • public Symbol getValue() - This returns the result-form that is returned with the transfer of control
  • public Object process() - This determines if the current exception object is supposed to handle the current catch tag name; otherwise, it throws the exception back up the runtime stack for the next exception handler to catch and process

In the sequence of compilation for catch/throw, the following occurs:
Catch

  1. The SemanticAnalyzer does not perform any special operations; it simply sends the remaining list back through the SA for processing
  2. In the IntermediateCodeGeneration, the first step is the code returns the catch tag form to icgMainLoop for code setup that will evaluate the form at runtime.
  3. This will leave the result of the eval'd catch tag at runtime as the next available item on the stack, in which, this will then be used as a parameter to store on the TOC runtime stack.
  4. The try block label will then be started and the remainder of the result form will be sent back to icgMainLoop.
  5. The catch block label will then be started and the catch block will get take the element from the exception passed to it and determine if it is able to process the corresponding exception or not.
  6. If so, it will move on to the continuation block; otherwise, it will rethrow the exception back up the runtime stack.

Throw

  1. The SemanticAnalyzer does not perform any special operations; it simply sends the remaining list back through the SA for processing
  2. In the IntermediateCodeGeneration, the catch tag and return forms are setup for runtime evaluation (sent to icgMainLoop).
  3. These results are used as parameters to instantiate a new instance of the ThrowException? .
  4. This exception is then thrown to the JRE for processing.

JUnit Testing Support in LISP

After a little research, the following needs to be completed to implement direct support for JUnit testing within LISP test cases.

  1. Upgrade to version 4 of JUnit
  2. Select the subset of functionality wanted from JUnit that will be directly accessible in LISP. For instance, methods such as setUp and tearDown can be utilized in JUnit, but for our needs, this appears unnecessary for the first iteration. Just implementing the test case will likely work for the first iteration.
  3. Define a single special operator used in compilation: something like deftest
  4. Define the parameters for the special operator: recommend two parameters...a form to be evaluated and the expected result of the evaluation.
  5. When the special operator is seen at compile time, it will do the following:
    1. Create a new method with the org.junit.Test.@Test annonation defined
    2. With the form to be evaluated, setup the runtime evaluation of the form in the method
    3. Using what will be the runtime result of evaluating the form and the second parameter (the expected result), setup a runtime call to assert-equal with the two values
    4. Close out the method

Java Implementation References

Core Java Classes Javadoc Links

Discussions

Forum -> Compiler

Release Level:

Open bug count: 0

Reference Documentation

Unwind-Protect

Test Suites

Catch/Throw

Unwind-Protect

Batch File to Run

java -cp C:\Users\Ellizit\CLforJava_TOCException\build\classes;C:\Users\Ellizit\CLforJava_TOCException\lib\asm-all-2.2.3.jar lisp.common.CLforJava pause
Topic revision: r22 - 2009-03-21 - 19:52:01 - MadelineWilliams
 
Home
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback