Author: allison Date: Wed Mar 22 18:00:36 2006 New Revision: 11993 Added: trunk/docs/pdds/clip/pddXX_exceptions.pod
Changes in other areas also in this revision: Modified: trunk/ (props changed) trunk/MANIFEST Log: A first draft of the PDD on exceptions. Added: trunk/docs/pdds/clip/pddXX_exceptions.pod ============================================================================== --- (empty file) +++ trunk/docs/pdds/clip/pddXX_exceptions.pod Wed Mar 22 18:00:36 2006 @@ -0,0 +1,332 @@ +# Copyright: 2001-2006 The Perl Foundation. +# $Id: $ + +=head1 NAME + +docs/pdds/clip/pddXX_exceptions.pod - Parrot Exceptions + +=head1 ABSTRACT + +This document defines the requirements and implementation strategy for +Parrot's exception system. + +=head1 VERSION + +$Revision: $ + +=head1 DESCRIPTION + +An exception system gives user-developed code control over how run-time +error conditions are handled. Exceptions are errors or unusual +conditions that requires special processing. An exception handler +performs the necessary steps to appropriately respond to a particular +kind of exception. + +=head2 Exception Opcodes + +These are the opcodes relevant to exceptions and exception handlers: + +=over + +=item * + +C<push_eh> creates an exception handler and pushes it onto the control +stack. It takes a label (the location of the exception handler) as its +only argument. [Is this right? Treating exception handlers as label +jumps rather than full subroutines seems error-prone.] + +=item * + +C<clear_eh> removes the most recently added exception from the control +stack. + +=item * + +C<throw> throws an exception object. + +=item * + +C<rethrow> rethrows an exception object. It can only be called from +inside an exception handler. + +=item * + +C<die> throws an exception. It takes two arguments, one for the severity +of the exception and one for the type of exception. + +If the severity is C<EXCEPT_DOOMED>, it exits via a call to +C<_exit($2)>, which is not a catchable exception. + +These are the constants defined for severity: + + 0 EXCEPT_NORMAL + 1 EXCEPT_WARNING + 2 EXCEPT_ERROR + 3 EXCEPT_SEVERE + 4 EXCEPT_FATAL + 5 EXCEPT_DOOMED + 6 EXCEPT_EXIT + +These are the constants defined for exception types: + + 0 E_Exception + 1 E_SystemExit + 2 E_StopIteration + 3 E_StandardError + 4 E_KeyboardInterrupt + 5 E_ImportError + 6 E_EnvironmentError + 7 E_IOError + 8 E_OSError + 9 E_WindowsError + 10 E_VMSError + 11 E_EOFError + 12 E_RuntimeError + 13 E_NotImplementedError + 14 E_LibraryNotLoadedError + 15 E_NameError + 16 E_UnboundLocalError + 17 E_AttributeError + 18 E_SyntaxError + 19 E_IndentationError + 20 E_TabError + 21 E_TypeError + 22 E_AssertionError + 23 E_LookupError + 24 E_IndexError + 25 E_KeyError + 26 E_ArithmeticError + 27 E_OverflowError + 28 E_ZeroDivisionError + 29 E_FloatingPointError + 30 E_ValueError + 31 E_UnicodeError + 32 E_UnicodeEncodeError + 33 E_UnicodeDecodeError + 34 E_UnicodeTranslateError + 35 E_ReferenceError + 36 E_SystemError + 37 E_MemoryError + 37 E_LAST_PYTHON_E + 38 BAD_BUFFER_SIZE + 39 MISSING_ENCODING_NAME + 40 INVALID_STRING_REPRESENTATION + 41 ICU_ERROR + 42 UNIMPLEMENTED + 43 NULL_REG_ACCESS + 44 NO_REG_FRAMES + 45 SUBSTR_OUT_OF_STRING + 46 ORD_OUT_OF_STRING + 47 MALFORMED_UTF8 + 48 MALFORMED_UTF16 + 49 MALFORMED_UTF32 + 50 INVALID_CHARACTER + 51 INVALID_CHARTYPE + 52 INVALID_ENCODING + 53 INVALID_CHARCLASS + 54 NEG_REPEAT + 55 NEG_SUBSTR + 56 NEG_SLEEP + 57 NEG_CHOP + 58 INVALID_OPERATION + 59 ARG_OP_NOT_HANDLED + 60 KEY_NOT_FOUND + 61 JIT_UNAVAILABLE + 62 EXEC_UNAVAILABLE + 63 INTERP_ERROR + 64 PREDEREF_LOAD_ERROR + 65 PARROT_USAGE_ERROR + 66 PIO_ERROR + 67 PARROT_POINTER_ERROR + 68 DIV_BY_ZERO + 69 PIO_NOT_IMPLEMENTED + 70 ALLOCATION_ERROR + 71 INTERNAL_PANIC + 72 OUT_OF_BOUNDS + 73 JIT_ERROR + 74 EXEC_ERROR + 75 ILL_INHERIT + 76 NO_PREV_CS + 77 NO_CLASS + 78 LEX_NOT_FOUND + 79 PAD_NOT_FOUND + 80 ATTRIB_NOT_FOUND + 81 GLOBAL_NOT_FOUND + 82 METH_NOT_FOUND + 83 WRITE_TO_CONSTCLASS + 84 NOSPAWN + 85 INTERNAL_NOT_IMPLEMENTED + 86 ERR_OVERFLOW + 87 LOSSY_CONVERSION + +=item * + +C<exit> throws an exception of severity C<EXCEPT_EXIT>. It takes a +single argument for the exception type. + +=item * + +C<pushaction> pushes a subroutine object onto the control stack. If the +control stack is unwound due to an exception (or C<popmark>, or +subroutine return), the subroutine is invoked with an integer argument: +C<0> means a normal return; C<1> means an exception has been raised. +[Seems like there's lots of room for dangerous collisions here.] + +=back + +=head1 IMPLEMENTATION + +[I'm not convinced the control stack is the right way to handle +exceptions. Most of Parrot is based on the continuation-passing style of +control, shouldn't exceptions be based on it too?] + +=head2 Opcodes that Throw Exceptions + +Exceptions have been incorporated into built-in opcodes in a limited +way, but they aren't used consistently. + +Divide by zero exceptions are thrown by C<div>, C<fdiv>, and C<cmod>. + +The C<ord> opcode throws an exception when it's passed an empty +argument, or passed a string index that's outside the length of the +string. + +The C<classoffset> opcode throws an exception when it's asked to +retrieve the attribute offset for a class that isn't in the object's +inheritance hierarchy. + +The C<find_charset> opcode throws an exception if the charset name it's +looking up doesn't exist. The C<trans_charset> opcode throws an +exception on "information loss" (presumably, this means when one charset +doesn't have a one-to-one correspondence in the other charset). + +The C<find_encoding> opcode throws an exception if the encoding name +it's looking up doesn't exist. The C<trans_encoding> opcode throws an +exception on "information loss" (presumably, this means when one +encoding doesn't have a one-to-one correspondence in the other +encoding). + +Parrot's default version of the C<LexPad> PMC uses exceptions, though +other implementations can choose to return error values instead. +C<store_lex> throws an exception when asked to store a lexical variable +in a name that doesn't exist. C<find_lex> throws an exception when asked +to retrieve a lexical name that doesn't exist. + +Other opcodes respond to an C<errorson> setting to decide whether to +throw an exception or return an error value. C<find_global> throws an +exception (or returns a Null PMC) if the global name requested doesn't +exist. C<find_name> throws an exception (or returns a Null PMC) if the +name requested doesn't exist in a lexical, current, global, or built-in +namespace. + +It's a little odd that so few opcodes throw exceptions (these are the +ones that are documented, but a few others throw exceptions internally +even though they aren't documented as doing so). It's worth considering +either expanding the use of exceptions consistently throughout the +opcode set, or eliminating exceptions from the opcode set entirely. The +strategy for error handling should be consistent, whatever it is. [I +like the way C<LexPad>s and the C<errorson> settings provide the option +for exception-based or non-exception-based implementations, rather than +forcing one or the other.] + +=head2 Excerpt + +[Excerpt from "Perl 6 and Parrot Essentials" to seed discussion. +Out-of-date in some ways, and in others it was simply speculative.] + +Exceptions provide a way of calling a piece of code outside the normal +flow of control. They are mainly used for error reporting or cleanup +tasks, but sometimes exceptions are just a funny way to branch from +one code location to another one. + +Exceptions are objects that hold all the information needed to handle +the exception: the error message, the severity and type of the error, +etc. The class of an exception object indicates the kind of exception +it is. + +Exception handlers are derived from continuations. They are ordinary +subroutines that follow the Parrot calling conventions, but are never +explicitly called from within user code. User code pushes an exception +handler onto the control stack with the C<set_eh> opcode. The system +calls the installed exception handler only when an exception is thrown. + + newsub P20, .Exception_Handler, _handler + set_eh P20 # push handler on control stack + null P10 # set register to null + find_global P10, "none" # may throw exception + clear_eh # pop the handler off the stack + ... + + _handler: # if not, execution continues here + is_null P10, not_found # test P10 + ... + +This example creates a new exception handler subroutine with the +C<newsub> opcode and installs it on the control stack with the +C<set_eh> opcode. It sets the C<P10> register to a null value (so it +can be checked later) and attempts to retrieve the global variable +named C<none>. If the global variable is found, the next statement +(C<clear_eh>) pops the exception handler off the control stack and +normal execution continues. If the C<find_global> call doesn't find +C<none> it throws an exception by pushing an exception object onto the +control stack. When Parrot sees that it has an exception, it pops it +off the control stack and calls the exception handler C<_handler>. + +The first exception handler in the control stack sees every exception +thrown. The handler has to examine the exception object and decide +whether it can handle it (or discard it) or whether it should +C<rethrow> the exception to pass it along to an exception handler +deeper in the stack. The C<rethrow> opcode is only valid in exception +handlers. It pushes the exception object back onto the control stack so +Parrot knows to search for the next exception handler in the stack. The +process continues until some exception handler deals with the exception +and returns normally, or until there are no more exception handlers on +the control stack. When the system finds no installed exception handlers +it defaults to a final action, which normally means it prints an +appropriate message and terminates the program. + +When the system installs an exception handler, it creates a return +continuation with a snapshot of the current interpreter context. If +the exception handler just returns (that is, if the exception is +cleanly caught) the return continuation restores the control stack +back to its state when the exception handler was called, cleaning up +the exception handler and any other changes that were made in the +process of handling the exception. + +Exceptions thrown by standard Parrot opcodes (like the one thrown by +C<find_global> above or by the C<throw> opcode) are always resumable, +so when the exception handler function returns normally it continues +execution at the opcode immediately after the one that threw the +exception. Other exceptions at the run-loop level are also generally +resumable. + + new P10, Exception # create new Exception object + set P10["_message"], "I die" # set message attribute + throw P10 # throw it + +Exceptions are designed to work with the Parrot calling conventions. +Since the return addresses of C<bsr> subroutine calls and exception +handlers are both pushed onto the control stack, it's generally a bad +idea to combine the two. + +=head1 ATTACHMENTS + +None. + +=head1 FOOTNOTES + +None. + +=head1 REFERENCES + + src/ops/core.ops + src/exceptions.c + runtime/parrot/include/except_types.pasm + runtime/parrot/include/except_severity.pasm + +=cut + +__END__ +Local Variables: + fill-column:78 +End: