about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorElliott Slaughter <eslaughter@mozilla.com>2012-07-23 16:00:19 -0700
committerElliott Slaughter <eslaughter@mozilla.com>2012-07-24 12:20:39 -0700
commitc341eb90522294dda6dbce646d1c0a7170a48bfc (patch)
tree05e85d095128d595c14ae8c49ea666e2a1e68704 /src
parent0930b953958232022727b83cf9e08a2397656f62 (diff)
Don't emit invoke instructions inside landing pads.
We can't throw an exception from inside a landing pad without
corrupting the exception handler, so we have no hope of dealing with
these exceptions anyway. See:

http://llvm.org/docs/ExceptionHandling.html#cleanups

Part of #2861.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/rt.rs6
-rw-r--r--src/rustc/middle/trans/base.rs38
-rw-r--r--src/rustc/middle/trans/closure.rs2
-rw-r--r--src/rustc/middle/trans/common.rs13
-rw-r--r--src/rustc/middle/trans/foreign.rs2
5 files changed, 40 insertions, 21 deletions
diff --git a/src/libcore/rt.rs b/src/libcore/rt.rs
index 356e81689f0..8990891112d 100644
--- a/src/libcore/rt.rs
+++ b/src/libcore/rt.rs
@@ -37,6 +37,9 @@ fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
     ret rustrt::rust_upcall_exchange_malloc(td, size);
 }
 
+// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
+// inside a landing pad may corrupt the state of the exception handler. If a
+// problem occurs, call exit instead.
 #[rt(exchange_free)]
 fn rt_exchange_free(ptr: *c_char) {
     rustrt::rust_upcall_exchange_free(ptr);
@@ -47,6 +50,9 @@ fn rt_malloc(td: *c_char, size: uintptr_t) -> *c_char {
     ret rustrt::rust_upcall_malloc(td, size);
 }
 
+// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
+// inside a landing pad may corrupt the state of the exception handler. If a
+// problem occurs, call exit instead.
 #[rt(free)]
 fn rt_free(ptr: *c_char) {
     rustrt::rust_upcall_free(ptr);
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 1d9080d2b19..beae7d59b7c 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -276,7 +276,7 @@ fn alloca_zeroed(cx: block, t: TypeRef) -> ValueRef {
 fn alloca_maybe_zeroed(cx: block, t: TypeRef, zero: bool) -> ValueRef {
     let _icx = cx.insn_ctxt(~"alloca");
     if cx.unreachable { ret llvm::LLVMGetUndef(t); }
-    let initcx = raw_block(cx.fcx, cx.fcx.llstaticallocas);
+    let initcx = raw_block(cx.fcx, false, cx.fcx.llstaticallocas);
     let p = Alloca(initcx, t);
     if zero { Store(initcx, C_null(t), p); }
     ret p;
@@ -294,7 +294,7 @@ fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) -> block {
 fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef {
     let _icx = cx.insn_ctxt(~"arrayalloca");
     if cx.unreachable { ret llvm::LLVMGetUndef(t); }
-    ret ArrayAlloca(raw_block(cx.fcx, cx.fcx.llstaticallocas), t, v);
+    ret ArrayAlloca(raw_block(cx.fcx, false, cx.fcx.llstaticallocas), t, v);
 }
 
 // Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes).
@@ -3228,6 +3228,11 @@ fn need_invoke(bcx: block) -> bool {
         ret false;
     }
 
+    // Avoid using invoke if we are already inside a landing pad.
+    if bcx.is_lpad {
+        ret false;
+    }
+
     if have_cached_lpad(bcx) {
         ret true;
     }
@@ -3291,7 +3296,7 @@ fn get_landing_pad(bcx: block) -> BasicBlockRef {
         alt copy inf.landing_pad {
           some(target) { cached = some(target); }
           none {
-            pad_bcx = sub_block(bcx, ~"unwind");
+            pad_bcx = lpad_block(bcx, ~"unwind");
             inf.landing_pad = some(pad_bcx.llbb);
           }
         }
@@ -4107,7 +4112,8 @@ fn trans_stmt(cx: block, s: ast::stmt) -> block {
 // You probably don't want to use this one. See the
 // next three functions instead.
 fn new_block(cx: fn_ctxt, parent: option<block>, +kind: block_kind,
-             name: ~str, opt_node_info: option<node_info>) -> block {
+             is_lpad: bool, name: ~str, opt_node_info: option<node_info>)
+    -> block {
 
     let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo {
         cx.ccx.names(name)
@@ -4115,7 +4121,7 @@ fn new_block(cx: fn_ctxt, parent: option<block>, +kind: block_kind,
     let llbb: BasicBlockRef = str::as_c_str(s, |buf| {
         llvm::LLVMAppendBasicBlock(cx.llfn, buf)
     });
-    let bcx = mk_block(llbb, parent, kind, opt_node_info, cx);
+    let bcx = mk_block(llbb, parent, kind, is_lpad, opt_node_info, cx);
     do option::iter(parent) |cx| {
         if cx.unreachable { Unreachable(bcx); }
     };
@@ -4129,14 +4135,14 @@ fn simple_block_scope() -> block_kind {
 
 // Use this when you're at the top block of a function or the like.
 fn top_scope_block(fcx: fn_ctxt, opt_node_info: option<node_info>) -> block {
-    ret new_block(fcx, none, simple_block_scope(),
+    ret new_block(fcx, none, simple_block_scope(), false,
                   ~"function top level", opt_node_info);
 }
 
 fn scope_block(bcx: block,
                opt_node_info: option<node_info>,
                n: ~str) -> block {
-    ret new_block(bcx.fcx, some(bcx), simple_block_scope(),
+    ret new_block(bcx.fcx, some(bcx), simple_block_scope(), bcx.is_lpad,
                   n, opt_node_info);
 }
 
@@ -4147,17 +4153,21 @@ fn loop_scope_block(bcx: block, loop_break: block, n: ~str,
         mut cleanups: ~[],
         mut cleanup_paths: ~[],
         mut landing_pad: none
-    }), n, opt_node_info);
+    }), bcx.is_lpad, n, opt_node_info);
 }
 
+// Use this when creating a block for the inside of a landing pad.
+fn lpad_block(bcx: block, n: ~str) -> block {
+    new_block(bcx.fcx, some(bcx), block_non_scope, true, n, none)
+}
 
 // Use this when you're making a general CFG BB within a scope.
 fn sub_block(bcx: block, n: ~str) -> block {
-    new_block(bcx.fcx, some(bcx), block_non_scope, n, none)
+    new_block(bcx.fcx, some(bcx), block_non_scope, bcx.is_lpad, n, none)
 }
 
-fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block {
-    mk_block(llbb, none, block_non_scope, none, fcx)
+fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block {
+    mk_block(llbb, none, block_non_scope, is_lpad, none, fcx)
 }
 
 
@@ -4475,14 +4485,14 @@ fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: ~[ast::arg],
 fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
     let _icx = fcx.insn_ctxt(~"finish_fn");
     tie_up_header_blocks(fcx, lltop);
-    let ret_cx = raw_block(fcx, fcx.llreturn);
+    let ret_cx = raw_block(fcx, false, fcx.llreturn);
     RetVoid(ret_cx);
 }
 
 fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
     let _icx = fcx.insn_ctxt(~"tie_up_header_blocks");
-    Br(raw_block(fcx, fcx.llstaticallocas), fcx.llloadenv);
-    Br(raw_block(fcx, fcx.llloadenv), lltop);
+    Br(raw_block(fcx, false, fcx.llstaticallocas), fcx.llloadenv);
+    Br(raw_block(fcx, false, fcx.llloadenv), lltop);
 }
 
 enum self_arg { impl_self(ty::t), no_self, }
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index c8d55ff0945..5cfc1d98ec6 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -319,7 +319,7 @@ fn load_environment(fcx: fn_ctxt,
                     load_ret_handle: bool,
                     ck: ty::closure_kind) {
     let _icx = fcx.insn_ctxt(~"closure::load_environment");
-    let bcx = raw_block(fcx, fcx.llloadenv);
+    let bcx = raw_block(fcx, false, fcx.llloadenv);
 
     // Load a pointer to the closure data, skipping over the box header:
     let llcdata = base::opaque_box_body(bcx, cdata_ty, fcx.llenv);
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index c002c5a2a43..fbea25964e6 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -393,17 +393,19 @@ class block_ {
     let parent: option<block>;
     // The 'kind' of basic block this is.
     let kind: block_kind;
+    // Is this block part of a landing pad?
+    let is_lpad: bool;
     // info about the AST node this block originated from, if any
     let node_info: option<node_info>;
     // The function context for the function to which this block is
     // attached.
     let fcx: fn_ctxt;
     new(llbb: BasicBlockRef, parent: option<block>, -kind: block_kind,
-        node_info: option<node_info>, fcx: fn_ctxt) {
+        is_lpad: bool, node_info: option<node_info>, fcx: fn_ctxt) {
         // sigh
         self.llbb = llbb; self.terminated = false; self.unreachable = false;
-        self.parent = parent; self.kind = kind; self.node_info = node_info;
-        self.fcx = fcx;
+        self.parent = parent; self.kind = kind; self.is_lpad = is_lpad;
+        self.node_info = node_info; self.fcx = fcx;
     }
 }
 
@@ -412,8 +414,9 @@ class block_ {
 enum block = @block_;
 
 fn mk_block(llbb: BasicBlockRef, parent: option<block>, -kind: block_kind,
-         node_info: option<node_info>, fcx: fn_ctxt) -> block {
-   block(@block_(llbb, parent, kind, node_info, fcx))
+            is_lpad: bool, node_info: option<node_info>, fcx: fn_ctxt)
+    -> block {
+    block(@block_(llbb, parent, kind, is_lpad, node_info, fcx))
 }
 
 // First two args are retptr, env
diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs
index 21ffefc5456..9d11c936a29 100644
--- a/src/rustc/middle/trans/foreign.rs
+++ b/src/rustc/middle/trans/foreign.rs
@@ -537,7 +537,7 @@ fn build_wrap_fn_(ccx: @crate_ctxt,
     tie_up_header_blocks(fcx, lltop);
 
     // Make sure our standard return block (that we didn't use) is terminated
-    let ret_cx = raw_block(fcx, fcx.llreturn);
+    let ret_cx = raw_block(fcx, false, fcx.llreturn);
     Unreachable(ret_cx);
 }