Skip to content

Commit 0284f94

Browse files
Elliott Slaughterbrson
Elliott Slaughter
authored andcommitted
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 0284f94

File tree

5 files changed

+112
-58
lines changed

5 files changed

+112
-58
lines changed

src/rustc/middle/trans/base.rs

+96-53
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
}
@@ -587,22 +587,34 @@ fn emit_tydescs(ccx: @crate_ctxt) {
587587
let take_glue =
588588
match copy ti.take_glue {
589589
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
590-
some(v) => { ccx.stats.n_real_glues += 1u; v }
590+
some(v) => {
591+
ccx.stats.n_real_glues += 1u;
592+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
593+
}
591594
};
592595
let drop_glue =
593596
match copy ti.drop_glue {
594597
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
595-
some(v) => { ccx.stats.n_real_glues += 1u; v }
598+
some(v) => {
599+
ccx.stats.n_real_glues += 1u;
600+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
601+
}
596602
};
597603
let free_glue =
598604
match copy ti.free_glue {
599605
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
600-
some(v) => { ccx.stats.n_real_glues += 1u; v }
606+
some(v) => {
607+
ccx.stats.n_real_glues += 1u;
608+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
609+
}
601610
};
602611
let visit_glue =
603612
match copy ti.visit_glue {
604613
none => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
605-
some(v) => { ccx.stats.n_real_glues += 1u; v }
614+
some(v) => {
615+
ccx.stats.n_real_glues += 1u;
616+
llvm::LLVMConstPointerCast(v, glue_fn_ty)
617+
}
606618
};
607619

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

693705

694706
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).
707+
// NB: v0 is an *alias* of type t here, not a direct value.
698708
let _icx = bcx.insn_ctxt(~"make_free_glue");
699709
let ccx = bcx.ccx();
700710
let bcx = match ty::get(t).struct {
701711
ty::ty_box(body_mt) => {
702-
let v = PointerCast(bcx, v, type_of(ccx, t));
712+
let v = Load(bcx, v);
703713
let body = GEPi(bcx, v, ~[0u, abi::box_field_body]);
714+
// Cast away the addrspace of the box pointer.
715+
let body = PointerCast(bcx, body, T_ptr(type_of(ccx, body_mt.ty)));
704716
let bcx = drop_ty(bcx, body, body_mt.ty);
705717
trans_free(bcx, v)
706718
}
707719
ty::ty_opaque_box => {
708-
let v = PointerCast(bcx, v, type_of(ccx, t));
720+
let v = Load(bcx, v);
709721
let td = Load(bcx, GEPi(bcx, v, ~[0u, abi::box_field_tydesc]));
710722
let valptr = GEPi(bcx, v, ~[0u, abi::box_field_body]);
711723
// Generate code that, dynamically, indexes into the
@@ -715,7 +727,6 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
715727
trans_free(bcx, v)
716728
}
717729
ty::ty_uniq(content_mt) => {
718-
let v = PointerCast(bcx, v, type_of(ccx, t));
719730
uniq::make_free_glue(bcx, v, t)
720731
}
721732
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
@@ -785,7 +796,7 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
785796
}
786797
ty::ty_uniq(_) |
787798
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
788-
free_ty(bcx, Load(bcx, v0), t)
799+
free_ty(bcx, v0, t)
789800
}
790801
ty::ty_unboxed_vec(_) => {
791802
tvec::make_drop_glue_unboxed(bcx, v0, t)
@@ -861,14 +872,12 @@ fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t) -> block {
861872
let ccx = bcx.ccx();
862873
maybe_validate_box(bcx, box_ptr);
863874

864-
let llbox_ty = T_opaque_box_ptr(ccx);
865-
let box_ptr = PointerCast(bcx, box_ptr, llbox_ty);
866875
do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
867876
let rc_ptr = GEPi(bcx, box_ptr, ~[0u, abi::box_field_refcnt]);
868877
let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
869878
Store(bcx, rc, rc_ptr);
870879
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))
880+
with_cond(bcx, zero_test, |bcx| free_ty_immediate(bcx, box_ptr, t))
872881
}
873882
}
874883

@@ -1097,17 +1106,16 @@ fn lazily_emit_all_tydesc_glue(ccx: @crate_ctxt,
10971106
fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
10981107
ti: @tydesc_info) {
10991108
let _icx = ccx.insn_ctxt(~"lazily_emit_tydesc_glue");
1109+
let llfnty = type_of_glue_fn(ccx, ti.ty);
11001110
if field == abi::tydesc_field_take_glue {
11011111
match ti.take_glue {
11021112
some(_) => (),
11031113
none => {
11041114
debug!{"+++ lazily_emit_tydesc_glue TAKE %s",
11051115
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1106-
let glue_fn = declare_generic_glue
1107-
(ccx, ti.ty, T_glue_fn(ccx), ~"take");
1116+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"take");
11081117
ti.take_glue = some(glue_fn);
1109-
make_generic_glue(ccx, ti.ty, glue_fn,
1110-
make_take_glue, ~"take");
1118+
make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, ~"take");
11111119
debug!{"--- lazily_emit_tydesc_glue TAKE %s",
11121120
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11131121
}
@@ -1118,11 +1126,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11181126
none => {
11191127
debug!{"+++ lazily_emit_tydesc_glue DROP %s",
11201128
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1121-
let glue_fn =
1122-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"drop");
1129+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"drop");
11231130
ti.drop_glue = some(glue_fn);
1124-
make_generic_glue(ccx, ti.ty, glue_fn,
1125-
make_drop_glue, ~"drop");
1131+
make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, ~"drop");
11261132
debug!{"--- lazily_emit_tydesc_glue DROP %s",
11271133
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11281134
}
@@ -1133,11 +1139,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11331139
none => {
11341140
debug!{"+++ lazily_emit_tydesc_glue FREE %s",
11351141
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1136-
let glue_fn =
1137-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"free");
1142+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"free");
11381143
ti.free_glue = some(glue_fn);
1139-
make_generic_glue(ccx, ti.ty, glue_fn,
1140-
make_free_glue, ~"free");
1144+
make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, ~"free");
11411145
debug!{"--- lazily_emit_tydesc_glue FREE %s",
11421146
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11431147
}
@@ -1148,11 +1152,9 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11481152
none => {
11491153
debug!{"+++ lazily_emit_tydesc_glue VISIT %s",
11501154
ppaux::ty_to_str(ccx.tcx, ti.ty)};
1151-
let glue_fn =
1152-
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), ~"visit");
1155+
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"visit");
11531156
ti.visit_glue = some(glue_fn);
1154-
make_generic_glue(ccx, ti.ty, glue_fn,
1155-
make_visit_glue, ~"visit");
1157+
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, ~"visit");
11561158
debug!{"--- lazily_emit_tydesc_glue VISIT %s",
11571159
ppaux::ty_to_str(ccx.tcx, ti.ty)};
11581160
}
@@ -1161,43 +1163,63 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
11611163
}
11621164

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

1169-
let mut static_glue_fn = none;
1170-
match static_ti {
1171-
none => {/* no-op */ }
1172+
let static_glue_fn = match static_ti {
1173+
none => none,
11721174
some(sti) => {
1173-
lazily_emit_tydesc_glue(cx.ccx(), field, sti);
1175+
lazily_emit_tydesc_glue(ccx, field, sti);
11741176
if field == abi::tydesc_field_take_glue {
1175-
static_glue_fn = sti.take_glue;
1177+
sti.take_glue
11761178
} else if field == abi::tydesc_field_drop_glue {
1177-
static_glue_fn = sti.drop_glue;
1179+
sti.drop_glue
11781180
} else if field == abi::tydesc_field_free_glue {
1179-
static_glue_fn = sti.free_glue;
1181+
sti.free_glue
11801182
} else if field == abi::tydesc_field_visit_glue {
1181-
static_glue_fn = sti.visit_glue;
1183+
sti.visit_glue
1184+
} else {
1185+
none
11821186
}
11831187
}
1184-
}
1188+
};
1189+
1190+
// When available, use static type info to give glue the right type.
1191+
let static_glue_fn = match static_ti {
1192+
none => none,
1193+
some(sti) => {
1194+
match static_glue_fn {
1195+
none => none,
1196+
some(sgf) => some(
1197+
PointerCast(bcx, sgf, T_ptr(type_of_glue_fn(ccx, sti.ty))))
1198+
}
1199+
}
1200+
};
11851201

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

11881210
let llfn = {
11891211
match static_glue_fn {
11901212
none => {
11911213
// Select out the glue function to call from the tydesc
1192-
let llfnptr = GEPi(cx, tydesc, ~[0u, field]);
1193-
Load(cx, llfnptr)
1214+
let llfnptr = GEPi(bcx, tydesc, ~[0u, field]);
1215+
Load(bcx, llfnptr)
11941216
}
11951217
some(sgf) => sgf
11961218
}
11971219
};
11981220

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]);
1221+
Call(bcx, llfn, ~[C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
1222+
C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))), llrawptr]);
12011223
}
12021224

12031225
// See [Note-arg-mode]
@@ -1231,6 +1253,7 @@ fn call_cmp_glue(bcx: block, lhs: ValueRef, rhs: ValueRef, t: ty::t,
12311253
}
12321254

12331255
fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1256+
// NB: v is an *alias* of type t here, not a direct value.
12341257
let _icx = cx.insn_ctxt(~"take_ty");
12351258
if ty::type_needs_drop(cx.tcx(), t) {
12361259
return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
@@ -1239,6 +1262,7 @@ fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
12391262
}
12401263

12411264
fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1265+
// NB: v is an *alias* of type t here, not a direct value.
12421266
let _icx = cx.insn_ctxt(~"drop_ty");
12431267
if ty::type_needs_drop(cx.tcx(), t) {
12441268
return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
@@ -1252,7 +1276,7 @@ fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
12521276
ty::ty_uniq(_) |
12531277
ty::ty_evec(_, ty::vstore_uniq) |
12541278
ty::ty_estr(ty::vstore_uniq) => {
1255-
free_ty(bcx, v, t)
1279+
free_ty_immediate(bcx, v, t)
12561280
}
12571281
ty::ty_box(_) | ty::ty_opaque_box |
12581282
ty::ty_evec(_, ty::vstore_box) |
@@ -1284,13 +1308,32 @@ fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result {
12841308
}
12851309

12861310
fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
1311+
// NB: v is an *alias* of type t here, not a direct value.
12871312
let _icx = cx.insn_ctxt(~"free_ty");
12881313
if ty::type_needs_drop(cx.tcx(), t) {
12891314
return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
12901315
}
12911316
return cx;
12921317
}
12931318

1319+
fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
1320+
let _icx = bcx.insn_ctxt(~"free_ty_immediate");
1321+
match ty::get(t).struct {
1322+
ty::ty_uniq(_) |
1323+
ty::ty_evec(_, ty::vstore_uniq) |
1324+
ty::ty_estr(ty::vstore_uniq) |
1325+
ty::ty_box(_) | ty::ty_opaque_box |
1326+
ty::ty_evec(_, ty::vstore_box) |
1327+
ty::ty_estr(ty::vstore_box) |
1328+
ty::ty_opaque_closure_ptr(_) => {
1329+
let vp = alloca_zeroed(bcx, type_of(bcx.ccx(), t));
1330+
Store(bcx, v, vp);
1331+
free_ty(bcx, vp, t)
1332+
}
1333+
_ => bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty")
1334+
}
1335+
}
1336+
12941337
fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
12951338
n_bytes: ValueRef) {
12961339
// 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/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

src/rustc/middle/trans/type_of.rs

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type_of_dtor;
1010
export type_of_explicit_args;
1111
export type_of_fn_from_ty;
1212
export type_of_fn;
13+
export type_of_glue_fn;
1314
export type_of_non_gc_box;
1415

1516
fn type_of_explicit_args(cx: @crate_ctxt,
@@ -244,3 +245,9 @@ fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
244245
llvm::LLVMVoidType())
245246
}
246247

248+
fn type_of_glue_fn(ccx: @crate_ctxt, t: ty::t) -> TypeRef {
249+
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
250+
let llty = T_ptr(type_of(ccx, t));
251+
return T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty],
252+
T_void());
253+
}

src/rustc/middle/trans/uniq.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import shape::llsize_of;
77

88
export make_free_glue, autoderef, duplicate;
99

10-
fn make_free_glue(bcx: block, vptr: ValueRef, t: ty::t)
10+
fn make_free_glue(bcx: block, vptrptr: ValueRef, t: ty::t)
1111
-> block {
1212
let _icx = bcx.insn_ctxt(~"uniq::make_free_glue");
13+
let vptr = Load(bcx, vptrptr);
1314
do with_cond(bcx, IsNotNull(bcx, vptr)) |bcx| {
1415
let content_ty = content_ty(t);
1516
let body_ptr = opaque_box_body(bcx, content_ty, vptr);

0 commit comments

Comments
 (0)