diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 13354e6128474..0b2519e6fb45f 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -10,13 +10,13 @@ //! Managed vectors -use cast::transmute; use clone::Clone; use container::Container; use iterator::IteratorUtil; use option::Option; use sys; use uint; +use unstable::raw::Repr; use vec::{ImmutableVector, OwnedVector}; /// Code for dealing with @-vectors. This is pretty incomplete, and @@ -26,8 +26,8 @@ use vec::{ImmutableVector, OwnedVector}; #[inline] pub fn capacity(v: @[T]) -> uint { unsafe { - let repr: **raw::VecRepr = transmute(&v); - (**repr).unboxed.alloc / sys::size_of::() + let box = v.repr(); + (*box).data.alloc / sys::size_of::() } } @@ -45,10 +45,10 @@ pub fn capacity(v: @[T]) -> uint { */ #[inline] pub fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { - let mut vec: @[A] = @[]; + let mut vec = @[]; unsafe { raw::reserve(&mut vec, size); } builder(|x| unsafe { raw::push(&mut vec, x) }); - return unsafe { transmute(vec) }; + vec } /** @@ -151,7 +151,7 @@ pub fn to_managed_consume(v: ~[T]) -> @[T] { for v.consume_iter().advance |x| { raw::push(&mut av, x); } - transmute(av) + av } } @@ -195,13 +195,9 @@ pub mod raw { use ptr; use sys; use uint; - use unstable::intrinsics; use unstable::intrinsics::{move_val_init, TyDesc}; - use vec; - use vec::UnboxedVecRepr; - - pub type VecRepr = vec::raw::VecRepr; - pub type SliceRepr = vec::raw::SliceRepr; + use unstable::intrinsics; + use unstable::raw::{Box, Vec}; /** * Sets the length of a vector @@ -211,9 +207,9 @@ pub mod raw { * the vector is actually the specified size. */ #[inline] - pub unsafe fn set_len(v: @[T], new_len: uint) { - let repr: **mut VecRepr = transmute(&v); - (**repr).unboxed.fill = new_len * sys::size_of::(); + pub unsafe fn set_len(v: &mut @[T], new_len: uint) { + let repr: *mut Box> = cast::transmute_copy(v); + (*repr).data.fill = new_len * sys::size_of::(); } /** @@ -221,9 +217,11 @@ pub mod raw { */ #[inline] pub unsafe fn push(v: &mut @[T], initval: T) { - let repr: **VecRepr = transmute_copy(&v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { + let full = { + let repr: *Box> = cast::transmute_copy(v); + (*repr).data.alloc > (*repr).data.fill + }; + if full { push_fast(v, initval); } else { push_slow(v, initval); @@ -232,16 +230,15 @@ pub mod raw { #[inline] // really pretty please unsafe fn push_fast(v: &mut @[T], initval: T) { - let repr: **mut VecRepr = ::cast::transmute(v); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::size_of::(); - let p = &((**repr).unboxed.data); - let p = ptr::offset(p, fill) as *mut T; + let repr: *mut Box> = cast::transmute_copy(v); + let amt = v.len(); + (*repr).data.fill += sys::size_of::(); + let p = ptr::offset(&(*repr).data.data as *T, amt) as *mut T; move_val_init(&mut(*p), initval); } unsafe fn push_slow(v: &mut @[T], initval: T) { - reserve_at_least(&mut *v, v.len() + 1u); + reserve_at_least(v, v.len() + 1u); push_fast(v, initval); } @@ -259,7 +256,7 @@ pub mod raw { pub unsafe fn reserve(v: &mut @[T], n: uint) { // Only make the (slow) call into the runtime if we have to if capacity(*v) < n { - let ptr: *mut *mut VecRepr = transmute(v); + let ptr: *mut *mut Box> = transmute(v); let ty = intrinsics::get_tydesc::(); // XXX transmute shouldn't be necessary let ty = cast::transmute(ty); @@ -269,16 +266,14 @@ pub mod raw { // Implementation detail. Shouldn't be public #[allow(missing_doc)] - pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut VecRepr, n: uint) { + pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut Box>, n: uint) { unsafe { let size_in_bytes = n * (*ty).size; - if size_in_bytes > (**ptr).unboxed.alloc { - let total_size = size_in_bytes + sys::size_of::(); - // XXX: UnboxedVecRepr has an extra u8 at the end - let total_size = total_size - sys::size_of::(); - (*ptr) = local_realloc(*ptr as *(), total_size) as *mut VecRepr; - (**ptr).unboxed.alloc = size_in_bytes; + if size_in_bytes > (**ptr).data.alloc { + let total_size = size_in_bytes + sys::size_of::>(); + (*ptr) = local_realloc(*ptr as *(), total_size) as *mut Box>; + (**ptr).data.alloc = size_in_bytes; } } diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index 86eec80ae6f8b..ee91d12790953 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -133,6 +133,7 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { #[cfg(test)] mod tests { use cast::{bump_box_refcount, transmute}; + use unstable::raw; #[test] fn test_transmute_copy() { @@ -156,10 +157,9 @@ mod tests { #[test] fn test_transmute() { - use managed::raw::BoxRepr; unsafe { let x = @100u8; - let x: *BoxRepr = transmute(x); + let x: *raw::Box = transmute(x); assert!((*x).data == 100); let _x: @int = transmute(x); } diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 2ea10b09c8ec1..ed2b0e1681817 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -12,9 +12,8 @@ use libc::c_void; use ptr::{mut_null}; -use repr::BoxRepr; -use cast::transmute; use unstable::intrinsics::TyDesc; +use unstable::raw; type DropGlue<'self> = &'self fn(**TyDesc, *c_void); @@ -31,27 +30,25 @@ struct AnnihilateStats { } unsafe fn each_live_alloc(read_next_before: bool, - f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) -> bool { + f: &fn(box: *mut raw::Box<()>, uniq: bool) -> bool) -> bool { //! Walks the internal list of allocations use managed; use rt::local_heap; - let box = local_heap::live_allocs(); - let mut box: *mut BoxRepr = transmute(box); + let mut box = local_heap::live_allocs(); while box != mut_null() { - let next_before = transmute((*box).header.next); - let uniq = - (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; + let next_before = (*box).next; + let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE; - if !f(box, uniq) { + if !f(box as *mut raw::Box<()>, uniq) { return false; } if read_next_before { box = next_before; } else { - box = transmute((*box).header.next); + box = (*box).next; } } return true; @@ -102,7 +99,7 @@ pub unsafe fn annihilate() { if uniq { stats.n_unique_boxes += 1; } else { - (*box).header.ref_count = managed::raw::RC_IMMORTAL; + (*box).ref_count = managed::RC_IMMORTAL; } } @@ -113,9 +110,9 @@ pub unsafe fn annihilate() { // callback, as the original value may have been freed. for each_live_alloc(false) |box, uniq| { if !uniq { - let tydesc: *TyDesc = transmute((*box).header.type_desc); - let data = transmute(&(*box).data); - ((*tydesc).drop_glue)(data); + let tydesc = (*box).type_desc; + let data = &(*box).data as *(); + ((*tydesc).drop_glue)(data as *i8); } } @@ -128,9 +125,9 @@ pub unsafe fn annihilate() { for each_live_alloc(true) |box, uniq| { if !uniq { stats.n_bytes_freed += - (*((*box).header.type_desc)).size - + sys::size_of::(); - local_free(transmute(box)); + (*((*box).type_desc)).size + + sys::size_of::>(); + local_free(box as *i8); } } diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs index 911fb5625e588..4feec26a2d982 100644 --- a/src/libstd/gc.rs +++ b/src/libstd/gc.rs @@ -74,14 +74,14 @@ pub mod rustrt { } unsafe fn bump(ptr: *T, count: uint) -> *U { - return cast::transmute(ptr::offset(ptr, count)); + return ptr::offset(ptr, count) as *U; } unsafe fn align_to_pointer(ptr: *T) -> *T { let align = sys::min_align_of::<*T>(); - let ptr: uint = cast::transmute(ptr); + let ptr = ptr as uint; let ptr = (ptr + (align - 1)) & -align; - return cast::transmute(ptr); + return ptr as *T; } unsafe fn get_safe_point_count() -> uint { @@ -126,8 +126,8 @@ type Visitor<'self> = &'self fn(root: **Word, tydesc: *TyDesc) -> bool; // Walks the list of roots for the given safe point, and calls visitor // on each root. unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { - let fp_bytes: *u8 = cast::transmute(fp); - let sp_meta: *u32 = cast::transmute(sp.sp_meta); + let fp_bytes = fp as *u8; + let sp_meta = sp.sp_meta as *u32; let num_stack_roots = *sp_meta as uint; let num_reg_roots = *ptr::offset(sp_meta, 1) as uint; @@ -173,9 +173,9 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { // Is fp contained in segment? unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool { - let begin: Word = cast::transmute(segment); - let end: Word = cast::transmute((*segment).end); - let frame: Word = cast::transmute(fp); + let begin = segment as Word; + let end = (*segment).end as Word; + let frame = fp as Word; return begin <= frame && frame <= end; } diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index 2c9fcb2999f06..bd4dc69537cb1 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -14,27 +14,8 @@ use ptr::to_unsafe_ptr; #[cfg(not(test))] use cmp::{Eq, Ord}; -pub mod raw { - use std::unstable::intrinsics::TyDesc; - - pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; - pub static RC_IMMORTAL : uint = 0x77777777; - - #[allow(missing_doc)] - pub struct BoxHeaderRepr { - ref_count: uint, - type_desc: *TyDesc, - prev: *BoxRepr, - next: *BoxRepr, - } - - #[allow(missing_doc)] - pub struct BoxRepr { - header: BoxHeaderRepr, - data: u8 - } - -} +pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; +pub static RC_IMMORTAL : uint = 0x77777777; /// Determine if two shared boxes point to the same object #[inline] diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index d49d54ae68fe6..1d093c4c14b8b 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -19,7 +19,7 @@ Runtime type reflection use unstable::intrinsics::{Opaque, TyDesc, TyVisitor}; use libc::c_void; use sys; -use vec; +use unstable::raw; /** * Trait for visitor that wishes to reflect on data. To use this, create a @@ -260,7 +260,7 @@ impl TyVisitor for MovePtrAdaptor { } fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::(); + self.align_to::>(); if ! self.inner.visit_vec(mtbl, inner) { return false; } true } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 07fd82e16160a..eb4e1918add12 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -22,21 +22,17 @@ use container::Container; use io::{Writer, WriterUtil}; use iterator::IteratorUtil; use libc::c_void; -use managed; use ptr; use reflect; use reflect::{MovePtr, align}; use str::StrSlice; use to_str::ToStr; -use vec::raw::{VecRepr, SliceRepr}; -use vec; -use vec::{OwnedVector, UnboxedVecRepr}; +use vec::OwnedVector; use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; +use unstable::raw; #[cfg(test)] use io; -pub use managed::raw::BoxRepr; - /// Helpers trait EscapedCharWriter { @@ -198,11 +194,11 @@ impl ReprVisitor { pub fn write_vec_range(&self, _mtbl: uint, - ptr: *u8, + ptr: *(), len: uint, inner: *TyDesc) -> bool { - let mut p = ptr; + let mut p = ptr as *u8; let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; self.writer.write_char('['); let mut first = true; @@ -225,7 +221,7 @@ impl ReprVisitor { pub fn write_unboxed_vec_repr(&self, mtbl: uint, - v: &UnboxedVecRepr, + v: &raw::Vec<()>, inner: *TyDesc) -> bool { self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data), @@ -289,7 +285,7 @@ impl TyVisitor for ReprVisitor { fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.writer.write_char('@'); self.write_mut_qualifier(mtbl); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, inner); } @@ -304,7 +300,7 @@ impl TyVisitor for ReprVisitor { fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool { self.writer.write_char('~'); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, inner); } @@ -330,35 +326,35 @@ impl TyVisitor for ReprVisitor { fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get:: |b| { + do self.get::> |b| { self.write_unboxed_vec_repr(mtbl, b, inner); } } fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { + do self.get::<&raw::Box>> |b| { self.writer.write_char('@'); self.write_mut_qualifier(mtbl); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + self.write_unboxed_vec_repr(mtbl, &b.data, inner); } } fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&UnboxedVecRepr> |b| { + do self.get::<&raw::Vec<()>> |b| { self.writer.write_char('~'); self.write_unboxed_vec_repr(mtbl, *b, inner); } } fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { + do self.get::<&raw::Box>> |b| { self.writer.write_char('~'); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + self.write_unboxed_vec_repr(mtbl, &b.data, inner); } } fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get:: |s| { + do self.get::> |s| { self.writer.write_char('&'); self.write_vec_range(mtbl, s.data, s.len, inner); } @@ -366,7 +362,7 @@ impl TyVisitor for ReprVisitor { fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint, mtbl: uint, inner: *TyDesc) -> bool { - do self.get:: |b| { + do self.get::<()> |b| { self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner); } } @@ -547,9 +543,9 @@ impl TyVisitor for ReprVisitor { fn visit_opaque_box(&self) -> bool { self.writer.write_char('@'); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; - self.visit_ptr_inner(p, b.header.type_desc); + self.visit_ptr_inner(p, b.type_desc); } } diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 1a468fcf215d7..2d489e4dbc30c 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -12,12 +12,12 @@ use cast::transmute; use libc::{c_char, c_void, size_t, STDERR_FILENO}; use io; use io::{Writer, WriterUtil}; -use managed::raw::BoxRepr; use option::{Option, None, Some}; use uint; use str; use str::{OwnedStr, StrSlice}; use sys; +use unstable::raw; use vec::ImmutableVector; #[allow(non_camel_case_types)] @@ -29,7 +29,7 @@ static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; #[deriving(Eq)] struct BorrowRecord { - box: *mut BoxRepr, + box: *mut raw::Box<()>, file: *c_char, line: size_t } @@ -70,7 +70,7 @@ pub unsafe fn clear_task_borrow_list() { let _ = try_take_task_borrow_list(); } -unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { +unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) { debug_borrow("fail_borrowed: ", box, 0, 0, file, line); match try_take_task_borrow_list() { @@ -172,8 +172,8 @@ impl DebugPrints for io::fd_t { #[inline] pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = old_ref_count | FROZEN_BIT; debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line); @@ -182,15 +182,15 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { fail_borrowed(a, file, line); } - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; old_ref_count } #[inline] pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT; debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line); @@ -199,7 +199,7 @@ pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { fail_borrowed(a, file, line); } - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; old_ref_count } @@ -208,7 +208,7 @@ pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, file: *c_char, line: size_t) { if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before - let a: *mut BoxRepr = transmute(a); + let a = a as *mut raw::Box<()>; debug_borrow("record_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; @@ -223,7 +223,7 @@ pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before, so we should find the record at // the end of the list - let a: *mut BoxRepr = transmute(a); + let a = a as *mut raw::Box<()>; debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; @@ -246,15 +246,15 @@ pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, // Sometimes the box is null, if it is conditionally frozen. // See e.g. #4904. if !a.is_null() { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS); debug_borrow("return_to_mut:", a, old_ref_count, new_ref_count, file, line); - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; } } @@ -262,8 +262,8 @@ pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, pub unsafe fn check_not_borrowed(a: *u8, file: *c_char, line: size_t) { - let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let ref_count = (*a).ref_count; debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line); if (ref_count & FROZEN_BIT) != 0 { fail_borrowed(a, file, line); diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 54e9cb263dbe7..7488b08da42c5 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -9,8 +9,8 @@ // except according to those terms. use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc}; -use managed::raw::{BoxHeaderRepr, BoxRepr}; use unstable::intrinsics::TyDesc; +use unstable::raw; use sys::size_of; extern { @@ -20,7 +20,7 @@ extern { #[inline] fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::(); + let header_size = size_of::>(); // FIXME (#2699): This alignment calculation is suspicious. Is it right? let total_size = align_to(header_size, body_align) + body_size; total_size @@ -82,8 +82,8 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { let total_size = get_box_size(size, (*td).align); let p = malloc_raw(total_size as uint); - let box: *mut BoxRepr = p as *mut BoxRepr; - (*box).header.type_desc = td; + let box = p as *mut raw::Box<()>; + (*box).type_desc = td; box as *c_char } diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 85917ae3edf12..cd8e8549211a7 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -13,11 +13,11 @@ use libc; use libc::{c_void, uintptr_t, size_t}; use ops::Drop; -use repr::BoxRepr; use rt; use rt::OldTaskContext; use rt::local::Local; use rt::task::Task; +use unstable::raw; type MemoryRegion = c_void; @@ -26,7 +26,7 @@ struct Env { priv opaque: () } struct BoxedRegion { env: *Env, backing_region: *MemoryRegion, - live_allocs: *BoxRepr + live_allocs: *raw::Box<()>, } pub type OpaqueBox = c_void; @@ -103,7 +103,7 @@ pub unsafe fn local_free(ptr: *libc::c_char) { } } -pub fn live_allocs() -> *BoxRepr { +pub fn live_allocs() -> *raw::Box<()> { let region = match rt::context() { OldTaskContext => { unsafe { rust_current_boxed_region() } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index d8d61806a5bba..33cfd69fcd2f4 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -10,9 +10,9 @@ use either::{Left, Right}; use option::{Option, Some, None}; -use sys; use cast::transmute; use clone::Clone; +use unstable::raw; use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; @@ -698,7 +698,7 @@ impl SchedHandle { // XXX: Some hacks to put a &fn in Scheduler without borrowck // complaining -type UnsafeTaskReceiver = sys::Closure; +type UnsafeTaskReceiver = raw::Closure; trait ClosureConverter { fn from_fn(&fn(&mut Scheduler, BlockedTask)) -> Self; fn to_fn(self) -> &fn(&mut Scheduler, BlockedTask); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index d297514835085..8cf864b9222ef 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -281,7 +281,7 @@ static UNWIND_TOKEN: uintptr_t = 839147; impl Unwinder { pub fn try(&mut self, f: &fn()) { - use sys::Closure; + use unstable::raw::Closure; unsafe { let closure: Closure = transmute(f); diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 636bbc48f8eb4..c600e7f6c0983 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -31,6 +31,7 @@ use ptr; use ptr::RawPtr; use to_str::ToStr; use uint; +use unstable::raw::Repr; use vec; use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector}; @@ -114,9 +115,9 @@ pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { unsafe { assert!(is_utf8(vector)); - let (ptr, len): (*u8, uint) = ::cast::transmute(vector); - let string: &'a str = ::cast::transmute((ptr, len + 1)); - string + let mut s = vector.repr(); + s.len += 1; + cast::transmute(s) } } @@ -142,7 +143,7 @@ impl ToStr for @str { */ pub fn from_byte(b: u8) -> ~str { assert!(b < 128u8); - unsafe { ::cast::transmute(~[b, 0u8]) } + unsafe { cast::transmute(~[b, 0u8]) } } /// Convert a char to a string @@ -217,7 +218,7 @@ impl<'self, S: Str> StrVector for &'self [S] { do s.as_mut_buf |buf, _| { do sep.as_imm_buf |sepbuf, seplen| { let seplen = seplen - 1; - let mut buf = ::cast::transmute_mut_unsafe(buf); + let mut buf = cast::transmute_mut_unsafe(buf); for self.iter().advance |ss| { do ss.as_slice().as_imm_buf |ssbuf, sslen| { let sslen = sslen - 1; @@ -771,10 +772,10 @@ pub mod raw { use cast; use libc; use ptr; - use str::raw; - use str::{is_utf8}; + use str::is_utf8; use vec; use vec::MutableVector; + use unstable::raw::{Slice, String}; /// Create a Rust string from a null-terminated *u8 buffer pub unsafe fn from_buf(buf: *u8) -> ~str { @@ -797,17 +798,17 @@ pub mod raw { v.push(0u8); assert!(is_utf8(v)); - return ::cast::transmute(v); + return cast::transmute(v); } /// Create a Rust string from a null-terminated C string pub unsafe fn from_c_str(c_str: *libc::c_char) -> ~str { - from_buf(::cast::transmute(c_str)) + from_buf(c_str as *u8) } /// Create a Rust string from a `*c_char` buffer of the given length pub unsafe fn from_c_str_len(c_str: *libc::c_char, len: uint) -> ~str { - from_buf_len(::cast::transmute(c_str), len) + from_buf_len(c_str as *u8, len) } /// Converts a vector of bytes to a new owned string. @@ -832,7 +833,7 @@ pub mod raw { } /// Converts a byte to a string. - pub unsafe fn from_byte(u: u8) -> ~str { raw::from_bytes([u]) } + pub unsafe fn from_byte(u: u8) -> ~str { from_bytes([u]) } /// Form a slice from a C string. Unsafe because the caller must ensure the /// C string has the static lifetime, or else the return value may be @@ -845,9 +846,9 @@ pub mod raw { len += 1u; curr = ptr::offset(s, len); } - let v = (s, len + 1); - assert!(is_utf8(::cast::transmute(v))); - ::cast::transmute(v) + let v = Slice { data: s, len: len + 1 }; + assert!(is_utf8(cast::transmute(v))); + cast::transmute(v) } /** @@ -866,8 +867,10 @@ pub mod raw { assert!((begin <= end)); assert!((end <= n)); - let tuple = (ptr::offset(sbuf, begin), end - begin + 1); - ::cast::transmute(tuple) + cast::transmute(Slice { + data: ptr::offset(sbuf, begin), + len: end - begin + 1, + }) } } @@ -909,11 +912,10 @@ pub mod raw { /// Sets the length of the string and adds the null terminator #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { - let v: **mut vec::UnboxedVecRepr = cast::transmute(v); - let repr: *mut vec::UnboxedVecRepr = *v; + let v: **mut String = cast::transmute(v); + let repr = *v; (*repr).fill = new_len + 1u; - let null = ptr::mut_offset(cast::transmute(&((*repr).data)), - new_len); + let null = ptr::mut_offset(&mut ((*repr).data), new_len); *null = 0u8; } @@ -1595,7 +1597,7 @@ impl<'self> StrSlice<'self> for &'self str { let v = at_vec::from_fn(self.len() + 1, |i| { if i == self.len() { 0 } else { self[i] } }); - unsafe { ::cast::transmute(v) } + unsafe { cast::transmute(v) } } /// Converts to a vector of `u16` encoded as UTF-16. @@ -1750,9 +1752,9 @@ impl<'self> StrSlice<'self> for &'self str { */ fn as_bytes(&self) -> &'self [u8] { unsafe { - let (ptr, len): (*u8, uint) = ::cast::transmute(*self); - let outgoing_tuple: (*u8, uint) = (ptr, len - 1); - ::cast::transmute(outgoing_tuple) + let mut slice = self.repr(); + slice.len -= 1; + cast::transmute(slice) } } @@ -2001,7 +2003,7 @@ impl NullTerminatedStr for ~str { */ #[inline] fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a ~[u8] = unsafe { ::cast::transmute(self) }; + let ptr: &'a ~[u8] = unsafe { cast::transmute(self) }; let slice: &'a [u8] = *ptr; slice } @@ -2014,7 +2016,7 @@ impl NullTerminatedStr for @str { */ #[inline] fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a @[u8] = unsafe { ::cast::transmute(self) }; + let ptr: &'a @[u8] = unsafe { cast::transmute(self) }; let slice: &'a [u8] = *ptr; slice } @@ -2058,7 +2060,7 @@ impl OwnedStr for ~str { do self.as_imm_buf |lbuf, _llen| { do rhs.as_imm_buf |rbuf, _rlen| { let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); + let dst = cast::transmute_mut_unsafe(dst); ptr::copy_memory(dst, rbuf, rlen); } } @@ -2076,7 +2078,7 @@ impl OwnedStr for ~str { do self.as_imm_buf |lbuf, _llen| { do rhs.as_imm_buf |rbuf, _rlen| { let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); + let dst = cast::transmute_mut_unsafe(dst); ptr::copy_memory(dst, rbuf, rlen); } } @@ -2232,7 +2234,7 @@ impl OwnedStr for ~str { /// string, and includes the null terminator. #[inline] fn to_bytes_with_null(self) -> ~[u8] { - unsafe { ::cast::transmute(self) } + unsafe { cast::transmute(self) } } #[inline] diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 28cd2345aab30..5cf77d901db4c 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -22,12 +22,6 @@ use str::StrSlice; use str; use unstable::intrinsics; -/// The representation of a Rust closure -pub struct Closure { - code: *(), - env: *(), -} - pub mod rustrt { use libc::{c_char, size_t}; @@ -278,6 +272,7 @@ mod tests { #[test] fn synthesize_closure() { + use unstable::raw::Closure; unsafe { let x = 10; let f: &fn(int) -> int = |y| x + y; diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index d5f4973e8c71a..477981c65e515 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -15,8 +15,8 @@ use libc; use local_data; use prelude::*; use ptr; -use sys; use task::rt; +use unstable::raw; use util; use super::rt::rust_task; @@ -158,7 +158,7 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { } unsafe fn key_to_key_value(key: local_data::Key) -> *libc::c_void { - let pair: sys::Closure = cast::transmute_copy(&key); + let pair: raw::Closure = cast::transmute_copy(&key); return pair.code as *libc::c_void; } diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index d6fd2cbcd1e4d..0d8cb1e8f743d 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -26,6 +26,7 @@ pub mod extfmt; pub mod lang; pub mod sync; pub mod atomics; +pub mod raw; /** diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs new file mode 100644 index 0000000000000..0e074b53d6b4b --- /dev/null +++ b/src/libstd/unstable/raw.rs @@ -0,0 +1,61 @@ +// Copyright 2013 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. + +use cast; +use unstable::intrinsics::TyDesc; + +/// The representation of a Rust managed box +pub struct Box { + ref_count: uint, + type_desc: *TyDesc, + prev: *Box, + next: *Box, + data: T +} + +/// The representation of a Rust vector +pub struct Vec { + fill: uint, + alloc: uint, + data: T +} + +/// The representation of a Rust string +pub type String = Vec; + +/// The representation of a Rust slice +pub struct Slice { + data: *T, + len: uint +} + +/// The representation of a Rust closure +pub struct Closure { + code: *(), + env: *(), +} + +/// This trait is meant to map equivalences between raw structs and their +/// corresponding rust values. +pub trait Repr { + /// This function "unwraps" a rust value (without consuming it) into its raw + /// struct representation. This can be used to read/write different values + /// for the struct. This is a safe method because by default it does not + /// give write-access to the struct returned. + fn repr(&self) -> T { unsafe { cast::transmute_copy(self) } } +} + +impl<'self, T> Repr> for &'self [T] {} +impl<'self> Repr> for &'self str {} +impl Repr<*Box> for @T {} +impl Repr<*Box>> for @[T] {} + +// sure would be nice to have this +// impl Repr<*Vec> for ~[T] {} diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 5f8a2796248ec..87ac4037e8ebe 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -12,7 +12,6 @@ #[warn(non_camel_case_types)]; -use cast::transmute; use cast; use clone::Clone; use container::{Container, Mutable}; @@ -32,6 +31,7 @@ use sys::size_of; use uint; use unstable::intrinsics; use unstable::intrinsics::{get_tydesc, contains_managed}; +use unstable::raw::{Box, Repr, Slice, Vec}; use vec; use util; @@ -96,7 +96,7 @@ pub fn with_capacity(capacity: uint) -> ~[T] { vec } else { let alloc = capacity * sys::nonzero_size_of::(); - let ptr = malloc_raw(alloc + sys::size_of::()) as *mut UnboxedVecRepr; + let ptr = malloc_raw(alloc + sys::size_of::>()) as *mut Vec<()>; (*ptr).alloc = alloc; (*ptr).fill = 0; cast::transmute(ptr) @@ -736,8 +736,10 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { assert!(end <= self.len()); do self.as_imm_buf |p, _len| { unsafe { - transmute((ptr::offset(p, start), - (end - start) * sys::nonzero_size_of::())) + cast::transmute(Slice { + data: ptr::offset(p, start), + len: (end - start) * sys::nonzero_size_of::(), + }) } } } @@ -767,8 +769,8 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { unsafe { let p = vec::raw::to_ptr(self); VecIterator{ptr: p, - end: cast::transmute(p as uint + self.len() * - sys::nonzero_size_of::()), + end: (p as uint + self.len() * + sys::nonzero_size_of::()) as *T, lifetime: cast::transmute(p)} } } @@ -947,8 +949,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// bounds checking. #[inline] unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) + self.repr().data.offset(index) } /** @@ -1002,11 +1003,8 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { // into `s` and pass them to `f()`, but in fact they are potentially // pointing at *mutable memory*. Use `as_mut_buf` instead! - unsafe { - let v : *(*T,uint) = transmute(self); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::()) - } + let s = self.repr(); + f(s.data, s.len / sys::nonzero_size_of::()) } } @@ -1158,17 +1156,17 @@ impl OwnedVector for ~[T] { unsafe { let td = get_tydesc::(); if contains_managed::() { - let ptr: *mut *mut raw::VecRepr = cast::transmute(self); + let ptr: *mut *mut Box> = cast::transmute(self); ::at_vec::raw::reserve_raw(td, ptr, n); } else { - let ptr: *mut *mut UnboxedVecRepr = cast::transmute(self); + let ptr: *mut *mut Vec<()> = cast::transmute(self); let alloc = n * sys::nonzero_size_of::(); - let size = alloc + sys::size_of::(); + let size = alloc + sys::size_of::>(); if alloc / sys::nonzero_size_of::() != n || size < alloc { fail!("vector size is too large: %u", n); } *ptr = realloc_raw(*ptr as *mut c_void, size) - as *mut UnboxedVecRepr; + as *mut Vec<()>; (**ptr).alloc = alloc; } } @@ -1198,10 +1196,10 @@ impl OwnedVector for ~[T] { fn capacity(&self) -> uint { unsafe { if contains_managed::() { - let repr: **raw::VecRepr = transmute(self); - (**repr).unboxed.alloc / sys::nonzero_size_of::() + let repr: **Box> = cast::transmute(self); + (**repr).data.alloc / sys::nonzero_size_of::() } else { - let repr: **UnboxedVecRepr = transmute(self); + let repr: **Vec<()> = cast::transmute(self); (**repr).alloc / sys::nonzero_size_of::() } } @@ -1212,16 +1210,16 @@ impl OwnedVector for ~[T] { fn push(&mut self, t: T) { unsafe { if contains_managed::() { - let repr: **raw::VecRepr = transmute(&mut *self); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc <= fill { + let repr: **Box> = cast::transmute(&mut *self); + let fill = (**repr).data.fill; + if (**repr).data.alloc <= fill { let new_len = self.len() + 1; self.reserve_at_least(new_len); } self.push_fast(t); } else { - let repr: **UnboxedVecRepr = transmute(&mut *self); + let repr: **Vec<()> = cast::transmute(&mut *self); let fill = (**repr).fill; if (**repr).alloc <= fill { let new_len = self.len() + 1; @@ -1237,14 +1235,14 @@ impl OwnedVector for ~[T] { #[inline] // really pretty please unsafe fn push_fast(&mut self, t: T) { if contains_managed::() { - let repr: **mut raw::VecRepr = transmute(self); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::nonzero_size_of::(); - let p = to_unsafe_ptr(&((**repr).unboxed.data)); + let repr: **mut Box> = cast::transmute(self); + let fill = (**repr).data.fill; + (**repr).data.fill += sys::nonzero_size_of::(); + let p = to_unsafe_ptr(&((**repr).data.data)); let p = ptr::offset(p, fill) as *mut T; intrinsics::move_val_init(&mut(*p), t); } else { - let repr: **mut UnboxedVecRepr = transmute(self); + let repr: **mut Vec = cast::transmute(self); let fill = (**repr).fill; (**repr).fill += sys::nonzero_size_of::(); let p = to_unsafe_ptr(&((**repr).data)); @@ -1338,14 +1336,14 @@ impl OwnedVector for ~[T] { { let first_slice = self.slice(0, 1); let last_slice = self.slice(next_ln, ln); - raw::copy_memory(transmute(last_slice), first_slice, 1); + raw::copy_memory(cast::transmute(last_slice), first_slice, 1); } // Memcopy everything to the left one element { let init_slice = self.slice(0, next_ln); let tail_slice = self.slice(1, ln); - raw::copy_memory(transmute(init_slice), + raw::copy_memory(cast::transmute(init_slice), tail_slice, next_ln); } @@ -1689,8 +1687,8 @@ pub trait MutableVector<'self, T> { */ fn move_from(self, src: ~[T], start: uint, end: uint) -> uint; - unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T; - unsafe fn unsafe_set(&self, index: uint, val: T); + unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T; + unsafe fn unsafe_set(self, index: uint, val: T); fn as_mut_buf(self, f: &fn(*mut T, uint) -> U) -> U; } @@ -1703,8 +1701,10 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { assert!(end <= self.len()); do self.as_mut_buf |p, _len| { unsafe { - transmute((ptr::mut_offset(p, start), - (end - start) * sys::nonzero_size_of::())) + cast::transmute(Slice { + data: ptr::mut_offset(p, start) as *T, + len: (end - start) * sys::nonzero_size_of::() + }) } } } @@ -1723,8 +1723,8 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { unsafe { let p = vec::raw::to_mut_ptr(self); VecMutIterator{ptr: p, - end: cast::transmute(p as uint + self.len() * - sys::nonzero_size_of::()), + end: (p as uint + self.len() * + sys::nonzero_size_of::()) as *mut T, lifetime: cast::transmute(p)} } } @@ -1771,22 +1771,20 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } #[inline] - unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { - let pair_ptr: &(*mut T, uint) = transmute(self); - let (ptr, _) = *pair_ptr; - ptr.offset(index) + unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T { + ptr::mut_offset(self.repr().data as *mut T, index) } #[inline] - unsafe fn unsafe_set(&self, index: uint, val: T) { + unsafe fn unsafe_set(self, index: uint, val: T) { *self.unsafe_mut_ref(index) = val; } /// Similar to `as_imm_buf` but passing a `*mut T` #[inline] fn as_mut_buf(self, f: &fn(*mut T, uint) -> U) -> U { - let (buf, len): (*mut T, uint) = unsafe { transmute(self) }; - f(buf, len / sys::nonzero_size_of::()) + let Slice{ data, len } = self.repr(); + f(data as *mut T, len / sys::nonzero_size_of::()) } } @@ -1821,40 +1819,17 @@ pub unsafe fn from_buf(ptr: *T, elts: uint) -> ~[T] { raw::from_buf_raw(ptr, elts) } -/// The internal 'unboxed' representation of a vector -#[allow(missing_doc)] -pub struct UnboxedVecRepr { - fill: uint, - alloc: uint, - data: u8 -} - /// Unsafe operations pub mod raw { - use cast::transmute; + use cast; use clone::Clone; - use managed; use option::Some; use ptr; use sys; use unstable::intrinsics; - use vec::{UnboxedVecRepr, with_capacity, ImmutableVector, MutableVector}; + use vec::{with_capacity, ImmutableVector, MutableVector}; use unstable::intrinsics::contains_managed; - - /// The internal representation of a (boxed) vector - #[allow(missing_doc)] - pub struct VecRepr { - box_header: managed::raw::BoxHeaderRepr, - unboxed: UnboxedVecRepr - } - - /// The internal representation of a slice - pub struct SliceRepr { - /// Pointer to the base of this slice - data: *u8, - /// The length of the slice - len: uint - } + use unstable::raw::{Box, Vec, Slice}; /** * Sets the length of a vector @@ -1866,10 +1841,10 @@ pub mod raw { #[inline] pub unsafe fn set_len(v: &mut ~[T], new_len: uint) { if contains_managed::() { - let repr: **mut VecRepr = transmute(v); - (**repr).unboxed.fill = new_len * sys::nonzero_size_of::(); + let repr: **mut Box> = cast::transmute(v); + (**repr).data.fill = new_len * sys::nonzero_size_of::(); } else { - let repr: **mut UnboxedVecRepr = transmute(v); + let repr: **mut Vec<()> = cast::transmute(v); (**repr).fill = new_len * sys::nonzero_size_of::(); } } @@ -1885,19 +1860,13 @@ pub mod raw { */ #[inline] pub fn to_ptr(v: &[T]) -> *T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } + v.repr().data } /** see `to_ptr()` */ #[inline] pub fn to_mut_ptr(v: &mut [T]) -> *mut T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } + v.repr().data as *mut T } /** @@ -1908,9 +1877,10 @@ pub mod raw { pub unsafe fn buf_as_slice(p: *T, len: uint, f: &fn(v: &[T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::()); - let v : *(&'blk [T]) = transmute(&pair); - f(*v) + f(cast::transmute(Slice { + data: p, + len: len * sys::nonzero_size_of::() + })) } /** @@ -1921,9 +1891,10 @@ pub mod raw { pub unsafe fn mut_buf_as_slice(p: *mut T, len: uint, f: &fn(v: &mut [T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::()); - let v : *(&'blk mut [T]) = transmute(&pair); - f(*v) + f(cast::transmute(Slice { + data: p as *T, + len: len * sys::nonzero_size_of::() + })) } /** diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 21d13c722e752..e91537bec3b19 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -14,8 +14,8 @@ use std::int; use std::libc::c_void; use std::ptr; use std::sys; -use std::vec::UnboxedVecRepr; use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; +use std::unstable::raw::Vec; #[doc = "High-level interfaces to `std::unstable::intrinsics::visit_ty` reflection system."] @@ -247,7 +247,7 @@ impl TyVisitor for ptr_visit_adaptor { } fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::(); + self.align_to::>(); // FIXME (#3732): Inner really has to move its own pointers on this one. // or else possibly we could have some weird interface wherein we // read-off a word from inner's pointers, but the read-word has to