1 = How exceptions are delivered.
3 There are 3 separate parts
4 1. The exception deliver table, one per compiled method.
5 2. A translator that converts rescues into the exception table
6 3. The exception deliverer, which searches tables and perform jumps.
8 == The exception table.
10 This is the core of the exception deliver mechanism. The table
11 is organized into rows, each row having 3 columns:
12 1. the start bytecode index
13 2. the end bytecode index
14 3. the bytecode index to jump to
16 == How they all work together
18 When an exception is raised, the deliverer takes the current
19 context's exception table and the current ip and searches
20 the table to find out if there is an entry where the start
21 is less than ip and the end is greater than ip. Because
22 the table is pre-sorted to have the smallest entries
23 first, the first valid entry hit during the search will
24 always be the correct one. The deliver then sets the
25 bytecode interpreter's ip to the 3rd bytecode index in the entry.
26 This causes the interpreter to begin executing a rescue.
28 The first bytecodes of a rescue perform checking that the
29 current exception matches the criteria given in the 'rescue'
30 statement in ruby code (currently, just that the exception is
31 of a certain klass, done using ===).
33 At the end of these first bytecodes is a raise which
34 triggers the whole thing to occur again. This raise is jumped
35 past if the exception matches the criteria.
37 If the deliverer is unable to find a valid exception table entry,
38 it reactivates the current context's sender and starts over.
40 If the exception reaches the top context and is still unable to
41 find someone to handle the exception, the cpu is trigger to handle it
42 itself. This typically means informing the user in some way that an
43 exception has reached the top and that the program is going to terminate.
47 find an exception handler:
49 I = @active_context.ip
50 T = @active_context.exceptions
54 if entry[0] <= I and entry[1] >= I
60 @active_context = @active_context.sender