From 6fe59bf8776f8913aacfb00a2281c94a117b95d1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 11 Aug 2013 13:29:14 -0400 Subject: [PATCH] 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. --- src/librustc/back/abi.rs | 3 ++- src/librustc/middle/trans/common.rs | 1 + src/librustc/middle/trans/context.rs | 30 ++++++++++++++++++++++++++++ src/librustc/middle/trans/glue.rs | 27 ++++++++++++++++++++----- src/librustc/middle/trans/type_.rs | 22 +++++++++++++++----- src/librustc/middle/ty.rs | 5 +---- src/libstd/unstable/intrinsics.rs | 20 ++++++++++++++++++- src/rt/rust_type.h | 1 + src/rt/rust_util.cpp | 1 + 9 files changed, 94 insertions(+), 16 deletions(-) diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs index 05b6e90c682..dae0ceed22d 100644 --- a/src/librustc/back/abi.rs +++ b/src/librustc/back/abi.rs @@ -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; diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 40a83eb9770..61ec4b2fedb 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -54,6 +54,7 @@ pub struct tydesc_info { tydesc: ValueRef, size: ValueRef, align: ValueRef, + borrow_offset: ValueRef, take_glue: Option, drop_glue: Option, free_glue: Option, diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index a644174731a..0a69f25c42c 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -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] diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index a70b907f262..c65d8d31b74 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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; diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 110febfcc9f..8d94a0d10d6 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -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 { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5685af2b74e..b91984f9b21 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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_; diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index c60edad3dbd..d2807303fb2 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -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"] diff --git a/src/rt/rust_type.h b/src/rt/rust_type.h index 60ca5674b01..57538f1ec75 100644 --- a/src/rt/rust_type.h +++ b/src/rt/rust_type.h @@ -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*); diff --git a/src/rt/rust_util.cpp b/src/rt/rust_util.cpp index 4a15830e529..28c69af427a 100644 --- a/src/rt/rust_util.cpp +++ b/src/rt/rust_util.cpp @@ -21,6 +21,7 @@ struct type_desc str_body_tydesc = { NULL, // drop_glue NULL, // free_glue NULL, // visit_glue + 0, // borrow_offset }; //