Skip to content

Commit 196d69b

Browse files
committed
make boxes self-describing (fixes #1493)" (take 2)
this will be used to generate a new snapshot.
1 parent 3116643 commit 196d69b

26 files changed

+584
-598
lines changed

mk/rt.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ RUNTIME_CS_$(1) := \
6161
rt/rust_cc.cpp \
6262
rt/rust_debug.cpp \
6363
rt/memory_region.cpp \
64+
rt/boxed_region.cpp \
6465
rt/test/rust_test_harness.cpp \
6566
rt/test/rust_test_runtime.cpp \
6667
rt/test/rust_test_util.cpp \

mk/target.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# If you are making non-backwards compatible changes to the runtime,
88
# set this flag to 1. It will cause stage1 to use the snapshot
99
# runtime rather than the runtime from the working directory.
10-
USE_SNAPSHOT_RUNTIME=0
10+
USE_SNAPSHOT_RUNTIME=1
1111

1212
define TARGET_STAGE_N
1313

src/comp/back/abi.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ const frame_glue_fns_field_drop: int = 1;
2626

2727
const frame_glue_fns_field_reloc: int = 2;
2828

29-
// n.b. must be same as cbox_elt_refcnt
30-
const box_rc_field_refcnt: int = 0;
31-
const box_rc_field_body: int = 1;
29+
const box_field_refcnt: int = 0;
30+
const box_field_tydesc: int = 1;
31+
const box_field_prev: int = 2;
32+
const box_field_next: int = 3;
33+
const box_field_body: int = 4;
3234

3335
const general_code_alignment: int = 16;
3436

@@ -59,13 +61,9 @@ const cmp_glue_op_le: uint = 2u;
5961
const fn_field_code: int = 0;
6062
const fn_field_box: int = 1;
6163

62-
// closure_box, see trans_closure.rs
63-
//
64-
// n.b. the refcnt must be compatible with a normal box
65-
const cbox_elt_refcnt: int = 0;
66-
const cbox_elt_tydesc: int = 1;
67-
const cbox_elt_ty_params: int = 2;
68-
const cbox_elt_bindings: int = 3;
64+
// closures, see trans_closure.rs
65+
const closure_body_ty_params: int = 0;
66+
const closure_body_bindings: int = 1;
6967

7068
const vec_elt_fill: int = 0;
7169

src/comp/back/upcall.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type upcalls =
1111
{_fail: ValueRef,
1212
malloc: ValueRef,
1313
free: ValueRef,
14+
validate_box: ValueRef,
1415
shared_malloc: ValueRef,
1516
shared_free: ValueRef,
1617
mark: ValueRef,
@@ -52,10 +53,12 @@ fn declare_upcalls(targ_cfg: @session::config,
5253
T_ptr(T_i8()),
5354
size_t]),
5455
malloc:
55-
d("malloc", [size_t, T_ptr(tydesc_type)],
56+
d("malloc", [T_ptr(tydesc_type)],
5657
T_ptr(T_i8())),
5758
free:
5859
dv("free", [T_ptr(T_i8()), int_t]),
60+
validate_box:
61+
dv("validate_box", [T_ptr(T_i8())]),
5962
shared_malloc:
6063
d("shared_malloc", [size_t, T_ptr(tydesc_type)],
6164
T_ptr(T_i8())),

src/comp/middle/trans/alt.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import syntax::ast_util::{dummy_sp};
1414
import syntax::ast::def_id;
1515
import syntax::codemap::span;
1616
import syntax::print::pprust::pat_to_str;
17+
import back::abi;
1718

1819
import common::*;
1920

@@ -465,7 +466,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
465466
// Unbox in case of a box field
466467
if any_box_pat(m, col) {
467468
let box = Load(bcx, val);
468-
let unboxed = GEPi(bcx, box, [0, back::abi::box_rc_field_body]);
469+
let unboxed = GEPi(bcx, box, [0, abi::box_field_body]);
469470
compile_submatch(bcx, enter_box(m, col, val), [unboxed] + vals_left,
470471
f, exits);
471472
ret;
@@ -776,7 +777,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
776777
ast::pat_box(inner) {
777778
let box = Load(bcx, val);
778779
let unboxed =
779-
GEPi(bcx, box, [0, back::abi::box_rc_field_body]);
780+
GEPi(bcx, box, [0, abi::box_field_body]);
780781
bcx = bind_irrefutable_pat(bcx, inner, unboxed, true);
781782
}
782783
ast::pat_uniq(inner) {

src/comp/middle/trans/base.rs

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fn type_of_fn(cx: @crate_ctxt, inputs: [ty::arg],
9191
atys += [out_ty];
9292

9393
// Arg 1: Environment
94-
atys += [T_opaque_cbox_ptr(cx)];
94+
atys += [T_opaque_box_ptr(cx)];
9595

9696
// Args >2: ty params, if not acquired via capture...
9797
for bounds in params {
@@ -193,7 +193,7 @@ fn type_of_inner(cx: @crate_ctxt, t: ty::t)
193193
T_struct(tys)
194194
}
195195
ty::ty_opaque_closure_ptr(_) {
196-
T_opaque_cbox_ptr(cx)
196+
T_opaque_box_ptr(cx)
197197
}
198198
ty::ty_constr(subt,_) {
199199
// FIXME: could be a constraint on ty_fn
@@ -764,54 +764,54 @@ fn trans_shared_malloc(cx: @block_ctxt, llptr_ty: TypeRef, llsize: ValueRef)
764764
ret rslt(cx, PointerCast(cx, rval, llptr_ty));
765765
}
766766

767-
// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to
768-
// enough space for something of that type, along with space for a reference
769-
// count; in other words, it allocates a box for something of that type.
770-
fn trans_malloc_boxed_raw(cx: @block_ctxt, t: ty::t) -> result {
771-
let bcx = cx;
772-
773-
// Synthesize a fake box type structurally so we have something
774-
// to measure the size of.
775-
776-
// We synthesize two types here because we want both the type of the
777-
// pointer and the pointee. boxed_body is the type that we measure the
778-
// size of; box_ptr is the type that's converted to a TypeRef and used as
779-
// the pointer cast target in trans_raw_malloc.
767+
// Returns a pointer to the body for the box. The box may be an opaque
768+
// box. The result will be casted to the type of body_t, if it is statically
769+
// known.
770+
//
771+
// The runtime equivalent is box_body() in "rust_internal.h".
772+
fn opaque_box_body(bcx: @block_ctxt,
773+
body_t: ty::t,
774+
boxptr: ValueRef) -> ValueRef {
775+
let ccx = bcx_ccx(bcx);
776+
let boxptr = PointerCast(bcx, boxptr, T_ptr(T_box_header(ccx)));
777+
let bodyptr = GEPi(bcx, boxptr, [1]);
778+
if check type_has_static_size(ccx, body_t) {
779+
PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t)))
780+
} else {
781+
PointerCast(bcx, bodyptr, T_ptr(T_i8()))
782+
}
783+
}
780784

781-
// The mk_int here is the space being
782-
// reserved for the refcount.
783-
let boxed_body = ty::mk_tup(bcx_tcx(bcx), [ty::mk_int(bcx_tcx(cx)), t]);
784-
let box_ptr = ty::mk_imm_box(bcx_tcx(bcx), t);
785-
let r = size_of(cx, boxed_body);
786-
let llsz = r.val; bcx = r.bcx;
785+
// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to
786+
// enough space for a box of that type. This includes a rust_opaque_box
787+
// header.
788+
fn trans_malloc_boxed_raw(bcx: @block_ctxt, t: ty::t,
789+
&static_ti: option<@tydesc_info>) -> result {
790+
let bcx = bcx;
791+
let ccx = bcx_ccx(bcx);
787792

788793
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
789794
// wants.
790-
// FIXME: Could avoid this check with a postcondition on mk_imm_box?
791-
// (requires Issue #586)
792-
let ccx = bcx_ccx(bcx);
795+
let box_ptr = ty::mk_imm_box(bcx_tcx(bcx), t);
793796
check (type_has_static_size(ccx, box_ptr));
794797
let llty = type_of(ccx, box_ptr);
795798

796-
let ti = none;
797-
let tydesc_result = get_tydesc(bcx, t, true, ti);
798-
let lltydesc = tydesc_result.result.val; bcx = tydesc_result.result.bcx;
799+
// Get the tydesc for the body:
800+
let {bcx, val: lltydesc} = get_tydesc(bcx, t, true, static_ti).result;
799801

800-
let rval = Call(cx, ccx.upcalls.malloc,
801-
[llsz, lltydesc]);
802-
ret rslt(cx, PointerCast(cx, rval, llty));
802+
// Allocate space:
803+
let rval = Call(bcx, ccx.upcalls.malloc, [lltydesc]);
804+
ret rslt(bcx, PointerCast(bcx, rval, llty));
803805
}
804806

805807
// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box,
806808
// initializes the reference count to 1, and pulls out the body and rc
807-
fn trans_malloc_boxed(cx: @block_ctxt, t: ty::t) ->
809+
fn trans_malloc_boxed(bcx: @block_ctxt, t: ty::t) ->
808810
{bcx: @block_ctxt, box: ValueRef, body: ValueRef} {
809-
let res = trans_malloc_boxed_raw(cx, t);
810-
let box = res.val;
811-
let rc = GEPi(res.bcx, box, [0, abi::box_rc_field_refcnt]);
812-
Store(res.bcx, C_int(bcx_ccx(cx), 1), rc);
813-
let body = GEPi(res.bcx, box, [0, abi::box_rc_field_body]);
814-
ret {bcx: res.bcx, box: res.val, body: body};
811+
let ti = none;
812+
let {bcx, val:box} = trans_malloc_boxed_raw(bcx, t, ti);
813+
let body = GEPi(bcx, box, [0, abi::box_field_body]);
814+
ret {bcx: bcx, box: box, body: body};
815815
}
816816

817817
// Type descriptor and type glue stuff
@@ -1231,8 +1231,8 @@ fn make_take_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) {
12311231

12321232
fn incr_refcnt_of_boxed(cx: @block_ctxt, box_ptr: ValueRef) -> @block_ctxt {
12331233
let ccx = bcx_ccx(cx);
1234-
let rc_ptr =
1235-
GEPi(cx, box_ptr, [0, abi::box_rc_field_refcnt]);
1234+
maybe_validate_box(cx, box_ptr);
1235+
let rc_ptr = GEPi(cx, box_ptr, [0, abi::box_field_refcnt]);
12361236
let rc = Load(cx, rc_ptr);
12371237
rc = Add(cx, rc, C_int(ccx, 1));
12381238
Store(cx, rc, rc_ptr);
@@ -1243,7 +1243,7 @@ fn free_box(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
12431243
ret alt ty::struct(bcx_tcx(bcx), t) {
12441244
ty::ty_box(body_mt) {
12451245
let v = PointerCast(bcx, v, type_of_1(bcx, t));
1246-
let body = GEPi(bcx, v, [0, abi::box_rc_field_body]);
1246+
let body = GEPi(bcx, v, [0, abi::box_field_body]);
12471247
let bcx = drop_ty(bcx, body, body_mt.ty);
12481248
trans_free_if_not_gc(bcx, v)
12491249
}
@@ -1274,7 +1274,7 @@ fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
12741274
let ccx = bcx_ccx(bcx);
12751275
let llbox_ty = T_opaque_iface_ptr(ccx);
12761276
let b = PointerCast(bcx, v, llbox_ty);
1277-
let body = GEPi(bcx, b, [0, abi::box_rc_field_body]);
1277+
let body = GEPi(bcx, b, [0, abi::box_field_body]);
12781278
let tydescptr = GEPi(bcx, body, [0, 0]);
12791279
let tydesc = Load(bcx, tydescptr);
12801280
let ti = none;
@@ -1375,18 +1375,31 @@ fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: ast::def_id,
13751375
ret next_cx;
13761376
}
13771377

1378+
fn maybe_validate_box(_cx: @block_ctxt, _box_ptr: ValueRef) {
1379+
// Uncomment this when debugging annoying use-after-free
1380+
// bugs. But do not commit with this uncommented! Big performance hit.
1381+
1382+
// let cx = _cx, box_ptr = _box_ptr;
1383+
// let ccx = bcx_ccx(cx);
1384+
// warn_not_to_commit(ccx, "validate_box() is uncommented");
1385+
// let raw_box_ptr = PointerCast(cx, box_ptr, T_ptr(T_i8()));
1386+
// Call(cx, ccx.upcalls.validate_box, [raw_box_ptr]);
1387+
}
1388+
13781389
fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
13791390
-> @block_ctxt {
13801391
let ccx = bcx_ccx(cx);
1392+
1393+
maybe_validate_box(cx, box_ptr);
1394+
13811395
let rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
13821396
let free_cx = new_sub_block_ctxt(cx, "free");
13831397
let next_cx = new_sub_block_ctxt(cx, "next");
13841398
let llbox_ty = T_opaque_iface_ptr(ccx);
13851399
let box_ptr = PointerCast(cx, box_ptr, llbox_ty);
13861400
let null_test = IsNull(cx, box_ptr);
13871401
CondBr(cx, null_test, next_cx.llbb, rc_adj_cx.llbb);
1388-
let rc_ptr =
1389-
GEPi(rc_adj_cx, box_ptr, [0, abi::box_rc_field_refcnt]);
1402+
let rc_ptr = GEPi(rc_adj_cx, box_ptr, [0, abi::box_field_refcnt]);
13901403
let rc = Load(rc_adj_cx, rc_ptr);
13911404
rc = Sub(rc_adj_cx, rc, C_int(ccx, 1));
13921405
Store(rc_adj_cx, rc, rc_ptr);
@@ -1397,7 +1410,6 @@ fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
13971410
ret next_cx;
13981411
}
13991412

1400-
14011413
// Structural comparison: a rather involved form of glue.
14021414
fn maybe_name_value(cx: @crate_ctxt, v: ValueRef, s: str) {
14031415
if cx.sess.opts.save_temps {
@@ -2208,7 +2220,7 @@ fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t {
22082220
while true {
22092221
alt ty::struct(ccx.tcx, t1) {
22102222
ty::ty_box(mt) {
2211-
let body = GEPi(cx, v1, [0, abi::box_rc_field_body]);
2223+
let body = GEPi(cx, v1, [0, abi::box_field_body]);
22122224
t1 = mt.ty;
22132225

22142226
// Since we're changing levels of box indirection, we may have
@@ -2514,7 +2526,7 @@ type lval_maybe_callee = {bcx: @block_ctxt,
25142526
generic: option<generic_info>};
25152527

25162528
fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
2517-
C_null(T_opaque_cbox_ptr(bcx_ccx(bcx)))
2529+
C_null(T_opaque_box_ptr(bcx_ccx(bcx)))
25182530
}
25192531

25202532
fn lval_from_local_var(bcx: @block_ctxt, r: local_var_result) -> lval_result {
@@ -2790,7 +2802,7 @@ fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
27902802
let val =
27912803
alt ty::struct(ccx.tcx, t) {
27922804
ty::ty_box(_) {
2793-
GEPi(sub.bcx, sub.val, [0, abi::box_rc_field_body])
2805+
GEPi(sub.bcx, sub.val, [0, abi::box_field_body])
27942806
}
27952807
ty::ty_res(_, _, _) {
27962808
GEPi(sub.bcx, sub.val, [0, 1])
@@ -3160,7 +3172,7 @@ fn trans_call_inner(in_cx: @block_ctxt, fn_expr_ty: ty::t,
31603172
let llenv, dict_param = none;
31613173
alt f_res.env {
31623174
null_env {
3163-
llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
3175+
llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(bcx_ccx(cx)));
31643176
}
31653177
self_env(e) { llenv = e; }
31663178
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
@@ -3465,6 +3477,8 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
34653477
let tcx = bcx_tcx(bcx);
34663478
debuginfo::update_source_pos(bcx, e.span);
34673479

3480+
#debug["trans_expr(%s,%?)", expr_to_str(e), dest];
3481+
34683482
if expr_is_lval(bcx, e) {
34693483
ret lval_to_dps(bcx, e, dest);
34703484
}
@@ -3998,6 +4012,8 @@ fn zero_alloca(cx: @block_ctxt, llptr: ValueRef, t: ty::t)
39984012
}
39994013

40004014
fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
4015+
#debug["trans_expr(%s)", stmt_to_str(s)];
4016+
40014017
if (!bcx_ccx(cx).sess.opts.no_asm_comments) {
40024018
add_span_comment(cx, s.span, stmt_to_str(s));
40034019
}
@@ -5122,8 +5138,7 @@ fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
51225138
let code_cell = GEPi(bcx, pair, [0, abi::fn_field_code]);
51235139
Store(bcx, llfn, code_cell);
51245140
let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]);
5125-
let llenvblobptr =
5126-
PointerCast(bcx, llenvptr, T_opaque_cbox_ptr(ccx));
5141+
let llenvblobptr = PointerCast(bcx, llenvptr, T_opaque_box_ptr(ccx));
51275142
Store(bcx, llenvblobptr, env_cell);
51285143
}
51295144

@@ -5591,7 +5606,8 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
55915606
shape_cx: shape::mk_ctxt(llmod),
55925607
gc_cx: gc::mk_ctxt(),
55935608
crate_map: crate_map,
5594-
dbg_cx: dbg_cx};
5609+
dbg_cx: dbg_cx,
5610+
mutable do_not_commit_warning_issued: false};
55955611
let cx = new_local_ctxt(ccx);
55965612
collect_items(ccx, crate);
55975613
trans_constants(ccx, crate);

src/comp/middle/trans/build.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef};
88
import lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False,
99
CallConv};
1010
import common::{block_ctxt, T_ptr, T_nil, T_i8, T_i1, T_void,
11-
T_fn, val_ty, bcx_ccx, C_i32};
11+
T_fn, val_ty, bcx_ccx, C_i32, val_str};
1212

1313
fn B(cx: @block_ctxt) -> BuilderRef {
1414
let b = *cx.fcx.lcx.ccx.builder;
@@ -95,6 +95,10 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
9595
if cx.unreachable { ret; }
9696
assert (!cx.terminated);
9797
cx.terminated = true;
98+
#debug["Invoke(%s with arguments (%s))",
99+
val_str(bcx_ccx(cx).tn, Fn),
100+
str::connect(vec::map(Args, {|a|val_str(bcx_ccx(cx).tn, a)}),
101+
", ")];
98102
unsafe {
99103
llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args),
100104
vec::len(Args) as c_uint, Then, Catch,

0 commit comments

Comments
 (0)