aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile23
-rw-r--r--src/boot/be/abi.ml5
-rw-r--r--src/boot/be/il.ml11
-rw-r--r--src/boot/be/x86.ml122
-rw-r--r--src/boot/fe/ast.ml45
-rw-r--r--src/boot/fe/item.ml5
-rw-r--r--src/boot/fe/pexp.ml79
-rw-r--r--src/boot/llvm/lltrans.ml39
-rw-r--r--src/boot/me/alias.ml2
-rw-r--r--src/boot/me/dwarf.ml4
-rw-r--r--src/boot/me/effect.ml2
-rw-r--r--src/boot/me/layout.ml10
-rw-r--r--src/boot/me/semant.ml69
-rw-r--r--src/boot/me/trans.ml247
-rw-r--r--src/boot/me/type.ml11
-rw-r--r--src/boot/me/typestate.ml4
-rw-r--r--src/boot/me/walk.ml2
-rw-r--r--src/etc/x86.supp12
-rw-r--r--src/lib/_int.rs44
-rw-r--r--src/lib/_io.rs23
-rw-r--r--src/lib/_str.rs29
-rw-r--r--src/lib/deque.rs22
-rw-r--r--src/lib/map.rs12
-rw-r--r--src/rt/circular_buffer.cpp4
-rw-r--r--src/rt/globals.h2
-rw-r--r--src/rt/rust.cpp10
-rw-r--r--src/rt/rust_builtin.cpp6
-rw-r--r--src/rt/rust_chan.cpp27
-rw-r--r--src/rt/rust_chan.h2
-rw-r--r--src/rt/rust_dom.cpp127
-rw-r--r--src/rt/rust_dom.h9
-rw-r--r--src/rt/rust_internal.h4
-rw-r--r--src/rt/rust_log.cpp1
-rw-r--r--src/rt/rust_message.cpp3
-rw-r--r--src/rt/rust_port.cpp40
-rw-r--r--src/rt/rust_port.h2
-rw-r--r--src/rt/rust_task.cpp56
-rw-r--r--src/rt/rust_task.h5
-rw-r--r--src/rt/rust_upcall.cpp142
-rw-r--r--src/rt/rust_util.h26
-rw-r--r--src/rt/sync/condition_variable.cpp28
-rw-r--r--src/rt/sync/condition_variable.h1
-rw-r--r--src/rt/sync/sync.cpp12
-rw-r--r--src/rt/sync/sync.h9
-rw-r--r--src/rt/util/array_list.h10
-rw-r--r--src/run.py81
-rw-r--r--src/test/run-pass/arith-0.rs5
-rw-r--r--src/test/run-pass/arith-1.rs22
-rw-r--r--src/test/run-pass/arith-2.rs5
-rw-r--r--src/test/run-pass/basic-1.rs25
-rw-r--r--src/test/run-pass/basic-2.rs26
-rw-r--r--src/test/run-pass/destructor-ordering.rs117
-rw-r--r--src/test/run-pass/int-lib.rs15
-rw-r--r--src/test/run-pass/integral-indexing.rs22
-rw-r--r--src/test/run-pass/lib-map.rs6
-rw-r--r--src/test/run-pass/str-lib.rs16
-rw-r--r--src/test/run-pass/task-comm-0.rs2
-rw-r--r--src/test/run-pass/task-comm-2.rs8
-rw-r--r--src/test/run-pass/task-comm-3.rs19
-rw-r--r--src/test/run-pass/task-comm-6.rs6
-rw-r--r--src/test/run-pass/task-comm.rs18
61 files changed, 1253 insertions, 488 deletions
diff --git a/src/Makefile b/src/Makefile
index 7236e02f..496457bb 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -245,7 +245,8 @@ BOOT_CMXS := $(BOOT_MLS:.ml=.cmx)
BOOT_OBJS := $(BOOT_MLS:.ml=.o)
BOOT_CMIS := $(BOOT_MLS:.ml=.cmi)
-RUNTIME_CS := rt/sync/spin_lock.cpp \
+RUNTIME_CS := rt/sync/sync.cpp \
+ rt/sync/spin_lock.cpp \
rt/sync/lock_free_queue.cpp \
rt/sync/condition_variable.cpp \
rt/rust.cpp \
@@ -279,7 +280,8 @@ RUNTIME_HDR := rt/globals.h \
rt/rust_message.h \
rt/circular_buffer.h \
rt/util/array_list.h \
- rt/util/hash_map.h
+ rt/util/hash_map.h \
+ rt/sync/sync.h
RUNTIME_INCS := -Irt/isaac -Irt/uthash
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=$(CFG_OBJ_SUFFIX))
@@ -383,17 +385,22 @@ TASK_XFAILS := test/run-pass/acyclic-unwind.rs \
test/run-pass/threads.rs \
test/run-pass/yield.rs
+TEST_XFAILS := test/run-pass/arith-0.rs
+
TEST_XFAILS_X86 := $(TASK_XFAILS) \
+ $(TEST_XFAILS) \
test/run-pass/arithmetic-interference.rs \
test/run-pass/bind-obj-ctor.rs \
test/run-pass/child-outlives-parent.rs \
test/run-pass/clone-with-exterior.rs \
test/run-pass/constrained-type.rs \
+ test/run-pass/destructor-ordering.rs \
test/run-pass/obj-as.rs \
test/run-pass/vec-slice.rs \
test/run-pass/fn-lval.rs \
test/run-pass/generic-fn-infer.rs \
test/run-pass/generic-recursive-tag.rs \
+ test/run-pass/int-lib.rs \
test/run-pass/iter-ret.rs \
test/run-pass/lib-deque.rs \
test/run-pass/lib-map.rs \
@@ -412,16 +419,19 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
test/compile-fail/writing-through-read-alias.rs
TEST_XFAILS_LLVM := $(TASK_XFAILS) \
+ $(TEST_XFAILS) \
$(addprefix test/run-pass/, \
+ arith-1.rs \
acyclic-unwind.rs \
alt-pattern-simple.rs \
alt-tag.rs \
arithmetic-interference.rs \
argv.rs \
- auto-deref.rs \
autoderef-full-lval.rs \
autoderef-objfn.rs \
basic.rs \
+ basic-1.rs \
+ basic-2.rs \
bind-obj-ctor.rs \
bind-thunk.rs \
bind-trivial.rs \
@@ -452,7 +462,6 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
generic-drop-glue.rs \
generic-exterior-box.rs \
generic-fn-infer.rs \
- generic-fn-twice.rs \
generic-fn.rs \
generic-obj-with-derived-type.rs \
generic-obj.rs \
@@ -463,7 +472,8 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
i32-sub.rs \
i8-incr.rs \
import.rs \
- inner-module.rs \
+ integral-indexing.rs \
+ int-lib.rs \
iter-range.rs \
iter-ret.rs \
large-records.rs \
@@ -481,8 +491,6 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
mutable-alias-vec.rs \
mutable-vec-drop.rs \
mutual-recursion-group.rs \
- native-mod.rc \
- native.rc \
obj-as.rs \
obj-drop.rs \
obj-dtor.rs \
@@ -506,6 +514,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
str-append.rs \
str-concat.rs \
str-idx.rs \
+ str-lib.rs \
tag.rs \
tail-cps.rs \
tail-direct.rs \
diff --git a/src/boot/be/abi.ml b/src/boot/be/abi.ml
index 347d49fc..5bdf21fa 100644
--- a/src/boot/be/abi.ml
+++ b/src/boot/be/abi.ml
@@ -41,7 +41,7 @@ let box_gc_header_size = 4;;
let box_gc_malloc_return_adjustment = 3;;
-let stk_field_valgrind_id = 0 + 1;;
+let stk_field_valgrind_id = 0;;
let stk_field_limit = stk_field_valgrind_id + 1;;
let stk_field_data = stk_field_limit + 1;;
@@ -121,7 +121,8 @@ type abi =
-> Common.size (* callsz *)
-> Common.nabi
-> Common.fixup (* grow_task *)
- -> unit);
+ -> bool (* is_obj_fn *)
+ -> unit);
abi_emit_fn_epilogue: (Il.emitter -> unit);
diff --git a/src/boot/be/il.ml b/src/boot/be/il.ml
index 792e83e2..2a5b643a 100644
--- a/src/boot/be/il.ml
+++ b/src/boot/be/il.ml
@@ -695,7 +695,7 @@ type emitter = { mutable emit_pc: int;
emit_target_specific: (emitter -> quad -> unit);
mutable emit_quads: quads;
emit_annotations: (int,string) Hashtbl.t;
- emit_size_cache: ((size,operand) Hashtbl.t) Stack.t;
+ emit_size_cache: (size,operand) Hashtbl.t;
emit_node: node_id option;
}
@@ -722,7 +722,7 @@ let new_emitter
emit_target_specific = emit_target_specific;
emit_quads = Array.create 4 badq;
emit_annotations = Hashtbl.create 0;
- emit_size_cache = Stack.create ();
+ emit_size_cache = Hashtbl.create 0;
emit_node = node;
}
;;
@@ -901,6 +901,13 @@ let get_element_ptr
(string_of_cell fmt mem_cell)
;;
+let ptr_cast (cell:cell) (rty:referent_ty) : cell =
+ match cell with
+ Mem (mem, _) -> Mem (mem, rty)
+ | Reg (reg, AddrTy _) -> Reg (reg, AddrTy rty)
+ | _ -> bug () "expected address cell in Il.ptr_cast"
+;;
+
(*
* Local Variables:
* fill-column: 78;
diff --git a/src/boot/be/x86.ml b/src/boot/be/x86.ml
index 217149c7..826127a0 100644
--- a/src/boot/be/x86.ml
+++ b/src/boot/be/x86.ml
@@ -302,11 +302,41 @@ let emit_target_specific
| Il.IMOD | Il.UMOD ->
let dst_eax = hr_like_cell eax dst in
let lhs_eax = hr_like_op eax lhs in
- let rhs_ecx = hr_like_op ecx lhs in
- if lhs <> (Il.Cell lhs_eax)
- then mov lhs_eax lhs;
- if rhs <> (Il.Cell rhs_ecx)
- then mov rhs_ecx rhs;
+ let rhs_ecx = hr_like_op ecx rhs in
+ (* Horrible: we bounce complex mul inputs off spill slots
+ * to ensure non-interference between the temporaries used
+ * during mem-base-reg reloads and the registers we're
+ * preparing. *)
+ let next_spill_like op =
+ Il.Mem (Il.next_spill_slot e
+ (Il.ScalarTy (Il.operand_scalar_ty op)))
+ in
+ let is_mem op =
+ match op with
+ Il.Cell (Il.Mem _) -> true
+ | _ -> false
+ in
+ let bounce_lhs = is_mem lhs in
+ let bounce_rhs = is_mem rhs in
+ let lhs_spill = next_spill_like lhs in
+ let rhs_spill = next_spill_like rhs in
+
+ if bounce_lhs
+ then mov lhs_spill lhs;
+
+ if bounce_rhs
+ then mov rhs_spill rhs;
+
+ mov lhs_eax
+ (if bounce_lhs
+ then (Il.Cell lhs_spill)
+ else lhs);
+
+ mov rhs_ecx
+ (if bounce_rhs
+ then (Il.Cell rhs_spill)
+ else rhs);
+
put (Il.Binary
{ b with
Il.binary_lhs = (Il.Cell lhs_eax);
@@ -314,7 +344,7 @@ let emit_target_specific
Il.binary_dst = dst_eax; });
if dst <> dst_eax
then mov dst (Il.Cell dst_eax);
-
+
| _ when (Il.Cell dst) <> lhs ->
mov dst lhs;
put (Il.Binary
@@ -563,6 +593,7 @@ let restore_frame_base (e:Il.emitter) (base:Il.reg) (retpc:Il.reg) : unit =
*
* *ebp+20+(4*N) = [argN ]
* ...
+ * *ebp+28 = [arg2 ] = obj/closure ptr
* *ebp+24 = [arg1 ] = task ptr
* *ebp+20 = [arg0 ] = out ptr
* *ebp+16 = [retpc ]
@@ -1003,7 +1034,7 @@ let unwind_glue
(* Puts result in eax; clobbers ecx, edx in the process. *)
-let rec calculate_sz (e:Il.emitter) (size:size) : unit =
+let rec calculate_sz (e:Il.emitter) (size:size) (in_obj:bool) : unit =
let emit = Il.emit e in
let mov dst src = emit (Il.umov dst src) in
let push x = emit (Il.Push x) in
@@ -1015,11 +1046,48 @@ let rec calculate_sz (e:Il.emitter) (size:size) : unit =
let mul x y = emit (Il.binary Il.UMUL (rc x) (ro x) (ro y)) in
let subi x y = emit (Il.binary Il.SUB (rc x) (ro x) (immi y)) in
let eax_gets_a_and_ecx_gets_b a b =
- calculate_sz e b;
+ calculate_sz e b in_obj;
push (ro eax);
- calculate_sz e a;
+ calculate_sz e a in_obj;
pop (rc ecx);
in
+
+ let ty_param_n_in_obj_fn i =
+ (*
+ * Here we are trying to immitate the obj-fn branch of
+ * Trans.get_ty_params_of_current_frame while using
+ * eax as our only register.
+ *)
+
+ (* Bind all the referent types we'll need... *)
+
+ let obj_body_rty = Semant.obj_closure_rty word_bits in
+ let tydesc_rty = Semant.tydesc_rty word_bits in
+ (* Note that we cheat here and pretend only to have i+1 tydescs (because
+ we GEP to the i'th while still in this function, so no one outside
+ finds out about the lie. *)
+ let tydesc_tys = Array.init (i + 1) (fun _ -> Ast.TY_type) in
+ let ty_params_ty = Ast.TY_tup tydesc_tys in
+ let ty_params_rty = Semant.referent_type word_bits ty_params_ty in
+
+ (* ... and fetch! *)
+
+ mov (rc eax) (Il.Cell closure_ptr);
+ let obj_body = word_n (h eax) Abi.box_rc_field_body in
+ let obj_body = Il.ptr_cast obj_body obj_body_rty in
+ let tydesc_ptr = get_element_ptr obj_body Abi.obj_body_elt_tydesc in
+
+ mov (rc eax) (Il.Cell tydesc_ptr);
+ let tydesc = Il.ptr_cast (word_at (h eax)) tydesc_rty in
+ let ty_params_ptr =
+ get_element_ptr tydesc Abi.tydesc_field_first_param
+ in
+
+ mov (rc eax) (Il.Cell ty_params_ptr);
+ let ty_params = Il.ptr_cast (word_at (h eax)) ty_params_rty in
+ get_element_ptr ty_params i
+ in
+
match size with
SIZE_fixed i ->
mov (rc eax) (immi i)
@@ -1031,15 +1099,23 @@ let rec calculate_sz (e:Il.emitter) (size:size) : unit =
mov (rc eax) (imm (Asm.M_POS f))
| SIZE_param_size i ->
- mov (rc eax) (Il.Cell (ty_param_n i));
+ if in_obj
+ then
+ mov (rc eax) (Il.Cell (ty_param_n_in_obj_fn i))
+ else
+ mov (rc eax) (Il.Cell (ty_param_n i));
mov (rc eax) (Il.Cell (word_n (h eax) Abi.tydesc_field_size))
| SIZE_param_align i ->
- mov (rc eax) (Il.Cell (ty_param_n i));
+ if in_obj
+ then
+ mov (rc eax) (Il.Cell (ty_param_n_in_obj_fn i))
+ else
+ mov (rc eax) (Il.Cell (ty_param_n i));
mov (rc eax) (Il.Cell (word_n (h eax) Abi.tydesc_field_align))
| SIZE_rt_neg a ->
- calculate_sz e a;
+ calculate_sz e a in_obj;
neg eax
| SIZE_rt_add (a, b) ->
@@ -1155,6 +1231,7 @@ let fn_prologue
(callsz:size)
(nabi:nabi)
(grow_task_fixup:fixup)
+ (is_obj_fn:bool)
: unit =
let esi_n = word_n (h esi) in
@@ -1284,7 +1361,7 @@ let fn_prologue
emit (Il.jmp Il.JA Il.CodeNone);
(* Calculate dynamic frame size. *)
- calculate_sz e call_and_frame_sz;
+ calculate_sz e call_and_frame_sz is_obj_fn;
((ro eax), Some primordial_underflow_jmp_pc)
end
| Some e -> ((imm e), None)
@@ -1936,15 +2013,20 @@ let zero (dst:Il.cell) (count:Il.operand) : Asm.frag =
;;
let mov (signed:bool) (dst:Il.cell) (src:Il.operand) : Asm.frag =
- if is_ty8 (Il.cell_scalar_ty dst) || is_ty8 (Il.operand_scalar_ty src)
+ if is_ty8 (Il.cell_scalar_ty dst)
+ then
+ begin
+ match dst with
+ Il.Reg (Il.Hreg r, _) -> assert (is_ok_r8 r)
+ | _ -> ()
+ end;
+
+ if is_ty8 (Il.operand_scalar_ty src)
then
begin
- (match dst with
- Il.Reg (Il.Hreg r, _)
- -> assert (is_ok_r8 r) | _ -> ());
- (match src with
- Il.Cell (Il.Reg (Il.Hreg r, _))
- -> assert (is_ok_r8 r) | _ -> ());
+ match src with
+ Il.Cell (Il.Reg (Il.Hreg r, _)) -> assert (is_ok_r8 r)
+ | _ -> ()
end;
match (signed, dst, src) with
diff --git a/src/boot/fe/ast.ml b/src/boot/fe/ast.ml
index 6cd1114a..357bf1e6 100644
--- a/src/boot/fe/ast.ml
+++ b/src/boot/fe/ast.ml
@@ -199,7 +199,7 @@ and tup_input = (mutability * atom)
and stmt' =
(* lval-assigning stmts. *)
- STMT_spawn of (lval * domain * lval * (atom array))
+ STMT_spawn of (lval * domain * string * lval * (atom array))
| STMT_new_rec of (lval * (rec_input array) * lval option)
| STMT_new_tup of (lval * (tup_input array))
| STMT_new_vec of (lval * mutability * atom array)
@@ -259,7 +259,7 @@ and stmt_alt_type =
and stmt_alt_port =
{
- (* else lval is a timeout value. *)
+ (* else atom is a timeout value. *)
alt_port_arms: port_arm array;
alt_port_else: (atom * block) option;
}
@@ -328,7 +328,7 @@ and type_arm = type_arm' identified
and port_arm' = port_case * block
and port_arm = port_arm' identified
-and port_case =
+and port_case =
PORT_CASE_send of (lval * lval)
| PORT_CASE_recv of (lval * lval)
@@ -664,7 +664,7 @@ and fmt_constrained ff (ty, constrs) : unit =
fmt_constrs ff constrs;
fmt ff "@]";
fmt ff "@]";
-
+
and fmt_ty (ff:Format.formatter) (t:ty) : unit =
match t with
@@ -707,7 +707,7 @@ and fmt_ty (ff:Format.formatter) (t:ty) : unit =
| TY_tag ttag -> fmt_tag ff ttag
| TY_iso tiso -> fmt_iso ff tiso
| TY_idx idx -> fmt ff "<idx#%d>" idx
- | TY_constrained ctrd -> fmt_constrained ff ctrd
+ | TY_constrained ctrd -> fmt_constrained ff ctrd
| TY_obj (effect, fns) ->
fmt_obox ff;
@@ -942,10 +942,11 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt ff ";"
end
- | STMT_spawn (dst, domain, fn, args) ->
+ | STMT_spawn (dst, domain, name, fn, args) ->
fmt_lval ff dst;
fmt ff " = spawn ";
fmt_domain ff domain;
+ fmt_str ff ("\"" ^ name ^ "\"");
fmt_lval ff fn;
fmt_atoms ff args;
fmt ff ";";
@@ -1233,7 +1234,7 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
Array.iter (fmt_tag_arm ff) at.alt_tag_arms;
fmt_cbb ff;
- | STMT_alt_type at ->
+ | STMT_alt_type at ->
fmt_obox ff;
fmt ff "alt type (";
fmt_lval ff at.alt_type_lval;
@@ -1241,7 +1242,7 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt_obr ff;
Array.iter (fmt_type_arm ff) at.alt_type_arms;
begin
- match at.alt_type_else with
+ match at.alt_type_else with
None -> ()
| Some block ->
fmt ff "@\n";
@@ -1252,7 +1253,8 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt_cbb ff;
end;
fmt_cbb ff;
- | STMT_alt_port at ->
+
+ | STMT_alt_port at ->
fmt_obox ff;
fmt ff "alt ";
fmt_obr ff;
@@ -1271,13 +1273,14 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt_cbb ff;
end;
fmt_cbb ff;
- | STMT_note at ->
+
+ | STMT_note at ->
begin
fmt ff "note ";
fmt_atom ff at;
fmt ff ";"
end
- | STMT_slice (dst, src, slice) ->
+ | STMT_slice (dst, src, slice) ->
fmt_lval ff dst;
fmt ff " = ";
fmt_lval ff src;
@@ -1285,11 +1288,11 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt_slice ff slice;
fmt ff ";";
end
-
-and fmt_arm
- (ff:Format.formatter)
+
+and fmt_arm
+ (ff:Format.formatter)
(fmt_arm_case_expr : Format.formatter -> unit)
- (block : block)
+ (block : block)
: unit =
fmt ff "@\n";
fmt_obox ff;
@@ -1299,15 +1302,16 @@ and fmt_arm
fmt_obr ff;
fmt_stmts ff block.node;
fmt_cbb ff;
-
+
and fmt_tag_arm (ff:Format.formatter) (tag_arm:tag_arm) : unit =
let (pat, block) = tag_arm.node in
fmt_arm ff (fun ff -> fmt_pat ff pat) block;
-
+
and fmt_type_arm (ff:Format.formatter) (type_arm:type_arm) : unit =
let (_, slot, block) = type_arm.node in
fmt_arm ff (fun ff -> fmt_slot ff slot) block;
-
+
+
and fmt_port_arm (ff:Format.formatter) (port_arm:port_arm) : unit =
let (port_case, block) = port_arm.node in
fmt_arm ff (fun ff -> fmt_port_case ff port_case) block;
@@ -1317,7 +1321,6 @@ and fmt_port_case (ff:Format.formatter) (port_case:port_case) : unit =
PORT_CASE_send params -> STMT_send params
| PORT_CASE_recv params -> STMT_recv params in
fmt_stmt ff {node = stmt'; id = Node 0};
-
and fmt_pat (ff:Format.formatter) (pat:pat) : unit =
match pat with
@@ -1348,9 +1351,9 @@ and fmt_slice (ff:Format.formatter) (slice:slice) : unit =
fmt ff "@]";
end;
fmt ff "@])";
-
-
+
+
and fmt_decl_param (ff:Format.formatter) (param:ty_param) : unit =
let (ident, (i, e)) = param in
diff --git a/src/boot/fe/item.ml b/src/boot/fe/item.ml
index 69fe5fc2..82ec2faf 100644
--- a/src/boot/fe/item.ml
+++ b/src/boot/fe/item.ml
@@ -253,7 +253,10 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
let lv = name_to_lval apos bpos name in
Ast.PAT_tag (lv, paren_comma_list parse_pat ps)
- | LIT_INT _ | LIT_CHAR _ | LIT_BOOL _ ->
+ | LIT_INT _
+ | LIT_UINT _
+ | LIT_CHAR _
+ | LIT_BOOL _ ->
Ast.PAT_lit (Pexp.parse_lit ps)
| UNDERSCORE -> bump ps; Ast.PAT_wild
diff --git a/src/boot/fe/pexp.ml b/src/boot/fe/pexp.ml
index fb2d91a0..75983c7f 100644
--- a/src/boot/fe/pexp.ml
+++ b/src/boot/fe/pexp.ml
@@ -18,7 +18,7 @@ open Parser;;
type pexp' =
PEXP_call of (pexp * pexp array)
- | PEXP_spawn of (Ast.domain * pexp)
+ | PEXP_spawn of (Ast.domain * string * pexp)
| PEXP_bind of (pexp * pexp option array)
| PEXP_rec of ((Ast.ident * Ast.mutability * pexp) array * pexp option)
| PEXP_tup of ((Ast.mutability * pexp) array)
@@ -558,9 +558,27 @@ and parse_bottom_pexp (ps:pstate) : pexp =
THREAD -> bump ps; Ast.DOMAIN_thread
| _ -> Ast.DOMAIN_local
in
- let pexp = ctxt "spawn [domain] pexp: init call" parse_pexp ps in
+ (* Spawns either have an explicit literal string for the spawned
+ task's name, or the task is named as the entry call
+ expression. *)
+ let explicit_name =
+ match peek ps with
+ LIT_STR s -> bump ps; Some s
+ | _ -> None
+ in
+ let pexp =
+ ctxt "spawn [domain] [name] pexp: init call" parse_pexp ps
+ in
let bpos = lexpos ps in
- span ps apos bpos (PEXP_spawn (domain, pexp))
+ let name =
+ match explicit_name with
+ Some s -> s
+ (* FIXME: string_of_span returns a string like
+ "./driver.rs:10:16 - 11:52", not the actual text at those
+ characters *)
+ | None -> Session.string_of_span { lo = apos; hi = bpos }
+ in
+ span ps apos bpos (PEXP_spawn (domain, name, pexp))
| BIND ->
let apos = lexpos ps in
@@ -817,11 +835,33 @@ and parse_or_pexp (ps:pstate) : pexp =
step lhs
+and parse_as_pexp (ps:pstate) : pexp =
+ let apos = lexpos ps in
+ let pexp = ctxt "as pexp" parse_or_pexp ps in
+ let rec step accum =
+ match peek ps with
+ AS ->
+ bump ps;
+ let tapos = lexpos ps in
+ let t = parse_ty ps in
+ let bpos = lexpos ps in
+ let t = span ps tapos bpos t in
+ let node =
+ span ps apos bpos
+ (PEXP_unop ((Ast.UNOP_cast t), accum))
+ in
+ step node
+
+ | _ -> accum
+ in
+ step pexp
+
+
and parse_relational_pexp (ps:pstate) : pexp =
let name = "relational pexp" in
let apos = lexpos ps in
- let lhs = ctxt (name ^ " lhs") parse_or_pexp ps in
- let build = binop_build ps name apos parse_or_pexp in
+ let lhs = ctxt (name ^ " lhs") parse_as_pexp ps in
+ let build = binop_build ps name apos parse_as_pexp in
let rec step accum =
match peek ps with
LT -> build accum step Ast.BINOP_lt
@@ -883,30 +923,8 @@ and parse_oror_pexp (ps:pstate) : pexp =
step lhs
-and parse_as_pexp (ps:pstate) : pexp =
- let apos = lexpos ps in
- let pexp = ctxt "as pexp" parse_oror_pexp ps in
- let rec step accum =
- match peek ps with
- AS ->
- bump ps;
- let tapos = lexpos ps in
- let t = parse_ty ps in
- let bpos = lexpos ps in
- let t = span ps tapos bpos t in
- let node =
- span ps apos bpos
- (PEXP_unop ((Ast.UNOP_cast t), accum))
- in
- step node
-
- | _ -> accum
- in
- step pexp
-
-
and parse_pexp (ps:pstate) : pexp =
- parse_as_pexp ps
+ parse_oror_pexp ps
and parse_mutable_and_pexp (ps:pstate) : (Ast.mutability * pexp) =
let mutability = parse_mutability ps in
@@ -1183,7 +1201,7 @@ and desugar_expr_init
let bind_stmt = ss (Ast.STMT_bind (dst_lval, fn_lval, arg_atoms)) in
ac [ fn_stmts; arg_stmts; [| bind_stmt |] ]
- | PEXP_spawn (domain, sub) ->
+ | PEXP_spawn (domain, name, sub) ->
begin
match sub.node with
PEXP_call (fn, args) ->
@@ -1191,7 +1209,8 @@ and desugar_expr_init
let (arg_stmts, arg_atoms) = desugar_expr_atoms ps args in
let fn_lval = atom_lval ps fn_atom in
let spawn_stmt =
- ss (Ast.STMT_spawn (dst_lval, domain, fn_lval, arg_atoms))
+ ss (Ast.STMT_spawn
+ (dst_lval, domain, name, fn_lval, arg_atoms))
in
ac [ fn_stmts; arg_stmts; [| spawn_stmt |] ]
| _ -> raise (err "non-call spawn" ps)
diff --git a/src/boot/llvm/lltrans.ml b/src/boot/llvm/lltrans.ml
index ee192725..c1ef49af 100644
--- a/src/boot/llvm/lltrans.ml
+++ b/src/boot/llvm/lltrans.ml
@@ -588,7 +588,7 @@ let trans_crate
(* Maps a fn's or block's id to an LLVM metadata node (subprogram or
lexical block) representing it. *)
let (dbg_llscopes:(node_id, Llvm.llvalue) Hashtbl.t) = Hashtbl.create 0 in
- let declare_mod_item
+ let rec declare_mod_item
(name:Ast.ident)
mod_item
: unit =
@@ -616,9 +616,8 @@ let trans_crate
| Ast.MOD_ITEM_type _ ->
() (* Types get translated with their terms. *)
- | Ast.MOD_ITEM_mod _ ->
- () (* Modules simply contain other items that are translated
- on their own. *)
+ | Ast.MOD_ITEM_mod (_, items) ->
+ Hashtbl.iter declare_mod_item items
| _ ->
Common.unimpl (Some id)
@@ -807,6 +806,17 @@ let trans_crate
Ast.sprintf_lval lval)
in
+ let trans_callee (fn:Ast.lval) : (Llvm.llvalue * Ast.ty) =
+ let fty = Hashtbl.find sem_cx.ctxt_all_lval_types (lval_base_id fn) in
+ if lval_base_is_item sem_cx fn then
+ let fn_item = lval_item sem_cx fn in
+ let llfn = Hashtbl.find llitems (fn_item.id) in
+ (llfn, fty)
+ else
+ (* indirect call to computed slot *)
+ trans_lval fn
+ in
+
let trans_atom (atom:Ast.atom) : Llvm.llvalue =
iflog (fun _ -> log sem_cx "trans_atom: %a" Ast.sprintf_atom atom);
match atom with
@@ -959,7 +969,7 @@ let trans_crate
| Ast.STMT_call (dest, fn, args) ->
let llargs = Array.map trans_atom args in
let (lldest, _) = trans_lval dest in
- let (llfn, _) = trans_lval fn in
+ let (llfn, _) = trans_callee fn in
let llallargs = Array.append [| lldest; lltask |] llargs in
let llrv = build_call llfn llallargs "" llbuilder in
Llvm.set_instruction_call_conv Llvm.CallConv.c llrv;
@@ -1072,13 +1082,22 @@ let trans_crate
ignore (Llvm.build_br llbodyblock llinitbuilder)
in
- let trans_mod_item
- (_:Ast.ident)
- { node = { Ast.decl_item = (item:Ast.mod_item') }; id = id }
+ let rec trans_mod_item
+ (name:Ast.ident)
+ mod_item
: unit =
+ let { node = { Ast.decl_item = (item:Ast.mod_item') }; id = id } =
+ mod_item in
match item with
- Ast.MOD_ITEM_fn fn -> trans_fn fn id
- | _ -> ()
+ Ast.MOD_ITEM_type _ ->
+ () (* Types get translated with their terms. *)
+ | Ast.MOD_ITEM_mod (_, items) ->
+ Hashtbl.iter trans_mod_item items
+ | Ast.MOD_ITEM_fn fn -> trans_fn fn id
+ | _ -> Common.unimpl (Some id)
+ "LLVM module declaration for: %a"
+ Ast.sprintf_mod_item (name, mod_item)
+
in
let exit_task_glue =
diff --git a/src/boot/me/alias.ml b/src/boot/me/alias.ml
index 94d34fb2..27575324 100644
--- a/src/boot/me/alias.ml
+++ b/src/boot/me/alias.ml
@@ -59,7 +59,7 @@ let alias_analysis_visitor
* survive 'into' a sub-block (those formed during iteration)
* need to be handled in this module. *)
Ast.STMT_call (dst, callee, args)
- | Ast.STMT_spawn (dst, _, callee, args)
+ | Ast.STMT_spawn (dst, _, _, callee, args)
-> alias_call_args dst callee args
| Ast.STMT_send (_, src) -> alias src
diff --git a/src/boot/me/dwarf.ml b/src/boot/me/dwarf.ml
index d3fb81de..0ec7af78 100644
--- a/src/boot/me/dwarf.ml
+++ b/src/boot/me/dwarf.ml
@@ -1677,7 +1677,7 @@ let dwarf_visitor
in
let record trec =
- let rty = referent_type abi (Ast.TY_rec trec) in
+ let rty = referent_type word_bits (Ast.TY_rec trec) in
let rty_sz = Il.referent_ty_size abi.Abi.abi_word_bits in
let fix = new_fixup "record type DIE" in
let die = DEF (fix, SEQ [|
@@ -1926,7 +1926,7 @@ let dwarf_visitor
* I'm a bit surprised by that!
*)
- let rty = referent_type abi (Ast.TY_tag ttag) in
+ let rty = referent_type word_bits (Ast.TY_tag ttag) in
let rty_sz = Il.referent_ty_size abi.Abi.abi_word_bits in
let rtys =
match rty with
diff --git a/src/boot/me/effect.ml b/src/boot/me/effect.ml
index 79868def..73797409 100644
--- a/src/boot/me/effect.ml
+++ b/src/boot/me/effect.ml
@@ -62,7 +62,7 @@ let mutability_checking_visitor
match s.node with
Ast.STMT_copy (lv_dst, _)
| Ast.STMT_call (lv_dst, _, _)
- | Ast.STMT_spawn (lv_dst, _, _, _)
+ | Ast.STMT_spawn (lv_dst, _, _, _, _)
| Ast.STMT_recv (lv_dst, _)
| Ast.STMT_bind (lv_dst, _, _)
| Ast.STMT_new_rec (lv_dst, _, _)
diff --git a/src/boot/me/layout.ml b/src/boot/me/layout.ml
index a9358795..cfd087ff 100644
--- a/src/boot/me/layout.ml
+++ b/src/boot/me/layout.ml
@@ -113,7 +113,7 @@ let layout_visitor
| Il.CodeTy -> true
| Il.NilTy -> false
in
- rt_in_mem (slot_referent_type cx.ctxt_abi slot)
+ rt_in_mem (slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot)
in
let rty_sz rty = Il.referent_ty_size cx.ctxt_abi.Abi.abi_word_bits rty in
@@ -142,7 +142,7 @@ let layout_visitor
: unit =
let accum (off,align) id : (size * size) =
let slot = get_slot cx id in
- let rt = slot_referent_type cx.ctxt_abi slot in
+ let rt = slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot in
let (elt_size, elt_align) = rty_layout rt in
if vregs_ok
&& (is_subword_size elt_size)
@@ -170,7 +170,9 @@ let layout_visitor
then elt_off
else neg_sz (add_sz elt_off elt_size)
in
- Stack.push (slot_referent_type cx.ctxt_abi slot) slot_accum;
+ Stack.push
+ (slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot)
+ slot_accum;
iflog
begin
fun _ ->
@@ -400,7 +402,7 @@ let layout_visitor
let callees =
match s.node with
Ast.STMT_call (_, lv, _)
- | Ast.STMT_spawn (_, _, lv, _) -> [| lv |]
+ | Ast.STMT_spawn (_, _, _, lv, _) -> [| lv |]
| Ast.STMT_check (_, calls) -> Array.map (fun (lv, _) -> lv) calls
| _ -> [| |]
in
diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml
index bcaec2b4..a3a8abdf 100644
--- a/src/boot/me/semant.ml
+++ b/src/boot/me/semant.ml
@@ -1822,24 +1822,24 @@ let run_passes
(* Rust type -> IL type conversion. *)
-let word_sty (abi:Abi.abi) : Il.scalar_ty =
- Il.ValTy abi.Abi.abi_word_bits
+let word_sty (word_bits:Il.bits) : Il.scalar_ty =
+ Il.ValTy word_bits
;;
-let word_rty (abi:Abi.abi) : Il.referent_ty =
- Il.ScalarTy (word_sty abi)
+let word_rty (word_bits:Il.bits) : Il.referent_ty =
+ Il.ScalarTy (word_sty word_bits)
;;
-let tydesc_rty (abi:Abi.abi) : Il.referent_ty =
+let tydesc_rty (word_bits:Il.bits) : Il.referent_ty =
(*
* NB: must match corresponding tydesc structure
* in trans and offsets in ABI exactly.
*)
Il.StructTy
[|
- word_rty abi; (* Abi.tydesc_field_first_param *)
- word_rty abi; (* Abi.tydesc_field_size *)
- word_rty abi; (* Abi.tydesc_field_align *)
+ word_rty word_bits; (* Abi.tydesc_field_first_param *)
+ word_rty word_bits; (* Abi.tydesc_field_size *)
+ word_rty word_bits; (* Abi.tydesc_field_align *)
Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_copy_glue *)
Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_drop_glue *)
Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_free_glue *)
@@ -1849,29 +1849,29 @@ let tydesc_rty (abi:Abi.abi) : Il.referent_ty =
|]
;;
-let obj_closure_rty (abi:Abi.abi) : Il.referent_ty =
+let obj_closure_rty (word_bits:Il.bits) : Il.referent_ty =
Il.StructTy [|
- word_rty abi;
+ word_rty word_bits;
Il.StructTy [|
- Il.ScalarTy (Il.AddrTy (tydesc_rty abi));
- word_rty abi (* A lie: it's opaque, but this permits
- * GEP'ing to it. *)
+ Il.ScalarTy (Il.AddrTy (tydesc_rty word_bits));
+ word_rty word_bits (* A lie: it's opaque, but this permits
+ * GEP'ing to it. *)
|]
|]
;;
-let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty =
+let rec referent_type (word_bits:Il.bits) (t:Ast.ty) : Il.referent_ty =
let s t = Il.ScalarTy t in
let v b = Il.ValTy b in
let p t = Il.AddrTy t in
let sv b = s (v b) in
let sp t = s (p t) in
- let word = word_rty abi in
+ let word = word_rty word_bits in
let ptr = sp Il.OpaqueTy in
let rc_ptr = sp (Il.StructTy [| word; Il.OpaqueTy |]) in
let codeptr = sp Il.CodeTy in
- let tup ttup = Il.StructTy (Array.map (referent_type abi) ttup) in
+ let tup ttup = Il.StructTy (Array.map (referent_type word_bits) ttup) in
let tag ttag =
let union =
Il.UnionTy
@@ -1916,7 +1916,7 @@ let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty =
Il.StructTy [| codeptr; fn_closure_ptr |]
| Ast.TY_obj _ ->
- let obj_closure_ptr = sp (obj_closure_rty abi) in
+ let obj_closure_ptr = sp (obj_closure_rty word_bits) in
Il.StructTy [| ptr; obj_closure_ptr |]
| Ast.TY_tag ttag -> tag ttag
@@ -1928,26 +1928,26 @@ let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty =
| Ast.TY_port _
| Ast.TY_task -> rc_ptr
- | Ast.TY_type -> sp (tydesc_rty abi)
+ | Ast.TY_type -> sp (tydesc_rty word_bits)
| Ast.TY_native _ -> ptr
| Ast.TY_box t ->
- sp (Il.StructTy [| word; referent_type abi t |])
+ sp (Il.StructTy [| word; referent_type word_bits t |])
- | Ast.TY_mutable t -> referent_type abi t
+ | Ast.TY_mutable t -> referent_type word_bits t
| Ast.TY_param (i, _) -> Il.ParamTy i
| Ast.TY_named _ -> bug () "named type in referent_type"
- | Ast.TY_constrained (t, _) -> referent_type abi t
+ | Ast.TY_constrained (t, _) -> referent_type word_bits t
-and slot_referent_type (abi:Abi.abi) (sl:Ast.slot) : Il.referent_ty =
+and slot_referent_type (word_bits:Il.bits) (sl:Ast.slot) : Il.referent_ty =
let s t = Il.ScalarTy t in
let p t = Il.AddrTy t in
let sp t = s (p t) in
- let rty = referent_type abi (slot_ty sl) in
+ let rty = referent_type word_bits (slot_ty sl) in
match sl.Ast.slot_mode with
| Ast.MODE_local -> rty
| Ast.MODE_alias -> sp rty
@@ -1958,7 +1958,7 @@ let task_rty (abi:Abi.abi) : Il.referent_ty =
begin
Array.init
Abi.n_visible_task_fields
- (fun _ -> word_rty abi)
+ (fun _ -> word_rty abi.Abi.abi_word_bits)
end
;;
@@ -1970,14 +1970,17 @@ let call_args_referent_type_full
(iterator_arg_rtys:Il.referent_ty array)
(indirect_arg_rtys:Il.referent_ty array)
: Il.referent_ty =
- let out_slot_rty = slot_referent_type abi out_slot in
+ let out_slot_rty = slot_referent_type abi.Abi.abi_word_bits out_slot in
let out_ptr_rty = Il.ScalarTy (Il.AddrTy out_slot_rty) in
let task_ptr_rty = Il.ScalarTy (Il.AddrTy (task_rty abi)) in
let ty_param_rtys =
- let td = Il.ScalarTy (Il.AddrTy (tydesc_rty abi)) in
+ let td = Il.ScalarTy (Il.AddrTy (tydesc_rty abi.Abi.abi_word_bits)) in
Il.StructTy (Array.init n_ty_params (fun _ -> td))
in
- let arg_rtys = Il.StructTy (Array.map (slot_referent_type abi) in_slots) in
+ let arg_rtys =
+ Il.StructTy
+ (Array.map (slot_referent_type abi.Abi.abi_word_bits) in_slots)
+ in
(*
* NB: must match corresponding calltup structure in trans and
* member indices in ABI exactly.
@@ -2003,7 +2006,7 @@ let call_args_referent_type
(* Abi.indirect_args_elt_closure *)
match closure with
None ->
- [| word_rty cx.ctxt_abi |]
+ [| word_rty cx.ctxt_abi.Abi.abi_word_bits |]
| Some c ->
[| Il.ScalarTy (Il.AddrTy c) |]
in
@@ -2057,16 +2060,18 @@ let direct_call_args_referent_type
;;
let ty_sz (abi:Abi.abi) (t:Ast.ty) : int64 =
- force_sz (Il.referent_ty_size abi.Abi.abi_word_bits (referent_type abi t))
+ let wb = abi.Abi.abi_word_bits in
+ force_sz (Il.referent_ty_size wb (referent_type wb t))
;;
let ty_align (abi:Abi.abi) (t:Ast.ty) : int64 =
- force_sz (Il.referent_ty_align abi.Abi.abi_word_bits (referent_type abi t))
+ let wb = abi.Abi.abi_word_bits in
+ force_sz (Il.referent_ty_align wb (referent_type wb t))
;;
let slot_sz (abi:Abi.abi) (s:Ast.slot) : int64 =
- force_sz (Il.referent_ty_size abi.Abi.abi_word_bits
- (slot_referent_type abi s))
+ let wb = abi.Abi.abi_word_bits in
+ force_sz (Il.referent_ty_size wb (slot_referent_type wb s))
;;
let word_slot (abi:Abi.abi) : Ast.slot =
diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml
index f2bb2287..620b27e7 100644
--- a/src/boot/me/trans.ml
+++ b/src/boot/me/trans.ml
@@ -163,7 +163,6 @@ let trans_visitor
abi.Abi.abi_emit_target_specific
vregs_ok fnid
in
- Stack.push (Hashtbl.create 0) e.Il.emit_size_cache;
Stack.push e emitters;
in
@@ -172,16 +171,20 @@ let trans_visitor
let pop_emitter _ = ignore (Stack.pop emitters) in
let emitter _ = Stack.top emitters in
- let emitter_size_cache _ = Stack.top (emitter()).Il.emit_size_cache in
- let push_emitter_size_cache _ =
- Stack.push
- (Hashtbl.copy (emitter_size_cache()))
- (emitter()).Il.emit_size_cache
+ let emitter_size_cache _ = (emitter()).Il.emit_size_cache in
+ let flush_emitter_size_cache _ =
+ Hashtbl.clear (emitter_size_cache())
in
- let pop_emitter_size_cache _ =
- ignore (Stack.pop (emitter()).Il.emit_size_cache)
+
+ let emit q =
+ begin
+ match q with
+ Il.Jmp _ -> flush_emitter_size_cache();
+ | _ -> ()
+ end;
+ Il.emit (emitter()) q
in
- let emit q = Il.emit (emitter()) q in
+
let next_vreg _ = Il.next_vreg (emitter()) in
let next_vreg_cell t = Il.next_vreg_cell (emitter()) t in
let next_spill_cell t =
@@ -190,12 +193,17 @@ let trans_visitor
let spill_ta = (spill_mem, Il.ScalarTy t) in
Il.Mem spill_ta
in
- let mark _ : quad_idx = (emitter()).Il.emit_pc in
+ let mark _ : quad_idx =
+ flush_emitter_size_cache ();
+ (emitter()).Il.emit_pc
+ in
let patch_existing (jmp:quad_idx) (targ:quad_idx) : unit =
- Il.patch_jump (emitter()) jmp targ
+ Il.patch_jump (emitter()) jmp targ;
+ flush_emitter_size_cache ();
in
let patch (i:quad_idx) : unit =
Il.patch_jump (emitter()) i (mark());
+ flush_emitter_size_cache ();
(* Insert a dead quad to ensure there's an otherwise-unused
* jump-target here.
*)
@@ -284,7 +292,7 @@ let trans_visitor
in
let ptr_at (mem:Il.mem) (pointee_ty:Ast.ty) : Il.cell =
- rty_ptr_at mem (referent_type abi pointee_ty)
+ rty_ptr_at mem (referent_type word_bits pointee_ty)
in
let need_scalar_ty (rty:Il.referent_ty) : Il.scalar_ty =
@@ -322,11 +330,7 @@ let trans_visitor
(cell_str mem_cell)
in
- let rec ptr_cast (cell:Il.cell) (rty:Il.referent_ty) : Il.cell =
- match cell with
- Il.Mem (mem, _) -> Il.Mem (mem, rty)
- | Il.Reg (reg, Il.AddrTy _) -> Il.Reg (reg, Il.AddrTy rty)
- | _ -> bug () "expected address cell in Trans.ptr_cast"
+ let rec ptr_cast = Il.ptr_cast
and curr_crate_ptr _ : Il.cell =
word_at (fp_imm frame_crate_ptr)
@@ -445,13 +449,22 @@ let trans_visitor
in
let slot_id_referent_type (slot_id:node_id) : Il.referent_ty =
- slot_referent_type abi (get_slot cx slot_id)
+ slot_referent_type word_bits (get_slot cx slot_id)
in
let caller_args_cell (args_rty:Il.referent_ty) : Il.cell =
Il.Mem (fp_imm out_mem_disp, args_rty)
in
+ let get_obj_box_from_calltup (args_cell:Il.cell) =
+ let indirect_args =
+ get_element_ptr args_cell Abi.calltup_elt_indirect_args
+ in
+ deref (ptr_cast
+ (get_element_ptr indirect_args Abi.indirect_args_elt_closure)
+ (Il.ScalarTy (Il.AddrTy (obj_closure_rty word_bits))))
+ in
+
let fp_to_args (fp:Il.cell) (args_rty:Il.referent_ty): Il.cell =
let (reg, _) = force_to_reg (Il.Cell fp) in
Il.Mem(based_imm reg out_mem_disp, args_rty)
@@ -461,11 +474,43 @@ let trans_visitor
get_element_ptr ty_params param_idx
in
- let get_ty_params_of_frame (fp:Il.reg) (n_params:int) : Il.cell =
- let fn_ty = mk_simple_ty_fn [| |] in
- let fn_rty = call_args_referent_type cx n_params fn_ty None in
- let args_cell = Il.Mem (based_imm fp out_mem_disp, fn_rty) in
- get_element_ptr args_cell Abi.calltup_elt_ty_params
+ let get_ty_params_of_frame
+ (fnid:node_id)
+ (fp:Il.reg)
+ (n_ty_params:int)
+ : Il.cell =
+
+ let fn_ty = mk_simple_ty_fn [| |] in
+ let fn_rty =
+ call_args_referent_type cx n_ty_params fn_ty (Some Il.OpaqueTy)
+ in
+ let args_cell = Il.Mem (based_imm fp out_mem_disp, fn_rty) in
+
+ if defn_id_is_obj_fn_or_drop cx fnid
+ then
+ (*
+ * To get the typarams in an obj fn, we must go to the
+ * implicit obj's captured type descriptor.
+ *)
+ let obj_box =
+ get_obj_box_from_calltup args_cell
+ in
+ let obj = get_element_ptr obj_box Abi.box_rc_field_body in
+ let tydesc = get_element_ptr obj Abi.obj_body_elt_tydesc in
+ let ty_params_ty = Ast.TY_tup (make_tydesc_tys n_ty_params) in
+ let ty_params_rty = referent_type word_bits ty_params_ty in
+ let ty_params =
+ get_element_ptr (deref tydesc) Abi.tydesc_field_first_param
+ in
+ let ty_params =
+ ptr_cast ty_params (Il.ScalarTy (Il.AddrTy ty_params_rty))
+ in
+ deref ty_params
+ else
+ (*
+ * Regular function --- typarams are right in the frame calltup.
+ *)
+ get_element_ptr args_cell Abi.calltup_elt_ty_params
in
let get_args_for_current_frame _ =
@@ -512,34 +557,10 @@ let trans_visitor
Abi.iterator_args_elt_outer_frame_ptr
in
- let get_obj_for_current_frame _ =
- deref (ptr_cast
- (get_closure_for_current_frame ())
- (Il.ScalarTy (Il.AddrTy (obj_closure_rty abi))))
- in
-
let get_ty_params_of_current_frame _ : Il.cell =
- let id = current_fn() in
- let n_ty_params = n_item_ty_params cx id in
- if defn_id_is_obj_fn_or_drop cx id
- then
- begin
- let obj_box = get_obj_for_current_frame() in
- let obj = get_element_ptr obj_box Abi.box_rc_field_body in
- let tydesc = get_element_ptr obj Abi.obj_body_elt_tydesc in
- let ty_params_ty = Ast.TY_tup (make_tydesc_tys n_ty_params) in
- let ty_params_rty = referent_type abi ty_params_ty in
- let ty_params =
- get_element_ptr (deref tydesc) Abi.tydesc_field_first_param
- in
- let ty_params =
- ptr_cast ty_params (Il.ScalarTy (Il.AddrTy ty_params_rty))
- in
- deref ty_params
- end
-
- else
- get_ty_params_of_frame abi.Abi.abi_fp_reg n_ty_params
+ let fnid = current_fn() in
+ let n_ty_params = n_item_ty_params cx fnid in
+ get_ty_params_of_frame fnid abi.Abi.abi_fp_reg n_ty_params
in
let get_ty_param_in_current_frame (param_idx:int) : Il.cell =
@@ -583,7 +604,13 @@ let trans_visitor
(string_of_size size)));
let sub_sz = calculate_sz ty_params in
match htab_search (emitter_size_cache()) size with
- Some op -> op
+ Some op ->
+ iflog (fun _ -> annotate
+ (Printf.sprintf "cached size %s is %s"
+ (string_of_size size)
+ (oper_str op)));
+ op
+
| _ ->
let res =
match size with
@@ -707,7 +734,7 @@ let trans_visitor
in
let ty_sz_in_current_frame (ty:Ast.ty) : Il.operand =
- let rty = referent_type abi ty in
+ let rty = referent_type word_bits ty in
let sz = Il.referent_ty_size word_bits rty in
calculate_sz_in_current_frame sz
in
@@ -716,7 +743,7 @@ let trans_visitor
(ty_params:Il.cell)
(ty:Ast.ty)
: Il.operand =
- let rty = referent_type abi ty in
+ let rty = referent_type word_bits ty in
let sz = Il.referent_ty_size word_bits rty in
calculate_sz ty_params sz
in
@@ -914,9 +941,10 @@ let trans_visitor
let atop = trans_atom at in
let unit_sz = ty_sz_in_current_frame ty in
let idx = next_vreg_cell word_sty in
- emit (Il.binary Il.UMUL idx atop unit_sz);
+ mov idx atop;
+ emit (Il.binary Il.UMUL idx (Il.Cell idx) unit_sz);
let elt_mem = trans_bounds_check (deref cell) (Il.Cell idx) in
- (Il.Mem (elt_mem, referent_type abi ty), ty)
+ (Il.Mem (elt_mem, referent_type word_bits ty), ty)
in
(*
* All lval components aside from explicit-deref just auto-deref
@@ -1105,7 +1133,7 @@ let trans_visitor
and trans_static_string (s:string) : Il.operand =
Il.Cell (crate_rel_to_ptr
(trans_crate_rel_static_string_operand s)
- (referent_type abi Ast.TY_str))
+ (referent_type word_bits Ast.TY_str))
and get_static_tydesc
(idopt:node_id option)
@@ -1211,7 +1239,7 @@ let trans_visitor
let fty = Hashtbl.find (snd caller) ident in
let self_args_rty =
call_args_referent_type cx 0
- (Ast.TY_fn fty) (Some (obj_closure_rty abi))
+ (Ast.TY_fn fty) (Some (obj_closure_rty word_bits))
in
let callsz = Il.referent_ty_size word_bits self_args_rty in
let spill = new_fixup "forwarding fn spill" in
@@ -1379,7 +1407,7 @@ let trans_visitor
push_new_emitter_with_vregs None;
iflog (fun _ -> annotate "prologue");
abi.Abi.abi_emit_fn_prologue (emitter())
- framesz callsz nabi_rust (upcall_fixup "upcall_grow_task");
+ framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") false;
write_frame_info_ptrs None;
(* FIXME: not clear why, but checking interrupt in glue context
* causes many.rs to crash when run on a sufficiently large number
@@ -1458,8 +1486,8 @@ let trans_visitor
(* FIXME (issue #5): mutability flag *)
: Il.referent_ty =
let rc = Il.ScalarTy word_sty in
- let targ = referent_type abi (mk_simple_ty_fn [||]) in
- let bindings = Array.map (slot_referent_type abi) bs in
+ let targ = referent_type word_bits (mk_simple_ty_fn [||]) in
+ let bindings = Array.map (slot_referent_type word_bits) bs in
Il.StructTy [| rc; targ; Il.StructTy bindings |]
(* FIXME (issue #2): this should eventually use tail calling logic *)
@@ -1923,8 +1951,8 @@ let trans_visitor
: quad_idx list =
emit (Il.cmp (Il.Cell (Il.Reg (force_to_reg lhs))) rhs);
let jmp = mark() in
- emit (Il.jmp cjmp Il.CodeNone);
- [ jmp ]
+ emit (Il.jmp cjmp Il.CodeNone);
+ [ jmp ]
and trans_compare
?ty_params:(ty_params=get_ty_params_of_current_frame())
@@ -1943,7 +1971,6 @@ let trans_visitor
| _ -> trans_compare_simple cjmp lhs rhs
and trans_cond (invert:bool) (expr:Ast.expr) : quad_idx list =
-
let anno _ =
iflog
begin
@@ -2075,15 +2102,14 @@ let trans_visitor
trans_atom a
and trans_block (block:Ast.block) : unit =
+ flush_emitter_size_cache();
trace_str cx.ctxt_sess.Session.sess_trace_block
"entering block";
- push_emitter_size_cache ();
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups block.id));
Array.iter trans_stmt block.node;
trace_str cx.ctxt_sess.Session.sess_trace_block
"exiting block";
emit Il.Leave;
- pop_emitter_size_cache ();
trace_str cx.ctxt_sess.Session.sess_trace_block
"exited block";
@@ -2115,10 +2141,12 @@ let trans_visitor
((*initializing*)_:bool)
(dst:Ast.lval)
(domain:Ast.domain)
+ (name:string)
(fn_lval:Ast.lval)
(args:Ast.atom array)
: unit =
let (task_cell, _) = trans_lval_init dst in
+ let runtime_name = trans_static_string name in
let (fptr_operand, fn_ty) = trans_callee fn_lval in
(*let fn_ty_params = [| |] in*)
let _ =
@@ -2152,7 +2180,7 @@ let trans_visitor
match domain with
Ast.DOMAIN_thread ->
begin
- trans_upcall "upcall_new_thread" new_task [| |];
+ trans_upcall "upcall_new_thread" new_task [| runtime_name |];
copy_fn_args false true (CLONE_all new_task) call;
trans_upcall "upcall_start_thread" task_cell
[|
@@ -2164,7 +2192,7 @@ let trans_visitor
end
| _ ->
begin
- trans_upcall "upcall_new_task" new_task [| |];
+ trans_upcall "upcall_new_task" new_task [| runtime_name |];
copy_fn_args false true (CLONE_chan new_task) call;
trans_upcall "upcall_start_task" task_cell
[|
@@ -2318,7 +2346,7 @@ let trans_visitor
(get_element_ptr_dyn_in_current_frame
vec Abi.vec_elt_data))
in
- let unit_rty = referent_type abi unit_ty in
+ let unit_rty = referent_type word_bits unit_ty in
let body_rty = Il.StructTy (Array.map (fun _ -> unit_rty) atoms) in
let body = Il.Mem (body_mem, body_rty) in
Array.iteri
@@ -2364,12 +2392,12 @@ let trans_visitor
let root_desc =
Il.Cell (crate_rel_to_ptr
(get_static_tydesc idopt t 0L 0L force_stateful)
- (tydesc_rty abi))
+ (tydesc_rty word_bits))
in
let (t, param_descs) = linearize_ty_params t in
let descs = Array.append [| root_desc |] param_descs in
let n = Array.length descs in
- let rty = referent_type abi t in
+ let rty = referent_type word_bits t in
let (size_sz, align_sz) = Il.referent_ty_layout word_bits rty in
let size = calculate_sz_in_current_frame size_sz in
let align = calculate_sz_in_current_frame align_sz in
@@ -2405,7 +2433,7 @@ let trans_visitor
(ty_sz abi ty)
(ty_align abi ty)
mut)
- (tydesc_rty abi))
+ (tydesc_rty word_bits))
and box_rc_cell (cell:Il.cell) : Il.cell =
get_element_ptr (deref cell) Abi.box_rc_field_refcnt
@@ -2422,7 +2450,7 @@ let trans_visitor
in
let ty = simplified_ty ty in
let refty_sz =
- Il.referent_ty_size abi.Abi.abi_word_bits (referent_type abi ty)
+ Il.referent_ty_size abi.Abi.abi_word_bits (referent_type word_bits ty)
in
match refty_sz with
SIZE_fixed _ -> imm (Int64.add (ty_sz abi ty) header_sz)
@@ -2519,7 +2547,7 @@ let trans_visitor
trans_compare_simple Il.JAE (Il.Cell ptr) (Il.Cell lim)
in
let unit_cell =
- deref (ptr_cast ptr (referent_type abi unit_ty))
+ deref (ptr_cast ptr (referent_type word_bits unit_ty))
in
f unit_cell unit_cell unit_ty curr_iso;
add_to ptr unit_sz;
@@ -2919,6 +2947,7 @@ let trans_visitor
(slot:Ast.slot)
(curr_iso:Ast.ty_iso option)
: unit =
+ check_and_flush_chan cell slot;
drop_slot (get_ty_params_of_current_frame()) cell slot curr_iso
and drop_ty_in_current_frame
@@ -4175,6 +4204,25 @@ let trans_visitor
let last_jumps = Array.map trans_arm at.Ast.alt_tag_arms in
Array.iter patch last_jumps
+ (* If we're about to drop a channel, synthesize an upcall_flush_chan.
+ * TODO: This should rather appear in a chan dtor when chans become
+ * objects. *)
+ and check_and_flush_chan
+ (cell:Il.cell)
+ (slot:Ast.slot)
+ : unit =
+ let ty = strip_mutable_or_constrained_ty (slot_ty slot) in
+ match simplified_ty ty with
+ Ast.TY_chan _ ->
+ annotate "check_and_flush_chan, flush_chan";
+ let rc = box_rc_cell cell in
+ emit (Il.cmp (Il.Cell rc) one);
+ let jump = mark () in
+ emit (Il.jmp Il.JNE Il.CodeNone);
+ trans_void_upcall "upcall_flush_chan" [| Il.Cell cell |];
+ patch jump;
+ | _ -> ()
+
and drop_slots_at_curr_stmt _ : unit =
let stmt = Stack.top curr_stmt in
match htab_search cx.ctxt_post_stmt_slot_drops stmt with
@@ -4277,7 +4325,7 @@ let trans_visitor
push_new_emitter_with_vregs (Some id);
iflog (fun _ -> annotate "prologue");
abi.Abi.abi_emit_fn_prologue (emitter())
- framesz callsz nabi_rust (upcall_fixup "upcall_grow_task");
+ framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") false;
write_frame_info_ptrs None;
iflog (fun _ -> annotate "finished prologue");
trans_block fe.Ast.for_each_body;
@@ -4361,7 +4409,7 @@ let trans_visitor
let dst_fill = get_element_ptr dst_vec Abi.vec_elt_fill in
(* Copy loop: *)
- let eltp_rty = Il.AddrTy (referent_type abi elt_ty) in
+ let eltp_rty = Il.AddrTy (referent_type word_bits elt_ty) in
let dptr = next_vreg_cell eltp_rty in
let sptr = next_vreg_cell eltp_rty in
let dlim = next_vreg_cell eltp_rty in
@@ -4395,11 +4443,11 @@ let trans_visitor
let back_jmp =
trans_compare_simple Il.JB (Il.Cell dptr) (Il.Cell dlim)
in
- List.iter
- (fun j -> patch_existing j back_jmp_targ) back_jmp;
- let v = next_vreg_cell word_sty in
- mov v (Il.Cell src_fill);
- add_to dst_fill (Il.Cell v);
+ List.iter
+ (fun j -> patch_existing j back_jmp_targ) back_jmp;
+ let v = next_vreg_cell word_sty in
+ mov v (Il.Cell src_fill);
+ add_to dst_fill (Il.Cell v);
| t ->
begin
bug () "unsupported vector-append type %a" Ast.sprintf_ty t
@@ -4483,8 +4531,9 @@ let trans_visitor
| Ast.STMT_send (chan,src) ->
trans_send chan src
- | Ast.STMT_spawn (dst, domain, plv, args) ->
- trans_spawn (maybe_init stmt.id "spawn" dst) dst domain plv args
+ | Ast.STMT_spawn (dst, domain, name, plv, args) ->
+ trans_spawn (maybe_init stmt.id "spawn" dst) dst
+ domain name plv args
| Ast.STMT_recv (dst, chan) ->
trans_recv (maybe_init stmt.id "recv" dst) dst chan
@@ -4680,6 +4729,8 @@ let trans_visitor
let get_frame_glue glue inner =
get_mem_glue glue
begin
+ (* `mem` here is a pointer to the frame we are marking, dropping,
+ or relocing, etc. *)
fun mem ->
iter_frame_and_arg_slots cx fnid
begin
@@ -4687,10 +4738,19 @@ let trans_visitor
match htab_search cx.ctxt_slot_offsets slot_id with
Some off when not (slot_is_obj_state cx slot_id) ->
let referent_type = slot_id_referent_type slot_id in
+ (*
+ * This might look as though we're always taking the
+ * pointer-to-frame and giving it the type of the
+ * frame/arg of interest, but this is because our
+ * deref_off a few lines later takes the referent
+ * type of the given poiinter (`st`) as the referent
+ * type of the mem-offset-from-the-given-pointer
+ * that it returns.
+ *)
let fp_cell = rty_ptr_at mem referent_type in
let (fp, st) = force_to_reg (Il.Cell fp_cell) in
let ty_params =
- get_ty_params_of_frame fp n_ty_params
+ get_ty_params_of_frame fnid fp n_ty_params
in
let slot_cell =
deref_off_sz ty_params (Il.Reg (fp,st)) off
@@ -4738,7 +4798,7 @@ let trans_visitor
end
in
- let trans_frame_entry (fnid:node_id) : unit =
+ let trans_frame_entry (fnid:node_id) (obj_fn:bool) : unit =
let framesz = get_framesz cx fnid in
let callsz = get_callsz cx fnid in
Stack.push (Stack.create()) epilogue_jumps;
@@ -4752,7 +4812,7 @@ let trans_visitor
(string_of_size callsz)));
abi.Abi.abi_emit_fn_prologue
(emitter()) framesz callsz nabi_rust
- (upcall_fixup "upcall_grow_task");
+ (upcall_fixup "upcall_grow_task") obj_fn;
write_frame_info_ptrs (Some fnid);
check_interrupt_flag ();
@@ -4776,8 +4836,9 @@ let trans_visitor
let trans_fn
(fnid:node_id)
(body:Ast.block)
+ (obj_fn:bool)
: unit =
- trans_frame_entry fnid;
+ trans_frame_entry fnid obj_fn;
trans_block body;
trans_frame_exit fnid true;
in
@@ -4786,7 +4847,7 @@ let trans_visitor
(obj_id:node_id)
(header:Ast.header_slots)
: unit =
- trans_frame_entry obj_id;
+ trans_frame_entry obj_id true;
let all_args_rty = current_fn_args_rty None in
let all_args_cell = caller_args_cell all_args_rty in
@@ -4805,7 +4866,7 @@ let trans_visitor
let obj_args_ty = Ast.TY_tup obj_args_tup in
let state_ty = Ast.TY_tup [| Ast.TY_type; obj_args_ty |] in
let state_ptr_ty = Ast.TY_box state_ty in
- let state_ptr_rty = referent_type abi state_ptr_ty in
+ let state_ptr_rty = referent_type word_bits state_ptr_ty in
let state_malloc_sz = box_allocation_size state_ptr_ty in
let ctor_ty = Hashtbl.find cx.ctxt_all_item_types obj_id in
@@ -4907,7 +4968,7 @@ let trans_visitor
in
let trans_required_fn (fnid:node_id) (blockid:node_id) : unit =
- trans_frame_entry fnid;
+ trans_frame_entry fnid false;
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups blockid));
let (ilib, conv) = Hashtbl.find cx.ctxt_required_items fnid in
let lib_num =
@@ -5045,7 +5106,7 @@ let trans_visitor
(tagid:node_id)
(tag:(Ast.header_tup * Ast.ty_tag * node_id))
: unit =
- trans_frame_entry tagid;
+ trans_frame_entry tagid false;
trace_str cx.ctxt_sess.Session.sess_trace_tag
("in tag constructor " ^ n);
let (header_tup, _, _) = tag in
@@ -5108,7 +5169,7 @@ let trans_visitor
iflog (fun _ -> log cx "translating defined item #%d = %s"
(int_of_node i.id) (path_name()));
match i.node.Ast.decl_item with
- Ast.MOD_ITEM_fn f -> trans_fn i.id f.Ast.fn_body
+ Ast.MOD_ITEM_fn f -> trans_fn i.id f.Ast.fn_body false
| Ast.MOD_ITEM_tag t -> trans_tag n i.id t
| Ast.MOD_ITEM_obj ob ->
trans_obj_ctor i.id
@@ -5142,7 +5203,7 @@ let trans_visitor
push_new_emitter_with_vregs (Some b.id);
iflog (fun _ -> annotate "prologue");
abi.Abi.abi_emit_fn_prologue (emitter())
- framesz callsz nabi_rust (upcall_fixup "upcall_grow_task");
+ framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") true;
write_frame_info_ptrs None;
iflog (fun _ -> annotate "finished prologue");
trans_block b;
@@ -5152,7 +5213,7 @@ let trans_visitor
in
let visit_defined_obj_fn_pre _ _ fn =
- trans_fn fn.id fn.node.Ast.fn_body
+ trans_fn fn.id fn.node.Ast.fn_body true
in
let visit_required_obj_fn_pre _ _ _ =
diff --git a/src/boot/me/type.ml b/src/boot/me/type.ml
index 787855f0..b2d5a622 100644
--- a/src/boot/me/type.ml
+++ b/src/boot/me/type.ml
@@ -380,19 +380,20 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
sprintf_itype ()
| `Type (Ast.TY_vec ty_vec), Ast.COMP_atom atom ->
- demand Ast.TY_int (check_atom atom);
+ demand_integer (check_atom atom);
LTYPE_mono ty_vec
| `Type (Ast.TY_vec _), _ ->
- Common.err None "the vector type '%a' must be indexed via an int"
+ Common.err None
+ "the vector type '%a' must be indexed by an integral type"
sprintf_itype ()
| `Type Ast.TY_str, Ast.COMP_atom atom ->
- demand Ast.TY_int (check_atom atom);
+ demand_integer (check_atom atom);
LTYPE_mono (Ast.TY_mach Common.TY_u8)
| `Type Ast.TY_str, _ ->
- Common.err None "strings must be indexed via an int"
+ Common.err None "strings must be indexed by an integral type"
| `Type (Ast.TY_box ty_box), Ast.COMP_deref -> LTYPE_mono ty_box
@@ -691,7 +692,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
and check_stmt (stmt:Ast.stmt) : unit =
check_ret stmt;
match stmt.Common.node with
- Ast.STMT_spawn (dst, _, callee, args) ->
+ Ast.STMT_spawn (dst, _, _, callee, args) ->
infer_lval Ast.TY_task dst;
demand Ast.TY_nil (check_fn callee args)
diff --git a/src/boot/me/typestate.ml b/src/boot/me/typestate.ml
index baf4a543..20702990 100644
--- a/src/boot/me/typestate.ml
+++ b/src/boot/me/typestate.ml
@@ -664,7 +664,7 @@ let condition_assigning_visitor
let precond = Array.append dst_init src_init in
raise_pre_post_cond s.id precond;
- | Ast.STMT_spawn (dst, _, lv, args)
+ | Ast.STMT_spawn (dst, _, _, lv, args)
| Ast.STMT_call (dst, lv, args) ->
raise_dst_init_precond_if_writing_through s.id dst;
visit_callable_pre s.id (lval_slots cx dst) lv args
@@ -1350,7 +1350,7 @@ let lifecycle_visitor
match s.node with
Ast.STMT_copy (lv_dst, _)
| Ast.STMT_call (lv_dst, _, _)
- | Ast.STMT_spawn (lv_dst, _, _, _)
+ | Ast.STMT_spawn (lv_dst, _, _, _, _)
| Ast.STMT_recv (lv_dst, _)
| Ast.STMT_bind (lv_dst, _, _)
| Ast.STMT_new_rec (lv_dst, _, _)
diff --git a/src/boot/me/walk.ml b/src/boot/me/walk.ml
index 0e65406a..cadfd66b 100644
--- a/src/boot/me/walk.ml
+++ b/src/boot/me/walk.ml
@@ -451,7 +451,7 @@ and walk_stmt
walk_lval v f;
Array.iter (walk_opt_atom v) az
- | Ast.STMT_spawn (dst,_,p,az) ->
+ | Ast.STMT_spawn (dst,_,_,p,az) ->
walk_lval v dst;
walk_lval v p;
Array.iter (walk_atom v) az
diff --git a/src/etc/x86.supp b/src/etc/x86.supp
index f829f2ad..beb48223 100644
--- a/src/etc/x86.supp
+++ b/src/etc/x86.supp
@@ -11,4 +11,14 @@
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
-} \ No newline at end of file
+}
+
+{
+ mac-dyld-oddity
+ Memcheck:Cond
+ fun:_ZN4dyld5_mainEPK12macho_headermiPPKcS5_S5_
+ fun:_ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
+ fun:_dyld_start
+ obj:*
+}
+
diff --git a/src/lib/_int.rs b/src/lib/_int.rs
index 9b756675..e76c2bf5 100644
--- a/src/lib/_int.rs
+++ b/src/lib/_int.rs
@@ -44,3 +44,47 @@ fn next_power_of_two(uint n) -> uint {
}
ret tmp + 1u;
}
+
+fn uto_str(mutable uint n, uint radix) -> str
+{
+ check (0u < radix && radix <= 16u);
+ fn digit(uint n) -> str {
+ alt (n) {
+ case (0u) { ret "0"; }
+ case (1u) { ret "1"; }
+ case (2u) { ret "2"; }
+ case (3u) { ret "3"; }
+ case (4u) { ret "4"; }
+ case (5u) { ret "5"; }
+ case (6u) { ret "6"; }
+ case (7u) { ret "7"; }
+ case (8u) { ret "8"; }
+ case (9u) { ret "9"; }
+ case (10u) { ret "a"; }
+ case (11u) { ret "b"; }
+ case (12u) { ret "c"; }
+ case (13u) { ret "d"; }
+ case (14u) { ret "e"; }
+ case (15u) { ret "f"; }
+ }
+ }
+
+ if (n == 0u) { ret "0"; }
+
+ let str s = "";
+ while (n > 0u) {
+ s = digit(n % radix) + s;
+ n /= radix;
+ }
+ ret s;
+}
+
+fn to_str(mutable int n, uint radix) -> str
+{
+ check (0u < radix && radix <= 16u);
+ if (n < 0) {
+ ret "-" + uto_str((-n) as uint, radix);
+ } else {
+ ret uto_str(n as uint, radix);
+ }
+}
diff --git a/src/lib/_io.rs b/src/lib/_io.rs
index 142f808a..93d06d41 100644
--- a/src/lib/_io.rs
+++ b/src/lib/_io.rs
@@ -1,3 +1,7 @@
+import std.os;
+import std._str;
+import std._vec;
+
type buf_reader = unsafe obj {
fn read() -> vec[u8];
};
@@ -107,3 +111,22 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
}
ret fd_buf_writer(fd);
}
+
+type writer =
+ unsafe obj {
+ fn write_str(str s);
+ fn write_int(int n);
+ fn write_uint(uint n);
+ };
+
+fn file_writer(str path,
+ vec[fileflag] flags)
+ -> writer
+{
+ unsafe obj fw(buf_writer out) {
+ fn write_str(str s) { out.write(_str.bytes(s)); }
+ fn write_int(int n) { out.write(_str.bytes(_int.to_str(n, 10u))); }
+ fn write_uint(uint n) { out.write(_str.bytes(_int.uto_str(n, 10u))); }
+ }
+ ret fw(new_buf_writer(path, flags));
+}
diff --git a/src/lib/_str.rs b/src/lib/_str.rs
index 062d8bf1..a607c7d5 100644
--- a/src/lib/_str.rs
+++ b/src/lib/_str.rs
@@ -3,7 +3,7 @@ import rustrt.sbuf;
native "rust" mod rustrt {
type sbuf;
fn str_buf(str s) -> sbuf;
- fn str_len(str s) -> uint;
+ fn str_byte_len(str s) -> uint;
fn str_alloc(uint n_bytes) -> str;
fn refcount[T](str s) -> uint;
}
@@ -12,14 +12,37 @@ fn is_utf8(vec[u8] v) -> bool {
fail; // FIXME
}
+fn is_ascii(str s) -> bool {
+ let uint i = byte_len(s);
+ while (i > 0u) {
+ i -= 1u;
+ if ((s.(i) & 0x80u8) != 0u8) {
+ ret false;
+ }
+ }
+ ret true;
+}
+
fn alloc(uint n_bytes) -> str {
ret rustrt.str_alloc(n_bytes);
}
-fn len(str s) -> uint {
- ret rustrt.str_len(s);
+// Returns the number of bytes (a.k.a. UTF-8 code units) in s.
+// Contrast with a function that would return the number of code
+// points (char's), combining character sequences, words, etc. See
+// http://icu-project.org/apiref/icu4c/classBreakIterator.html for a
+// way to implement those.
+fn byte_len(str s) -> uint {
+ ret rustrt.str_byte_len(s);
}
fn buf(str s) -> sbuf {
ret rustrt.str_buf(s);
}
+
+fn bytes(&str s) -> vec[u8] {
+ fn ith(str s, uint i) -> u8 {
+ ret s.(i);
+ }
+ ret _vec.init_fn[u8](bind ith(s, _), _str.byte_len(s));
+}
diff --git a/src/lib/deque.rs b/src/lib/deque.rs
index bd42d7cb..3f2a81a4 100644
--- a/src/lib/deque.rs
+++ b/src/lib/deque.rs
@@ -36,7 +36,7 @@ fn create[T]() -> t[T] {
fn fill[T](uint i, uint nelts, uint lo, &vec[cell[T]] old) -> cell[T] {
if (i < nelts) {
- ret old.(((lo + i) % nelts) as int);
+ ret old.((lo + i) % nelts);
} else {
ret util.none[T]();
}
@@ -47,14 +47,8 @@ fn create[T]() -> t[T] {
ret _vec.init_fn[cell[T]](copy_op, nalloc);
}
- /**
- * FIXME (issue #94): We're converting to int every time we index into the
- * vec, but we really want to index with the lo and hi uints that we have
- * around.
- */
-
- fn get[T](&vec[cell[T]] elts, uint i) -> T {
- alt (elts.(i as int)) {
+ fn get[T](vec[cell[T]] elts, uint i) -> T {
+ alt (elts.(i)) {
case (util.some[T](t)) { ret t; }
case (_) { fail; }
}
@@ -82,7 +76,7 @@ fn create[T]() -> t[T] {
hi = nelts;
}
- elts.(lo as int) = util.some[T](t);
+ elts.(lo) = util.some[T](t);
nelts += 1u;
}
@@ -93,7 +87,7 @@ fn create[T]() -> t[T] {
hi = nelts;
}
- elts.(hi as int) = util.some[T](t);
+ elts.(hi) = util.some[T](t);
hi = (hi + 1u) % _vec.len[cell[T]](elts);
nelts += 1u;
}
@@ -104,8 +98,9 @@ fn create[T]() -> t[T] {
*/
fn pop_front() -> T {
let T t = get[T](elts, lo);
- elts.(lo as int) = util.none[T]();
+ elts.(lo) = util.none[T]();
lo = (lo + 1u) % _vec.len[cell[T]](elts);
+ nelts -= 1u;
ret t;
}
@@ -117,7 +112,8 @@ fn create[T]() -> t[T] {
}
let T t = get[T](elts, hi);
- elts.(hi as int) = util.none[T]();
+ elts.(hi) = util.none[T]();
+ nelts -= 1u;
ret t;
}
diff --git a/src/lib/map.rs b/src/lib/map.rs
index f9574176..ff7b4411 100644
--- a/src/lib/map.rs
+++ b/src/lib/map.rs
@@ -75,8 +75,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
{
let uint i = 0u;
while (i < nbkts) {
- // FIXME (issue #94): as in find_common()
- let int j = (hash[K](hasher, nbkts, key, i)) as int;
+ let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](k, _)) {
if (eqer(key, k)) {
@@ -103,8 +102,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
{
let uint i = 0u;
while (i < nbkts) {
- // FIXME (issue #94): Pending bugfix, remove uint coercion.
- let int j = (hash[K](hasher, nbkts, key, i)) as int;
+ let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](k, v)) {
if (eqer(key, k)) {
@@ -149,9 +147,6 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
if (!util.rational_leq(load, lf)) {
let uint nnewbkts = _int.next_power_of_two(nbkts + 1u);
- // FIXME (issue #94): Enforce our workaround to issue #94.
- check ((nnewbkts as int) > 0);
-
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
}
@@ -183,8 +178,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
fn remove(&K key) -> util.option[V] {
let uint i = 0u;
while (i < nbkts) {
- // FIXME (issue #94): as in find_common()
- let int j = (hash[K](hasher, nbkts, key, i)) as int;
+ let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](_, val)) {
bkts.(j) = deleted[K, V]();
diff --git a/src/rt/circular_buffer.cpp b/src/rt/circular_buffer.cpp
index a93f2572..dbf5059b 100644
--- a/src/rt/circular_buffer.cpp
+++ b/src/rt/circular_buffer.cpp
@@ -31,9 +31,7 @@ circular_buffer::circular_buffer(rust_dom *dom, size_t unit_sz) :
}
circular_buffer::~circular_buffer() {
- dom->log(rust_log::MEM | rust_log::COMM,
- "~circular_buffer 0x%" PRIxPTR,
- this);
+ dom->log(rust_log::MEM, "~circular_buffer 0x%" PRIxPTR, this);
I(dom, _buffer);
W(dom, _unread == 0, "~circular_buffer with unread messages.");
dom->free(_buffer);
diff --git a/src/rt/globals.h b/src/rt/globals.h
index f8025a40..85aa5860 100644
--- a/src/rt/globals.h
+++ b/src/rt/globals.h
@@ -20,12 +20,14 @@ extern "C" {
}
#elif defined(__GNUC__)
#include <unistd.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <pthread.h>
#include <errno.h>
+#include <time.h>
#else
#error "Platform not supported."
#endif
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index 9cc2fe41..d0215edc 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -53,7 +53,9 @@ rust_srv::realloc(void *p, size_t bytes)
}
void * val = ::realloc(p, bytes);
#ifdef TRACK_ALLOCATIONS
- if (allocation_list.replace(p, val) == NULL) {
+ if (allocation_list.replace(p, val) == false) {
+ printf("realloc: ptr 0x%" PRIxPTR " is not in allocation_list\n",
+ (uintptr_t) p);
fatal("not in allocation_list", __FILE__, __LINE__);
}
#endif
@@ -64,8 +66,8 @@ void
rust_srv::free(void *p)
{
#ifdef TRACK_ALLOCATIONS
- if (allocation_list.replace(p, NULL) == NULL) {
- printf("ptr 0x%" PRIxPTR " is not in allocation_list\n",
+ if (allocation_list.replace(p, NULL) == false) {
+ printf("free: ptr 0x%" PRIxPTR " is not in allocation_list\n",
(uintptr_t) p);
fatal("not in allocation_list", __FILE__, __LINE__);
}
@@ -182,7 +184,7 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc, char **argv)
int ret;
{
rust_srv srv;
- rust_dom dom(&srv, crate);
+ rust_dom dom(&srv, crate, "main");
command_line_args args(dom, argc, argv);
dom.log(rust_log::DOM, "startup: %d args", args.argc);
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 657109c6..d8d9b8d6 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -115,6 +115,12 @@ str_buf(rust_task *task, rust_str *s)
return (char const *)&s->data[0];
}
+extern "C" CDECL size_t
+str_byte_len(rust_task *task, rust_str *s)
+{
+ return s->fill - 1; // -1 for the '\0' terminator.
+}
+
extern "C" CDECL void *
vec_buf(rust_task *task, type_desc *ty, rust_vec *v, size_t offset)
{
diff --git a/src/rt/rust_chan.cpp b/src/rt/rust_chan.cpp
index f107d287..2a0a61db 100644
--- a/src/rt/rust_chan.cpp
+++ b/src/rt/rust_chan.cpp
@@ -18,9 +18,11 @@ rust_chan::rust_chan(rust_task *task, maybe_proxy<rust_port> *port) :
}
rust_chan::~rust_chan() {
- if (port && !port->is_proxy()) {
- port->delegate()->chans.swap_delete(this);
- }
+ task->log(rust_log::MEM | rust_log::COMM,
+ "del rust_chan(task=0x%" PRIxPTR ")", (uintptr_t) this);
+
+ A(task->dom, is_associated() == false,
+ "Channel must be disassociated before being freed.");
}
/**
@@ -28,7 +30,10 @@ rust_chan::~rust_chan() {
*/
void rust_chan::associate(maybe_proxy<rust_port> *port) {
this->port = port;
- if (!port->is_proxy()) {
+ if (port->is_proxy() == false) {
+ task->log(rust_log::TASK,
+ "associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR,
+ this, port);
this->port->delegate()->chans.push(this);
}
}
@@ -43,14 +48,23 @@ bool rust_chan::is_associated() {
void rust_chan::disassociate() {
A(task->dom, is_associated(), "Channel must be associated with a port.");
+ if (port->is_proxy() == false) {
+ task->log(rust_log::TASK,
+ "disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR,
+ this, port->delegate());
+ port->delegate()->chans.swap_delete(this);
+ }
+
// Delete reference to the port.
port = NULL;
}
/**
- * Attempt to transmit channel data to the associated port.
+ * Attempt to send data to the associated port.
*/
-void rust_chan::transmit() {
+void rust_chan::send(void *sptr) {
+ buffer.enqueue(sptr);
+
rust_dom *dom = task->dom;
if (!is_associated()) {
W(dom, is_associated(),
@@ -81,7 +95,6 @@ void rust_chan::transmit() {
return;
}
-
//
// Local Variables:
// mode: C++
diff --git a/src/rt/rust_chan.h b/src/rt/rust_chan.h
index 055e359a..6aa98247 100644
--- a/src/rt/rust_chan.h
+++ b/src/rt/rust_chan.h
@@ -17,7 +17,7 @@ public:
void disassociate();
bool is_associated();
- void transmit();
+ void send(void *sptr);
};
//
diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp
index 99aaddb2..f7b8e97b 100644
--- a/src/rt/rust_dom.cpp
+++ b/src/rt/rust_dom.cpp
@@ -4,12 +4,16 @@
template class ptr_vec<rust_task>;
+// Keeps track of all live domains, for debugging purposes.
+array_list<rust_dom*> _live_domains;
-rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate) :
+rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate,
+ const char *name) :
interrupt_flag(0),
root_crate(root_crate),
_log(srv, this),
srv(srv),
+ name(name),
running_tasks(this),
blocked_tasks(this),
dead_tasks(this),
@@ -25,14 +29,19 @@ rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate) :
pthread_attr_setstacksize(&attr, 1024 * 1024);
pthread_attr_setdetachstate(&attr, true);
#endif
- root_task = new (this) rust_task(this, NULL);
+ root_task = new (this) rust_task(this, NULL, name);
+
+ if (_live_domains.replace(NULL, this) == false) {
+ _live_domains.append(this);
+ }
}
static void
del_all_tasks(rust_dom *dom, ptr_vec<rust_task> *v) {
I(dom, v);
while (v->length()) {
- dom->log(rust_log::TASK, "deleting task %" PRIdPTR, v->length() - 1);
+ dom->log(rust_log::TASK, "deleting task 0x%" PRIdPTR,
+ v->length() - 1);
delete v->pop();
}
}
@@ -42,23 +51,25 @@ rust_dom::delete_proxies() {
rust_task *task;
rust_proxy<rust_task> *task_proxy;
while (_task_proxies.pop(&task, &task_proxy)) {
- log(rust_log::TASK, "deleting proxy %" PRIxPTR
- " in dom %" PRIxPTR, task_proxy, task_proxy->dom);
+ log(rust_log::TASK,
+ "deleting proxy 0x%" PRIxPTR " in dom %s 0x%" PRIxPTR,
+ task_proxy, task_proxy->dom->name, task_proxy->dom);
delete task_proxy;
}
rust_port *port;
rust_proxy<rust_port> *port_proxy;
while (_port_proxies.pop(&port, &port_proxy)) {
- log(rust_log::TASK, "deleting proxy %" PRIxPTR
- " in dom %" PRIxPTR, port_proxy, port_proxy->dom);
+ log(rust_log::TASK,
+ "deleting proxy 0x%" PRIxPTR " in dom %s 0x%" PRIxPTR,
+ port_proxy, port_proxy->dom->name, port_proxy->dom);
delete port_proxy;
}
}
rust_dom::~rust_dom() {
log(rust_log::MEM | rust_log::DOM,
- "~rust_dom 0x%" PRIxPTR, (uintptr_t)this);
+ "~rust_dom %s @0x%" PRIxPTR, name, (uintptr_t)this);
log(rust_log::TASK, "deleting all proxies");
delete_proxies();
@@ -73,6 +84,8 @@ rust_dom::~rust_dom() {
#endif
while (caches.length())
delete caches.pop();
+
+ _live_domains.replace(this, NULL);
}
void
@@ -124,7 +137,8 @@ rust_dom::logptr(char const *msg, T* ptrval) {
void
rust_dom::fail() {
- log(rust_log::DOM, "domain 0x%" PRIxPTR " root task failed", this);
+ log(rust_log::DOM, "domain %s @0x%" PRIxPTR " root task failed",
+ name, this);
I(this, rval == 0);
rval = 1;
}
@@ -133,8 +147,9 @@ void *
rust_dom::malloc(size_t sz) {
void *p = srv->malloc(sz);
I(this, p);
- log(rust_log::MEM, "0x%" PRIxPTR " rust_dom::malloc(%d) -> 0x%" PRIxPTR,
- (uintptr_t) this, sz, p);
+ log(rust_log::MEM,
+ "%s @0x%" PRIxPTR " rust_dom::malloc(%d) -> 0x%" PRIxPTR,
+ name, (uintptr_t) this, sz, p);
return p;
}
@@ -190,8 +205,8 @@ void
rust_dom::add_task_to_state_vec(ptr_vec<rust_task> *v, rust_task *task)
{
log(rust_log::MEM|rust_log::TASK,
- "adding task 0x%" PRIxPTR " in state '%s' to vec 0x%" PRIxPTR,
- (uintptr_t)task, state_vec_name(v), (uintptr_t)v);
+ "adding task %s @0x%" PRIxPTR " in state '%s' to vec 0x%" PRIxPTR,
+ task->name, (uintptr_t)task, state_vec_name(v), (uintptr_t)v);
v->push(task);
}
@@ -200,8 +215,8 @@ void
rust_dom::remove_task_from_state_vec(ptr_vec<rust_task> *v, rust_task *task)
{
log(rust_log::MEM|rust_log::TASK,
- "removing task 0x%" PRIxPTR " in state '%s' from vec 0x%" PRIxPTR,
- (uintptr_t)task, state_vec_name(v), (uintptr_t)v);
+ "removing task %s @0x%" PRIxPTR " in state '%s' from vec 0x%" PRIxPTR,
+ task->name, (uintptr_t)task, state_vec_name(v), (uintptr_t)v);
I(this, (*v)[task->idx] == task);
v->swap_delete(task);
}
@@ -226,10 +241,10 @@ rust_dom::reap_dead_tasks() {
rust_task *task = dead_tasks[i];
if (task->ref_count == 0) {
I(this, task->tasks_waiting_to_join.is_empty());
-
dead_tasks.swap_delete(task);
log(rust_log::TASK,
- "deleting unreferenced dead task 0x%" PRIxPTR, task);
+ "deleting unreferenced dead task %s @0x%" PRIxPTR,
+ task->name, task);
delete task;
continue;
}
@@ -243,14 +258,14 @@ rust_dom::reap_dead_tasks() {
*/
void rust_dom::send_message(rust_message *message) {
log(rust_log::COMM, "==> enqueueing \"%s\" 0x%" PRIxPTR
- " in queue 0x%" PRIxPTR,
+ " in queue 0x%" PRIxPTR
+ " in domain 0x%" PRIxPTR,
message->label,
message,
- &_incoming_message_queue);
+ &_incoming_message_queue,
+ this);
A(this, message->dom == this, "Message owned by non-local domain.");
_incoming_message_queue.enqueue(message);
- _incoming_message_pending.signal();
- _progress.signal();
}
/**
@@ -272,7 +287,7 @@ rust_dom::get_task_proxy(rust_task *task) {
if (_task_proxies.get(task, &proxy)) {
return proxy;
}
- log(rust_log::COMM, "no proxy for 0x%" PRIxPTR, task);
+ log(rust_log::COMM, "no proxy for %s @0x%" PRIxPTR, task->name, task);
proxy = new (this) rust_proxy<rust_task> (this, task, false);
_task_proxies.put(task, proxy);
return proxy;
@@ -322,12 +337,20 @@ rust_dom::schedule_task()
}
void
+rust_dom::log_all_state() {
+ for (uint32_t i = 0; i < _live_domains.size(); i++) {
+ _live_domains[i]->log_state();
+ }
+}
+
+void
rust_dom::log_state() {
if (!running_tasks.is_empty()) {
log(rust_log::TASK, "running tasks:");
for (size_t i = 0; i < running_tasks.length(); i++) {
log(rust_log::TASK,
- "\t task: 0x%" PRIxPTR, running_tasks[i]);
+ "\t task: %s @0x%" PRIxPTR,
+ running_tasks[i]->name, running_tasks[i]);
}
}
@@ -335,15 +358,18 @@ rust_dom::log_state() {
log(rust_log::TASK, "blocked tasks:");
for (size_t i = 0; i < blocked_tasks.length(); i++) {
log(rust_log::TASK,
- "\t task: 0x%" PRIxPTR ", blocked on: 0x%" PRIxPTR,
- blocked_tasks[i], blocked_tasks[i]->cond);
+ "\t task: %s @0x%" PRIxPTR ", blocked on: 0x%" PRIxPTR,
+ blocked_tasks[i]->name, blocked_tasks[i],
+ blocked_tasks[i]->cond);
}
}
if (!dead_tasks.is_empty()) {
log(rust_log::TASK, "dead tasks:");
for (size_t i = 0; i < dead_tasks.length(); i++) {
- log(rust_log::TASK, "\t task: 0x%" PRIxPTR, dead_tasks[i]);
+ log(rust_log::TASK, "\t task: %s 0x%" PRIxPTR ", ref_count: %d",
+ dead_tasks[i], dead_tasks[i]->name,
+ dead_tasks[i]->ref_count);
}
}
}
@@ -360,7 +386,8 @@ rust_dom::start_main_loop()
// Make sure someone is watching, to pull us out of infinite loops.
rust_timer timer(this);
- log(rust_log::DOM, "running main-loop on domain 0x%" PRIxPTR, this);
+ log(rust_log::DOM, "running main-loop on domain %s @0x%" PRIxPTR,
+ name, this);
logptr("exit-task glue", root_crate->get_exit_task_glue());
while (n_live_tasks() > 0) {
@@ -373,29 +400,38 @@ rust_dom::start_main_loop()
// if progress is made in other domains.
if (scheduled_task == NULL) {
- log(rust_log::TASK,
- "all tasks are blocked, waiting for progress ...");
- if (_log.is_tracing(rust_log::TASK))
+ if (_log.is_tracing(rust_log::TASK)) {
log_state();
- _progress.wait();
+ }
log(rust_log::TASK,
- "progress made, resuming ...");
+ "all tasks are blocked, scheduler yielding ...");
+ sync::yield();
+ log(rust_log::TASK,
+ "scheduler resuming ...");
continue;
}
I(this, scheduled_task->running());
log(rust_log::TASK,
- "activating task 0x%" PRIxPTR ", sp=0x%" PRIxPTR,
- (uintptr_t)scheduled_task, scheduled_task->rust_sp);
+ "activating task %s 0x%" PRIxPTR
+ ", sp=0x%" PRIxPTR
+ ", ref_count=%d"
+ ", state: %s",
+ scheduled_task->name,
+ (uintptr_t)scheduled_task,
+ scheduled_task->rust_sp,
+ scheduled_task->ref_count,
+ scheduled_task->state_str());
interrupt_flag = 0;
activate(scheduled_task);
log(rust_log::TASK,
- "returned from task 0x%" PRIxPTR
+ "returned from task %s @0x%" PRIxPTR
" in state '%s', sp=0x%" PRIxPTR,
+ scheduled_task->name,
(uintptr_t)scheduled_task,
state_vec_name(scheduled_task->state),
scheduled_task->rust_sp);
@@ -410,20 +446,15 @@ rust_dom::start_main_loop()
log(rust_log::DOM, "terminated scheduler loop, reaping dead tasks ...");
while (dead_tasks.length() > 0) {
- log(rust_log::DOM,
- "waiting for %d dead tasks to become dereferenced ...",
- dead_tasks.length());
-
- if (_log.is_tracing(rust_log::DOM)) {
- for (size_t i = 0; i < dead_tasks.length(); i++) {
- log(rust_log::DOM,
- "task: 0x%" PRIxPTR ", index: %d, ref_count: %d",
- dead_tasks[i], i, dead_tasks[i]->ref_count);
- }
- }
-
if (_incoming_message_queue.is_empty()) {
- _incoming_message_pending.wait();
+ log(rust_log::DOM,
+ "waiting for %d dead tasks to become dereferenced, "
+ "scheduler yielding ...",
+ dead_tasks.length());
+ if (_log.is_tracing(rust_log::TASK)) {
+ log_state();
+ }
+ sync::yield();
} else {
drain_incoming_message_queue();
}
diff --git a/src/rt/rust_dom.h b/src/rt/rust_dom.h
index 528790d5..3aaf635a 100644
--- a/src/rt/rust_dom.h
+++ b/src/rt/rust_dom.h
@@ -25,6 +25,7 @@ struct rust_dom
rust_crate const *root_crate;
rust_log _log;
rust_srv *srv;
+ const char *const name;
ptr_vec<rust_task> running_tasks;
ptr_vec<rust_task> blocked_tasks;
ptr_vec<rust_task> dead_tasks;
@@ -34,20 +35,19 @@ struct rust_dom
rust_task *curr_task;
int rval;
- condition_variable _progress;
-
hash_map<rust_task *, rust_proxy<rust_task> *> _task_proxies;
hash_map<rust_port *, rust_proxy<rust_port> *> _port_proxies;
// Incoming messages from other domains.
- condition_variable _incoming_message_pending;
lock_free_queue _incoming_message_queue;
#ifndef __WIN32__
pthread_attr_t attr;
#endif
- rust_dom(rust_srv *srv, rust_crate const *root_crate);
+ // Only a pointer to 'name' is kept, so it must live as long as this
+ // domain.
+ rust_dom(rust_srv *srv, rust_crate const *root_crate, const char *name);
~rust_dom();
void activate(rust_task *task);
@@ -84,6 +84,7 @@ struct rust_dom
int start_main_loop();
void log_state();
+ static void log_all_state();
};
//
diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h
index a89144d7..46ea843f 100644
--- a/src/rt/rust_internal.h
+++ b/src/rt/rust_internal.h
@@ -38,6 +38,7 @@ extern "C" {
#error "Platform not supported."
#endif
+#include "sync/sync.h"
#include "sync/condition_variable.h"
#ifndef __i386__
@@ -75,7 +76,7 @@ template <typename T>
struct
rc_base
{
- size_t ref_count;
+ int32_t ref_count;
void ref() {
++ref_count;
@@ -151,6 +152,7 @@ public:
T *& operator[](size_t offset);
void push(T *p);
T *pop();
+ T *peek();
void trim(size_t fill);
void swap_delete(T* p);
};
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 48fcd0f1..8e089791 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -27,6 +27,7 @@ read_type_bit_mask() {
bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0;
bits |= strstr(env_str, "gc") ? rust_log::GC : 0;
bits |= strstr(env_str, "all") ? rust_log::ALL : 0;
+ bits = strstr(env_str, "none") ? 0 : bits;
}
return bits;
}
diff --git a/src/rt/rust_message.cpp b/src/rt/rust_message.cpp
index 8b396b4d..1de804c9 100644
--- a/src/rt/rust_message.cpp
+++ b/src/rt/rust_message.cpp
@@ -90,8 +90,7 @@ send(uint8_t *buffer, size_t buffer_sz, const char* label, rust_task *source,
}
void data_message::process() {
- _port->remote_channel->buffer.enqueue(_buffer);
- _port->remote_channel->transmit();
+ _port->remote_channel->send(_buffer);
_target->log(rust_log::COMM, "<=== received data via message ===");
}
diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp
index 0a5b7ee7..c97b5d41 100644
--- a/src/rt/rust_port.cpp
+++ b/src/rt/rust_port.cpp
@@ -17,16 +17,50 @@ rust_port::~rust_port() {
task->log(rust_log::COMM | rust_log::MEM,
"~rust_port 0x%" PRIxPTR, (uintptr_t) this);
+ log_state();
+
// Disassociate channels from this port.
while (chans.is_empty() == false) {
- chans.pop()->disassociate();
+ rust_chan *chan = chans.peek();
+ chan->disassociate();
}
- // We're the only ones holding a reference to the remote channel, so
- // clean it up.
delete remote_channel;
}
+bool rust_port::receive(void *dptr) {
+ for (uint32_t i = 0; i < chans.length(); i++) {
+ rust_chan *chan = chans[i];
+ if (chan->buffer.is_empty() == false) {
+ chan->buffer.dequeue(dptr);
+ if (chan->buffer.is_empty() && chan->task->blocked()) {
+ task->log(rust_log::COMM,
+ "chan: 0x%" PRIxPTR
+ " is flushing, wakeup task: 0x%" PRIxPTR,
+ chan, chan->task);
+ chan->task->wakeup(this);
+ }
+ task->log(rust_log::COMM, "<=== read data ===");
+ return true;
+ }
+ }
+ return false;
+}
+
+void rust_port::log_state() {
+ task->log(rust_log::COMM,
+ "rust_port: 0x%" PRIxPTR ", associated channel(s): %d",
+ this, chans.length());
+ for (uint32_t i = 0; i < chans.length(); i++) {
+ rust_chan *chan = chans[i];
+ task->log(rust_log::COMM,
+ "\tchan: 0x%" PRIxPTR ", data pending: %s, remote: %s",
+ chan,
+ !chan->buffer.is_empty() ? "yes" : "no",
+ chan == remote_channel ? "yes" : "no");
+ }
+}
+
//
// Local Variables:
// mode: C++
diff --git a/src/rt/rust_port.h b/src/rt/rust_port.h
index 49a89437..7a58f839 100644
--- a/src/rt/rust_port.h
+++ b/src/rt/rust_port.h
@@ -15,6 +15,8 @@ public:
rust_port(rust_task *task, size_t unit_sz);
~rust_port();
+ void log_state();
+ bool receive(void *dptr);
};
//
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 9f4fa611..aca8bca7 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -52,7 +52,7 @@ align_down(uintptr_t sp)
}
-rust_task::rust_task(rust_dom *dom, rust_task *spawner) :
+rust_task::rust_task(rust_dom *dom, rust_task *spawner, const char *name) :
maybe_proxy<rust_task>(this),
stk(new_stk(dom, 0)),
runtime_sp(0),
@@ -60,6 +60,7 @@ rust_task::rust_task(rust_dom *dom, rust_task *spawner) :
gc_alloc_chain(0),
dom(dom),
cache(NULL),
+ name(name),
state(&dom->running_tasks),
cond(NULL),
supervisor(spawner),
@@ -77,8 +78,8 @@ rust_task::rust_task(rust_dom *dom, rust_task *spawner) :
rust_task::~rust_task()
{
dom->log(rust_log::MEM|rust_log::TASK,
- "~rust_task 0x%" PRIxPTR ", refcnt=%d",
- (uintptr_t)this, ref_count);
+ "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
+ name, (uintptr_t)this, ref_count);
/*
for (uintptr_t fp = get_fp(); fp; fp = get_previous_fp(fp)) {
@@ -311,7 +312,7 @@ void
rust_task::yield(size_t nargs)
{
log(rust_log::TASK,
- "task 0x%" PRIxPTR " yielding", this);
+ "task %s @0x%" PRIxPTR " yielding", name, this);
run_after_return(nargs, dom->root_crate->get_yield_glue());
}
@@ -323,23 +324,29 @@ get_callee_save_fp(uintptr_t *top_of_callee_saves)
void
rust_task::kill() {
+ if (dead()) {
+ // Task is already dead, can't kill what's already dead.
+ return;
+ }
+
// Note the distinction here: kill() is when you're in an upcall
// from task A and want to force-fail task B, you do B->kill().
// If you want to fail yourself you do self->fail(upcall_nargs).
- log(rust_log::TASK, "killing task 0x%" PRIxPTR, this);
+ log(rust_log::TASK, "killing task %s @0x%" PRIxPTR, name, this);
// Unblock the task so it can unwind.
unblock();
if (this == dom->root_task)
dom->fail();
+ log(rust_log::TASK, "preparing to unwind task: 0x%" PRIxPTR, this);
run_on_resume(dom->root_crate->get_unwind_glue());
}
void
rust_task::fail(size_t nargs) {
// See note in ::kill() regarding who should call this.
- dom->log(rust_log::TASK, "task 0x%" PRIxPTR " failing", this);
+ dom->log(rust_log::TASK, "task %s @0x%" PRIxPTR " failing", name, this);
// Unblock the task so it can unwind.
unblock();
if (this == dom->root_task)
@@ -347,9 +354,9 @@ rust_task::fail(size_t nargs) {
run_after_return(nargs, dom->root_crate->get_unwind_glue());
if (supervisor) {
dom->log(rust_log::TASK,
- "task 0x%" PRIxPTR
- " propagating failure to supervisor 0x%" PRIxPTR,
- this, supervisor);
+ "task %s @0x%" PRIxPTR
+ " propagating failure to supervisor %s @0x%" PRIxPTR,
+ name, this, supervisor->name, supervisor);
supervisor->kill();
}
}
@@ -358,7 +365,7 @@ void
rust_task::gc(size_t nargs)
{
dom->log(rust_log::TASK|rust_log::MEM,
- "task 0x%" PRIxPTR " garbage collecting", this);
+ "task %s @0x%" PRIxPTR " garbage collecting", name, this);
run_after_return(nargs, dom->root_crate->get_gc_glue());
}
@@ -366,8 +373,9 @@ void
rust_task::unsupervise()
{
dom->log(rust_log::TASK,
- "task 0x%" PRIxPTR " disconnecting from supervisor 0x%" PRIxPTR,
- this, supervisor);
+ "task %s @0x%" PRIxPTR
+ " disconnecting from supervisor %s @0x%" PRIxPTR,
+ name, this, supervisor->name, supervisor);
supervisor = NULL;
}
@@ -468,8 +476,9 @@ rust_task::malloc(size_t sz, type_desc *td)
if (td) {
gc_alloc *gcm = (gc_alloc*) mem;
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
- "task 0x%" PRIxPTR " allocated %d GC bytes = 0x%" PRIxPTR,
- (uintptr_t)this, sz, gcm);
+ "task %s @0x%" PRIxPTR
+ " allocated %d GC bytes = 0x%" PRIxPTR,
+ name, (uintptr_t)this, sz, gcm);
memset((void*) gcm, 0, sizeof(gc_alloc));
link_gc(gcm);
gcm->ctrl_word = (uintptr_t)td;
@@ -488,8 +497,9 @@ rust_task::realloc(void *data, size_t sz, bool is_gc)
sz += sizeof(gc_alloc);
gcm = (gc_alloc*) dom->realloc((void*)gcm, sz);
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
- "task 0x%" PRIxPTR " reallocated %d GC bytes = 0x%" PRIxPTR,
- (uintptr_t)this, sz, gcm);
+ "task %s @0x%" PRIxPTR
+ " reallocated %d GC bytes = 0x%" PRIxPTR,
+ name, (uintptr_t)this, sz, gcm);
if (!gcm)
return gcm;
link_gc(gcm);
@@ -507,21 +517,26 @@ rust_task::free(void *p, bool is_gc)
gc_alloc *gcm = (gc_alloc*)(((char *)p) - sizeof(gc_alloc));
unlink_gc(gcm);
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
- "task 0x%" PRIxPTR " freeing GC memory = 0x%" PRIxPTR,
- (uintptr_t)this, gcm);
+ "task %s @0x%" PRIxPTR " freeing GC memory = 0x%" PRIxPTR,
+ name, (uintptr_t)this, gcm);
dom->free(gcm);
} else {
dom->free(p);
}
}
+const char *
+rust_task::state_str() {
+ return dom->state_vec_name(state);
+}
void
rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst)
{
I(dom, state == src);
dom->log(rust_log::TASK,
- "task 0x%" PRIxPTR " state change '%s' -> '%s'",
+ "task %s @0x%" PRIxPTR " state change '%s' -> '%s'",
+ name,
(uintptr_t)this,
dom->state_vec_name(src),
dom->state_vec_name(dst));
@@ -551,9 +566,6 @@ rust_task::wakeup(rust_cond *from)
A(dom, cond == from, "Cannot wake up blocked task on wrong condition.");
transition(&dom->blocked_tasks, &dom->running_tasks);
- // TODO: Signaling every time the task is awaken is kind of silly,
- // do this a nicer way.
- dom->_progress.signal();
I(dom, cond == from);
cond = NULL;
}
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index b657592a..27495e2c 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -21,6 +21,7 @@ rust_task : public maybe_proxy<rust_task>,
rust_crate_cache *cache;
// Fields known only to the runtime.
+ const char *const name;
ptr_vec<rust_task> *state;
rust_cond *cond;
rust_task *supervisor; // Parent-link for failure propagation.
@@ -41,8 +42,10 @@ rust_task : public maybe_proxy<rust_task>,
rust_alarm alarm;
+ // Only a pointer to 'name' is kept, so it must live as long as this task.
rust_task(rust_dom *dom,
- rust_task *spawner);
+ rust_task *spawner,
+ const char *name);
~rust_task();
void start(uintptr_t exit_task_glue,
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 574cb703..90d6f6d9 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -6,19 +6,37 @@
#define LOG_UPCALL_ENTRY(task) \
(task)->dom->get_log().reset_indent(0); \
(task)->log(rust_log::UPCALL, \
- "> UPCALL %s - task: 0x%" PRIxPTR \
- " retpc: x%" PRIxPTR, \
+ "> UPCALL %s - task: %s 0x%" PRIxPTR \
+ " retpc: x%" PRIxPTR \
+ " ref_count: %d", \
__FUNCTION__, \
- (task), __builtin_return_address(0)); \
+ (task)->name, (task), \
+ __builtin_return_address(0), \
+ (task->ref_count)); \
(task)->dom->get_log().indent();
#else
#define LOG_UPCALL_ENTRY(task) \
(task)->dom->get_log().reset_indent(0); \
(task)->log(rust_log::UPCALL, \
- "> UPCALL task: x%" PRIxPTR (task)); \
+ "> UPCALL task: %s @x%" PRIxPTR, \
+ (task)->name, (task)); \
(task)->dom->get_log().indent();
#endif
+void
+log_task_state(rust_task *task, maybe_proxy<rust_task> *target) {
+ rust_task *delegate = target->delegate();
+ if (target->is_proxy()) {
+ task->log(rust_log::TASK,
+ "remote task: 0x%" PRIxPTR ", ref_count: %d state: %s",
+ delegate, delegate->ref_count, delegate->state_str());
+ } else {
+ task->log(rust_log::TASK,
+ "local task: 0x%" PRIxPTR ", ref_count: %d state: %s",
+ delegate, delegate->ref_count, delegate->state_str());
+ }
+}
+
extern "C" CDECL char const *str_buf(rust_task *task, rust_str *s);
extern "C" void upcall_grow_task(rust_task *task, size_t n_frame_bytes) {
@@ -29,14 +47,13 @@ extern "C" void upcall_grow_task(rust_task *task, size_t n_frame_bytes) {
extern "C" CDECL void upcall_log_int(rust_task *task, int32_t i) {
LOG_UPCALL_ENTRY(task);
task->log(rust_log::UPCALL | rust_log::ULOG,
- "upcall log_int(0x%" PRIx32 " = %" PRId32 " = '%c')", i, i,
- (char) i);
+ "rust: %" PRId32 " (0x%" PRIx32 ")", i, i);
}
extern "C" CDECL void upcall_log_str(rust_task *task, rust_str *str) {
LOG_UPCALL_ENTRY(task);
const char *c = str_buf(task, str);
- task->log(rust_log::UPCALL | rust_log::ULOG, "upcall log_str(\"%s\")", c);
+ task->log(rust_log::UPCALL | rust_log::ULOG, "rust: %s", c);
}
extern "C" CDECL void upcall_trace_word(rust_task *task, uintptr_t i) {
@@ -55,8 +72,8 @@ upcall_new_port(rust_task *task, size_t unit_sz) {
LOG_UPCALL_ENTRY(task);
rust_dom *dom = task->dom;
task->log(rust_log::UPCALL | rust_log::MEM | rust_log::COMM,
- "upcall_new_port(task=0x%" PRIxPTR ", unit_sz=%d)",
- (uintptr_t) task, unit_sz);
+ "upcall_new_port(task=0x%" PRIxPTR " (%s), unit_sz=%d)",
+ (uintptr_t) task, task->name, unit_sz);
return new (dom) rust_port(task, unit_sz);
}
@@ -76,33 +93,58 @@ upcall_new_chan(rust_task *task, rust_port *port) {
LOG_UPCALL_ENTRY(task);
rust_dom *dom = task->dom;
task->log(rust_log::UPCALL | rust_log::MEM | rust_log::COMM,
- "upcall_new_chan(task=0x%" PRIxPTR ", port=0x%" PRIxPTR ")",
- (uintptr_t) task, port);
+ "upcall_new_chan("
+ "task=0x%" PRIxPTR " (%s), port=0x%" PRIxPTR ")",
+ (uintptr_t) task, task->name, port);
I(dom, port);
return new (dom) rust_chan(task, port);
}
/**
+ * Called whenever this channel needs to be flushed. This can happen due to a
+ * flush statement, or automatically whenever a channel's ref count is
+ * about to drop to zero.
+ */
+extern "C" CDECL void
+upcall_flush_chan(rust_task *task, rust_chan *chan) {
+ LOG_UPCALL_ENTRY(task);
+ rust_dom *dom = task->dom;
+ task->log(rust_log::UPCALL | rust_log::COMM,
+ "flush chan: 0x%" PRIxPTR, chan);
+
+ if (chan->buffer.is_empty()) {
+ return;
+ }
+
+ A(dom, chan->port->is_proxy() == false,
+ "Channels to remote ports should be flushed automatically.");
+
+ // Block on the port until this channel has been completely drained
+ // by the port.
+ task->block(chan->port);
+ task->yield(2);
+}
+
+/**
* Called whenever the channel's ref count drops to zero.
+ *
+ * Cannot Yield: If the task were to unwind, the dropped ref would still
+ * appear to be live, causing modify-after-free errors.
*/
extern "C" CDECL void upcall_del_chan(rust_task *task, rust_chan *chan) {
LOG_UPCALL_ENTRY(task);
- rust_dom *dom = task->dom;
+
task->log(rust_log::UPCALL | rust_log::MEM | rust_log::COMM,
"upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan);
- I(dom, !chan->ref_count);
-
- if (!chan->buffer.is_empty() && chan->is_associated()) {
- A(dom, !chan->port->is_proxy(),
- "Channels to remote ports should be flushed automatically.");
- // A target port may still be reading from this channel.
- // Block on this channel until it has been completely drained
- // by the port.
- task->block(chan);
- task->yield(2);
- return;
- }
+ A(task->dom, chan->ref_count == 0,
+ "Channel's ref count should be zero.");
+
+ if (chan->is_associated()) {
+ A(task->dom, chan->buffer.is_empty(),
+ "Channel's buffer should be empty.");
+ chan->disassociate();
+ }
delete chan;
}
@@ -136,11 +178,11 @@ extern "C" CDECL void upcall_yield(rust_task *task) {
extern "C" CDECL void
upcall_join(rust_task *task, maybe_proxy<rust_task> *target) {
LOG_UPCALL_ENTRY(task);
+ rust_task *target_task = target->delegate();
task->log(rust_log::UPCALL | rust_log::COMM,
- "target: 0x%" PRIxPTR ", task: 0x%" PRIxPTR,
- target, target->delegate());
+ "target: 0x%" PRIxPTR ", task: %s @0x%" PRIxPTR,
+ target, target_task->name, target_task);
- rust_task *target_task = target->delegate();
if (target->is_proxy()) {
notify_message::
send(notify_message::JOIN, "join", task, target->as_proxy());
@@ -168,8 +210,7 @@ upcall_send(rust_task *task, rust_chan *chan, void *sptr) {
"chan: 0x%" PRIxPTR ", sptr: 0x%" PRIxPTR ", size: %d",
(uintptr_t) chan, (uintptr_t) sptr,
chan->port->delegate()->unit_sz);
- chan->buffer.enqueue(sptr);
- chan->transmit();
+ chan->send(sptr);
task->log(rust_log::COMM, "=== sent data ===>");
}
@@ -182,17 +223,8 @@ upcall_recv(rust_task *task, uintptr_t *dptr, rust_port *port) {
(uintptr_t) port, (uintptr_t) dptr, port->unit_sz,
port->chans.length());
- for (uint32_t i = 0; i < port->chans.length(); i++) {
- rust_chan *chan = port->chans[i];
- if (chan->buffer.is_empty() == false) {
- chan->buffer.dequeue(dptr);
- if (chan->buffer.is_empty() && chan->task->blocked()) {
- chan->task->wakeup(chan);
- delete chan;
- }
- task->log(rust_log::COMM, "<=== read data ===");
- return;
- }
+ if (port->receive(dptr)) {
+ return;
}
// No data was buffered on any incoming channel, so block this task
@@ -219,11 +251,12 @@ extern "C" CDECL void upcall_fail(rust_task *task, char const *expr,
extern "C" CDECL void
upcall_kill(rust_task *task, maybe_proxy<rust_task> *target) {
LOG_UPCALL_ENTRY(task);
+ log_task_state(task, target);
rust_task *target_task = target->delegate();
task->log(rust_log::UPCALL | rust_log::TASK,
- "kill task 0x%" PRIxPTR ", ref count %d",
- target_task,
+ "kill task %s @0x%" PRIxPTR ", ref count %d",
+ target_task->name, target_task,
target_task->ref_count);
if (target->is_proxy()) {
@@ -244,6 +277,8 @@ upcall_exit(rust_task *task) {
LOG_UPCALL_ENTRY(task);
task->log(rust_log::UPCALL | rust_log::TASK,
"task ref_count: %d", task->ref_count);
+ A(task->dom, task->ref_count >= 0,
+ "Task ref_count should not be negative on exit!");
task->die();
task->notify_tasks_waiting_to_join();
task->yield(1);
@@ -498,14 +533,14 @@ static void *rust_thread_start(void *ptr)
}
extern "C" CDECL rust_task *
-upcall_new_task(rust_task *spawner) {
+upcall_new_task(rust_task *spawner, const char *name) {
LOG_UPCALL_ENTRY(spawner);
rust_dom *dom = spawner->dom;
- rust_task *task = new (dom) rust_task(dom, spawner);
+ rust_task *task = new (dom) rust_task(dom, spawner, name);
dom->log(rust_log::UPCALL | rust_log::MEM | rust_log::TASK,
- "upcall new_task(spawner 0x%" PRIxPTR ") = 0x%" PRIxPTR,
- spawner, task);
+ "upcall new_task(spawner %s @0x%" PRIxPTR ", %s) = 0x%" PRIxPTR,
+ spawner->name, spawner, name, task);
return task;
}
@@ -516,26 +551,27 @@ upcall_start_task(rust_task *spawner, rust_task *task,
rust_dom *dom = spawner->dom;
dom->log(rust_log::UPCALL | rust_log::MEM | rust_log::TASK,
- "upcall start_task(task 0x%" PRIxPTR
+ "upcall start_task(task %s @0x%" PRIxPTR
" exit_task_glue 0x%" PRIxPTR
", spawnee 0x%" PRIxPTR
- ", callsz %" PRIdPTR ")", task, exit_task_glue, spawnee_fn,
- callsz);
+ ", callsz %" PRIdPTR ")", task->name, task, exit_task_glue,
+ spawnee_fn, callsz);
task->start(exit_task_glue, spawnee_fn, spawner->rust_sp, callsz);
return task;
}
extern "C" CDECL maybe_proxy<rust_task> *
-upcall_new_thread(rust_task *task) {
+upcall_new_thread(rust_task *task, const char *name) {
LOG_UPCALL_ENTRY(task);
rust_dom *old_dom = task->dom;
rust_dom *new_dom = new rust_dom(old_dom->srv->clone(),
- old_dom->root_crate);
+ old_dom->root_crate,
+ name);
task->log(rust_log::UPCALL | rust_log::MEM,
- "upcall new_thread() = dom 0x%" PRIxPTR " task 0x%" PRIxPTR,
- new_dom, new_dom->root_task);
+ "upcall new_thread(%s) = dom 0x%" PRIxPTR " task 0x%" PRIxPTR,
+ name, new_dom, new_dom->root_task);
rust_proxy<rust_task> *proxy =
new (old_dom) rust_proxy<rust_task>(old_dom,
new_dom->root_task, true);
diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h
index 42082119..03b7766d 100644
--- a/src/rt/rust_util.h
+++ b/src/rt/rust_util.h
@@ -70,6 +70,13 @@ ptr_vec<T>::pop()
}
template <typename T>
+T *
+ptr_vec<T>::peek()
+{
+ return data[fill - 1];
+}
+
+template <typename T>
void
ptr_vec<T>::trim(size_t sz)
{
@@ -140,11 +147,20 @@ isaac_init(rust_dom *dom, randctx *rctx)
CryptReleaseContext(hProv, 0));
}
#else
- int fd = open("/dev/urandom", O_RDONLY);
- I(dom, fd > 0);
- I(dom, read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl))
- == sizeof(rctx->randrsl));
- I(dom, close(fd) == 0);
+ char *rust_seed = getenv("RUST_SEED");
+ if (rust_seed != NULL) {
+ ub4 seed = (ub4) atoi(rust_seed);
+ for (size_t i = 0; i < RANDSIZ; i ++) {
+ memcpy(&rctx->randrsl[i], &seed, sizeof(ub4));
+ seed = (seed + 0x7ed55d16) + (seed << 12);
+ }
+ } else {
+ int fd = open("/dev/urandom", O_RDONLY);
+ I(dom, fd > 0);
+ I(dom, read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl))
+ == sizeof(rctx->randrsl));
+ I(dom, close(fd) == 0);
+ }
#endif
randinit(rctx, 1);
}
diff --git a/src/rt/sync/condition_variable.cpp b/src/rt/sync/condition_variable.cpp
index d4032572..c34ab7f4 100644
--- a/src/rt/sync/condition_variable.cpp
+++ b/src/rt/sync/condition_variable.cpp
@@ -9,14 +9,16 @@
// #define TRACE
-condition_variable::condition_variable() {
#if defined(__WIN32__)
+condition_variable::condition_variable() {
_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
#else
+condition_variable::condition_variable() {
pthread_cond_init(&_cond, NULL);
pthread_mutex_init(&_mutex, NULL);
-#endif
}
+#endif
condition_variable::~condition_variable() {
#if defined(__WIN32__)
@@ -31,15 +33,31 @@ condition_variable::~condition_variable() {
* Wait indefinitely until condition is signaled.
*/
void condition_variable::wait() {
+ timed_wait(0);
+}
+
+void condition_variable::timed_wait(size_t timeout_in_ns) {
#ifdef TRACE
- printf("waiting on condition_variable: 0x%" PRIxPTR "\n",
- (uintptr_t)this);
+ printf("waiting on condition_variable: 0x%" PRIxPTR " for %d ns. \n",
+ (uintptr_t) this, (int) timeout_in_ns);
#endif
#if defined(__WIN32__)
WaitForSingleObject(_event, INFINITE);
#else
pthread_mutex_lock(&_mutex);
- pthread_cond_wait(&_cond, &_mutex);
+ // wait() automatically releases the mutex while it waits, and acquires
+ // it right before exiting. This allows signal() to acquire the mutex
+ // when signaling.)
+ if (timeout_in_ns == 0) {
+ pthread_cond_wait(&_cond, &_mutex);
+ } else {
+ timeval time_val;
+ gettimeofday(&time_val, NULL);
+ timespec time_spec;
+ time_spec.tv_sec = time_val.tv_sec + 0;
+ time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ns;
+ pthread_cond_timedwait(&_cond, &_mutex, &time_spec);
+ }
pthread_mutex_unlock(&_mutex);
#endif
#ifdef TRACE
diff --git a/src/rt/sync/condition_variable.h b/src/rt/sync/condition_variable.h
index f847ef99..f336a7f2 100644
--- a/src/rt/sync/condition_variable.h
+++ b/src/rt/sync/condition_variable.h
@@ -13,6 +13,7 @@ public:
virtual ~condition_variable();
void wait();
+ void timed_wait(size_t timeout_in_ns);
void signal();
};
diff --git a/src/rt/sync/sync.cpp b/src/rt/sync/sync.cpp
new file mode 100644
index 00000000..eba51a49
--- /dev/null
+++ b/src/rt/sync/sync.cpp
@@ -0,0 +1,12 @@
+#include "../globals.h"
+#include "sync.h"
+
+void sync::yield() {
+#ifdef __APPLE__
+ pthread_yield_np();
+#elif __WIN32__
+
+#else
+ pthread_yield();
+#endif
+}
diff --git a/src/rt/sync/sync.h b/src/rt/sync/sync.h
new file mode 100644
index 00000000..902b5661
--- /dev/null
+++ b/src/rt/sync/sync.h
@@ -0,0 +1,9 @@
+#ifndef SYNC_H
+#define SYNC_H
+
+class sync {
+public:
+ static void yield();
+};
+
+#endif /* SYNC_H */
diff --git a/src/rt/util/array_list.h b/src/rt/util/array_list.h
index e6ce55ab..929117f3 100644
--- a/src/rt/util/array_list.h
+++ b/src/rt/util/array_list.h
@@ -16,7 +16,7 @@ public:
int32_t append(T value);
int32_t push(T value);
T pop();
- T replace(T old_value, T new_value);
+ bool replace(T old_value, T new_value);
int32_t index_of(T value);
bool is_empty();
T & operator[](size_t index);
@@ -62,16 +62,16 @@ array_list<T>::pop() {
/**
* Replaces the old_value in the list with the new_value.
- * Returns the old_value if the replacement succeeded, or NULL otherwise.
+ * Returns the true if the replacement succeeded, or false otherwise.
*/
-template<typename T> T
+template<typename T> bool
array_list<T>::replace(T old_value, T new_value) {
int index = index_of(old_value);
if (index < 0) {
- return NULL;
+ return false;
}
_data[index] = new_value;
- return old_value;
+ return true;
}
template<typename T> int32_t
diff --git a/src/run.py b/src/run.py
new file mode 100644
index 00000000..4cce4102
--- /dev/null
+++ b/src/run.py
@@ -0,0 +1,81 @@
+import os
+import sys
+import time
+import glob
+import fnmatch
+from optparse import OptionParser
+
+rustDir = os.path.abspath('.')
+rustTestDir = rustDir + "/test";
+rustTestRunPassDir = rustTestDir + "/run-pass";
+rustTestRunFailDir = rustTestDir + "/run-fail";
+rustTestCompileFailDir = rustTestDir + "/run-compile-fail";
+rustTestRunBenchDir = rustTestDir + "/run-bench";
+
+parser = OptionParser()
+parser.set_usage("run.py [options] pattern : run.py -n 100 \"bas*\" -q");
+parser.add_option("-n", dest="repetitions",
+ help="number of repetitions", metavar="NUMBER")
+parser.add_option("-q", action="store_true", dest="quiet", default=False,
+ help="suppresses rust log output")
+parser.add_option("-p", action="store_true", dest="printSource",
+ default=False, help="prints the test case's source")
+parser.add_option("-s", dest="seed", metavar="NUMBER", default=-1,
+ help="seeds the rust scheduler, use -1 to generate seeds, "
+ + " or >= 0 to specify a seed")
+
+(options, args) = parser.parse_args()
+
+def getRustTests(filter):
+ tests = []
+ for root, dirnames, filenames in os.walk(rustTestDir):
+ for filename in fnmatch.filter(filenames, filter + '.rs'):
+ tests.append(os.path.join(root, filename).
+ replace(rustDir + "/", ""));
+ return tests
+
+
+if len(args) != 1:
+ parser.print_usage();
+ sys.exit(0);
+
+tests = getRustTests(args[0]);
+
+# Make
+for rustProgram in tests:
+ print "Making: " + rustProgram;
+ result = os.system("make " + rustProgram.replace(".rs", ".x86")) >> 8;
+ if (result != 0):
+ print "Make failed!";
+ sys.exit(1);
+
+if (options.quiet):
+ os.putenv("RUST_LOG", "none")
+
+# Rut
+totalPassed = 0;
+for rustProgram in tests:
+ repetitions = 1;
+ if (options.repetitions):
+ repetitions = int(options.repetitions);
+ passed = 0;
+ if (options.printSource):
+ os.system("cat " + rustProgram);
+ for i in range(0, repetitions):
+ print "Running: " + rustProgram + " " + str(i) + \
+ " of " + str(repetitions);
+ if (options.seed):
+ if (int(options.seed) >= 0):
+ os.putenv("RUST_SEED", options.seed);
+ else:
+ os.putenv("RUST_SEED", str(i));
+ result = os.system(rustProgram.replace(".rs", ".x86"));
+ exitStatus = result >> 8;
+ signalNumber = result & 0xF;
+ if (result == 0):
+ passed += 1;
+ print "Result for: " + rustProgram + " " + str(passed) + \
+ " of " + str(repetitions) + " passed.";
+ totalPassed += passed;
+print "Total: " + str(totalPassed) + " of " + \
+ str(len(tests) * repetitions) + " passed." \ No newline at end of file
diff --git a/src/test/run-pass/arith-0.rs b/src/test/run-pass/arith-0.rs
new file mode 100644
index 00000000..7587b005
--- /dev/null
+++ b/src/test/run-pass/arith-0.rs
@@ -0,0 +1,5 @@
+fn main() -> () {
+ let int a = 10;
+ log a;
+ check (a * (a - 1) == 90);
+} \ No newline at end of file
diff --git a/src/test/run-pass/arith-1.rs b/src/test/run-pass/arith-1.rs
new file mode 100644
index 00000000..bac6a055
--- /dev/null
+++ b/src/test/run-pass/arith-1.rs
@@ -0,0 +1,22 @@
+fn main() -> () {
+ let int i32_a = 10;
+ check(i32_a == 10);
+ check(i32_a - 10 == 0);
+ check(i32_a / 10 == 1);
+ check(i32_a - 20 == -10);
+ check(i32_a << 10 == 10240);
+ check(i32_a << 16 == 655360);
+ check(i32_a * 16 == 160);
+ check(i32_a * i32_a * i32_a == 1000);
+ check(i32_a * i32_a * i32_a * i32_a == 10000);
+ check(((i32_a * i32_a) / i32_a) * i32_a == 100);
+ check(i32_a * (i32_a - 1) << 2 + i32_a == 368640);
+
+ let int i32_b = 0x10101010;
+ check(i32_b + 1 - 1 == i32_b);
+ check(i32_b << 1 == i32_b << 1);
+ check(i32_b >> 1 == i32_b >> 1);
+ check((i32_b & (i32_b << 1)) == 0);
+ log ((i32_b | (i32_b << 1)));
+ check((i32_b | (i32_b << 1)) == 0x30303030);
+} \ No newline at end of file
diff --git a/src/test/run-pass/arith-2.rs b/src/test/run-pass/arith-2.rs
new file mode 100644
index 00000000..33a740c8
--- /dev/null
+++ b/src/test/run-pass/arith-2.rs
@@ -0,0 +1,5 @@
+fn main() -> () {
+ let int i32_c = 0x10101010;
+ check (i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) ==
+ i32_c + (((i32_c * 2) / 3) * 2) + (i32_c - (7 % 3)));
+} \ No newline at end of file
diff --git a/src/test/run-pass/basic-1.rs b/src/test/run-pass/basic-1.rs
new file mode 100644
index 00000000..bdd7ee25
--- /dev/null
+++ b/src/test/run-pass/basic-1.rs
@@ -0,0 +1,25 @@
+// -*- rust -*-
+
+io fn a(chan[int] c) {
+ c <| 10;
+}
+
+io fn main() {
+ let port[int] p = port();
+ spawn a(chan(p));
+ spawn b(chan(p));
+ let int n = 0;
+ n <- p;
+ n <- p;
+// log "Finished.";
+}
+
+io fn b(chan[int] c) {
+// log "task b0";
+// log "task b1";
+// log "task b2";
+// log "task b3";
+// log "task b4";
+// log "task b5";
+ c <| 10;
+} \ No newline at end of file
diff --git a/src/test/run-pass/basic-2.rs b/src/test/run-pass/basic-2.rs
new file mode 100644
index 00000000..975a0d4b
--- /dev/null
+++ b/src/test/run-pass/basic-2.rs
@@ -0,0 +1,26 @@
+// -*- rust -*-
+
+io fn a(chan[int] c) {
+ log "task a0";
+ log "task a1";
+ c <| 10;
+}
+
+io fn main() {
+ let port[int] p = port();
+ spawn a(chan(p));
+ spawn b(chan(p));
+ let int n = 0;
+ n <- p;
+ n <- p;
+ log "Finished.";
+}
+
+io fn b(chan[int] c) {
+ log "task b0";
+ log "task b1";
+ log "task b2";
+ log "task b2";
+ log "task b3";
+ c <| 10;
+}
diff --git a/src/test/run-pass/destructor-ordering.rs b/src/test/run-pass/destructor-ordering.rs
index 99479c55..f7f5b8c8 100644
--- a/src/test/run-pass/destructor-ordering.rs
+++ b/src/test/run-pass/destructor-ordering.rs
@@ -1,58 +1,93 @@
-// We share an instance of this type among all the destructor-order
-// checkers. It tracks how many destructors have run so far and
-// 'fail's when one runs out of order.
-// FIXME: Make it easier to collect a failure message.
-state obj order_tracker(mutable int init) {
- fn assert_order(int expected, str fail_message) {
- if (expected != init) {
- log expected;
+// This test checks that destructors run in the right order. Because
+// stateful objects can't have destructors, we have the destructors
+// record their expected order into a channel when they execute (so
+// the object becomes 'io' rather than 'state'). Then each test case
+// asserts that the channel produces values in ascending order.
+//
+// FIXME: Write an int->str function and concatenate the whole failure
+// message into a single log statement (or, even better, a print).
+//
+// FIXME: check_order should take only 1 line in a test, not 2+a block
+// block. Since destructor-having objects can't refer to mutable state
+// (like the port), we'd need a with-like construct to do the same for
+// stateful objects within a scope.
+//
+// FIXME #21: Each test should execute in its own task, so it can fail
+// independently, writing its error message to a channel that the
+// parent task aggregates.
+
+type order_info = rec(int order, str msg);
+
+io fn check_order(port[order_info] expected_p) {
+ chan(expected_p) <| rec(order=-1, msg="");
+ let mutable int actual = 0;
+ auto expected <- expected_p; // FIXME #121: Workaround for while(true) bug.
+ auto done = -1; // FIXME: Workaround for typechecking bug.
+ while(expected.order != done) {
+ if (expected.order != actual) {
+ log expected.order;
log " != ";
- log init;
- log fail_message;
+ log actual;
+ log expected.msg;
fail;
}
- init += 1;
+ actual += 1;
+ expected <- expected_p;
}
}
-obj dorder(@order_tracker tracker, int order, str message) {
+obj dorder(chan[order_info] expected, int order, str message) {
drop {
- tracker.assert_order(order, message);
+ expected <| rec(order=order, msg=message);
}
}
-fn test_simple() {
- auto tracker = @order_tracker(0);
+io fn test_simple() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
dorder(tracker, 1, "Reverse decl order");
dorder(tracker, 0, "Reverse decl order");
+ check_order(tracker_p);
}
-fn test_block() {
- auto tracker = @order_tracker(0);
- dorder(tracker, 2, "Before block");
+io fn test_block() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
{
- dorder(tracker, 0, "Inside block");
+ dorder(tracker, 2, "Before block");
+ {
+ dorder(tracker, 0, "Inside block");
+ }
+ dorder(tracker, 1, "After block");
}
- dorder(tracker, 1, "After block");
+ check_order(tracker_p);
}
-fn test_decl_v_init() {
- auto tracker = @order_tracker(0);
- auto var1;
- auto var2;
- var2 = dorder(tracker, 0, "decl, not init");
- var1 = dorder(tracker, 1, "decl, not init");
+io fn test_decl_v_init() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
+ {
+ auto var1;
+ auto var2;
+ var2 = dorder(tracker, 0, "decl, not init");
+ var1 = dorder(tracker, 1, "decl, not init");
+ }
+ check_order(tracker_p);
}
-fn test_overwritten_obj() {
- auto tracker = @order_tracker(0);
- auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
- auto var2 = dorder(tracker, 2, "destroyed at end of scope");
- var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
+io fn test_overwritten_obj() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
{
- dorder(tracker, 1, "overwritten object destroyed before end of scope");
+ auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
+ auto var2 = dorder(tracker, 2, "destroyed at end of scope");
+ var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
+ {
+ dorder(tracker, 1, "overwritten object destroyed before end of scope");
+ }
}
+ check_order(tracker_p);
}
// Used to embed dorder objects into an expression. Note that the
@@ -60,17 +95,21 @@ fn test_overwritten_obj() {
fn combine_dorders(dorder d1, dorder d2) -> int {
ret 1;
}
-fn test_expression_destroyed_right_to_left() {
- auto tracker = @order_tracker(0);
- combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
- / combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
+io fn test_expression_destroyed_right_to_left() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
{
- dorder(tracker, 0,
- "expression objects live to end of block, not statement");
+ combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
+ / combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
+ {
+ dorder(tracker, 0,
+ "expression objects live to end of block, not statement");
+ }
}
+ check_order(tracker_p);
}
-fn main() {
+io fn main() {
test_simple();
test_block();
test_decl_v_init();
diff --git a/src/test/run-pass/int-lib.rs b/src/test/run-pass/int-lib.rs
new file mode 100644
index 00000000..ce39de43
--- /dev/null
+++ b/src/test/run-pass/int-lib.rs
@@ -0,0 +1,15 @@
+use std;
+
+import std._int;
+
+fn test_to_str() {
+ check (_int.to_str(0, 10u) == "0");
+ check (_int.to_str(1, 10u) == "1");
+ check (_int.to_str(-1, 10u) == "-1");
+ check (_int.to_str(255, 16u) == "ff");
+ check (_int.to_str(-71, 36u) == "-1z");
+}
+
+fn main() {
+ test_to_str();
+}
diff --git a/src/test/run-pass/integral-indexing.rs b/src/test/run-pass/integral-indexing.rs
new file mode 100644
index 00000000..fe7d147c
--- /dev/null
+++ b/src/test/run-pass/integral-indexing.rs
@@ -0,0 +1,22 @@
+// This is a testcase for issue #94.
+
+fn main() {
+
+ let vec[int] v = vec(0, 1, 2, 3, 4, 5);
+ let str s = "abcdef";
+ check (v.(3u) == 3);
+ check (v.(3u8) == 3);
+ check (v.(3i8) == 3);
+ check (v.(3u32) == 3);
+ check (v.(3i32) == 3);
+
+ log v.(3u8);
+
+ check (s.(3u) == 'd' as u8);
+ check (s.(3u8) == 'd' as u8);
+ check (s.(3i8) == 'd' as u8);
+ check (s.(3u32) == 'd' as u8);
+ check (s.(3i32) == 'd' as u8);
+
+ log s.(3u8);
+} \ No newline at end of file
diff --git a/src/test/run-pass/lib-map.rs b/src/test/run-pass/lib-map.rs
index 11101c84..058fb237 100644
--- a/src/test/run-pass/lib-map.rs
+++ b/src/test/run-pass/lib-map.rs
@@ -4,13 +4,17 @@ use std;
import std.map;
fn test_simple() {
+ log "*** starting test_simple";
+
fn eq(&uint x, &uint y) -> bool { ret x == y; }
let map.hashfn[uint] hasher = std.util.id[uint];
let map.eqfn[uint] eqer = eq;
let map.hashmap[uint, uint] hm = map.mk_hashmap[uint, uint](hasher, eqer);
+
+ log "*** finished test_simple";
}
fn main() {
test_simple();
-} \ No newline at end of file
+}
diff --git a/src/test/run-pass/str-lib.rs b/src/test/run-pass/str-lib.rs
new file mode 100644
index 00000000..585f9b8d
--- /dev/null
+++ b/src/test/run-pass/str-lib.rs
@@ -0,0 +1,16 @@
+use std;
+import std._str;
+
+fn test_bytes_len() {
+ check (_str.byte_len("") == 0u);
+ check (_str.byte_len("hello world") == 11u);
+ check (_str.byte_len("\x63") == 1u);
+ check (_str.byte_len("\xa2") == 2u);
+ check (_str.byte_len("\u03c0") == 2u);
+ check (_str.byte_len("\u2620") == 3u);
+ check (_str.byte_len("\U0001d11e") == 4u);
+}
+
+fn main() {
+ test_bytes_len();
+}
diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs
index 5992ba5c..28294422 100644
--- a/src/test/run-pass/task-comm-0.rs
+++ b/src/test/run-pass/task-comm-0.rs
@@ -15,5 +15,5 @@ io fn test05() {
let int value <- po;
value <- po;
value <- po;
- log value;
+ check(value == 30);
}
diff --git a/src/test/run-pass/task-comm-2.rs b/src/test/run-pass/task-comm-2.rs
index 9c85da34..864d49de 100644
--- a/src/test/run-pass/task-comm-2.rs
+++ b/src/test/run-pass/task-comm-2.rs
@@ -1,8 +1,8 @@
fn main() -> () {
- log "===== THREADS =====";
+ log "===== SPAWNING and JOINING TASKS =====";
+ test00(false);
+ log "===== SPAWNING and JOINING THREAD TASKS =====";
test00(true);
- log "====== TASKS ======";
- // test00(false);
}
fn start(int task_number) {
@@ -15,7 +15,7 @@ fn start(int task_number) {
}
fn test00(bool create_threads) {
- let int number_of_tasks = 0;
+ let int number_of_tasks = 8;
let int i = 0;
let vec[task] tasks = vec();
diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs
index 6dd620cc..9a3f9e16 100644
--- a/src/test/run-pass/task-comm-3.rs
+++ b/src/test/run-pass/task-comm-3.rs
@@ -1,6 +1,8 @@
io fn main() -> () {
- log "===== THREADS =====";
+ log "===== WITHOUT THREADS =====";
test00(false);
+ log "====== WITH THREADS ======";
+ test00(true);
}
io fn test00_start(chan[int] ch, int message, int count) {
@@ -15,8 +17,9 @@ io fn test00_start(chan[int] ch, int message, int count) {
}
io fn test00(bool is_multithreaded) {
- let int number_of_tasks = 1;
- let int number_of_messages = 0;
+ let int number_of_tasks = 16;
+ let int number_of_messages = 4;
+
log "Creating tasks";
let port[int] po = port();
@@ -27,13 +30,13 @@ io fn test00(bool is_multithreaded) {
// Create and spawn tasks...
let vec[task] tasks = vec();
while (i < number_of_tasks) {
- i = i + 1;
if (is_multithreaded) {
tasks += vec(
spawn thread test00_start(ch, i, number_of_messages));
} else {
tasks += vec(spawn test00_start(ch, i, number_of_messages));
}
+ i = i + 1;
}
// Read from spawned tasks...
@@ -53,7 +56,7 @@ io fn test00(bool is_multithreaded) {
}
log "Completed: Final number is: ";
- check (sum + 1 == number_of_messages *
- (number_of_tasks * number_of_tasks + number_of_tasks) / 2);
- log sum;
-} \ No newline at end of file
+ // check (sum == (((number_of_tasks * (number_of_tasks - 1)) / 2) *
+ // number_of_messages));
+ check (sum == 480);
+}
diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs
index c579a98c..2774c0ba 100644
--- a/src/test/run-pass/task-comm-6.rs
+++ b/src/test/run-pass/task-comm-6.rs
@@ -31,6 +31,8 @@ io fn test00() {
r <- p; sum += r;
i += 1;
}
-
- check (sum == 4 * ((number_of_messages * (number_of_messages - 1)) / 2));
+
+ check (sum == 1998000);
+ // check (sum == 4 * ((number_of_messages *
+ // (number_of_messages - 1)) / 2));
} \ No newline at end of file
diff --git a/src/test/run-pass/task-comm.rs b/src/test/run-pass/task-comm.rs
index ef71c6e1..3c5d3216 100644
--- a/src/test/run-pass/task-comm.rs
+++ b/src/test/run-pass/task-comm.rs
@@ -1,11 +1,11 @@
-fn main() -> () {
- // test00(true);
+io fn main() -> () {
+ test00(true);
// test01();
- // test02();
- // test03();
- // test04();
- // test05();
+ test02();
+ test03();
+ test04();
+ test05();
test06();
}
@@ -22,7 +22,7 @@ io fn test00_start(chan[int] ch, int message, int count) {
io fn test00(bool is_multithreaded) {
let int number_of_tasks = 1;
- let int number_of_messages = 64;
+ let int number_of_messages = 4;
log "Creating tasks";
let port[int] po = port();
@@ -103,7 +103,7 @@ fn test04_start() {
fn test04() {
log "Spawning lots of tasks.";
- let int i = 64;
+ let int i = 4;
while (i > 0) {
i = i - 1;
spawn thread test04_start();
@@ -139,7 +139,7 @@ fn test06_start(int task_number) {
}
fn test06() {
- let int number_of_tasks = 32;
+ let int number_of_tasks = 4;
log "Creating tasks";
let int i = 0;