about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2010-11-09 14:15:07 -0800
committerGraydon Hoare <graydon@mozilla.com>2010-11-09 14:15:07 -0800
commit89946609f2de815ea87df3b001fff0caf9efa0d5 (patch)
tree0945861dddd480b822827d77205f90584d0c2586 /src
parent3e9be14757bfcaa65e388a9acd7e2ca97cccfbd0 (diff)
Support a special const-value refcount, use it for const strings.
Diffstat (limited to 'src')
-rw-r--r--src/boot/be/abi.ml3
-rw-r--r--src/boot/me/trans.ml56
-rw-r--r--src/lib/_str.rs9
-rw-r--r--src/lib/_vec.rs9
-rw-r--r--src/lib/dbg.rs3
-rw-r--r--src/rt/rust_builtin.cpp12
-rw-r--r--src/rt/rust_internal.h7
-rw-r--r--src/rt/rust_upcall.cpp5
-rw-r--r--src/test/run-pass/alt-pattern-drop.rs8
-rw-r--r--src/test/run-pass/vec-append.rs15
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 <typename T> 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() {