From 89946609f2de815ea87df3b001fff0caf9efa0d5 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 9 Nov 2010 14:15:07 -0800 Subject: [PATCH] Support a special const-value refcount, use it for const strings. --- src/boot/be/abi.ml | 3 ++ src/boot/me/trans.ml | 56 ++++++++++++++++++++------- src/lib/_str.rs | 9 ++++- src/lib/_vec.rs | 9 ++++- src/lib/dbg.rs | 3 ++ src/rt/rust_builtin.cpp | 12 ++++-- src/rt/rust_internal.h | 7 ++++ src/rt/rust_upcall.cpp | 5 ++- src/test/run-pass/alt-pattern-drop.rs | 8 +++- src/test/run-pass/vec-append.rs | 15 ++++--- 10 files changed, 97 insertions(+), 30 deletions(-) diff --git a/src/boot/be/abi.ml b/src/boot/be/abi.ml index 13df33cdb07..9f2e819cd4c 100644 --- a/src/boot/be/abi.ml +++ b/src/boot/be/abi.ml @@ -12,6 +12,9 @@ let rc_base_field_refcnt = 0;; +(* FIXME: this needs updating if you ever want to work on 64 bit. *) +let const_refcount = 0x7badfaceL;; + let task_field_refcnt = rc_base_field_refcnt;; let task_field_stk = task_field_refcnt + 2;; let task_field_runtime_sp = task_field_stk + 1;; diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml index 051050bb4f2..686e7417a0b 100644 --- a/src/boot/me/trans.ml +++ b/src/boot/me/trans.ml @@ -1531,13 +1531,32 @@ let trans_visitor if not init then drop_ty_in_current_frame cell ty - and trans_new_str (initializing:bool) (dst:Ast.lval) (s:string) : unit = + and trans_new_str + (initializing:bool) + (dst:Ast.lval) + (s:string) + (id:node_id) + : unit = (* Include null byte. *) let init_sz = Int64.of_int ((String.length s) + 1) in - let static = trans_static_string s in let (dst_cell, dst_ty) = trans_lval_maybe_init initializing dst in drop_existing_if_not_init initializing dst_cell dst_ty; - trans_upcall "upcall_new_str" dst_cell [| static; imm init_sz |] + let ptr = + crate_rel_to_ptr + (trans_crate_rel_data_operand + (DATA_const id) + (fun _ -> + Asm.SEQ + [| + Asm.WORD (word_ty_signed_mach, + Asm.IMM Abi.const_refcount); + Asm.WORD (word_ty_mach, Asm.IMM init_sz); + Asm.WORD (word_ty_mach, Asm.IMM init_sz); + Asm.ZSTRING s + |])) + (referent_type cx Ast.TY_str) + in + mov dst_cell (Il.Cell ptr); and trans_lit (lit:Ast.lit) : Il.operand = match lit with @@ -3185,7 +3204,7 @@ let trans_visitor in let _ = check_box_rty box_ptr in let null_jmp = null_check box_ptr in - let rc_jmp = drop_refcount_and_cmp box_ptr in + let rc_jmps = drop_refcount_and_cmp box_ptr in let box = deref box_ptr in let body = get_element_ptr box Abi.box_rc_field_body in let tydesc = get_element_ptr body Abi.obj_body_elt_tydesc in @@ -3230,7 +3249,7 @@ let trans_visitor note_drop_step ty "drop_ty: freeing obj/fn body"; trans_free box_ptr (type_has_state cx ty); mov box_ptr zero; - patch rc_jmp; + List.iter patch rc_jmps; patch null_jmp; note_drop_step ty "drop_ty: done obj path"; @@ -3262,7 +3281,7 @@ let trans_visitor let _ = check_box_rty cell in let null_jmp = null_check cell in - let j = drop_refcount_and_cmp cell in + let js = drop_refcount_and_cmp cell in (* FIXME (issue #25): check to see that the box has * further box members; if it doesn't we can elide the @@ -3277,7 +3296,7 @@ let trans_visitor (* Null the slot out to prevent double-free if the frame * unwinds. *) mov cell zero; - patch j; + List.iter patch js; patch null_jmp; note_drop_step ty "drop_ty: done box-drop path"; @@ -3525,7 +3544,7 @@ let trans_visitor (* Returns a mark for a jmp that must be patched to the continuation of * the non-zero refcount case (i.e. fall-through means zero refcount). *) - and drop_refcount_and_cmp (boxed:Il.cell) : quad_idx = + and drop_refcount_and_cmp (boxed:Il.cell) : quad_idx list = in_quad_category "refcount" begin fun _ -> @@ -3539,11 +3558,14 @@ let trans_visitor trace_word true boxed; trace_word true rc end; - emit (Il.binary Il.SUB rc (Il.Cell rc) one); - emit (Il.cmp (Il.Cell rc) zero); - let j = mark () in - emit (Il.jmp Il.JNE Il.CodeNone); - j + emit (Il.cmp (Il.Cell rc) (simm Abi.const_refcount)); + let j0 = mark() in + emit (Il.jmp Il.JE Il.CodeNone); + emit (Il.binary Il.SUB rc (Il.Cell rc) one); + emit (Il.cmp (Il.Cell rc) zero); + let j1 = mark () in + emit (Il.jmp Il.JNE Il.CodeNone); + [j0; j1] end and incr_refcount (boxed:Il.cell) : unit = @@ -3559,7 +3581,11 @@ let trans_visitor trace_word true boxed; trace_word true rc end; - add_to rc one + emit (Il.cmp (Il.Cell rc) (simm Abi.const_refcount)); + let j = mark() in + emit (Il.jmp Il.JE Il.CodeNone); + add_to rc one; + patch j; end and drop_slot @@ -5316,7 +5342,7 @@ let trans_visitor | Ast.STMT_new_str (dst, s) -> let init = maybe_init stmt.id "new str" dst in - trans_new_str init dst s + trans_new_str init dst s stmt.id | Ast.STMT_new_vec (dst, _, atoms) -> let init = maybe_init stmt.id "new vec" dst in diff --git a/src/lib/_str.rs b/src/lib/_str.rs index 0fc7b373950..4ea5ca2844f 100644 --- a/src/lib/_str.rs +++ b/src/lib/_str.rs @@ -97,8 +97,13 @@ fn from_bytes(vec[u8] v) : is_utf8(v) -> str { } fn refcount(str s) -> uint { - // -1 because calling this function incremented the refcount. - ret rustrt.refcount[u8](s) - 1u; + auto r = rustrt.refcount[u8](s); + if (r == dbg.const_refcount) { + ret r; + } else { + // -1 because calling this function incremented the refcount. + ret r - 1u; + } } diff --git a/src/lib/_vec.rs b/src/lib/_vec.rs index c2ca95fcb67..6fa0ed425ac 100644 --- a/src/lib/_vec.rs +++ b/src/lib/_vec.rs @@ -30,8 +30,13 @@ fn alloc[T](uint n_elts) -> vec[T] { } fn refcount[T](vec[T] v) -> uint { - // -1 because calling this function incremented the refcount. - ret rustrt.refcount[T](v) - 1u; + auto r = rustrt.refcount[T](v); + if (r == dbg.const_refcount) { + ret r; + } else { + // -1 because calling this function incremented the refcount. + ret r - 1u; + } } type init_op[T] = fn(uint i) -> T; diff --git a/src/lib/dbg.rs b/src/lib/dbg.rs index 6c856cf7983..51a31e07d13 100644 --- a/src/lib/dbg.rs +++ b/src/lib/dbg.rs @@ -7,6 +7,9 @@ import std._vec; +// FIXME: handle 64-bit case. +const uint const_refcount = 0x7bad_face_u; + native "rust" mod rustrt { fn debug_tydesc[T](); fn debug_opaque[T](&T x); diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index d221e6e587b..cb16fbf067d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -61,8 +61,12 @@ align_of(rust_task *task, type_desc *t) { return t->align; } -extern "C" CDECL size_t -refcount(rust_task *task, type_desc *t, size_t *v) { +extern "C" CDECL intptr_t +refcount(rust_task *task, type_desc *t, intptr_t *v) { + + if (*v == CONST_REFCOUNT) + return CONST_REFCOUNT; + // Passed-in value has refcount 1 too high // because it was ref'ed while making the call. return (*v) - 1; @@ -277,7 +281,9 @@ debug_box(rust_task *task, type_desc *t, rust_box *box) task->log(rust_log::STDLIB, "debug_box(0x%" PRIxPTR ")", box); debug_tydesc_helper(task, t); task->log(rust_log::STDLIB, " refcount %" PRIdPTR, - box->ref_count - 1); // -1 because we ref'ed for this call + box->ref_count == CONST_REFCOUNT + ? CONST_REFCOUNT + : box->ref_count - 1); // -1 because we ref'ed for this call for (uintptr_t i = 0; i < t->size; ++i) { task->log(rust_log::STDLIB, " byte %" PRIdPTR ": 0x%" PRIx8, i, box->data[i]); diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index d1eec48bc3b..f008d9f6bdb 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -81,6 +81,13 @@ struct frame_glue_fns; static size_t const TIME_SLICE_IN_MS = 10; +// Since every refcounted object is > 4 bytes, any refcount with any of the +// top two bits set is invalid. We reserve a particular bit pattern in this +// set for indicating objects that are "constant" as far as the memory model +// knows. + +static intptr_t const CONST_REFCOUNT = 0x7badface; + // Every reference counted object should derive from this base class. template struct rc_base { diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 9742b22af78..ebf81faf3ac 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -424,7 +424,10 @@ upcall_vec_grow(rust_task *task, task->fail(4); return NULL; } - v->deref(); + + if (v->ref_count != CONST_REFCOUNT) + v->deref(); + v = new (mem) rust_vec(dom, alloc, 0, NULL); *need_copy = 1; } diff --git a/src/test/run-pass/alt-pattern-drop.rs b/src/test/run-pass/alt-pattern-drop.rs index 1c9cc000dbc..4ee2c12bec2 100644 --- a/src/test/run-pass/alt-pattern-drop.rs +++ b/src/test/run-pass/alt-pattern-drop.rs @@ -3,6 +3,10 @@ use std; import std._str; +// FIXME: import std.dbg.const_refcount. Currently +// cross-crate const references don't work. +const uint const_refcount = 0x7bad_face_u; + tag t { make_t(str); clam; @@ -17,12 +21,12 @@ fn foo(str s) { } log _str.refcount(s); - check (_str.refcount(s) == 3u); + check (_str.refcount(s) == const_refcount); } fn main() { let str s = "hi"; // ref up foo(s); // ref up then down log _str.refcount(s); - check (_str.refcount(s) == 1u); + check (_str.refcount(s) == const_refcount); } diff --git a/src/test/run-pass/vec-append.rs b/src/test/run-pass/vec-append.rs index 5b0a92ae358..ca906e5568e 100644 --- a/src/test/run-pass/vec-append.rs +++ b/src/test/run-pass/vec-append.rs @@ -4,6 +4,11 @@ use std; import std._str; import std._vec; + +// FIXME: import std.dbg.const_refcount. Currently +// cross-crate const references don't work. +const uint const_refcount = 0x7bad_face_u; + fn fast_growth() { let vec[int] v = vec(1,2,3,4,5); v += vec(6,7,8,9,0); @@ -55,8 +60,8 @@ fn slow_growth2_helper(str s) { // ref up: s log _str.refcount(mumble); check (_vec.refcount[str](v) == 1u); - check (_str.refcount(s) == 4u); - check (_str.refcount(mumble) == 3u); + check (_str.refcount(s) == const_refcount); + check (_str.refcount(mumble) == const_refcount); log v.(0); log _vec.len[str](v); @@ -67,8 +72,8 @@ fn slow_growth2_helper(str s) { // ref up: s log _str.refcount(s); log _str.refcount(mumble); - check (_str.refcount(s) == 3u); - check (_str.refcount(mumble) == 1u); + check (_str.refcount(s) == const_refcount); + check (_str.refcount(mumble) == const_refcount); log mumble; log ss; @@ -78,7 +83,7 @@ fn slow_growth2() { let str s = "hi"; // ref up: s slow_growth2_helper(s); log _str.refcount(s); - check (_str.refcount(s) == 1u); + check (_str.refcount(s) == const_refcount); } fn main() {