Add a field borrow_offset to the type descriptor indicating

what amount a T* pointer must be adjusted to reach the contents
of the box. For `~T` types, this requires knowing the type `T`,
which is not known in the case of objects.
This commit is contained in:
Niko Matsakis 2013-08-11 13:29:14 -04:00
parent 3aefb9649d
commit 6fe59bf877
9 changed files with 94 additions and 16 deletions

View File

@ -46,7 +46,8 @@ pub static tydesc_field_take_glue: uint = 2u;
pub static tydesc_field_drop_glue: uint = 3u;
pub static tydesc_field_free_glue: uint = 4u;
pub static tydesc_field_visit_glue: uint = 5u;
pub static n_tydesc_fields: uint = 6u;
pub static tydesc_field_borrow_offset: uint = 6u;
pub static n_tydesc_fields: uint = 7u;
// The two halves of a closure: code and environment.
pub static fn_field_code: uint = 0u;

View File

@ -54,6 +54,7 @@ pub struct tydesc_info {
tydesc: ValueRef,
size: ValueRef,
align: ValueRef,
borrow_offset: ValueRef,
take_glue: Option<ValueRef>,
drop_glue: Option<ValueRef>,
free_glue: Option<ValueRef>,

View File

@ -236,6 +236,36 @@ impl CrateContext {
pub fn builder(@mut self) -> Builder {
Builder::new(self)
}
pub fn const_inbounds_gepi(&self,
pointer: ValueRef,
indices: &[uint]) -> ValueRef {
debug!("const_inbounds_gepi: pointer=%s indices=%?",
self.tn.val_to_str(pointer), indices);
let v: ~[ValueRef] =
indices.iter().transform(|i| C_i32(*i as i32)).collect();
unsafe {
llvm::LLVMConstInBoundsGEP(pointer,
vec::raw::to_ptr(v),
indices.len() as c_uint)
}
}
pub fn offsetof_gep(&self,
llptr_ty: Type,
indices: &[uint]) -> ValueRef {
/*!
* Returns the offset of applying the given GEP indices
* to an instance of `llptr_ty`. Similar to `offsetof` in C,
* except that `llptr_ty` must be a pointer type.
*/
unsafe {
let null = C_null(llptr_ty);
llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
self.int_type.to_ref())
}
}
}
#[unsafe_destructor]

View File

@ -655,6 +655,18 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
ppaux::ty_to_str(ccx.tcx, t));
}
let has_header = match ty::get(t).sty {
ty::ty_box(*) => true,
ty::ty_uniq(*) => ty::type_contents(ccx.tcx, t).contains_managed(),
_ => false
};
let borrow_offset = if has_header {
ccx.offsetof_gep(llty, [0u, abi::box_field_body])
} else {
C_uint(ccx, 0)
};
let llsize = llsize_of(ccx, llty);
let llalign = llalign_of(ccx, llty);
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed();
@ -670,6 +682,7 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
tydesc: gvar,
size: llsize,
align: llalign,
borrow_offset: borrow_offset,
take_glue: None,
drop_glue: None,
free_glue: None,
@ -785,13 +798,17 @@ pub fn emit_tydescs(ccx: &mut CrateContext) {
}
};
debug!("ti.borrow_offset: %s",
ccx.tn.val_to_str(ti.borrow_offset));
let tydesc = C_named_struct(ccx.tydesc_type,
[ti.size, // size
ti.align, // align
take_glue, // take_glue
drop_glue, // drop_glue
free_glue, // free_glue
visit_glue]); // visit_glue
ti.align, // align
take_glue, // take_glue
drop_glue, // drop_glue
free_glue, // free_glue
visit_glue, // visit_glue
ti.borrow_offset]); // borrow_offset
unsafe {
let gvar = ti.tydesc;

View File

@ -205,10 +205,18 @@ impl Type {
let int_ty = Type::int(arch);
let elems = [
int_ty, int_ty,
glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty
];
// Must mirror:
//
// std::unstable::intrinsics::TyDesc
// type_desc in rt
let elems = [int_ty, // size
int_ty, // align
glue_fn_ty, // take
glue_fn_ty, // drop
glue_fn_ty, // free
glue_fn_ty, // visit
int_ty]; // borrow_offset
tydesc.set_struct_body(elems, false);
@ -249,8 +257,12 @@ impl Type {
Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
}
pub fn opaque() -> Type {
Type::i8()
}
pub fn opaque_box(ctx: &CrateContext) -> Type {
Type::box(ctx, &Type::i8())
Type::box(ctx, &Type::opaque())
}
pub fn unique(ctx: &CrateContext, ty: &Type) -> Type {

View File

@ -226,10 +226,7 @@ pub enum AutoRef {
AutoBorrowFn(Region),
/// Convert from T to *T
AutoUnsafe(ast::mutability),
/// Convert from @Trait/~Trait/&Trait to &Trait
AutoBorrowObj(Region, ast::mutability),
AutoUnsafe(ast::mutability)
}
pub type ctxt = @ctxt_;

View File

@ -38,16 +38,34 @@ pub use realstd::unstable::intrinsics::{TyDesc, Opaque, TyVisitor};
pub type GlueFn = extern "Rust" fn(*i8);
// NB: this has to be kept in sync with the Rust ABI.
// NB: this has to be kept in sync with `type_desc` in `rt`
#[lang="ty_desc"]
#[cfg(not(test))]
pub struct TyDesc {
// sizeof(T)
size: uint,
// alignof(T)
align: uint,
// Called on a copy of a value of type `T` *after* memcpy
take_glue: GlueFn,
// Called when a value of type `T` is no longer needed
drop_glue: GlueFn,
// Called by drop glue when a value of type `T` can be freed
free_glue: GlueFn,
// Called by reflection visitor to visit a value of type `T`
visit_glue: GlueFn,
// If T represents a box pointer (`@U` or `~U`), then
// `borrow_offset` is the amount that the pointer must be adjusted
// to find the payload. This is always derivable from the type
// `U`, but in the case of `@Trait` or `~Trait` objects, the type
// `U` is unknown.
borrow_offset: uint,
}
#[lang="opaque"]

View File

@ -58,6 +58,7 @@ struct type_desc {
glue_fn *drop_glue;
glue_fn *free_glue;
glue_fn *visit_glue;
size_t borrow_offset;
};
extern "C" type_desc *rust_clone_type_desc(type_desc*);

View File

@ -21,6 +21,7 @@ struct type_desc str_body_tydesc = {
NULL, // drop_glue
NULL, // free_glue
NULL, // visit_glue
0, // borrow_offset
};
//