Skip to content

Commit 166cb1b

Browse files
author
Elliott Slaughter
committed
rustc: Strict enforcement of glue function types.
Make all glue functions take values by alias to remove the need for bitcasts at the top of every glue function. Use static type information to produce the correct type for glue functions so that LLVM can enforce the type system at call sites.
1 parent 76d04af commit 166cb1b

File tree

6 files changed

+118
-60
lines changed

6 files changed

+118
-60
lines changed

src/rustc/middle/trans/base.rs

+101-54
Original file line numberDiff line numberDiff line change
@@ -546,18 +546,18 @@ fn make_generic_glue_inner(ccx: @crate_ctxt, t: ty::t,
546546
let fcx = new_fn_ctxt(ccx, ~[], llfn, none);
547547
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
548548
ccx.stats.n_glues_created += 1u;
549-
// Any nontrivial glue is with values passed *by alias*; this is a
549+
// All glue functions take values passed *by alias*; this is a
550550
// requirement since in many contexts glue is invoked indirectly and
551551
// the caller has no idea if it's dealing with something that can be
552552
// passed by value.
553-
554-
let llty = T_ptr(type_of(ccx, t));
553+
//
554+
// llfn is expected be declared to take a parameter of the appropriate
555+
// type, so we don't need to explicitly cast the function parameter.
555556

556557
let bcx = top_scope_block(fcx, none);
557558
let lltop = bcx.llbb;
558559
let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint);
559-
let llval0 = BitCast(bcx, llrawptr0, llty);
560-
helper(bcx, llval0, t);
560+
helper(bcx, llrawptr0, t);
561561
finish_fn(fcx, lltop);
562562
return llfn;
563563
}
@@ -581,28 +581,44 @@ fn make_generic_glue(ccx: @crate_ctxt, t: ty::t, llfn: ValueRef,
581581
fn emit_tydescs(ccx: @crate_ctxt) {
582582
let _icx = ccx.insn_ctxt(~"emit_tydescs");
583583
for ccx.tydescs.each |key, val| {
584-
let glue_fn_ty = T_ptr(T_glue_fn(ccx));
584+
let glue_fn_ty = T_ptr(T_generic_glue_fn(ccx));
585585
let ti = val;
586586

587+
// Each of the glue functions needs to be cast to a generic type
588+
// before being put into the tydesc because we only have a singleton
589+
// tydesc type. Then we'll recast each function to its real type when
590+
// calling it.
587591
let take_glue =
588592
match copy ti.take_glue {
589593
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
590-
some(v) => { ccx.stats.n_real_glues += 1u; v }
594+
some(v) => {
595+
ccx.stats.n_real_glues += 1u;
596+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
597+
}
591598
};
592599
let drop_glue =
593600
match copy ti.drop_glue {
594601
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
595-
some(v) => { ccx.stats.n_real_glues += 1u; v }
602+
some(v) => {
603+
ccx.stats.n_real_glues += 1u;
604+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
605+
}
596606
};
597607
let free_glue =
598608
match copy ti.free_glue {
599609
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
600-
some(v) => { ccx.stats.n_real_glues += 1u; v }
610+
some(v) => {
611+
ccx.stats.n_real_glues += 1u;
612+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
613+
}
601614
};
602615
let visit_glue =
603616
match copy ti.visit_glue {
604617
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
605-
some(v) => { ccx.stats.n_real_glues += 1u; v }
618+
some(v) => {
619+
ccx.stats.n_real_glues += 1u;
620+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
621+
}
606622
};
607623

608624
let shape = shape_of(ccx, key);
@@ -692,20 +708,20 @@ fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
692708

693709

694710
fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
695-
// v is a pointer to the actual box component of the type here. The
696-
// ValueRef will have the wrong type here (make_generic_glue is casting
697-
// everything to a pointer to the type that the glue acts on).
711+
// NB: v0 is an *alias* of type t here, not a direct value.
698712
let _icx = bcx.insn_ctxt(~"make_free_glue");
699713
let ccx = bcx.ccx();
700714
let bcx = match ty::get(t).struct {
701715
ty::ty_box(body_mt) => {
702-
let v = PointerCast(bcx, v, type_of(ccx, t));
716+
let v = Load(bcx, v);
703717
let body = GEPi(bcx, v, ~[0u, abi::box_field_body]);
718+
// Cast away the addrspace of the box pointer.
719+
let body = PointerCast(bcx, body, T_ptr(type_of(ccx, body_mt.ty)));
704720
let bcx = drop_ty(bcx, body, body_mt.ty);
705721
trans_free(bcx, v)
706722
}
707723
ty::ty_opaque_box => {
708-
let v = PointerCast(bcx, v, type_of(ccx, t));
724+
let v = Load(bcx, v);
709725
let td = Load(bcx, GEPi(bcx, v, ~[0u, abi::box_field_tydesc]));
710726
let valptr = GEPi(bcx, v, ~[0u, abi::box_field_body]);
711727
// Generate code that, dynamically, indexes into the
@@ -715,7 +731,6 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
715731
trans_free(bcx, v)
716732
}
717733
ty::ty_uniq(content_mt) => {
718-
let v = PointerCast(bcx, v, type_of(ccx, t));
719734
uniq::make_free_glue(bcx, v, t)
720735
}
721736
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
@@ -785,7 +800,7 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
785800
}
786801
ty::ty_uniq(_) |
787802
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
788-
free_ty(bcx, Load(bcx, v0), t)
803+
free_ty(bcx, v0, t)
789804
}
790805
ty::ty_unboxed_vec(_) => {
791806
tvec::make_drop_glue_unboxed(bcx, v0, t)
@@ -861,14 +876,12 @@ fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t) -> block {
861876
let ccx = bcx.ccx();
862877
maybe_validate_box(bcx, box_ptr);
863878

864-
let llbox_ty = T_opaque_box_ptr(ccx);
865-
let box_ptr = PointerCast(bcx, box_ptr, llbox_ty);
866879
do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
867880
let rc_ptr = GEPi(bcx, box_ptr, ~[0u, abi::box_field_refcnt]);
868881
let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
869882
Store(bcx, rc, rc_ptr);
870883
let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
871-
with_cond(bcx, zero_test, |bcx| free_ty(bcx, box_ptr, t))
884+
with_cond(bcx, zero_test, |bcx| free_ty_immediate(bcx, box_ptr, t))
872885
}
873886
}
874887

@@ -1097,17 +1110,16 @@ fn lazily_emit_all_tydesc_glue(ccx: @crate_ctxt,
10971110
fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
10981111
ti: @tydesc_info) {
10991112
let _icx = ccx.insn_ctxt(~"lazily_emit_tydesc_glue");
1113+
let llfnty = type_of_glue_fn(ccx, ti.ty);
11001114
if field == abi::tydesc_field_take_glue {
11011115
match ti.take_glue {
11021116
some(_) => (),
11031117
none => {
11041118
debug!{"+++ lazily_emit_tydesc_glue TAKE %s",
11051119
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1106-
let glue_fn = declare_generic_glue
1107-
(ccx, ti.ty, T_glue_fn(ccx), ~"take");
1120+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"take");
11081121
ti.take_glue = some(glue_fn);
1109-
make_generic_glue(ccx, ti.ty, glue_fn,
1110-
make_take_glue, ~"take");
1122+
make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, ~"take");
11111123
debug!{"--- lazily_emit_tydesc_glue TAKE %s",
11121124
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11131125
}
@@ -1118,11 +1130,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11181130
none => {
11191131
debug!{"+++ lazily_emit_tydesc_glue DROP %s",
11201132
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1121-
let glue_fn =
1122-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"drop");
1133+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"drop");
11231134
ti.drop_glue = some(glue_fn);
1124-
make_generic_glue(ccx, ti.ty, glue_fn,
1125-
make_drop_glue, ~"drop");
1135+
make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, ~"drop");
11261136
debug!{"--- lazily_emit_tydesc_glue DROP %s",
11271137
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11281138
}
@@ -1133,11 +1143,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11331143
none => {
11341144
debug!{"+++ lazily_emit_tydesc_glue FREE %s",
11351145
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1136-
let glue_fn =
1137-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"free");
1146+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"free");
11381147
ti.free_glue = some(glue_fn);
1139-
make_generic_glue(ccx, ti.ty, glue_fn,
1140-
make_free_glue, ~"free");
1148+
make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, ~"free");
11411149
debug!{"--- lazily_emit_tydesc_glue FREE %s",
11421150
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11431151
}
@@ -1148,11 +1156,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11481156
none => {
11491157
debug!{"+++ lazily_emit_tydesc_glue VISIT %s",
11501158
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1151-
let glue_fn =
1152-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"visit");
1159+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"visit");
11531160
ti.visit_glue = some(glue_fn);
1154-
make_generic_glue(ccx, ti.ty, glue_fn,
1155-
make_visit_glue, ~"visit");
1161+
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, ~"visit");
11561162
debug!{"--- lazily_emit_tydesc_glue VISIT %s",
11571163
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11581164
}
@@ -1161,43 +1167,63 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11611167
}
11621168

11631169
// See [Note-arg-mode]
1164-
fn call_tydesc_glue_full(++cx: block, v: ValueRef, tydesc: ValueRef,
1170+
fn call_tydesc_glue_full(++bcx: block, v: ValueRef, tydesc: ValueRef,
11651171
field: uint, static_ti: option<@tydesc_info>) {
1166-
let _icx = cx.insn_ctxt(~"call_tydesc_glue_full");
1167-
if cx.unreachable { return; }
1172+
let _icx = bcx.insn_ctxt(~"call_tydesc_glue_full");
1173+
if bcx.unreachable { return; }
1174+
let ccx = bcx.ccx();
11681175

1169-
let mut static_glue_fn = none;
1170-
match static_ti {
1171-
none => {/* no-op */ }
1176+
let static_glue_fn = match static_ti {
1177+
none => none,
11721178
some(sti) => {
1173-
lazily_emit_tydesc_glue(cx.ccx(), field, sti);
1179+
lazily_emit_tydesc_glue(ccx, field, sti);
11741180
if field == abi::tydesc_field_take_glue {
1175-
static_glue_fn = sti.take_glue;
1181+
sti.take_glue
11761182
} else if field == abi::tydesc_field_drop_glue {
1177-
static_glue_fn = sti.drop_glue;
1183+
sti.drop_glue
11781184
} else if field == abi::tydesc_field_free_glue {
1179-
static_glue_fn = sti.free_glue;
1185+
sti.free_glue
11801186
} else if field == abi::tydesc_field_visit_glue {
1181-
static_glue_fn = sti.visit_glue;
1187+
sti.visit_glue
1188+
} else {
1189+
none
11821190
}
11831191
}
1184-
}
1192+
};
1193+
1194+
// When available, use static type info to give glue the right type.
1195+
let static_glue_fn = match static_ti {
1196+
none => none,
1197+
some(sti) => {
1198+
match static_glue_fn {
1199+
none => none,
1200+
some(sgf) => some(
1201+
PointerCast(bcx, sgf, T_ptr(type_of_glue_fn(ccx, sti.ty))))
1202+
}
1203+
}
1204+
};
11851205

1186-
let llrawptr = PointerCast(cx, v, T_ptr(T_i8()));
1206+
// When static type info is available, avoid casting parameter because the
1207+
// function already has the right type. Otherwise cast to generic pointer.
1208+
let llrawptr = if is_none(static_ti) || is_none(static_glue_fn) {
1209+
PointerCast(bcx, v, T_ptr(T_i8()))
1210+
} else {
1211+
v
1212+
};
11871213

11881214
let llfn = {
11891215
match static_glue_fn {
11901216
none => {
11911217
// Select out the glue function to call from the tydesc
1192-
let llfnptr = GEPi(cx, tydesc, ~[0u, field]);
1193-
Load(cx, llfnptr)
1218+
let llfnptr = GEPi(bcx, tydesc, ~[0u, field]);
1219+
Load(bcx, llfnptr)
11941220
}
11951221
some(sgf) => sgf
11961222
}
11971223
};
11981224

1199-
Call(cx, llfn, ~[C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
1200-
C_null(T_ptr(T_ptr(cx.ccx().tydesc_type))), llrawptr]);
1225+
Call(bcx, llfn, ~[C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
1226+
C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))), llrawptr]);
12011227
}
12021228

12031229
// See [Note-arg-mode]
@@ -1231,6 +1257,7 @@ fn call_cmp_glue(bcx: block, lhs: ValueRef, rhs: ValueRef, t: ty::t,
12311257
}
12321258

12331259
fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1260+
// NB: v is an *alias* of type t here, not a direct value.
12341261
let _icx = cx.insn_ctxt(~"take_ty");
12351262
if ty::type_needs_drop(cx.tcx(), t) {
12361263
return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
@@ -1239,6 +1266,7 @@ fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
12391266
}
12401267

12411268
fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1269+
// NB: v is an *alias* of type t here, not a direct value.
12421270
let _icx = cx.insn_ctxt(~"drop_ty");
12431271
if ty::type_needs_drop(cx.tcx(), t) {
12441272
return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
@@ -1252,7 +1280,7 @@ fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
12521280
ty::ty_uniq(_) |
12531281
ty::ty_evec(_, ty::vstore_uniq) |
12541282
ty::ty_estr(ty::vstore_uniq) => {
1255-
free_ty(bcx, v, t)
1283+
free_ty_immediate(bcx, v, t)
12561284
}
12571285
ty::ty_box(_) | ty::ty_opaque_box |
12581286
ty::ty_evec(_, ty::vstore_box) |
@@ -1284,13 +1312,32 @@ fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result {
12841312
}
12851313

12861314
fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1315+
// NB: v is an *alias* of type t here, not a direct value.
12871316
let _icx = cx.insn_ctxt(~"free_ty");
12881317
if ty::type_needs_drop(cx.tcx(), t) {
12891318
return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
12901319
}
12911320
return cx;
12921321
}
12931322

1323+
fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
1324+
let _icx = bcx.insn_ctxt(~"free_ty_immediate");
1325+
match ty::get(t).struct {
1326+
ty::ty_uniq(_) |
1327+
ty::ty_evec(_, ty::vstore_uniq) |
1328+
ty::ty_estr(ty::vstore_uniq) |
1329+
ty::ty_box(_) | ty::ty_opaque_box |
1330+
ty::ty_evec(_, ty::vstore_box) |
1331+
ty::ty_estr(ty::vstore_box) |
1332+
ty::ty_opaque_closure_ptr(_) => {
1333+
let vp = alloca_zeroed(bcx, type_of(bcx.ccx(), t));
1334+
Store(bcx, v, vp);
1335+
free_ty(bcx, vp, t)
1336+
}
1337+
_ => bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty")
1338+
}
1339+
}
1340+
12941341
fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
12951342
n_bytes: ValueRef) {
12961343
// FIXME (Related to #1645, I think?): Provide LLVM with better

src/rustc/middle/trans/closure.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ fn make_opaque_cbox_drop_glue(
492492
ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
493493
}
494494
ty::ck_uniq => {
495-
free_ty(bcx, Load(bcx, cboxptr),
495+
free_ty(bcx, cboxptr,
496496
ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
497497
}
498498
}
@@ -501,7 +501,7 @@ fn make_opaque_cbox_drop_glue(
501501
fn make_opaque_cbox_free_glue(
502502
bcx: block,
503503
ck: ty::closure_kind,
504-
cbox: ValueRef) // ptr to the opaque closure
504+
cbox: ValueRef) // ptr to ptr to the opaque closure
505505
-> block {
506506
let _icx = bcx.insn_ctxt(~"closure::make_opaque_cbox_free_glue");
507507
match ck {
@@ -513,7 +513,7 @@ fn make_opaque_cbox_free_glue(
513513
do with_cond(bcx, IsNotNull(bcx, cbox)) |bcx| {
514514
// Load the type descr found in the cbox
515515
let lltydescty = T_ptr(ccx.tydesc_type);
516-
let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx));
516+
let cbox = Load(bcx, cbox);
517517
let tydescptr = GEPi(bcx, cbox, ~[0u, abi::box_field_tydesc]);
518518
let tydesc = Load(bcx, tydescptr);
519519
let tydesc = PointerCast(bcx, tydesc, lltydescty);

src/rustc/middle/trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ fn T_tydesc_field(cx: @crate_ctxt, field: uint) -> TypeRef unsafe {
655655
return t;
656656
}
657657

658-
fn T_glue_fn(cx: @crate_ctxt) -> TypeRef {
658+
fn T_generic_glue_fn(cx: @crate_ctxt) -> TypeRef {
659659
let s = ~"glue_fn";
660660
match name_has_type(cx.tn, s) {
661661
some(t) => return t,

src/rustc/middle/trans/tvec.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,13 @@ fn trans_evec(bcx: block, elements: evec_elements,
175175
let ty = ty::mk_evec(bcx.tcx(),
176176
{ty: unit_ty, mutbl: ast::m_mutbl},
177177
ty::vstore_fixed(count));
178+
let llty = T_ptr(type_of::type_of(bcx.ccx(), ty));
178179

179180
let n = C_uint(ccx, count);
180181
let vp = base::arrayalloca(bcx, llunitty, n);
181-
add_clean(bcx, vp, ty);
182+
// Cast to the fake type we told cleanup to expect.
183+
let vp0 = BitCast(bcx, vp, llty);
184+
add_clean(bcx, vp0, ty);
182185

183186
let len = Mul(bcx, n, unit_sz);
184187

0 commit comments

Comments
 (0)