From 34d607f9c9e3c103fc7f98b4c6fa18ff71905bb6 Mon Sep 17 00:00:00 2001 From: Nick Cameron <ncameron@mozilla.com> Date: Fri, 25 Apr 2014 15:14:52 +1200 Subject: [PATCH] Use the slice repr for ~[T] --- src/libcollections/slice.rs | 60 ++++++++ src/libcore/mem.rs | 2 +- src/librustc/middle/trans/adt.rs | 4 +- src/librustc/middle/trans/base.rs | 19 ++- src/librustc/middle/trans/debuginfo.rs | 81 +---------- src/librustc/middle/trans/expr.rs | 12 +- src/librustc/middle/trans/glue.rs | 22 +-- src/librustc/middle/trans/reflect.rs | 13 +- src/librustc/middle/trans/tvec.rs | 185 ++++++++++--------------- src/librustc/middle/trans/type_.rs | 2 +- src/librustc/middle/trans/type_of.rs | 23 +-- src/librustc/middle/ty.rs | 3 +- src/librustc_back/abi.rs | 6 - src/libserialize/serialize.rs | 1 + src/libtime/lib.rs | 36 ++++- src/rt/rust_builtin.c | 42 +++++- 16 files changed, 247 insertions(+), 264 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index c137cc25b25..bd8e18d1f3c 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -92,6 +92,8 @@ use core::iter::{range_step, MultiplicativeIterator}; use MutableSeq; use vec::Vec; +#[cfg(not(stage0))] +use raw::Slice; pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice}; pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems}; @@ -282,6 +284,64 @@ pub trait CloneableVector<T> { impl<'a, T: Clone> CloneableVector<T> for &'a [T] { /// Returns a copy of `v`. + #[cfg(not(stage0))] + fn to_owned(&self) -> ~[T] { + use num::CheckedMul; + use option::Expect; + + let len = self.len(); + + if len == 0 { + unsafe { + let slice: Slice<T> = Slice{data: 0 as *T, len: 0}; + mem::transmute(slice) + } + } else { + let unit_size = mem::size_of::<T>(); + let data_size = if unit_size == 0 { + len + } else { + let data_size = len.checked_mul(&unit_size); + data_size.expect("overflow in from_iter()") + }; + + unsafe { + // this should pass the real required alignment + let ret = allocate(data_size, 8) as *mut T; + + if unit_size > 0 { + // Be careful with the following loop. We want it to be optimized + // to a memcpy (or something similarly fast) when T is Copy. LLVM + // is easily confused, so any extra operations during the loop can + // prevent this optimization. + let mut i = 0; + let p = &mut (*ret) as *mut _ as *mut T; + try_finally( + &mut i, (), + |i, ()| while *i < len { + mem::move_val_init( + &mut(*p.offset(*i as int)), + self.unsafe_ref(*i).clone()); + *i += 1; + }, + |i| if *i < len { + // we must be failing, clean up after ourselves + for j in range(0, *i as int) { + ptr::read(&*p.offset(j)); + } + // FIXME: #13994 (should pass align and size here) + deallocate(ret as *mut u8, 0, 8); + }); + } + let slice: Slice<T> = Slice{data: ret as *T, len: len}; + mem::transmute(slice) + } + } + } + + /// Returns a copy of `v`. + // NOTE: remove after snapshot + #[cfg(stage0)] #[inline] fn to_vec(&self) -> Vec<T> { Vec::from_slice(*self) } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 4de81db1013..f0c39766ebb 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -174,7 +174,7 @@ pub unsafe fn overwrite<T>(dst: *mut T, src: T) { /// Deprecated, use `overwrite` instead #[inline] -#[deprecated = "use ptr::write"] +#[deprecated = "this function has been renamed to overwrite()"] pub unsafe fn move_val_init<T>(dst: &mut T, src: T) { ptr::write(dst, src) } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index bf8caef2e97..57f8f8d6692 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -305,8 +305,7 @@ impl Case { // Box<T> could either be a thin or fat pointer depending on T ty::ty_uniq(t) => match ty::get(t).sty { - // Box<[T]>/Box<str> might be FatPointer in a post DST world - ty::ty_vec(_, None) | ty::ty_str => continue, + ty::ty_vec(_, None) | return Some(FatPointer(i, slice_elt_base)), // Box<Trait> is a pair of pointers: the actual object and a vtable ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)), @@ -326,7 +325,6 @@ impl Case { // Anything else is not a pointer _ => continue - } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 043636a32c0..7c2f251bd16 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -195,6 +195,16 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::NoReturnAttribute as uint64_t) } } + // `~` pointer return values never alias because ownership is transferred + ty::ty_uniq(t) + => match ty::get(t).sty { + ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {} + _ => unsafe { + llvm::LLVMAddReturnAttribute(llfn, + lib::llvm::NoAliasAttribute as c_uint, + lib::llvm::NoReturnAttribute as uint64_t); + } + }, _ => {} } @@ -364,20 +374,19 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId { // a given type, but with a potentially dynamic size. pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>, - ptr_ty: ty::t, + llty_ptr: Type, + info_ty: ty::t, size: ValueRef, align: ValueRef) -> Result<'a> { let _icx = push_ctxt("malloc_raw_exchange"); - let ccx = bcx.ccx(); // Allocate space: let r = callee::trans_lang_call(bcx, - require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem), + require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem), [size, align], None); - let llty_ptr = type_of::type_of(ccx, ptr_ty); Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } @@ -731,8 +740,8 @@ pub fn iter_structural_ty<'r, } } ty::ty_vec(_, Some(n)) => { + let (base, len) = tvec::get_fixed_base_and_len(cx, av, n); let unit_ty = ty::sequence_element_type(cx.tcx(), t); - let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n); cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); } ty::ty_tup(ref args) => { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 88bdb00a7c9..db674b4028f 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2718,81 +2718,6 @@ fn fixed_vec_metadata(cx: &CrateContext, return MetadataCreationResult::new(metadata, false); } -fn heap_vec_metadata(cx: &CrateContext, - vec_pointer_type: ty::t, - element_type: ty::t, - unique_type_id: UniqueTypeId, - span: Span) - -> MetadataCreationResult { - let element_type_metadata = type_metadata(cx, element_type, span); - let element_llvm_type = type_of::type_of(cx, element_type); - let (element_size, element_align) = size_and_align_of(cx, element_llvm_type); - - return_if_metadata_created_in_meantime!(cx, unique_type_id); - - let vecbox_llvm_type = Type::vec(cx, &element_llvm_type); - let vec_pointer_type_name = compute_debuginfo_type_name(cx, - vec_pointer_type, - true); - let vec_pointer_type_name = vec_pointer_type_name.as_slice(); - - let member_llvm_types = vecbox_llvm_type.field_types(); - - let int_type_metadata = type_metadata(cx, ty::mk_int(), span); - let array_type_metadata = unsafe { - llvm::LLVMDIBuilderCreateArrayType( - DIB(cx), - bytes_to_bits(element_size), - bytes_to_bits(element_align), - element_type_metadata, - create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)])) - }; - - let member_descriptions = [ - MemberDescription { - name: "fill".to_string(), - llvm_type: *member_llvm_types.get(0), - type_metadata: int_type_metadata, - offset: ComputedMemberOffset, - }, - MemberDescription { - name: "alloc".to_string(), - llvm_type: *member_llvm_types.get(1), - type_metadata: int_type_metadata, - offset: ComputedMemberOffset, - }, - MemberDescription { - name: "elements".to_string(), - llvm_type: *member_llvm_types.get(2), - type_metadata: array_type_metadata, - offset: ComputedMemberOffset, - } - ]; - - assert!(member_descriptions.len() == member_llvm_types.len()); - - let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, loc.file.name.as_slice()); - - let vec_box_unique_id = debug_context(cx).type_map - .borrow_mut() - .get_unique_type_id_of_heap_vec_box(cx, - element_type); - - let vecbox_metadata = composite_type_metadata(cx, - vecbox_llvm_type, - vec_pointer_type_name, - vec_box_unique_id, - member_descriptions, - UNKNOWN_SCOPE_METADATA, - file_metadata, - span); - - MetadataCreationResult::new(pointer_type_metadata(cx, - vec_pointer_type, - vecbox_metadata), false) -} - fn vec_slice_metadata(cx: &CrateContext, vec_type: ty::t, element_type: ty::t, @@ -2995,11 +2920,13 @@ fn type_metadata(cx: &CrateContext, ty::ty_uniq(pointee_type) => { match ty::get(pointee_type).sty { ty::ty_vec(ref mt, None) => { - heap_vec_metadata(cx, pointee_type, mt.ty, unique_type_id, usage_site_span) + let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span); + pointer_type_metadata(cx, t, vec_metadata) } ty::ty_str => { let i8_t = ty::mk_i8(); - heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span) + let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span); + pointer_type_metadata(cx, t, vec_metadata) } ty::ty_trait(..) => { MetadataCreationResult::new( diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 748274b1201..ead90dbe36b 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -395,8 +395,8 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, ast::ExprField(ref base, ident, _) => { trans_rec_field(bcx, &**base, ident.node) } - ast::ExprIndex(ref base, ref idx) => { - trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) + ast::ExprIndex(base, idx) => { + trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id)) } ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => { fcx.push_ast_cleanup_scope(contents.id); @@ -465,7 +465,7 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, } fn trans_index<'a>(bcx: &'a Block<'a>, - index_expr: &ast::Expr, + sp: codemap::Span, base: &ast::Expr, idx: &ast::Expr, method_call: MethodCall) @@ -1256,10 +1256,8 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>, let llty = type_of::type_of(bcx.ccx(), contents_ty); let size = llsize_of(bcx.ccx(), llty); let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint); - // We need to a make a pointer type because box_ty is ty_bot - // if content_ty is, e.g. box fail!(). - let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty); - let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align); + let llty_ptr = llty.ptr_to(); + let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align); // Unique boxes do not allocate for zero-size types. The standard library // may assume that `free` is never called on the pointer returned for // `Box<ZeroSizeType>`. diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 570f4d37042..8faf27d1aa4 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -51,7 +51,7 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> { Some(expr::Ignore)).bcx } -fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, +pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, align: u64) -> &'a Block<'a> { let _icx = push_ctxt("trans_exchange_free"); let ccx = cx.ccx(); @@ -120,8 +120,8 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) -> &'a Block<'a> { // NB: v is an *alias* of type t here, not a direct value. let _icx = push_ctxt("drop_ty"); - let ccx = bcx.ccx(); if ty::type_needs_drop(bcx.tcx(), t) { + let ccx = bcx.ccx(); let glue = get_drop_glue(ccx, t); let glue_type = get_drop_glue_type(ccx, t); let ptr = if glue_type != t { @@ -277,23 +277,11 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' ty::ty_uniq(content_ty) => { match ty::get(content_ty).sty { ty::ty_vec(mt, None) => { - let llbox = Load(bcx, v0); - let not_null = IsNotNull(bcx, llbox); - with_cond(bcx, not_null, |bcx| { - let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty); - // FIXME: #13994: the old `Box<[T]>` will not support sized deallocation - trans_exchange_free(bcx, llbox, 0, 8) - }) + tvec::make_drop_glue_unboxed(bcx, v0, mt.ty) } ty::ty_str => { - let llbox = Load(bcx, v0); - let not_null = IsNotNull(bcx, llbox); - with_cond(bcx, not_null, |bcx| { - let unit_ty = ty::sequence_element_type(bcx.tcx(), t); - let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty); - // FIXME: #13994: the old `Box<str>` will not support sized deallocation - trans_exchange_free(bcx, llbox, 0, 8) - }) + let unit_ty = ty::sequence_element_type(bcx.tcx(), t); + tvec::make_drop_glue_unboxed(bcx, v0, unit_ty) } ty::ty_trait(..) => { let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 2aff12c2b68..fcc1b827876 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -164,6 +164,10 @@ impl<'a, 'b> Reflector<'a, 'b> { }); self.visit("box", extra.as_slice()) } + ty::ty_ptr(ref mt) => { + let extra = self.c_mt(mt); + self.visit("ptr", extra.as_slice()) + } ty::ty_uniq(typ) => { match ty::get(typ).sty { ty::ty_vec(ref mt, None) => { @@ -188,17 +192,12 @@ impl<'a, 'b> Reflector<'a, 'b> { } } } - ty::ty_ptr(ref mt) => { - let extra = self.c_mt(mt); - self.visit("ptr", extra.as_slice()) - } ty::ty_rptr(_, ref mt) => { match ty::get(mt.ty).sty { ty::ty_vec(ref mt, None) => { - let (name, extra) = ("slice".to_string(), Vec::new()); + let extra = Vec::new(); let extra = extra.append(self.c_mt(mt).as_slice()); - self.visit(format!("evec_{}", name).as_slice(), - extra.as_slice()) + self.visit("evec_slice", extra.as_slice()) } ty::ty_str => self.visit("estr_slice", &[]), ty::ty_trait(..) => { diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 1241a85e95c..7b8537b15c5 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -17,7 +17,6 @@ use middle::lang_items::StrDupUniqFnLangItem; use middle::trans::base::*; use middle::trans::base; use middle::trans::build::*; -use middle::trans::callee; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; use middle::trans::common::*; @@ -25,7 +24,7 @@ use middle::trans::datum::*; use middle::trans::expr::{Dest, Ignore, SaveIn}; use middle::trans::expr; use middle::trans::glue; -use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc}; +use middle::trans::machine::{nonzero_llsize_of, llsize_of_alloc}; use middle::trans::type_::Type; use middle::trans::type_of; use middle::ty; @@ -34,14 +33,14 @@ use util::ppaux::ty_to_string; use syntax::ast; use syntax::parse::token::InternedString; -pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef { - let _icx = push_ctxt("tvec::get_fill"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill])) +fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef { + let _icx = push_ctxt("tvec::get_lenl"); + Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len])) } -pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { +fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_dataptr"); - GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u]) + Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base])) } pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { @@ -56,13 +55,21 @@ pub fn make_drop_glue_unboxed<'a>( vptr: ValueRef, unit_ty: ty::t) -> &'a Block<'a> { - let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); - let tcx = bcx.tcx(); - if ty::type_needs_drop(tcx, unit_ty) { - let fill = get_fill(bcx, vptr); + let not_null = IsNotNull(bcx, vptr); + with_cond(bcx, not_null, |bcx| { + let tcx = bcx.tcx(); + let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); + + let len = get_len(bcx, vptr); let dataptr = get_dataptr(bcx, vptr); - iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty) - } else { bcx } + let bcx = if ty::type_needs_drop(tcx, unit_ty) { + iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty) + } else { + bcx + }; + + glue::trans_exchange_free(bcx, dataptr, 0, 8) + }) } pub struct VecTypes { @@ -112,12 +119,11 @@ pub fn trans_fixed_vstore<'a>( }; } -pub fn trans_slice_vstore<'a>( - bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, - dest: expr::Dest) - -> &'a Block<'a> { +pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, + vstore_expr: &ast::Expr, + content_expr: &ast::Expr, + dest: expr::Dest) + -> &'a Block<'a> { /*! * &[...] allocates memory on the stack and writes the values into it, * returning a slice (pair of ptr, len). &"..." is similar except that @@ -150,17 +156,16 @@ pub fn trans_slice_vstore<'a>( // Handle the &[...] case: let vt = vec_types_from_expr(bcx, vstore_expr); let count = elements_required(bcx, content_expr); - debug!("vt={}, count={:?}", vt.to_string(ccx), count); - + debug!(" vt={}, count={:?}", vt.to_str(ccx), count); let llcount = C_uint(ccx, count); - let llfixed; - if count == 0 { + + let llfixed = if count == 0 { // Just create a zero-sized alloca to preserve // the non-null invariant of the inner slice ptr - llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); + base::arrayalloca(bcx, vt.llunit_ty, llcount) } else { // Make a fixed-length backing array and allocate it on the stack. - llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); + let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); // Arrange for the backing array to be cleaned up. let fixed_ty = ty::mk_vec(bcx.tcx(), @@ -176,7 +181,9 @@ pub fn trans_slice_vstore<'a>( // Generate the content into the backing array. bcx = write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(llfixed)); - } + + llfixed + }; // Finally, create the slice pair itself. match dest { @@ -198,7 +205,7 @@ pub fn trans_lit_str<'a>( -> &'a Block<'a> { /*! * Literal strings translate to slices into static memory. This is - * different from trans_slice_vstore() above because it does need to copy + * different from trans_slice_vstore() above because it doesn't need to copy * the content anywhere. */ @@ -214,17 +221,14 @@ pub fn trans_lit_str<'a>( let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), str_lit, false); let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref()); - Store(bcx, llcstr, - GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - Store(bcx, llbytes, - GEPi(bcx, lldest, [0u, abi::slice_elt_len])); + Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); + Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); bcx } } } } - pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, vstore_expr: &ast::Expr, content_expr: &ast::Expr) @@ -238,74 +242,47 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, let fcx = bcx.fcx; let ccx = fcx.ccx; - // Handle "".to_string(). - match content_expr.node { - ast::ExprLit(lit) => { - match lit.node { - ast::LitStr(ref s, _) => { - let llptrval = C_cstr(ccx, (*s).clone(), false); - let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx)); - let llsizeval = C_uint(ccx, s.get().len()); - let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx())); - let lldestval = rvalue_scratch_datum(bcx, - typ, - ""); - let alloc_fn = langcall(bcx, - Some(lit.span), - "", - StrDupUniqFnLangItem); - let bcx = callee::trans_lang_call( - bcx, - alloc_fn, - [ llptrval, llsizeval ], - Some(expr::SaveIn(lldestval.val))).bcx; - return DatumBlock::new(bcx, lldestval).to_expr_datumblock(); - } - _ => {} - } - } - _ => {} - } - - let vec_ty = node_id_type(bcx, vstore_expr.id); - let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); + let vt = vec_types_from_expr(bcx, vstore_expr); let count = elements_required(bcx, content_expr); + debug!(" vt={}, count={:?}", vt.to_str(ccx), count); + let llcount = C_uint(ccx, count); + let vec_ty = node_id_type(bcx, vstore_expr.id); - let llunitty = type_of::type_of(ccx, vt.unit_ty); - let unit_sz = nonzero_llsize_of(ccx, llunitty); - + let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty)); let fill = Mul(bcx, C_uint(ccx, count), unit_sz); - let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) } - else { fill }; - - let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type)); - - // ~[T] is not going to be changed to support alignment, since it's obsolete. + let alloc = if count < 4u { + Mul(bcx, C_int(ccx, 4), unit_sz) + } else { + fill + }; + let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to(); let align = C_uint(ccx, 8); - let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align); - Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill])); - Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc])); + let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx, + llty_ptr, + vec_ty, + alloc, + align); // Create a temporary scope lest execution should fail while // constructing the vector. let temp_scope = fcx.push_custom_cleanup_scope(); - - // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder - let content_ty = vt.unit_ty; + // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, + // this is a placeholder fcx.schedule_free_value(cleanup::CustomScope(temp_scope), - val, cleanup::HeapExchange, content_ty); + dataptr, cleanup::HeapExchange, vt.unit_ty); - let dataptr = get_dataptr(bcx, val); + debug!(" alloc_uniq_vec() returned dataptr={}, len={}", + bcx.val_to_str(dataptr), count); - debug!("alloc_uniq_vec() returned val={}, dataptr={}", - bcx.val_to_string(val), bcx.val_to_string(dataptr)); - - let bcx = write_content(bcx, &vt, vstore_expr, - content_expr, SaveIn(dataptr)); + let bcx = write_content(bcx, &vt, vstore_expr, + content_expr, SaveIn(dataptr)); fcx.pop_custom_cleanup_scope(temp_scope); - immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock() + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); + Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + DatumBlock(bcx, scratch.to_expr_datum()) } pub fn write_content<'a>( @@ -451,21 +428,19 @@ pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint { } } -pub fn get_fixed_base_and_byte_len(bcx: &Block, - llval: ValueRef, - unit_ty: ty::t, - vec_length: uint) - -> (ValueRef, ValueRef) { +pub fn get_fixed_base_and_len(bcx: &Block, + llval: ValueRef, + vec_length: uint) + -> (ValueRef, ValueRef) { /*! * Converts a fixed-length vector into the slice pair. * The vector should be stored in `llval` which should be by ref. */ let ccx = bcx.ccx(); - let vt = vec_types(bcx, unit_ty); - let base = GEPi(bcx, llval, [0u, 0u]); - let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size); + let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]); + let len = C_uint(ccx, vec_length); (base, len) } @@ -488,23 +463,13 @@ pub fn get_base_and_len(bcx: &Block, let base = GEPi(bcx, llval, [0u, 0u]); (base, C_uint(ccx, n)) } - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_vec(_, None) | ty::ty_str => { - assert!(!type_is_immediate(bcx.ccx(), vec_ty)); let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); - let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); - (base, count) + let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + (base, len) } - _ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"), - }, - ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_vec(_, None) | ty::ty_str => { - assert!(type_is_immediate(bcx.ccx(), vec_ty)); - let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); - let body = Load(bcx, llval); - (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size)) - } - _ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"), + _ => ccx.sess().bug("unexpected type in get_base_and_len"), }, _ => ccx.sess().bug("unexpected type in get_base_and_len"), } @@ -576,13 +541,15 @@ pub fn iter_vec_raw<'r, bcx: &'b Block<'b>, data_ptr: ValueRef, unit_ty: ty::t, - fill: ValueRef, + len: ValueRef, f: iter_vec_block<'r,'b>) -> &'b Block<'b> { let _icx = push_ctxt("tvec::iter_vec_raw"); let fcx = bcx.fcx; let vt = vec_types(bcx, unit_ty); + let fill = Mul(bcx, len, vt.llunit_size); + if vt.llunit_alloc_size == 0 { // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) iter_vec_loop(bcx, data_ptr, &vt, fill, f) diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index e9d92e45f62..99850fb9386 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -215,7 +215,7 @@ impl Type { pub fn vec(ccx: &CrateContext, ty: &Type) -> Type { Type::struct_(ccx, - [Type::int(ccx), Type::int(ccx), Type::array(ty, 0)], + [Type::array(ty, 0), Type::int(ccx)], false) } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 8a445fc4839..bc17824ca32 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -169,14 +169,8 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(..) | ty::ty_ptr(..) => Type::i8p(cx), - ty::ty_uniq(ty) => { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { match ty::get(ty).sty { - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => Type::i8p(cx), - } - } - ty::ty_rptr(_, mt) => { - match ty::get(mt.ty).sty { ty::ty_vec(_, None) | ty::ty_str => { Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) } @@ -283,17 +277,10 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(typ) => { Type::at_box(cx, type_of(cx, typ)).ptr_to() } - ty::ty_uniq(typ) => { - match ty::get(typ).sty { - ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(), - ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(), - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => type_of(cx, typ).ptr_to(), - } - } ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(), - ty::ty_rptr(_, ref mt) => { - match ty::get(mt.ty).sty { + + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + match ty::get(ty).sty { ty::ty_vec(mt, None) => { let p_ty = type_of(cx, mt.ty).ptr_to(); let u_ty = Type::uint_from_ty(cx, ast::TyU); @@ -304,7 +291,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { cx.tn.find_type("str_slice").unwrap() } ty::ty_trait(..) => Type::opaque_trait(cx), - _ => type_of(cx, mt.ty).ptr_to(), + _ => type_of(cx, ty).ptr_to(), } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dc463ffe5df..c00c462afae 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1816,8 +1816,7 @@ pub fn type_is_boxed(ty: t) -> bool { pub fn type_is_region_ptr(ty: t) -> bool { match get(ty).sty { ty_rptr(_, mt) => match get(mt.ty).sty { - // FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this - // odd behaviour for now. (But ~[] were unique. I have no idea why). + // DST pointers should not be treated like regular pointers. ty_vec(_, None) | ty_str | ty_trait(..) => false, _ => true }, diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs index c722beb43ae..015331b8be0 100644 --- a/src/librustc_back/abi.rs +++ b/src/librustc_back/abi.rs @@ -23,11 +23,5 @@ pub static fn_field_box: uint = 1u; pub static trt_field_vtable: uint = 0u; pub static trt_field_box: uint = 1u; -pub static vec_elt_fill: uint = 0u; - -pub static vec_elt_alloc: uint = 1u; - -pub static vec_elt_elems: uint = 2u; - pub static slice_elt_base: uint = 0u; pub static slice_elt_len: uint = 1u; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index bbaac7a96e9..a9cbacb07be 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -18,6 +18,7 @@ use std::path; use std::rc::Rc; use std::gc::{Gc, GC}; use std::cell::{Cell, RefCell}; +use std::strbuf::StrBuf; pub trait Encoder<E> { // Primitive types: diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index d0b4c6b1e4c..9a56dd5c0e4 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -268,7 +268,19 @@ pub struct Tm { pub tm_nsec: i32, } +impl Tm { + pub fn tm_zone<'a>(&'a self) -> &'a str { + self.tm_zone.as_slice() + } +} + pub fn empty_tm() -> Tm { + // 64 is the max size of the timezone buffer allocated on windows + // in rust_localtime. In glibc the max timezone size is supposedly 3. + let mut zone = StrBuf::new(); + for _ in range(0, 64) { + zone.push_char(' ') + } Tm { tm_sec: 0_i32, tm_min: 0_i32, @@ -280,6 +292,7 @@ pub fn empty_tm() -> Tm { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, + tm_zone: zone, tm_nsec: 0_i32, } } @@ -760,6 +773,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> { 'Z' => { if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") { tm.tm_gmtoff = 0_i32; + tm.tm_zone = "UTC".into_strbuf(); Ok(pos + 3u) } else { // It's odd, but to maintain compatibility with c's @@ -784,6 +798,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> { let (v, pos) = item; if v == 0_i32 { tm.tm_gmtoff = 0_i32; + tm.tm_zone = "UTC".into_strbuf(); } Ok(pos) @@ -813,6 +828,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, + tm_zone: StrBuf::new(), tm_nsec: 0_i32, }; let mut pos = 0u; @@ -859,6 +875,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> { tm_yday: tm.tm_yday, tm_isdst: tm.tm_isdst, tm_gmtoff: tm.tm_gmtoff, + tm_zone: tm.tm_zone.clone(), tm_nsec: tm.tm_nsec, }) } else { result } @@ -1060,7 +1077,7 @@ pub fn strftime(format: &str, tm: &Tm) -> String { 'w' => (tm.tm_wday as int).to_string(), 'Y' => (tm.tm_year as int + 1900).to_string(), 'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100), - 'Z' => "".to_string(), // FIXME(pcwalton): Implement this. + 'Z' => tm.tm_zone.as_slice().to_owned(), 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = num::abs(tm.tm_gmtoff) / 60_i32; @@ -1186,6 +1203,7 @@ mod tests { assert_eq!(utc.tm_yday, 43_i32); assert_eq!(utc.tm_isdst, 0_i32); assert_eq!(utc.tm_gmtoff, 0_i32); + assert_eq!(utc.tm_zone(), "UTC"); assert_eq!(utc.tm_nsec, 54321_i32); } @@ -1207,6 +1225,12 @@ mod tests { assert_eq!(local.tm_yday, 43_i32); assert_eq!(local.tm_isdst, 0_i32); assert_eq!(local.tm_gmtoff, -28800_i32); + + // FIXME (#2350): We should probably standardize on the timezone + // abbreviation. + let zone = local.tm_zone(); + assert!(zone == "PST" || zone == "Pacific Standard Time"); + assert_eq!(local.tm_nsec, 54321_i32); } @@ -1249,6 +1273,7 @@ mod tests { assert!(tm.tm_wday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); + assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 0_i32); } Err(_) => () @@ -1272,6 +1297,7 @@ mod tests { assert!(tm.tm_yday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); + assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 12340000_i32); } } @@ -1383,10 +1409,10 @@ mod tests { assert!(test("6", "%w")); assert!(test("2009", "%Y")); assert!(test("09", "%y")); - assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == - 0); - assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == - 0); + assert!(strptime("UTC", "%Z").unwrap().tm_zone() == "UTC"); + assert!(strptime("PST", "%Z").unwrap().tm_zone() == ""); + assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == 0); + assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == 0); assert!(test("%", "%%")); // Test for #7256 diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index ba20f2c6f27..1a9b1c1c818 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -127,6 +127,15 @@ rust_list_dir_wfd_fp_buf(void* wfd) { } #endif +typedef struct +{ + size_t fill; // in bytes; if zero, heapified + size_t alloc; // in bytes + uint8_t *data; +} rust_vec; + +typedef rust_vec rust_str_buf; + typedef struct { int32_t tm_sec; int32_t tm_min; @@ -138,6 +147,7 @@ typedef struct { int32_t tm_yday; int32_t tm_isdst; int32_t tm_gmtoff; + rust_str_buf tm_zone; int32_t tm_nsec; } rust_tm; @@ -154,10 +164,8 @@ void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) { out_tm->tm_isdst = in_tm->tm_isdst; } -void tm_to_rust_tm(struct tm* in_tm, - rust_tm* out_tm, - int32_t gmtoff, - int32_t nsec) { +void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff, + const char *zone, int32_t nsec) { out_tm->tm_sec = in_tm->tm_sec; out_tm->tm_min = in_tm->tm_min; out_tm->tm_hour = in_tm->tm_hour; @@ -169,6 +177,13 @@ void tm_to_rust_tm(struct tm* in_tm, out_tm->tm_isdst = in_tm->tm_isdst; out_tm->tm_gmtoff = gmtoff; out_tm->tm_nsec = nsec; + + if (zone != NULL) { + size_t size = strlen(zone); + assert(out_tm->tm_zone.alloc >= size); + memcpy(out_tm->tm_zone.data, zone, size); + out_tm->tm_zone.fill = size; + } } #if defined(__WIN32__) @@ -210,7 +225,7 @@ rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; GMTIME(&s, &tm); - tm_to_rust_tm(&tm, timeptr, 0, nsec); + tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec); } void @@ -219,13 +234,28 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; LOCALTIME(&s, &tm); + const char* zone = NULL; #if defined(__WIN32__) int32_t gmtoff = -timezone; + wchar_t wbuffer[64] = {0}; + char buffer[256] = {0}; + // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418), + // so time zone should be converted from UTF-16 string. + // Since wcsftime depends on setlocale() result, + // instead we convert it using MultiByteToWideChar. + if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) { + // ANSI -> UTF-16 + MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t)); + // UTF-16 -> UTF-8 + WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); + zone = buffer; + } #else int32_t gmtoff = tm.tm_gmtoff; + zone = tm.tm_zone; #endif - tm_to_rust_tm(&tm, timeptr, gmtoff, nsec); + tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec); } int64_t