From 3df03217ee580b2a43d15930af555a4b3e537c11 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 18 Sep 2015 16:32:52 +0200 Subject: [PATCH 1/5] VecDeque: Use power of two capacity even for zero sized types VecDeque depends on using a power of two capacity. Use the largest possible power of two capacity for ZSTs. --- src/libcollections/vec_deque.rs | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index b6bf0669d0ff1..4ee9787c9ec8a 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -21,9 +21,11 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator}; +use core::mem; use core::ops::{Index, IndexMut}; use core::ptr; use core::slice; +use core::usize; use core::hash::{Hash, Hasher}; use core::cmp; @@ -32,6 +34,7 @@ use alloc::raw_vec::RawVec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 +const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two /// `VecDeque` is a growable ring buffer, which can be used as a /// double-ended queue efficiently. @@ -83,7 +86,12 @@ impl VecDeque { /// Marginally more convenient #[inline] fn cap(&self) -> usize { - self.buf.cap() + if mem::size_of::() == 0 { + // For zero sized types, we are always at maximum capacity + MAXIMUM_ZST_CAPACITY + } else { + self.buf.cap() + } } /// Turn ptr into a slice @@ -1465,6 +1473,7 @@ impl VecDeque { #[inline] fn wrap_index(index: usize, size: usize) -> usize { // size is always a power of 2 + debug_assert!(size.is_power_of_two()); index & (size - 1) } @@ -2032,4 +2041,34 @@ mod tests { } } } + + #[test] + fn test_zst_push() { + const N: usize = 8; + + // Zero sized type + struct Zst; + + // Test that for all possible sequences of push_front / push_back, + // we end up with a deque of the correct size + + for len in 0..N { + let mut tester = VecDeque::with_capacity(len); + assert_eq!(tester.len(), 0); + assert!(tester.capacity() >= len); + for case in 0..(1 << len) { + assert_eq!(tester.len(), 0); + for bit in 0..len { + if case & (1 << bit) != 0 { + tester.push_front(Zst); + } else { + tester.push_back(Zst); + } + } + assert_eq!(tester.len(), len); + assert_eq!(tester.iter().count(), len); + tester.clear(); + } + } + } } From 77a57147243cda936b01c4dfd35c342efa480a42 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 21 Aug 2015 00:41:07 -0700 Subject: [PATCH 2/5] Fix dllimports of static data from rlibs --- src/librustc_trans/trans/base.rs | 100 +++++++++++++++------- src/test/run-make/msvc-data-only/Makefile | 8 ++ src/test/run-make/msvc-data-only/bar.rs | 15 ++++ src/test/run-make/msvc-data-only/foo.rs | 13 +++ 4 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 src/test/run-make/msvc-data-only/Makefile create mode 100644 src/test/run-make/msvc-data-only/bar.rs create mode 100644 src/test/run-make/msvc-data-only/foo.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1359252e0351a..f631fbc282296 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2570,20 +2570,6 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { unsafe { let mut declared = HashSet::new(); - let iter_globals = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstGlobal(llmod), - step: llvm::LLVMGetNextGlobal, - } - }; - - let iter_functions = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstFunction(llmod), - step: llvm::LLVMGetNextFunction, - } - }; - // Collect all external declarations in all compilation units. for ccx in cx.iter() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { @@ -2623,28 +2609,74 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { } } } +} +// Create a `__imp_ = &symbol` global for every public static `symbol`. +// This is required to satisfy `dllimport` references to static data in .rlibs +// when using MSVC linker. We do this only for data, as linker can fix up +// code references on its own. +// See #26591, #27438 +fn create_imps(cx: &SharedCrateContext, _reachable: &HashSet<&str>) { + unsafe { - struct ValueIter { - cur: ValueRef, - step: unsafe extern "C" fn(ValueRef) -> ValueRef, + for ccx in cx.iter() { + let exported: Vec<_> = iter_globals(ccx.llmod()) + .filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && + llvm::LLVMIsDeclaration(val) == 0) + .collect(); + + let i8p_ty = Type::i8p(&ccx); + for val in exported { + let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let imp_name = String::from("__imp_") + + str::from_utf8(name.to_bytes()).unwrap(); + let imp_name = CString::new(imp_name).unwrap(); + let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(), + imp_name.as_ptr() as *const _); + llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref())); + llvm::SetLinkage(imp, llvm::ExternalLinkage); + } + } } +} - impl Iterator for ValueIter { - type Item = ValueRef; +struct ValueIter { + cur: ValueRef, + step: unsafe extern "C" fn(ValueRef) -> ValueRef, +} - fn next(&mut self) -> Option { - let old = self.cur; - if !old.is_null() { - self.cur = unsafe { - let step: unsafe extern "C" fn(ValueRef) -> ValueRef = - mem::transmute_copy(&self.step); - step(old) - }; - Some(old) - } else { - None - } +impl Iterator for ValueIter { + type Item = ValueRef; + + fn next(&mut self) -> Option { + let old = self.cur; + if !old.is_null() { + self.cur = unsafe { + let step: unsafe extern "C" fn(ValueRef) -> ValueRef = + mem::transmute_copy(&self.step); + step(old) + }; + Some(old) + } else { + None + } + } +} + +fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstGlobal(llmod), + step: llvm::LLVMGetNextGlobal, + } + } +} + +fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstFunction(llmod), + step: llvm::LLVMGetNextFunction, } } } @@ -2824,6 +2856,12 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat &reachable_symbols.iter().map(|x| &x[..]).collect()); } + if sess.target.target.options.is_like_msvc && + sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib || + *ct == config::CrateTypeStaticlib) { + create_imps(&shared_ccx, &reachable_symbols.iter().map(|x| &x[..]).collect()); + } + let metadata_module = ModuleTranslation { llcx: shared_ccx.metadata_llcx(), llmod: shared_ccx.metadata_llmod(), diff --git a/src/test/run-make/msvc-data-only/Makefile b/src/test/run-make/msvc-data-only/Makefile new file mode 100644 index 0000000000000..251a3a9768d78 --- /dev/null +++ b/src/test/run-make/msvc-data-only/Makefile @@ -0,0 +1,8 @@ +# Test that on *-pc-windows-msvc we can link to a rlib containing only data. +# See #26591, #27438 + +-include ../tools.mk + +all: + $(RUSTC) foo.rs + $(RUSTC) bar.rs diff --git a/src/test/run-make/msvc-data-only/bar.rs b/src/test/run-make/msvc-data-only/bar.rs new file mode 100644 index 0000000000000..0e3af9ff3fd48 --- /dev/null +++ b/src/test/run-make/msvc-data-only/bar.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate foo; + +fn main() { + println!("The answer is {} !", foo::FOO); +} diff --git a/src/test/run-make/msvc-data-only/foo.rs b/src/test/run-make/msvc-data-only/foo.rs new file mode 100644 index 0000000000000..38bff8be125b6 --- /dev/null +++ b/src/test/run-make/msvc-data-only/foo.rs @@ -0,0 +1,13 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] + +pub static FOO: i32 = 42; From bb8f8622e4fd43141e04f82066329dfae4fde336 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 25 Sep 2015 18:48:54 -0700 Subject: [PATCH 3/5] Converted test to rpass. --- .../foo.rs => auxiliary/msvc-data-only-lib.rs} | 2 ++ src/test/run-make/msvc-data-only/Makefile | 8 -------- .../msvc-data-only/bar.rs => run-pass/msvc-data-only.rs} | 6 ++++-- 3 files changed, 6 insertions(+), 10 deletions(-) rename src/test/{run-make/msvc-data-only/foo.rs => auxiliary/msvc-data-only-lib.rs} (95%) delete mode 100644 src/test/run-make/msvc-data-only/Makefile rename src/test/{run-make/msvc-data-only/bar.rs => run-pass/msvc-data-only.rs} (78%) diff --git a/src/test/run-make/msvc-data-only/foo.rs b/src/test/auxiliary/msvc-data-only-lib.rs similarity index 95% rename from src/test/run-make/msvc-data-only/foo.rs rename to src/test/auxiliary/msvc-data-only-lib.rs index 38bff8be125b6..71fb9a519489b 100644 --- a/src/test/run-make/msvc-data-only/foo.rs +++ b/src/test/auxiliary/msvc-data-only-lib.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// no-prefer-dynamic + #![crate_type = "rlib"] pub static FOO: i32 = 42; diff --git a/src/test/run-make/msvc-data-only/Makefile b/src/test/run-make/msvc-data-only/Makefile deleted file mode 100644 index 251a3a9768d78..0000000000000 --- a/src/test/run-make/msvc-data-only/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# Test that on *-pc-windows-msvc we can link to a rlib containing only data. -# See #26591, #27438 - --include ../tools.mk - -all: - $(RUSTC) foo.rs - $(RUSTC) bar.rs diff --git a/src/test/run-make/msvc-data-only/bar.rs b/src/test/run-pass/msvc-data-only.rs similarity index 78% rename from src/test/run-make/msvc-data-only/bar.rs rename to src/test/run-pass/msvc-data-only.rs index 0e3af9ff3fd48..ad6888c4d3096 100644 --- a/src/test/run-make/msvc-data-only/bar.rs +++ b/src/test/run-pass/msvc-data-only.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate foo; +// aux-build:msvc-data-only-lib.rs + +extern crate msvc_data_only_lib; fn main() { - println!("The answer is {} !", foo::FOO); + println!("The answer is {} !", msvc_data_only_lib::FOO); } From d16e5ed69baca149566bd58ee7f1d9824bc7d310 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 25 Sep 2015 18:53:14 -0700 Subject: [PATCH 4/5] Removed unused parameter. --- src/librustc_trans/trans/base.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f631fbc282296..13d2cbf57997a 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2616,9 +2616,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { // when using MSVC linker. We do this only for data, as linker can fix up // code references on its own. // See #26591, #27438 -fn create_imps(cx: &SharedCrateContext, _reachable: &HashSet<&str>) { +fn create_imps(cx: &SharedCrateContext) { unsafe { - for ccx in cx.iter() { let exported: Vec<_> = iter_globals(ccx.llmod()) .filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && @@ -2857,9 +2856,8 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat } if sess.target.target.options.is_like_msvc && - sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib || - *ct == config::CrateTypeStaticlib) { - create_imps(&shared_ccx, &reachable_symbols.iter().map(|x| &x[..]).collect()); + sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { + create_imps(&shared_ccx); } let metadata_module = ModuleTranslation { From 773cf0f59b25fa33db238fc1bb22bfe1a3e39aba Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 29 Sep 2015 16:26:34 -0700 Subject: [PATCH 5/5] trans: Fix __imp_ creation for i686 MSVC Turns out the symbol names are slightly different on 32-bit than on 64, so the prefix needs to be tweaked just a bit! --- src/librustc_trans/trans/base.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 13d2cbf57997a..79484ad3ddd56 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2617,6 +2617,15 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { // code references on its own. // See #26591, #27438 fn create_imps(cx: &SharedCrateContext) { + // The x86 ABI seems to require that leading underscores are added to symbol + // names, so we need an extra underscore on 32-bit. There's also a leading + // '\x01' here which disables LLVM's symbol mangling (e.g. no extra + // underscores added in front). + let prefix = if cx.sess().target.target.target_pointer_width == "32" { + "\x01__imp__" + } else { + "\x01__imp_" + }; unsafe { for ccx in cx.iter() { let exported: Vec<_> = iter_globals(ccx.llmod()) @@ -2627,12 +2636,13 @@ fn create_imps(cx: &SharedCrateContext) { let i8p_ty = Type::i8p(&ccx); for val in exported { let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - let imp_name = String::from("__imp_") + - str::from_utf8(name.to_bytes()).unwrap(); + let mut imp_name = prefix.as_bytes().to_vec(); + imp_name.extend(name.to_bytes()); let imp_name = CString::new(imp_name).unwrap(); let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(), imp_name.as_ptr() as *const _); - llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref())); + let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); + llvm::LLVMSetInitializer(imp, init); llvm::SetLinkage(imp, llvm::ExternalLinkage); } }