From 06e3e63c9046c160a00122990f31b82dd729a4a3 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 21 Feb 2014 19:28:44 +1100 Subject: [PATCH] flate: return CVec rather than copying into a new vector. This trades an O(n) allocation + memcpy for a O(1) proc allocation (for the destructor). Most users only need &[u8] anyway (all of the users in the main repo), and so this offers large gains. --- mk/crates.mk | 2 +- src/libextra/c_vec.rs | 16 ++++++++++++ src/libflate/lib.rs | 41 ++++++++++++++----------------- src/librustc/back/link.rs | 2 +- src/librustc/back/lto.rs | 2 +- src/librustc/metadata/cstore.rs | 3 ++- src/librustc/middle/trans/base.rs | 2 +- 7 files changed, 40 insertions(+), 28 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 8e624cb313f..9489b907b4d 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -65,7 +65,7 @@ DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \ collections time extra DEPS_rustdoc := rustc native:sundown serialize sync getopts collections \ test time -DEPS_flate := std native:miniz +DEPS_flate := std extra native:miniz DEPS_arena := std collections DEPS_glob := std DEPS_serialize := std diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index fec5b105c4b..b93ffce636b 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -35,7 +35,9 @@ * if necessary. */ +use std::cast; use std::ptr; +use std::raw; /** * The type representing a foreign chunk of memory @@ -111,6 +113,20 @@ impl CVec { } } + /// View the stored data as a slice. + pub fn as_slice<'a>(&'a self) -> &'a [T] { + unsafe { + cast::transmute(raw::Slice { data: self.base as *T, len: self.len }) + } + } + + /// View the stored data as a mutable slice. + pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { + unsafe { + cast::transmute(raw::Slice { data: self.base as *T, len: self.len }) + } + } + /** * Retrieves an element at a given index * diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index d4a85b01324..1a14432be6a 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -20,9 +20,10 @@ Simple compression #[license = "MIT/ASL2"]; #[allow(missing_doc)]; +extern crate extra; use std::libc::{c_void, size_t, c_int}; use std::libc; -use std::vec; +use extra::c_vec::CVec; pub mod rustrt { use std::libc::{c_int, c_void, size_t}; @@ -33,13 +34,13 @@ pub mod rustrt { src_buf_len: size_t, pout_len: *mut size_t, flags: c_int) - -> *c_void; + -> *mut c_void; pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void, src_buf_len: size_t, pout_len: *mut size_t, flags: c_int) - -> *c_void; + -> *mut c_void; } } @@ -47,49 +48,43 @@ static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> CVec { unsafe { let mut outsz : size_t = 0; let res = rustrt::tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void, bytes.len() as size_t, &mut outsz, flags); - assert!(res as int != 0); - let out = vec::raw::from_buf_raw(res as *u8, - outsz as uint); - libc::free(res as *mut c_void); - out + assert!(!res.is_null()); + CVec::new_with_dtor(res as *mut u8, outsz as uint, proc() libc::free(res)) } } -pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { +pub fn deflate_bytes(bytes: &[u8]) -> CVec { deflate_bytes_internal(bytes, LZ_NORM) } -pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> CVec { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> CVec { unsafe { let mut outsz : size_t = 0; let res = rustrt::tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void, bytes.len() as size_t, &mut outsz, flags); - assert!(res as int != 0); - let out = vec::raw::from_buf_raw(res as *u8, - outsz as uint); - libc::free(res as *mut c_void); - out + assert!(!res.is_null()); + CVec::new_with_dtor(res as *mut u8, outsz as uint, proc() libc::free(res)) } } -pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { +pub fn inflate_bytes(bytes: &[u8]) -> CVec { inflate_bytes_internal(bytes, 0) } -pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> CVec { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } @@ -115,11 +110,11 @@ mod tests { debug!("de/inflate of {} bytes of random word-sequences", input.len()); let cmp = deflate_bytes(input); - let out = inflate_bytes(cmp); + let out = inflate_bytes(cmp.as_slice()); debug!("{} bytes deflated to {} ({:.1f}% size)", input.len(), cmp.len(), 100.0 * ((cmp.len() as f64) / (input.len() as f64))); - assert_eq!(input, out); + assert_eq!(input.as_slice(), out.as_slice()); } } @@ -127,7 +122,7 @@ mod tests { fn test_zlib_flate() { let bytes = ~[1, 2, 3, 4, 5]; let deflated = deflate_bytes(bytes); - let inflated = inflate_bytes(deflated); - assert_eq!(inflated, bytes); + let inflated = inflate_bytes(deflated.as_slice()); + assert_eq!(inflated.as_slice(), bytes.as_slice()); } } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index bd0748761ee..a8758814c54 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -944,7 +944,7 @@ fn link_rlib(sess: Session, // into the archive. let bc = obj_filename.with_extension("bc"); match fs::File::open(&bc).read_to_end().and_then(|data| { - fs::File::create(&bc).write(flate::deflate_bytes(data)) + fs::File::create(&bc).write(flate::deflate_bytes(data).as_slice()) }) { Ok(()) => {} Err(e) => { diff --git a/src/librustc/back/lto.rs b/src/librustc/back/lto.rs index 75fde2fdc51..c0d18672a9b 100644 --- a/src/librustc/back/lto.rs +++ b/src/librustc/back/lto.rs @@ -58,7 +58,7 @@ pub fn run(sess: session::Session, llmod: ModuleRef, let bc = bc.expect("missing bytecode in archive!"); let bc = time(sess.time_passes(), format!("inflate {}.bc", name), (), |_| flate::inflate_bytes(bc)); - let ptr = bc.as_ptr(); + let ptr = bc.as_slice().as_ptr(); debug!("linking {}", name); time(sess.time_passes(), format!("ll link {}", name), (), |()| unsafe { if !llvm::LLVMRustLinkInExternalBitcode(llmod, diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 1a8b86b3510..ce6b5af8d0e 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -18,6 +18,7 @@ use metadata::loader; use std::cell::RefCell; use collections::HashMap; +use extra::c_vec::CVec; use syntax::ast; use syntax::parse::token::IdentInterner; @@ -28,7 +29,7 @@ use syntax::parse::token::IdentInterner; pub type cnum_map = @RefCell>; pub enum MetadataBlob { - MetadataVec(~[u8]), + MetadataVec(CVec), MetadataArchive(loader::ArchiveMetadata), } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d920378f508..5b3c18a5a93 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2569,7 +2569,7 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> ~[u8] { let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item); let metadata = encoder::encode_metadata(encode_parms, krate); let compressed = encoder::metadata_encoding_version + - flate::deflate_bytes(metadata); + flate::deflate_bytes(metadata).as_slice(); let llmeta = C_bytes(compressed); let llconst = C_struct([llmeta], false); let name = format!("rust_metadata_{}_{}_{}", cx.link_meta.crateid.name,