270 likes | 456 Views
Exception. Compiler Baojian Hua bjhua@ustc.edu.cn. Exception. Exception is for error-handling Invalid input Invalid resource state file not exists, network error, … error execution condition divide-by-zero, … In real production code, error-handling code may be a large part
E N D
Exception Compiler Baojian Hua bjhua@ustc.edu.cn
Exception • Exception is for error-handling • Invalid input • Invalid resource state • file not exists, network error, … • error execution condition • divide-by-zero, … • In real production code, error-handling code may be a large part • 30%-50% or more
Scale the language e -> num -> id -> e1 bop e2 -> throw -> try e1 catch e2 // Example: try 3 catch 5 try (3 + throw) catch 5
Semantics throw: // abort the current execution, and notify the // system some bad things happen! // Q: what kind of bad things? try e1 catch e2: // first execute e1, if e1 runs smoothly, then // its value is return; else run e2 and return // its value. // Q: what about e2 “throw”?
Two strategies • Setjmp/longjmp-based • global “goto” • C’s primitive exception • Table-driven method • more complex and more space usage • but faster
Setjmp/longjmp buffer buf; void f () { if (0==setjmp (buf)) g (); } void g () { h (); } void h () { longjmp (buf, 1); }
Setjmp/longjmp struct context { int ebx; int edi; int esi; int ebp; int esp; int eip; }; typedef struct context buffer[1];
Setjmp/longjmp buf buffer buf; void f () { if (0==setjmp (buf)) g (); } void g () { h (); } void h () { longjmp (buf, 1); } frame f
Setjmp/longjmp buf buffer buf; void f () { if (0==setjmp (buf)) g (); } void g () { h (); } void h () { longjmp (buf, 1); } frame f
Setjmp/longjmp buf buffer buf; void f () { if (0==setjmp (buf)) g (); } void g () { h (); } void h () { longjmp (buf, 1); } frame f frame g frame h
Compiling to setjmp/longjmp • Basic idea: • try e1 catch e2 == setjmp • the context (callee-saved registers, e2’s code label, etc.) is saved • the context is also called a handler • throw == longjmp • fetch the handler, restore machine states and jump to the handler’s code • “Try” can be nested, so the handlers are organized in a stack
Machine configuration • M = (C, S, X): • C: code heap • S: operand stack • as we did in the stack-based codegen • X: exception handler stack top xsp
Compiling to setjmp/longjmp C (throw) = jmp [xsp+8] // Essentially the same as // “setjmp”. // To simplify things, we omit the // callee-saved regs here. xsp
Compiling to setjmp/longjmp C (try e1 catch e2) = pushHandler C (e1) popHandler jmp .end .handler restore C (e2) .end xsp
Compiling to setjmp/longjmp C (try e1 catch e2) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (e1) popHandler jmp .end .handler restore C (e2) .end xsp
Compiling to setjmp/longjmp C (try e1 catch e2) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (e1) add xsp, 12 jmp .end .handler restore C (e2) .end xsp
Compiling to setjmp/longjmp C (try e1 catch e2) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (e1) add xsp, 12 jmp .end .handler mov top, [xsp+4] add xsp, 12 C (e2) .end xsp
Example #1 C (try 3 catch 5) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (3) add xsp, 12 jmp .end .handler mov top, [xsp+4] add xsp, 12 C (5) .end ### 3 top xsp
Example #1 C (try 3 catch 5) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (3) add xsp, 12 jmp .end .handler mov top, [xsp+4] add xsp, 12 C (5) .end ### 3 top xsp
Example #1 C (try 3 catch 5) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (3) add xsp, 12 jmp .end .handler mov top, [xsp+4] add xsp, 12 C (5) .end ### 3 top xsp
Example #2 C (try throw catch 5) = sub xsp, 12 mov [xsp+4], top mov [xsp+8], .handler C (throw) add xsp, 12 jmp .end .handler mov top, [xsp+4] add xsp, 12 C (5) .end // Rest leave to you! ### top xsp
Moral • Relatively easy to implement • C++ compilers use this scheme, e.g. VC • the exception handler stack can be combined with operand stack (and even with the implicit control stack) • Disadvantage: • performance penalty at each “try”
Table-driven approach C (try e1 catch e2) = .L1: C (e1) jmp .L3 .L2 C (e2) .L3 C (throw) = search_table
Table-driven approach • Compilers produce an exception table, which is referred to when an exception is raised • based on the value of current “eip” • Normal execution can proceed at full speed
Example #1 C (try 3 catch 5) = .L1 C (3) jmp .L3 .L2 C (5) .L3
Example #2 C (try throw catch 5) = .L1 C (throw) jmp .L3 .L2 C (5) .L3
Moral • Table-driven scheme has no cost with normal execution • exceptions are exceptional, pay as you go • JVM uses this scheme • Disadvantage: • exception table takes space