diff options
| author | Brian Anderson <banderson@mozilla.com> | 2011-09-12 09:36:51 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2011-09-12 09:36:51 -0700 |
| commit | 393deeb06ff8017a93b0fd26c1f6968fdff2b15b (patch) | |
| tree | 3dacb71e604095ec94a8f350f44467b7640f289d /src/comp | |
| parent | edde2e0c457de6e5d17373bfa90ef319df4a1566 (diff) | |
| parent | 6ffcfba6b990d6f27243e4dd6ddfffab141e1f44 (diff) | |
| download | rust-393deeb06ff8017a93b0fd26c1f6968fdff2b15b.tar.gz rust-393deeb06ff8017a93b0fd26c1f6968fdff2b15b.zip | |
Merge branch 'unwind'
Conflicts: src/comp/middle/trans.rs src/comp/middle/trans_build.rs src/lib/run_program.rs src/test/compiletest/runtest.rs
Diffstat (limited to 'src/comp')
| -rw-r--r-- | src/comp/back/upcall.rs | 7 | ||||
| -rw-r--r-- | src/comp/lib/llvm.rs | 9 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 118 | ||||
| -rw-r--r-- | src/comp/middle/trans_build.rs | 38 |
4 files changed, 144 insertions, 28 deletions
diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 3b1ee9c9cee..021617d1f18 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -37,7 +37,8 @@ type upcalls = log_type: ValueRef, dynastack_mark: ValueRef, dynastack_alloc: ValueRef, - dynastack_free: ValueRef}; + dynastack_free: ValueRef, + rust_personality: ValueRef}; fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef, taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls { @@ -89,7 +90,9 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef, dynastack_alloc: d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())), - dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void())}; + dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void()), + rust_personality: dr("rust_personality", [], T_i32()) + }; } // // Local Variables: diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index fa7871042b8..8e00c8d63cd 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -572,6 +572,9 @@ native "cdecl" mod llvm = "rustllvm" { fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef, NumArgs: uint, Then: BasicBlockRef, Catch: BasicBlockRef, Name: sbuf) -> ValueRef; + fn LLVMBuildLandingPad(B: BuilderRef, Ty: TypeRef, PersFn: ValueRef, + NumClauses: uint, Name: sbuf) -> ValueRef; + fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; /* Add a case to the switch instruction */ @@ -580,6 +583,12 @@ native "cdecl" mod llvm = "rustllvm" { /* Add a destination to the indirectbr instruction */ fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); + /* Add a clause to the landing pad instruction */ + fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); + + /* Set the cleanup on a landing pad instruction */ + fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); + /* Arithmetic */ fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) -> ValueRef; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 2276d348611..391d56526df 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3715,7 +3715,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr, for the call itself is unreachable. */ let retval = C_nil(); if !is_terminated(bcx) { - FastCall(bcx, faddr, llargs); + bcx = invoke_fastcall(bcx, faddr, llargs).bcx; alt lliterbody { none. { if !ty::type_is_nil(bcx_tcx(cx), ret_ty) { @@ -3748,6 +3748,67 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr, ret rslt(bcx, retval); } +fn invoke(bcx: @block_ctxt, llfn: ValueRef, + llargs: [ValueRef]) -> result { + ret invoke_(bcx, llfn, llargs, Invoke); +} + +fn invoke_fastcall(bcx: @block_ctxt, llfn: ValueRef, + llargs: [ValueRef]) -> result { + ret invoke_(bcx, llfn, llargs, FastInvoke); +} + +fn invoke_(bcx: @block_ctxt, llfn: ValueRef, + llargs: [ValueRef], + invoker: fn(@block_ctxt, ValueRef, [ValueRef], + BasicBlockRef, BasicBlockRef) -> ValueRef) -> result { + // FIXME: May be worth turning this into a plain call when there are no + // cleanups to run + let normal_bcx = new_sub_block_ctxt(bcx, "normal return"); + let unwind_bcx = new_sub_block_ctxt(bcx, "unwind"); + let retval = invoker(bcx, llfn, llargs, + normal_bcx.llbb, + unwind_bcx.llbb); + trans_landing_pad(unwind_bcx); + ret rslt(normal_bcx, retval); +} + +fn trans_landing_pad(bcx: @block_ctxt) { + // The landing pad return type (the type being propagated). Not sure what + // this represents but it's determined by the personality function and + // this is what the EH proposal example uses. + let llretty = T_struct([T_ptr(T_i8()), T_i32()]); + // The exception handling personality function. This is the C++ + // personality function __gxx_personality_v0, wrapped in our naming + // convention. + let personality = bcx_ccx(bcx).upcalls.rust_personality; + // The only landing pad clause will be 'cleanup' + let clauses = 1u; + let llpad = LandingPad(bcx, llretty, personality, clauses); + // The landing pad result is used both for modifying the landing pad + // in the C API and as the exception value + let llretval = llpad; + // The landing pad block is a cleanup + SetCleanup(bcx, llpad); + + // FIXME: This seems like a very naive and redundant way to generate the + // landing pads, as we're re-generating all in-scope cleanups for each + // function call. Probably good optimization opportunities here. + let bcx = bcx; + let scope_cx = bcx; + while true { + scope_cx = find_scope_cx(scope_cx); + bcx = trans_block_cleanups(bcx, scope_cx); + scope_cx = alt scope_cx.parent { + parent_some(b) { b } + parent_none. { break; } + }; + } + + // Continue unwinding + Resume(bcx, llretval); +} + fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) -> result { let bcx = cx; @@ -4211,7 +4272,7 @@ fn trans_fail_value(cx: @block_ctxt, sp_opt: option::t<span>, let V_str = PointerCast(cx, V_fail_str, T_ptr(T_i8())); V_filename = PointerCast(cx, V_filename, T_ptr(T_i8())); let args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)]; - Call(cx, bcx_ccx(cx).upcalls._fail, args); + let cx = invoke(cx, bcx_ccx(cx).upcalls._fail, args).bcx; Unreachable(cx); ret rslt(cx, C_nil()); } @@ -4247,7 +4308,7 @@ fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result { llargs += [r.val]; } } - FastCall(bcx, llcallee, llargs); + bcx = invoke_fastcall(bcx, llcallee, llargs).bcx; bcx = trans_block_cleanups(bcx, cx); let next_cx = new_sub_block_ctxt(in_cx, "next"); Br(bcx, next_cx.llbb); @@ -4379,7 +4440,9 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result { // Make a note to drop this slot on the way out. add_clean(bcx, llptr, ty); - if must_zero(local) { bcx = zero_alloca(bcx, llptr, ty).bcx; } + if must_zero(bcx_ccx(bcx), local) { + bcx = zero_alloca(bcx, llptr, ty).bcx; + } alt local.node.init { some(init) { @@ -4405,35 +4468,38 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result { bcx.fcx.lllocals, false); ret rslt(bcx, llptr); - fn must_zero(local: @ast::local) -> bool { + fn must_zero(ccx: @crate_ctxt, local: @ast::local) -> bool { alt local.node.init { - some(init) { might_not_init(init.expr) } + some(init) { might_not_init(ccx, init.expr) } none. { true } } } - fn might_not_init(expr: @ast::expr) -> bool { - type env = @mutable bool; - let e = @mutable false; - // FIXME: Probably also need to account for expressions that - // fail but since we don't unwind yet, it doesn't seem to be a - // problem + fn might_not_init(ccx: @crate_ctxt, expr: @ast::expr) -> bool { + type env = {mutable mightnt: bool, + ccx: @crate_ctxt}; + let e = {mutable mightnt: false, + ccx: ccx}; + fn visit_expr(ex: @ast::expr, e: env, v: vt<env>) { + let might_not_init = alt ex.node { + ast::expr_ret(_) { true } + ast::expr_break. { true } + ast::expr_cont. { true } + ast::expr_call(_, _) { true } + _ { + let ex_ty = ty::expr_ty(e.ccx.tcx, ex); + ty::type_is_bot(e.ccx.tcx, ex_ty) + } + }; + if might_not_init { + e.mightnt = true; + } else { visit::visit_expr(ex, e, v); } + } let visitor = - visit::mk_vt(@{visit_expr: - fn (ex: @ast::expr, e: env, v: vt<env>) { - let might_not_init = - alt ex.node { - ast::expr_ret(_) { true } - ast::expr_break. { true } - ast::expr_cont. { true } - _ { false } - }; - if might_not_init { - *e = true; - } else { visit::visit_expr(ex, e, v); } - } with *visit::default_visitor()}); + visit::mk_vt(@{visit_expr: visit_expr + with *visit::default_visitor()}); visitor.visit_expr(expr, e, visitor); - ret *e; + ret e.mightnt; } } diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index ebf1b20c0ca..5c2a763603b 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -68,6 +68,21 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], }); } +fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], + Then: BasicBlockRef, Catch: BasicBlockRef) -> ValueRef { + assert (!cx.terminated); + cx.terminated = true; + let v = str::as_buf("", + {|buf| + llvm::LLVMBuildInvoke(B(cx), Fn, + vec::to_ptr(Args), + vec::len(Args), Then, + Catch, buf) + }); + llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + ret v; +} + fn Unreachable(cx: @block_ctxt) -> ValueRef { assert (!cx.terminated); cx.terminated = true; @@ -527,6 +542,29 @@ fn Trap(cx: @block_ctxt) -> ValueRef { }); } +fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef, + NumClauses: uint) -> ValueRef { + assert (!cx.terminated); + ret str::as_buf("", + {|buf| + llvm::LLVMBuildLandingPad(B(cx), + Ty, + PersFn, + NumClauses, + buf) + }); +} + +fn SetCleanup(_cx: @block_ctxt, LandingPad: ValueRef) { + llvm::LLVMSetCleanup(LandingPad, lib::llvm::True); +} + +fn Resume(cx: @block_ctxt, Exn: ValueRef) -> ValueRef { + assert (!cx.terminated); + cx.terminated = true; + ret llvm::LLVMBuildResume(B(cx), Exn); +} + // // Local Variables: // mode: rust |
