tagged release 0.6.4
[parrot.git] / languages / dotnet / src / exception.pir
blob214dac15435d8eca657a7fcdba679f264f8662a3
1 # This file contains code related to translating exception handling.
3 .HLL '_dotnet', ''
5 # This generates code that goes before a leave instruction to ensure the
6 # correct stuff is removed from the exception stack and any finally blocks are
7 # executed.
8 .sub handler_leave_code
9     .param pmc assembly
10     .param pmc ehs
11     .param int dest
12     .param int pc
13     .local int try_start, try_length, try_end, i, num_handlers, mark, flags
14     .local int finallys_walked, handler_start, handler_length, handler_end
15     .local string pir_output, tmp
16     .local pmc eh
18     # Loop over handlers.
19     num_handlers = elements ehs
20     i = 0
21     mark = 0
22 EH_LOOP:
23     if i >= num_handlers goto EH_LOOP_END
24     eh = ehs[i]
26     # Get info about handler.
27     flags = eh.get_flags()
28     try_start = eh.get_try_offset()
29     try_length = eh.get_try_length()
30     try_end = try_start + try_length
31     handler_start = eh.get_handler_offset()
32     handler_length = eh.get_handler_length()
33     handler_end = handler_start + handler_length
35     # See if we've got to the block we're leaving for. If so, we know the
36     # mark to pop to and we've found all finally blocks we need to call.
37     if dest < try_start goto EH_LOOP_NEXT
38     if pc < try_start goto EH_LOOP_NEXT
39     if dest > try_end goto EH_LOOP_NEXT
40     mark = i + 1
41     goto EH_LOOP_END
42 EH_LOOP_NEXT:
44     # Now check if the current try or handler contains the location we're
45     # leaving from. If it does, then we now find stuff we ain't walked
46     # over.
47     finallys_walked = 1
48     if pc < try_start goto TRY_WALKED_OVER
49     if pc >= try_end goto TRY_WALKED_OVER
50     finallys_walked = 0
51 TRY_WALKED_OVER:
52     if pc < handler_start goto CATCH_WALKED_OVER
53     if pc >= handler_end goto CATCH_WALKED_OVER
54     finallys_walked = 0
55 CATCH_WALKED_OVER:
57     # If this is a finally handler we need to check if it's one that has
58     # not yet been walked over, and if so emit a call to it.
59     if flags != 2 goto NOT_FINALLY
60     if finallys_walked != 0 goto NOT_FINALLY
61     pir_output = concat "$P1000000 = null\nsaved_ehs["
62     tmp = i
63     pir_output = concat tmp
64     pir_output = concat "] = $P1000000\n"
65     pir_output = concat "bsr FINALLY_"
66     tmp = handler_start
67     pir_output = concat tmp
68     pir_output = concat "\n"
69 NOT_FINALLY:
70     inc i
71     goto EH_LOOP
72 EH_LOOP_END:
74     # Generate mark code.
75     tmp = mark
76     pir_output = concat "popmark "
77     pir_output = concat tmp
78     pir_output = concat "\npushmark "
79     pir_output = concat tmp
80     pir_output = concat "\n"
82     # Return generated code.
83     .return(pir_output)
84 .end
87 # This generates the code that terminates a finally block.
88 .sub endfinally_code
89     .param pmc assembly
90     .param pmc ehs
91     .param int pc
92     .local string pir_output, tmp
93     .local pmc eh, ex
94     .local int num_handlers, i, found, flags
95     .local int handler_start, handler_length, handler_end
97     # Look for the entry in the handlers table that relates to the current
98     # finally handler.
99     num_handlers = elements ehs
100     i = 0
101     found = -1
102 EH_LOOP:
103     if i >= num_handlers goto EH_LOOP_END
104     eh = ehs[i]
105     flags = eh.get_flags()
106     if flags != 2 goto EH_LOOP_NEXT
107     handler_start = eh.get_handler_offset()
108     if pc < handler_start goto EH_LOOP_NEXT
109     handler_length = eh.get_handler_length()
110     handler_end = handler_start + handler_length
111     if pc > handler_end goto EH_LOOP_NEXT
112     found = i
113     goto EH_LOOP_END
114 EH_LOOP_NEXT:
115     inc i
116     goto EH_LOOP
117 EH_LOOP_END:
119     # If we didn't find the current finally block, we're shafted.
120     if found >= 0 goto NOT_SHAFTED
121     ex = new .Exception
122     ex["_message"] = "Failed to find finally handler for an endfinally"
123     throw ex
124 NOT_SHAFTED:
126     # Now just generate the code.
127     pir_output = "$P1000000 = saved_ehs["
128     tmp = found
129     pir_output = concat tmp
130     pir_output = concat "]\nif null $P1000000 goto FINALLY_RET_"
131     tmp = pc
132     pir_output = concat tmp
133     pir_output = concat "\nthrow $P1000000\nFINALLY_RET_"
134     pir_output = concat tmp
135     pir_output = concat ": ret\n"
137     # Return produced PIR.
138     .return(pir_output)
139 .end
142 # This gets info from a class type and class id from an exception handler.
143 .sub class_info_from_ehtype
144     .param pmc assembly
145     .param int class_type
146     .param int class_id
147     .local pmc ex, classes, pclass
148     .local string pclass_ns, tmp
150     # Find out what type of class we have.
151     dec class_id
152     if class_type == 2 goto DEF
153     if class_type == 1 goto REF
154     ex = new .Exception
155     ex["_message"] = "Unknown class type."
156     throw ex
158     # A type in this file.
159 DEF:
160     dec class_id # Because row 2 = element 0 here, thanks to the global class
161     classes = assembly.get_classes()
162     pclass = classes[class_id]
163     pclass_ns = pclass.get_fullname()
164     goto DONE
166     # A type in another file.
167 REF:
168     classes = assembly.get_typerefs()
169     pclass = classes[class_id]
170     pclass_ns = pclass.get_namespace()
171     pclass_ns = clone pclass_ns
172     if pclass_ns == "" goto NO_NS
173     pclass_ns = concat "."
174 NO_NS:
175     tmp = pclass
176     pclass_ns = concat tmp
178     # Return class and its namespace.
179 DONE:
180     .return (pclass, pclass_ns)
181 .end
183 # Local Variables:
184 #   mode: pir
185 #   fill-column: 100
186 # End:
187 # vim: expandtab shiftwidth=4 ft=pir: