Drop slots on block exits even when blocks have no statements. Part way to fixing bind leakage in rustc.
This commit is contained in:
parent
f6e3e6903b
commit
62c224ffe4
7 changed files with 156 additions and 90 deletions
|
@ -462,6 +462,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
|
||||||
deep.rs \
|
deep.rs \
|
||||||
deref.rs \
|
deref.rs \
|
||||||
destructor-ordering.rs \
|
destructor-ordering.rs \
|
||||||
|
drop-on-empty-block-exit.rs \
|
||||||
export-non-interference.rs \
|
export-non-interference.rs \
|
||||||
exterior.rs \
|
exterior.rs \
|
||||||
fn-lval.rs \
|
fn-lval.rs \
|
||||||
|
|
|
@ -1545,6 +1545,7 @@ and fmt_pat (ff:Format.formatter) (pat:pat) : unit =
|
||||||
fmt_lval ff ctor;
|
fmt_lval ff ctor;
|
||||||
fmt_bracketed_arr_sep "(" ")" "," fmt_pat ff pats
|
fmt_bracketed_arr_sep "(" ")" "," fmt_pat ff pats
|
||||||
| PAT_slot (_, ident) ->
|
| PAT_slot (_, ident) ->
|
||||||
|
fmt ff "?";
|
||||||
fmt_ident ff ident
|
fmt_ident ff ident
|
||||||
| PAT_wild ->
|
| PAT_wild ->
|
||||||
fmt ff "_"
|
fmt ff "_"
|
||||||
|
|
|
@ -114,6 +114,8 @@ let loop_depth_visitor
|
||||||
let visit_block_pre b =
|
let visit_block_pre b =
|
||||||
if Hashtbl.mem cx.ctxt_block_is_loop_body b.id
|
if Hashtbl.mem cx.ctxt_block_is_loop_body b.id
|
||||||
then push_loop ();
|
then push_loop ();
|
||||||
|
let fcx = Stack.top fcxs in
|
||||||
|
htab_put cx.ctxt_block_loop_depths b.id fcx.current_depth;
|
||||||
inner.Walk.visit_block_pre b
|
inner.Walk.visit_block_pre b
|
||||||
in
|
in
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@ type ctxt =
|
||||||
(* Typestate-y stuff. *)
|
(* Typestate-y stuff. *)
|
||||||
ctxt_stmt_is_init: (node_id,unit) Hashtbl.t;
|
ctxt_stmt_is_init: (node_id,unit) Hashtbl.t;
|
||||||
ctxt_post_stmt_slot_drops: (node_id,node_id list) Hashtbl.t;
|
ctxt_post_stmt_slot_drops: (node_id,node_id list) Hashtbl.t;
|
||||||
|
ctxt_post_block_slot_drops: (node_id,node_id list) Hashtbl.t;
|
||||||
|
|
||||||
(* Layout-y stuff. *)
|
(* Layout-y stuff. *)
|
||||||
ctxt_slot_aliased: (node_id,unit) Hashtbl.t;
|
ctxt_slot_aliased: (node_id,unit) Hashtbl.t;
|
||||||
|
@ -141,6 +142,7 @@ type ctxt =
|
||||||
ctxt_call_sizes: (node_id,size) Hashtbl.t;
|
ctxt_call_sizes: (node_id,size) Hashtbl.t;
|
||||||
ctxt_block_is_loop_body: (node_id,unit) Hashtbl.t;
|
ctxt_block_is_loop_body: (node_id,unit) Hashtbl.t;
|
||||||
ctxt_stmt_loop_depths: (node_id,int) Hashtbl.t;
|
ctxt_stmt_loop_depths: (node_id,int) Hashtbl.t;
|
||||||
|
ctxt_block_loop_depths: (node_id,int) Hashtbl.t;
|
||||||
ctxt_slot_loop_depths: (node_id,int) Hashtbl.t;
|
ctxt_slot_loop_depths: (node_id,int) Hashtbl.t;
|
||||||
|
|
||||||
(* Translation-y stuff. *)
|
(* Translation-y stuff. *)
|
||||||
|
@ -216,6 +218,7 @@ let new_ctxt sess abi crate =
|
||||||
|
|
||||||
ctxt_stmt_is_init = Hashtbl.create 0;
|
ctxt_stmt_is_init = Hashtbl.create 0;
|
||||||
ctxt_post_stmt_slot_drops = Hashtbl.create 0;
|
ctxt_post_stmt_slot_drops = Hashtbl.create 0;
|
||||||
|
ctxt_post_block_slot_drops = Hashtbl.create 0;
|
||||||
|
|
||||||
ctxt_slot_aliased = Hashtbl.create 0;
|
ctxt_slot_aliased = Hashtbl.create 0;
|
||||||
ctxt_slot_is_obj_state = Hashtbl.create 0;
|
ctxt_slot_is_obj_state = Hashtbl.create 0;
|
||||||
|
@ -227,6 +230,7 @@ let new_ctxt sess abi crate =
|
||||||
ctxt_block_is_loop_body = Hashtbl.create 0;
|
ctxt_block_is_loop_body = Hashtbl.create 0;
|
||||||
ctxt_slot_loop_depths = Hashtbl.create 0;
|
ctxt_slot_loop_depths = Hashtbl.create 0;
|
||||||
ctxt_stmt_loop_depths = Hashtbl.create 0;
|
ctxt_stmt_loop_depths = Hashtbl.create 0;
|
||||||
|
ctxt_block_loop_depths = Hashtbl.create 0;
|
||||||
|
|
||||||
ctxt_fn_fixups = Hashtbl.create 0;
|
ctxt_fn_fixups = Hashtbl.create 0;
|
||||||
ctxt_block_fixups = Hashtbl.create 0;
|
ctxt_block_fixups = Hashtbl.create 0;
|
||||||
|
@ -399,6 +403,10 @@ let get_stmt_depth (cx:ctxt) (id:node_id) : int =
|
||||||
Hashtbl.find cx.ctxt_stmt_loop_depths id
|
Hashtbl.find cx.ctxt_stmt_loop_depths id
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
let get_block_depth (cx:ctxt) (id:node_id) : int =
|
||||||
|
Hashtbl.find cx.ctxt_block_loop_depths id
|
||||||
|
;;
|
||||||
|
|
||||||
let get_slot_depth (cx:ctxt) (id:node_id) : int =
|
let get_slot_depth (cx:ctxt) (id:node_id) : int =
|
||||||
Hashtbl.find cx.ctxt_slot_loop_depths id
|
Hashtbl.find cx.ctxt_slot_loop_depths id
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -826,10 +826,51 @@ let trans_visitor
|
||||||
out diff current_fp
|
out diff current_fp
|
||||||
in
|
in
|
||||||
|
|
||||||
|
let curr_stmt_depth _ =
|
||||||
|
if (Stack.is_empty curr_stmt)
|
||||||
|
then None
|
||||||
|
else
|
||||||
|
Some
|
||||||
|
(get_stmt_depth cx (Stack.top curr_stmt))
|
||||||
|
in
|
||||||
|
|
||||||
let cell_of_block_slot
|
let cell_of_block_slot
|
||||||
|
?access_depth:(access_depth=curr_stmt_depth())
|
||||||
(slot_id:node_id)
|
(slot_id:node_id)
|
||||||
: Il.cell =
|
: Il.cell =
|
||||||
|
|
||||||
let referent_type = slot_id_referent_type slot_id in
|
let referent_type = slot_id_referent_type slot_id in
|
||||||
|
|
||||||
|
let local_access off =
|
||||||
|
Il.Mem (fp_off_sz off, referent_type)
|
||||||
|
in
|
||||||
|
|
||||||
|
let outer_access off slot_depth depth =
|
||||||
|
let _ = assert (slot_depth < depth) in
|
||||||
|
let _ =
|
||||||
|
iflog
|
||||||
|
begin
|
||||||
|
fun _ ->
|
||||||
|
let k =
|
||||||
|
Hashtbl.find cx.ctxt_slot_keys slot_id
|
||||||
|
in
|
||||||
|
annotate (Printf.sprintf
|
||||||
|
"access outer frame slot #%d = %s"
|
||||||
|
(int_of_node slot_id)
|
||||||
|
(Fmt.fmt_to_str Ast.fmt_slot_key k))
|
||||||
|
end
|
||||||
|
in
|
||||||
|
let diff = depth - slot_depth in
|
||||||
|
let _ = annotate "get outer frame pointer" in
|
||||||
|
let fp = get_nth_outer_frame_ptr diff in
|
||||||
|
let _ = annotate "calculate size" in
|
||||||
|
let p =
|
||||||
|
based_sz (get_ty_params_of_current_frame())
|
||||||
|
(fst (force_to_reg (Il.Cell fp))) off
|
||||||
|
in
|
||||||
|
Il.Mem (p, referent_type)
|
||||||
|
in
|
||||||
|
|
||||||
match htab_search cx.ctxt_slot_vregs slot_id with
|
match htab_search cx.ctxt_slot_vregs slot_id with
|
||||||
Some vr ->
|
Some vr ->
|
||||||
begin
|
begin
|
||||||
|
@ -865,43 +906,15 @@ let trans_visitor
|
||||||
Il.Mem (slot_mem, referent_type)
|
Il.Mem (slot_mem, referent_type)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if (Stack.is_empty curr_stmt)
|
match access_depth with
|
||||||
then
|
None -> local_access off
|
||||||
Il.Mem (fp_off_sz off, referent_type)
|
| Some depth ->
|
||||||
else
|
let slot_depth = get_slot_depth cx slot_id in
|
||||||
let slot_depth = get_slot_depth cx slot_id in
|
if slot_depth <> depth
|
||||||
let stmt_depth =
|
then
|
||||||
get_stmt_depth cx (Stack.top curr_stmt)
|
outer_access off slot_depth depth
|
||||||
in
|
else
|
||||||
if slot_depth <> stmt_depth
|
local_access off
|
||||||
then
|
|
||||||
let _ = assert (slot_depth < stmt_depth) in
|
|
||||||
let _ =
|
|
||||||
iflog
|
|
||||||
begin
|
|
||||||
fun _ ->
|
|
||||||
let k =
|
|
||||||
Hashtbl.find cx.ctxt_slot_keys slot_id
|
|
||||||
in
|
|
||||||
annotate
|
|
||||||
(Printf.sprintf
|
|
||||||
"access outer frame slot #%d = %s"
|
|
||||||
(int_of_node slot_id)
|
|
||||||
(Fmt.fmt_to_str
|
|
||||||
Ast.fmt_slot_key k))
|
|
||||||
end
|
|
||||||
in
|
|
||||||
let diff = stmt_depth - slot_depth in
|
|
||||||
let _ = annotate "get outer frame pointer" in
|
|
||||||
let fp = get_nth_outer_frame_ptr diff in
|
|
||||||
let _ = annotate "calculate size" in
|
|
||||||
let p =
|
|
||||||
based_sz (get_ty_params_of_current_frame())
|
|
||||||
(fst (force_to_reg (Il.Cell fp))) off
|
|
||||||
in
|
|
||||||
Il.Mem (p, referent_type)
|
|
||||||
else
|
|
||||||
Il.Mem (fp_off_sz off, referent_type)
|
|
||||||
end
|
end
|
||||||
in
|
in
|
||||||
|
|
||||||
|
@ -2434,12 +2447,35 @@ let trans_visitor
|
||||||
| Ast.EXPR_atom a ->
|
| Ast.EXPR_atom a ->
|
||||||
trans_atom a
|
trans_atom a
|
||||||
|
|
||||||
|
and drop_slots_after_block bid : unit =
|
||||||
|
match htab_search cx.ctxt_post_block_slot_drops bid with
|
||||||
|
None -> ()
|
||||||
|
| Some slots ->
|
||||||
|
List.iter
|
||||||
|
begin
|
||||||
|
fun slot_id ->
|
||||||
|
let slot = get_slot cx slot_id in
|
||||||
|
let k = Hashtbl.find cx.ctxt_slot_keys slot_id in
|
||||||
|
let depth = Hashtbl.find cx.ctxt_block_loop_depths bid in
|
||||||
|
iflog (fun _ ->
|
||||||
|
annotate
|
||||||
|
(Printf.sprintf
|
||||||
|
"post-block, drop_slot %d = %s "
|
||||||
|
(int_of_node slot_id)
|
||||||
|
(Fmt.fmt_to_str Ast.fmt_slot_key k)));
|
||||||
|
drop_slot_in_current_frame
|
||||||
|
(cell_of_block_slot
|
||||||
|
~access_depth:(Some depth) slot_id) slot
|
||||||
|
end
|
||||||
|
slots
|
||||||
|
|
||||||
and trans_block (block:Ast.block) : unit =
|
and trans_block (block:Ast.block) : unit =
|
||||||
flush_emitter_size_cache();
|
flush_emitter_size_cache();
|
||||||
trace_str cx.ctxt_sess.Session.sess_trace_block
|
trace_str cx.ctxt_sess.Session.sess_trace_block
|
||||||
"entering block";
|
"entering block";
|
||||||
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups block.id));
|
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups block.id));
|
||||||
Array.iter trans_stmt block.node;
|
Array.iter trans_stmt block.node;
|
||||||
|
drop_slots_after_block block.id;
|
||||||
trace_str cx.ctxt_sess.Session.sess_trace_block
|
trace_str cx.ctxt_sess.Session.sess_trace_block
|
||||||
"exiting block";
|
"exiting block";
|
||||||
emit Il.Leave;
|
emit Il.Leave;
|
||||||
|
|
|
@ -449,9 +449,12 @@ type slots_stack = node_id Stack.t;;
|
||||||
type block_slots_stack = slots_stack Stack.t;;
|
type block_slots_stack = slots_stack Stack.t;;
|
||||||
type frame_block_slots_stack = block_slots_stack Stack.t;;
|
type frame_block_slots_stack = block_slots_stack Stack.t;;
|
||||||
type loop_block_slots_stack = block_slots_stack option Stack.t;;
|
type loop_block_slots_stack = block_slots_stack option Stack.t;;
|
||||||
(* like ret drops slots from all blocks in the frame
|
|
||||||
* break from a simple loo drops slots from all block in a loop *)
|
(* Like ret drops slots from all blocks in the frame
|
||||||
let (loop_blocks:loop_block_slots_stack) =
|
* break from a simple loop drops slots from all block in a loop
|
||||||
|
*)
|
||||||
|
|
||||||
|
let (loop_blocks:loop_block_slots_stack) =
|
||||||
let s = Stack.create() in Stack.push None s; s
|
let s = Stack.create() in Stack.push None s; s
|
||||||
|
|
||||||
let condition_assigning_visitor
|
let condition_assigning_visitor
|
||||||
|
@ -583,7 +586,7 @@ let condition_assigning_visitor
|
||||||
let precond = slot_inits (lval_slots cx lval) in
|
let precond = slot_inits (lval_slots cx lval) in
|
||||||
raise_precondition sid precond;
|
raise_precondition sid precond;
|
||||||
in
|
in
|
||||||
|
|
||||||
let visit_stmt_pre s =
|
let visit_stmt_pre s =
|
||||||
begin
|
begin
|
||||||
match s.node with
|
match s.node with
|
||||||
|
@ -1317,11 +1320,12 @@ let lifecycle_visitor
|
||||||
|
|
||||||
|
|
||||||
let visit_block_pre b =
|
let visit_block_pre b =
|
||||||
|
|
||||||
let s = Stack.create() in
|
let s = Stack.create() in
|
||||||
begin
|
begin
|
||||||
match Stack.top loop_blocks with
|
match Stack.top loop_blocks with
|
||||||
Some loop -> Stack.push s loop | None -> ()
|
Some loop -> Stack.push s loop
|
||||||
|
| None -> ()
|
||||||
end;
|
end;
|
||||||
Stack.push s (Stack.top frame_blocks);
|
Stack.push s (Stack.top frame_blocks);
|
||||||
begin
|
begin
|
||||||
|
@ -1337,7 +1341,7 @@ let lifecycle_visitor
|
||||||
inner.Walk.visit_block_pre b
|
inner.Walk.visit_block_pre b
|
||||||
in
|
in
|
||||||
|
|
||||||
let note_drops stmt slots =
|
let note_stmt_drops stmt slots =
|
||||||
iflog cx
|
iflog cx
|
||||||
begin
|
begin
|
||||||
fun _ ->
|
fun _ ->
|
||||||
|
@ -1352,6 +1356,21 @@ let lifecycle_visitor
|
||||||
htab_put cx.ctxt_post_stmt_slot_drops stmt.id slots
|
htab_put cx.ctxt_post_stmt_slot_drops stmt.id slots
|
||||||
in
|
in
|
||||||
|
|
||||||
|
let note_block_drops bid slots =
|
||||||
|
iflog cx
|
||||||
|
begin
|
||||||
|
fun _ ->
|
||||||
|
log cx "implicit drop of %d slots after block %d: "
|
||||||
|
(List.length slots)
|
||||||
|
(int_of_node bid);
|
||||||
|
List.iter (fun s -> log cx "drop: %a"
|
||||||
|
Ast.sprintf_slot_key
|
||||||
|
(Hashtbl.find cx.ctxt_slot_keys s))
|
||||||
|
slots
|
||||||
|
end;
|
||||||
|
htab_put cx.ctxt_post_block_slot_drops bid slots
|
||||||
|
in
|
||||||
|
|
||||||
let filter_live_block_slots slots =
|
let filter_live_block_slots slots =
|
||||||
List.filter (fun i -> Hashtbl.mem live_block_slots i) slots
|
List.filter (fun i -> Hashtbl.mem live_block_slots i) slots
|
||||||
in
|
in
|
||||||
|
@ -1360,37 +1379,24 @@ let lifecycle_visitor
|
||||||
inner.Walk.visit_block_post b;
|
inner.Walk.visit_block_post b;
|
||||||
begin
|
begin
|
||||||
match Stack.top loop_blocks with
|
match Stack.top loop_blocks with
|
||||||
Some loop ->
|
Some loop ->
|
||||||
ignore(Stack.pop loop);
|
ignore (Stack.pop loop);
|
||||||
if Stack.is_empty loop then
|
if Stack.is_empty loop
|
||||||
ignore(Stack.pop loop_blocks);
|
then ignore (Stack.pop loop_blocks);
|
||||||
| None -> ()
|
| None -> ()
|
||||||
end;
|
end;
|
||||||
let block_slots = Stack.pop (Stack.top frame_blocks) in
|
let block_slots = Stack.pop (Stack.top frame_blocks) in
|
||||||
let stmts = b.node in
|
(* The blk_slots stack we have has accumulated slots in
|
||||||
let len = Array.length stmts in
|
* declaration order as we walked the block; the top of the
|
||||||
if len > 0
|
* stack is the last-declared slot. We want to generate
|
||||||
then
|
* slot-drop obligations here for the slots in top-down order
|
||||||
begin
|
* (starting with the last-declared) but only hitting those
|
||||||
let s = stmts.(len-1) in
|
* slots that actually got initialized (went live) at some
|
||||||
match s.node with
|
* point in the block.
|
||||||
Ast.STMT_ret _
|
*)
|
||||||
| Ast.STMT_be _
|
let slots = stk_elts_from_top block_slots in
|
||||||
| Ast.STMT_break ->
|
let live = filter_live_block_slots slots in
|
||||||
() (* Taken care of in visit_stmt_post below. *)
|
note_block_drops b.id live
|
||||||
| _ ->
|
|
||||||
(* The blk_slots stack we have has accumulated slots in
|
|
||||||
* declaration order as we walked the block; the top of the
|
|
||||||
* stack is the last-declared slot. We want to generate
|
|
||||||
* slot-drop obligations here for the slots in top-down order
|
|
||||||
* (starting with the last-declared) but only hitting those
|
|
||||||
* slots that actually got initialized (went live) at some
|
|
||||||
* point in the block.
|
|
||||||
*)
|
|
||||||
let slots = stk_elts_from_top block_slots in
|
|
||||||
let live = filter_live_block_slots slots in
|
|
||||||
note_drops s live
|
|
||||||
end;
|
|
||||||
in
|
in
|
||||||
|
|
||||||
let visit_stmt_pre s =
|
let visit_stmt_pre s =
|
||||||
|
@ -1499,33 +1505,34 @@ let lifecycle_visitor
|
||||||
|
|
||||||
let visit_stmt_post s =
|
let visit_stmt_post s =
|
||||||
inner.Walk.visit_stmt_post s;
|
inner.Walk.visit_stmt_post s;
|
||||||
let handle_ret_like_stmt block_stack =
|
|
||||||
|
let handle_outward_jump_stmt block_stack =
|
||||||
let blocks = stk_elts_from_top block_stack in
|
let blocks = stk_elts_from_top block_stack in
|
||||||
let slots = List.concat (List.map stk_elts_from_top blocks) in
|
let slots = List.concat (List.map stk_elts_from_top blocks) in
|
||||||
let live = filter_live_block_slots slots in
|
let live = filter_live_block_slots slots in
|
||||||
note_drops s live
|
note_stmt_drops s live
|
||||||
in
|
in
|
||||||
match s.node with
|
|
||||||
Ast.STMT_ret _
|
match s.node with
|
||||||
| Ast.STMT_be _ ->
|
Ast.STMT_ret _
|
||||||
handle_ret_like_stmt (Stack.top frame_blocks)
|
| Ast.STMT_be _ ->
|
||||||
| Ast.STMT_break ->
|
handle_outward_jump_stmt (Stack.top frame_blocks)
|
||||||
begin
|
|
||||||
match (Stack.top loop_blocks) with
|
| Ast.STMT_break ->
|
||||||
Some loop -> handle_ret_like_stmt loop
|
begin
|
||||||
| None ->
|
match (Stack.top loop_blocks) with
|
||||||
iflog cx (fun _ ->
|
Some loop -> handle_outward_jump_stmt loop
|
||||||
log cx "break statement outside of a loop");
|
| None ->
|
||||||
err (Some s.id) "break statement outside of a loop"
|
err (Some s.id) "break statement outside of a loop"
|
||||||
end
|
end
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
in
|
in
|
||||||
|
|
||||||
let enter_frame _ =
|
let enter_frame _ =
|
||||||
Stack.push (Stack.create()) frame_blocks;
|
Stack.push (Stack.create()) frame_blocks;
|
||||||
Stack.push None loop_blocks
|
Stack.push None loop_blocks
|
||||||
in
|
in
|
||||||
|
|
||||||
let leave_frame _ =
|
let leave_frame _ =
|
||||||
ignore (Stack.pop frame_blocks);
|
ignore (Stack.pop frame_blocks);
|
||||||
match Stack.pop loop_blocks with
|
match Stack.pop loop_blocks with
|
||||||
|
|
11
src/test/run-pass/drop-on-empty-block-exit.rs
Normal file
11
src/test/run-pass/drop-on-empty-block-exit.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
tag t {
|
||||||
|
foo(@int);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
auto tt = foo(@10);
|
||||||
|
alt (tt) {
|
||||||
|
case (foo(?z)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue