aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--doc/rust.texi54
-rw-r--r--src/Makefile76
-rw-r--r--src/boot/be/abi.ml5
-rw-r--r--src/boot/be/elf.ml142
-rw-r--r--src/boot/be/il.ml7
-rw-r--r--src/boot/be/pe.ml30
-rw-r--r--src/boot/be/x86.ml109
-rw-r--r--src/boot/driver/session.ml4
-rw-r--r--src/boot/fe/ast.ml41
-rw-r--r--src/boot/fe/cexp.ml45
-rw-r--r--src/boot/fe/item.ml24
-rw-r--r--src/boot/fe/lexer.mll87
-rw-r--r--src/boot/fe/parser.ml3
-rw-r--r--src/boot/fe/pexp.ml29
-rw-r--r--src/boot/me/alias.ml2
-rw-r--r--src/boot/me/dwarf.ml14
-rw-r--r--src/boot/me/effect.ml2
-rw-r--r--src/boot/me/layout.ml10
-rw-r--r--src/boot/me/resolve.ml1
-rw-r--r--src/boot/me/semant.ml74
-rw-r--r--src/boot/me/trans.ml264
-rw-r--r--src/boot/me/type.ml37
-rw-r--r--src/boot/me/typestate.ml66
-rw-r--r--src/boot/me/walk.ml2
-rw-r--r--src/boot/util/common.ml2
-rw-r--r--src/comp/driver/rustc.rs52
-rw-r--r--src/comp/fe/ast.rs58
-rw-r--r--src/comp/fe/lexer.rs113
-rw-r--r--src/comp/fe/parser.rs33
-rw-r--r--src/comp/fe/token.rs333
-rw-r--r--src/comp/lib/llvm.rs1145
-rw-r--r--src/comp/rustc.rc28
-rw-r--r--src/comp/util/common.rs28
-rw-r--r--src/etc/tidy.py17
-rw-r--r--src/lib/_int.rs58
-rw-r--r--src/lib/_io.rs226
-rw-r--r--src/lib/_str.rs51
-rw-r--r--src/lib/_task.rs12
-rw-r--r--src/lib/_uint.rs86
-rw-r--r--src/lib/_vec.rs44
-rw-r--r--src/lib/deque.rs6
-rw-r--r--src/lib/linux_os.rs6
-rw-r--r--src/lib/macos_os.rs6
-rw-r--r--src/lib/map.rs2
-rw-r--r--src/lib/std.rc5
-rw-r--r--src/lib/win32_os.rs6
-rw-r--r--src/rt/circular_buffer.cpp12
-rw-r--r--src/rt/circular_buffer.h1
-rw-r--r--src/rt/globals.h2
-rw-r--r--src/rt/memory.h60
-rw-r--r--src/rt/memory_region.cpp100
-rw-r--r--src/rt/memory_region.h37
-rw-r--r--src/rt/rust.cpp105
-rw-r--r--src/rt/rust.h21
-rw-r--r--src/rt/rust_builtin.cpp125
-rw-r--r--src/rt/rust_chan.cpp27
-rw-r--r--src/rt/rust_chan.h2
-rw-r--r--src/rt/rust_dom.cpp242
-rw-r--r--src/rt/rust_dom.h25
-rw-r--r--src/rt/rust_internal.h41
-rw-r--r--src/rt/rust_log.cpp20
-rw-r--r--src/rt/rust_log.h2
-rw-r--r--src/rt/rust_message.cpp22
-rw-r--r--src/rt/rust_message.h7
-rw-r--r--src/rt/rust_port.cpp39
-rw-r--r--src/rt/rust_port.h2
-rw-r--r--src/rt/rust_srv.cpp80
-rw-r--r--src/rt/rust_srv.h34
-rw-r--r--src/rt/rust_task.cpp82
-rw-r--r--src/rt/rust_task.h14
-rw-r--r--src/rt/rust_upcall.cpp153
-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/lock_free_queue.cpp4
-rw-r--r--src/rt/sync/lock_free_queue.h3
-rw-r--r--src/rt/sync/sync.cpp12
-rw-r--r--src/rt/sync/sync.h9
-rw-r--r--src/rt/sync/timer.cpp61
-rw-r--r--src/rt/sync/timer.h25
-rw-r--r--src/rt/util/array_list.h10
-rwxr-xr-xsrc/run.py102
-rw-r--r--src/test/run-pass/acyclic-unwind.rs5
-rw-r--r--src/test/run-pass/append-units.rs15
-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/arithmetic-interference.rs7
-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/lib-deque.rs104
-rw-r--r--src/test/run-pass/lib-io.rs26
-rw-r--r--src/test/run-pass/lib-vec-str-conversions.rs41
-rw-r--r--src/test/run-pass/size-and-align.rs15
-rw-r--r--src/test/run-pass/task-comm-0.rs2
-rw-r--r--src/test/run-pass/task-comm-10.rs15
-rw-r--r--src/test/run-pass/task-comm-11.rs10
-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
-rw-r--r--src/test/run-pass/task-lib.rs6
-rw-r--r--src/test/run-pass/task-life-0.rs7
-rw-r--r--src/test/run-pass/while-flow-graph.rs4
105 files changed, 4087 insertions, 1289 deletions
diff --git a/.gitignore b/.gitignore
index e4a13eba..f515b922 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
*.x86
*.llvm
*.out
+*.x86.tmp
+*.llvm.tmp
*.cmx
*.dll
*.exe
@@ -30,6 +32,8 @@
*.swp
.hg/
.hgignore
+.cproject
+.project
lexer.ml
rustboot
rustc
diff --git a/doc/rust.texi b/doc/rust.texi
index 3aa079d7..fcfb6499 100644
--- a/doc/rust.texi
+++ b/doc/rust.texi
@@ -599,6 +599,7 @@ Unicode characters.
* Ref.Lex.Ignore:: Ignored characters.
* Ref.Lex.Ident:: Identifier tokens.
* Ref.Lex.Key:: Keyword tokens.
+* Ref.Lex.Res:: Reserved tokens.
* Ref.Lex.Num:: Numeric tokens.
* Ref.Lex.Text:: String and character tokens.
* Ref.Lex.Syntax:: Syntactic extension tokens.
@@ -636,7 +637,7 @@ token or a syntactic extension token. Multi-line comments may be nested.
Identifiers follow the pattern of C identifiers: they begin with a
@emph{letter} or @emph{underscore}, and continue with any combination of
@emph{letters}, @emph{decimal digits} and underscores, and must not be equal
-to any keyword. @xref{Ref.Lex.Key}.
+to any keyword or reserved token. @xref{Ref.Lex.Key}. @xref{Ref.Lex.Res}.
A @emph{letter} is a Unicode character in the ranges U+0061-U+007A and
U+0041-U+005A (@code{'a'}-@code{'z'} and @code{'A'}-@code{'Z'}).
@@ -728,6 +729,35 @@ The keywords are:
@tab @code{be}
@end multitable
+@node Ref.Lex.Res
+@subsection Ref.Lex.Res
+@c * Ref.Lex.Res:: Reserved tokens.
+
+The reserved tokens are:
+@cindex Reserved
+
+@sp 2
+
+@multitable @columnfractions .15 .15 .15 .15 .15
+@item @code{f16}
+@tab @code{f80}
+@tab @code{f128}
+@item @code{m32}
+@tab @code{m64}
+@tab @code{m128}
+@tab @code{dec}
+@end multitable
+
+@sp 2
+
+At present these tokens have no defined meaning in the Rust language.
+
+These tokens may correspond, in some current or future implementation,
+to additional built-in types for decimal floating-point, extended
+binary and interchange floating-point formats, as defined in the IEEE
+754-1985 and IEEE 754-2008 specifications.
+
+
@node Ref.Lex.Num
@subsection Ref.Lex.Num
@c * Ref.Lex.Num:: Numeric tokens.
@@ -785,6 +815,10 @@ only two floating-point suffixes: @code{f32} and @code{f64}. Each of these
gives the floating point literal the associated type, rather than
@code{float}.
+A set of suffixes are also reserved to accommodate literal support for
+types corresponding to reserved tokens. The reserved suffixes are @code{f16},
+@code{f80}, @code{f128}, @code{m}, @code{m32}, @code{m64} and @code{m128}.
+
@sp 1
A @dfn{hex digit} is either a @emph{decimal digit} or else a character in the
ranges U+0061-U+0066 and U+0041-U+0046 (@code{'a'}-@code{'f'},
@@ -2024,7 +2058,7 @@ The signed two's complement word types @code{i8}, @code{i16}, @code{i32} and
@end ifhtml
respectively.
@item
-The IEEE 754 single-precision and double-precision floating-point types:
+The IEEE 754-2008 @code{binary32} and @code{binary64} floating-point types:
@code{f32} and @code{f64}, respectively.
@end itemize
@@ -2822,12 +2856,15 @@ x.y = z + 2;
@c * Ref.Stmt.Spawn:: Statements creating new tasks.
@cindex Spawn statement
-A @code{spawn} statement consists of keyword @code{spawn}, followed by a
-normal @emph{call} statement (@pxref{Ref.Stmt.Call}). A @code{spawn}
-statement causes the runtime to construct a new task executing the called
-function. The called function is referred to as the @dfn{entry function} for
-the spawned task, and its arguments are copied from the spawning task to the
-spawned task before the spawned task begins execution.
+A @code{spawn} statement consists of keyword @code{spawn}, followed by
+an optional literal string naming the new task and then a normal
+@emph{call} statement (@pxref{Ref.Stmt.Call}). A @code{spawn}
+statement causes the runtime to construct a new task executing the
+called function with the given name. The called function is referred
+to as the @dfn{entry function} for the spawned task, and its arguments
+are copied from the spawning task to the spawned task before the
+spawned task begins execution. If no explicit name is present, the
+task is implicitly named with the string of the call statement.
Functions taking alias-slot arguments, or returning non-nil values, cannot be
spawned. Iterators cannot be spawned.
@@ -2843,6 +2880,7 @@ fn helper(chan[u8] out) @{
let port[u8] out;
let task p = spawn helper(chan(out));
+let task p2 = spawn "my_helper" helper(chan(out));
// let task run, do other things.
auto result <- out;
diff --git a/src/Makefile b/src/Makefile
index 10810c05..76e11272 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -35,7 +35,7 @@ ifeq ($(CFG_OSTYPE), Linux)
CFG_RUNTIME := librustrt.so
CFG_STDLIB := libstd.so
CFG_GCC_CFLAGS += -fPIC
- CFG_GCC_LINK_FLAGS += -shared -fPIC -ldl -lpthread
+ CFG_GCC_LINK_FLAGS += -shared -fPIC -ldl -lpthread -lrt
ifeq ($(CFG_CPUTYPE), x86_64)
CFG_GCC_CFLAGS += -m32
CFG_GCC_LINK_FLAGS += -m32
@@ -245,7 +245,9 @@ 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/timer.cpp \
+ rt/sync/sync.cpp \
+ rt/sync/spin_lock.cpp \
rt/sync/lock_free_queue.cpp \
rt/sync/condition_variable.cpp \
rt/rust.cpp \
@@ -263,7 +265,9 @@ RUNTIME_CS := rt/sync/spin_lock.cpp \
rt/rust_message.cpp \
rt/rust_timer.cpp \
rt/circular_buffer.cpp \
- rt/isaac/randport.cpp
+ rt/isaac/randport.cpp \
+ rt/rust_srv.cpp \
+ rt/memory_region.cpp
RUNTIME_HDR := rt/globals.h \
rt/rust.h \
@@ -279,7 +283,12 @@ 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 \
+ rt/sync/timer.h \
+ rt/rust_srv.h \
+ rt/memory_region.h \
+ rt/memory.h
RUNTIME_INCS := -Irt/isaac -Irt/uthash
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=$(CFG_OBJ_SUFFIX))
@@ -296,7 +305,7 @@ all: $(CFG_COMPILER) $(MKFILES) $(GENERATED)
boot/util/version.ml: Makefile
$(CFG_QUIET)git log -1 \
- --format='let version = "prerelease (%h %ci)";;' >$@
+ --format='let version = "prerelease (%h %ci)";;' >$@ || exit 1
loc:
$(CFG_QUIET)wc -l $(BOOT_MLS) $(RUNTIME_CS) $(RUNTIME_HDR)
@@ -380,13 +389,14 @@ TASK_XFAILS := test/run-pass/acyclic-unwind.rs \
test/run-pass/task-comm-7.rs \
test/run-pass/task-comm-8.rs \
test/run-pass/task-comm-9.rs \
+ test/run-pass/task-comm-10.rs \
+ test/run-pass/task-comm-11.rs \
+ test/run-pass/task-life-0.rs \
test/run-pass/task-comm.rs \
test/run-pass/threads.rs \
test/run-pass/yield.rs
TEST_XFAILS_X86 := $(TASK_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 \
@@ -398,16 +408,13 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
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-io.rs \
test/run-pass/lib-map.rs \
test/run-pass/mlist-cycle.rs \
test/run-pass/obj-as.rs \
test/run-pass/task-comm.rs \
test/run-pass/vec-slice.rs \
- test/run-pass/task-comm-2.rs \
test/run-pass/task-comm-3.rs \
- test/run-pass/task-comm-5.rs \
- test/run-pass/task-comm-6.rs \
test/compile-fail/bad-recv.rs \
test/compile-fail/bad-send.rs \
test/compile-fail/infinite-tag-type-recursion.rs \
@@ -416,14 +423,17 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
TEST_XFAILS_LLVM := $(TASK_XFAILS) \
$(addprefix test/run-pass/, \
+ arith-1.rs \
acyclic-unwind.rs \
alt-pattern-simple.rs \
alt-tag.rs \
- arithmetic-interference.rs \
+ append-units.rs \
argv.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 \
@@ -464,7 +474,6 @@ 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 \
@@ -474,8 +483,10 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
lazy-init.rs \
lazychan.rs \
lib-deque.rs \
+ lib-io.rs \
lib-map.rs \
lib-rand.rs \
+ lib-vec-str-conversions.rs \
linear-for-loop.rs \
list.rs \
many.rs \
@@ -500,6 +511,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
rec-tup.rs \
rec.rs \
simple-obj.rs \
+ size-and-align.rs \
spawn-fn.rs \
spawn-module-qualified.rs \
spawn.rs \
@@ -508,6 +520,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
str-concat.rs \
str-idx.rs \
str-lib.rs \
+ task-lib.rs \
tag.rs \
tail-cps.rs \
tail-direct.rs \
@@ -522,6 +535,9 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
task-comm-7.rs \
task-comm-8.rs \
task-comm-9.rs \
+ task-comm-10.rs \
+ task-comm-11.rs \
+ task-life-0.rs \
threads.rs \
type-sizes.rs \
u8-incr.rs \
@@ -541,6 +557,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
vec-lib.rs \
vec-slice.rs \
vec.rs \
+ while-flow-graph.rs \
writealias.rs \
yield.rs \
yield2.rs \
@@ -602,6 +619,10 @@ TEST_RPASS_OUTS_X86 := \
$(TEST_RPASS_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
TEST_RPASS_OUTS_LLVM := \
$(TEST_RPASS_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
+TEST_RPASS_TMPS_X86 := \
+ $(TEST_RPASS_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
+TEST_RPASS_TMPS_LLVM := \
+ $(TEST_RPASS_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_RFAIL_CRATES_X86 := $(filter-out $(TEST_XFAILS_X86), $(RFAIL_RC))
@@ -619,6 +640,10 @@ TEST_RFAIL_OUTS_X86 := \
$(TEST_RFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
TEST_RFAIL_OUTS_LLVM := \
$(TEST_RFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
+TEST_RFAIL_TMPS_X86 := \
+ $(TEST_RFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
+TEST_RFAIL_TMPS_LLVM := \
+ $(TEST_RFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_CFAIL_CRATES_X86 := $(filter-out $(TEST_XFAILS_X86), $(CFAIL_RC))
@@ -636,6 +661,11 @@ TEST_CFAIL_OUTS_X86 := \
$(TEST_CFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
TEST_CFAIL_OUTS_LLVM := \
$(TEST_CFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
+TEST_CFAIL_TMPS_X86 := \
+ $(TEST_CFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
+TEST_CFAIL_TMPS_LLVM := \
+ $(TEST_CFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
+
ALL_TEST_CRATES := $(TEST_CFAIL_CRATES_X86) \
$(TEST_RFAIL_CRATES_X86) \
@@ -690,10 +720,12 @@ BOOT := $(CFG_QUIET)OCAMLRUNPARAM="b1" $(CFG_BOOT) $(CFG_BOOT_FLAGS)
$(CFG_QUIET)mv $< $@
test/run-pass/%.out.tmp: test/run-pass/%$(CFG_EXE_SUFFIX) $(CFG_RUNTIME)
+ $(CFG_QUIET)rm -f $<.tmp
@$(call CFG_ECHO, run: $<)
$(CFG_QUIET)$(call CFG_RUN_TARG, $<) > $@
test/run-fail/%.out.tmp: test/run-fail/%$(CFG_EXE_SUFFIX) $(CFG_RUNTIME)
+ $(CFG_QUIET)rm -f $<.tmp
@$(call CFG_ECHO, run: $<)
$(CFG_QUIET)rm -f $@
$(CFG_QUIET)$(call CFG_RUN_TARG, $<) >$@ 2>&1 ; X=$$? ; \
@@ -886,12 +918,18 @@ clean:
$(CFG_QUIET)rm -f $(ML_DEPFILES) $(C_DEPFILES) $(CRATE_DEPFILES)
$(CFG_QUIET)rm -f $(GENERATED)
$(CFG_QUIET)rm -f $(CFG_BOOT) $(CFG_RUNTIME) $(CFG_STDLIB)
- $(CFG_QUIET)rm -f $(TEST_RPASS_EXES_X86) $(TEST_RPASS_OUTS_X86)
- $(CFG_QUIET)rm -f $(TEST_RPASS_EXES_LLVM) $(TEST_RPASS_OUTS_LLVM)
- $(CFG_QUIET)rm -f $(TEST_RFAIL_EXES_X86) $(TEST_RFAIL_OUTS_X86)
- $(CFG_QUIET)rm -f $(TEST_RFAIL_EXES_LLVM) $(TEST_RFAIL_OUTS_LLVM)
- $(CFG_QUIET)rm -f $(TEST_CFAIL_EXES_X86) $(TEST_CFAIL_OUTS_X86)
- $(CFG_QUIET)rm -f $(TEST_CFAIL_EXES_LLVM) $(TEST_CFAIL_OUTS_LLVM)
+ $(CFG_QUIET)rm -f $(TEST_RPASS_EXES_X86) $(TEST_RPASS_OUTS_X86) \
+ $(TEST_RPASS_TMPS_X86)
+ $(CFG_QUIET)rm -f $(TEST_RPASS_EXES_LLVM) $(TEST_RPASS_OUTS_LLVM) \
+ $(TEST_RPASS_TMPS_LLVM)
+ $(CFG_QUIET)rm -f $(TEST_RFAIL_EXES_X86) $(TEST_RFAIL_OUTS_X86) \
+ $(TEST_RFAIL_TMPS_X86)
+ $(CFG_QUIET)rm -f $(TEST_RFAIL_EXES_LLVM) $(TEST_RFAIL_OUTS_LLVM) \
+ $(TEST_RFAIL_TMPS_LLVM)
+ $(CFG_QUIET)rm -f $(TEST_CFAIL_EXES_X86) $(TEST_CFAIL_OUTS_X86) \
+ $(TEST_CFAIL_TMPS_X86)
+ $(CFG_QUIET)rm -f $(TEST_CFAIL_EXES_LLVM) $(TEST_CFAIL_OUTS_LLVM) \
+ $(TEST_CFAIL_TMPS_LLVM)
$(CFG_QUIET)rm -rf $(TEST_RPASS_EXES_LLVM:.llvm=.llvm.dSYM)
$(CFG_QUIET)rm -rf $(TEST_RFAIL_EXES_LLVM:.llvm=.llvm.dSYM)
$(CFG_QUIET)rm -Rf $(PKG_NAME)-*.tar.gz dist
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/elf.ml b/src/boot/be/elf.ml
index 3d25657b..406508e4 100644
--- a/src/boot/be/elf.ml
+++ b/src/boot/be/elf.ml
@@ -169,14 +169,16 @@ type sh_flags =
let section_header
+ ?(sh_link:int64 option=None)
+ ?(sh_info:int64 option=None)
+ ?(zero_sh_addr:bool=false)
+ ?(sh_flags:sh_flags list=[])
+ ?(section_fixup:fixup option=None)
+ ?(sh_addralign:int64=1L)
+ ?(sh_entsize:int64=0L)
~(shstring_table_fixup:fixup)
~(shname_string_fixup:fixup)
- ~(sh_type:sh_type)
- ~(sh_flags:sh_flags list)
- ~(section_fixup:fixup option)
- ~(sh_addralign:int64)
- ~(sh_entsize:int64)
- ~(sh_link:int64 option)
+ (sh_type:sh_type)
: frag =
SEQ
[|
@@ -201,9 +203,12 @@ let section_header
SHF_WRITE -> 0x1L
| SHF_ALLOC -> 0x2L
| SHF_EXECINSTR -> 0x4L) sh_flags)));
- WORD (TY_u32, (match section_fixup with
- None -> (IMM 0L)
- | Some s -> (M_POS s)));
+ WORD (TY_u32,
+ if zero_sh_addr
+ then IMM 0L
+ else (match section_fixup with
+ None -> (IMM 0L)
+ | Some s -> (M_POS s)));
WORD (TY_u32, (match section_fixup with
None -> (IMM 0L)
| Some s -> (F_POS s)));
@@ -213,7 +218,9 @@ let section_header
WORD (TY_u32, (IMM (match sh_link with
None -> 0L
| Some i -> i)));
- WORD (TY_u32, (IMM 0L)); (* sh_info *)
+ WORD (TY_u32, (IMM (match sh_info with
+ None -> 0L
+ | Some i -> i)));
WORD (TY_u32, (IMM sh_addralign));
WORD (TY_u32, (IMM sh_entsize));
|]
@@ -633,7 +640,7 @@ let elf32_linux_x86_file
let dynsymndx = 4L in (* Section index of .dynsym *)
let dynstrndx = 5L in (* Section index of .dynstr *)
(* let hashndx = 6L in *) (* Section index of .hash *)
- (* let pltndx = 7L in *) (* Section index of .plt *)
+ let pltndx = 7L in (* Section index of .plt *)
(* let gotpltndx = 8L in *) (* Section index of .got.plt *)
(* let relapltndx = 9L in *) (* Section index of .rela.plt *)
let datandx = 10L in (* Section index of .data *)
@@ -690,155 +697,129 @@ let elf32_linux_x86_file
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: null_section_name_fixup
- ~sh_type: SHT_NULL
- ~sh_flags: []
~section_fixup: None
~sh_addralign: 0L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_NULL);
(* .interp *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: interp_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some interp_section_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .text *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: text_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC; SHF_EXECINSTR ]
~section_fixup: (Some text_section_fixup)
~sh_addralign: 32L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .rodata *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: rodata_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some rodata_section_fixup)
~sh_addralign: 32L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .dynsym *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: dynsym_section_name_fixup
- ~sh_type: SHT_DYNSYM
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some dynsym_section_fixup)
- ~sh_addralign: 8L
+ ~sh_addralign: 4L
~sh_entsize: elf32_symsize
- ~sh_link: (Some dynstrndx) );
+ ~sh_link: (Some dynstrndx)
+ SHT_DYNSYM);
(* .dynstr *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: dynstr_section_name_fixup
- ~sh_type: SHT_STRTAB
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some dynstr_section_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_STRTAB);
(* .hash *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: hash_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some hash_section_fixup)
~sh_addralign: 4L
~sh_entsize: 4L
- ~sh_link: (Some dynsymndx));
+ SHT_PROGBITS);
(* .plt *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: plt_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC; SHF_EXECINSTR ]
~section_fixup: (Some plt_section_fixup)
~sh_addralign: 4L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .got.plt *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: got_plt_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC; SHF_WRITE ]
~section_fixup: (Some got_plt_section_fixup)
~sh_addralign: 4L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .rela.plt *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: rela_plt_section_name_fixup
- ~sh_type: SHT_RELA
~sh_flags: [ SHF_ALLOC ]
~section_fixup: (Some rela_plt_section_fixup)
~sh_addralign: 4L
~sh_entsize: elf32_rela_entsz
- ~sh_link: (Some dynsymndx));
+ ~sh_link: (Some dynsymndx)
+ ~sh_info: (Some pltndx)
+ SHT_RELA);
(* .data *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: data_section_name_fixup
- ~sh_type: SHT_PROGBITS
~sh_flags: [ SHF_ALLOC; SHF_WRITE ]
~section_fixup: (Some data_section_fixup)
~sh_addralign: 32L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_PROGBITS);
(* .bss *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: bss_section_name_fixup
- ~sh_type: SHT_NOBITS
~sh_flags: [ SHF_ALLOC; SHF_WRITE ]
~section_fixup: (Some bss_section_fixup)
~sh_addralign: 32L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_NOBITS);
(* .dynamic *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: dynamic_section_name_fixup
- ~sh_type: SHT_DYNAMIC
~sh_flags: [ SHF_ALLOC; SHF_WRITE ]
~section_fixup: (Some dynamic_section_fixup)
~sh_addralign: 8L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~sh_link: (Some dynstrndx)
+ SHT_DYNAMIC);
(* .shstrtab *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: shstrtab_section_name_fixup
- ~sh_type: SHT_STRTAB
- ~sh_flags: []
~section_fixup: (Some shstrtab_section_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_STRTAB);
(*
FIXME: uncomment the dwarf section headers as you make use of them;
@@ -852,58 +833,45 @@ let elf32_linux_x86_file
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_aranges_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_aranges_fixup)
~sh_addralign: 8L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
*)
(* .debug_pubnames *)
(*
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_pubnames_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_pubnames_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
*)
(* .debug_info *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_info_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_info_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
(* .debug_abbrev *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_abbrev_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_abbrev_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
+
(* .debug_line *)
(*
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_line_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_line_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
*)
(* .debug_frame *)
@@ -911,24 +879,18 @@ let elf32_linux_x86_file
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: debug_frame_section_name_fixup
- ~sh_type: SHT_PROGBITS
- ~sh_flags: []
~section_fixup: (Some sem.Semant.ctxt_debug_frame_fixup)
~sh_addralign: 4L
- ~sh_entsize: 0L
- ~sh_link: None);
+ ~zero_sh_addr: true
+ SHT_PROGBITS);
*)
(* .note.rust *)
(section_header
~shstring_table_fixup: shstrtab_section_fixup
~shname_string_fixup: note_rust_section_name_fixup
- ~sh_type: SHT_NOTE
- ~sh_flags: []
~section_fixup: (Some note_rust_section_fixup)
- ~sh_addralign: 1L
- ~sh_entsize: 0L
- ~sh_link: None);
+ SHT_NOTE);
|]
in
@@ -999,7 +961,7 @@ let elf32_linux_x86_file
elf32_header
~sess
~ei_data: ELFDATA2LSB
- ~e_type: ET_DYN
+ ~e_type: (if sess.Session.sess_library_mode then ET_DYN else ET_EXEC)
~e_machine: EM_386
~e_version: EV_CURRENT
diff --git a/src/boot/be/il.ml b/src/boot/be/il.ml
index 172d8661..2a5b643a 100644
--- a/src/boot/be/il.ml
+++ b/src/boot/be/il.ml
@@ -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/pe.ml b/src/boot/be/pe.ml
index d360ddf5..b85cb1a9 100644
--- a/src/boot/be/pe.ml
+++ b/src/boot/be/pe.ml
@@ -783,9 +783,35 @@ let crate_exports (sem:Semant.ctxt) : pe_export array =
let export_seg (_, tab) =
Array.of_list (List.map export_sym (htab_pairs tab))
in
+
+ (* Make some fake symbol table entries to aid in debugging. *)
+ let export_stab name fixup =
+ {
+ pe_export_name_fixup = new_fixup "export name fixup";
+ pe_export_name = "rust$" ^ name;
+ pe_export_address_fixup = fixup
+ }
+ in
+ let export_stab_of_item (node_id, code) =
+ let name = Hashtbl.find sem.Semant.ctxt_all_item_names node_id in
+ let name' = "item$" ^ (Semant.string_of_name name) in
+ export_stab name' code.Semant.code_fixup
+ in
+ let export_stab_of_glue (glue, code) =
+ export_stab (Semant.glue_str sem glue) code.Semant.code_fixup
+ in
+
+ let stabs =
+ Array.of_list (List.concat [
+ (List.map export_stab_of_item
+ (htab_pairs sem.Semant.ctxt_all_item_code));
+ (List.map export_stab_of_glue (htab_pairs sem.Semant.ctxt_glue_code))
+ ])
+ in
+
Array.concat
- (List.map export_seg
- (htab_pairs sem.Semant.ctxt_native_provided))
+ (stabs::(List.map export_seg
+ (htab_pairs sem.Semant.ctxt_native_provided)))
;;
diff --git a/src/boot/be/x86.ml b/src/boot/be/x86.ml
index 55b101bb..f879027b 100644
--- a/src/boot/be/x86.ml
+++ b/src/boot/be/x86.ml
@@ -303,7 +303,7 @@ let emit_target_specific
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 rhs in
- (* Horrible: we bounce complex mul inputs off spill slots
+ (* Horrible: we bounce mul/div/mod inputs off spill slots
* to ensure non-interference between the temporaries used
* during mem-base-reg reloads and the registers we're
* preparing. *)
@@ -311,32 +311,26 @@ let emit_target_specific
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
+ let is_eax cell =
+ match cell with
+ Il.Cell (Il.Reg (Il.Hreg hr, _)) -> hr = eax
| _ -> 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);
-
+ in
+ if is_eax lhs
+ then
+ mov rhs_ecx rhs
+ else
+ begin
+ let lhs_spill = next_spill_like lhs in
+ let rhs_spill = next_spill_like rhs in
+
+ mov lhs_spill lhs;
+ mov rhs_spill rhs;
+
+ mov lhs_eax (Il.Cell lhs_spill);
+ mov rhs_ecx (Il.Cell rhs_spill);
+ end;
+
put (Il.Binary
{ b with
Il.binary_lhs = (Il.Cell lhs_eax);
@@ -344,7 +338,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
@@ -593,6 +587,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 ]
@@ -1033,7 +1028,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
@@ -1045,11 +1040,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)
@@ -1061,15 +1093,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) ->
@@ -1185,6 +1225,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
@@ -1314,7 +1355,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)
diff --git a/src/boot/driver/session.ml b/src/boot/driver/session.ml
index d9e57b02..d295763a 100644
--- a/src/boot/driver/session.ml
+++ b/src/boot/driver/session.ml
@@ -93,7 +93,7 @@ let string_of_pos (p:pos) =
let string_of_span (s:span) =
let (filename, line0, col0) = s.lo in
let (_, line1, col1) = s.hi in
- Printf.sprintf "%s:%d:%d - %d:%d" filename line0 col0 line1 col1
+ Printf.sprintf "%s:%d:%d:%d:%d" filename line0 col0 line1 col1
;;
let filename_of (fo:filename option) : filename =
@@ -111,7 +111,7 @@ let report_err sess ido str =
None ->
fail sess "Error: %s\n%!" str
| Some span ->
- fail sess "%s:E:Error: %s\n%!"
+ fail sess "%s: error: %s\n%!"
(string_of_span span) str
;;
diff --git a/src/boot/fe/ast.ml b/src/boot/fe/ast.ml
index 3f3d5145..79ff2c7c 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,7 @@ 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 +1272,13 @@ 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 +1286,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,18 +1300,17 @@ 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 ((ident, slot), block) = type_arm.node in
let fmt_type_arm_case (ff:Format.formatter) =
fmt_slot ff slot; fmt ff " "; fmt_ident ff ident
in
fmt_arm ff fmt_type_arm_case 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;
@@ -1320,7 +1320,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
@@ -1351,9 +1350,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/cexp.ml b/src/boot/fe/cexp.ml
index fc849b28..9c1b40e1 100644
--- a/src/boot/fe/cexp.ml
+++ b/src/boot/fe/cexp.ml
@@ -310,7 +310,7 @@ type cdir =
| CDIR_mod of (Ast.ident * Ast.mod_item)
| CDIR_auth of auth
-type env = { env_bindings: (Ast.ident * pval) list;
+type env = { env_bindings: ((Ast.ident * pval) list) ref;
env_prefix: filename list;
env_items: (filename, Ast.mod_items) Hashtbl.t;
env_files: (node_id,filename) Hashtbl.t;
@@ -357,10 +357,11 @@ and eval_cexp (env:env) (exp:cexp) : cdir array =
| CEXP_let {node=cl} ->
let ident = cl.let_ident in
let v = eval_pexp env cl.let_value in
- let env = { env with
- env_bindings = ((ident,v)::env.env_bindings ) }
- in
- eval_cexps env cl.let_body
+ let old_bindings = !(env.env_bindings) in
+ env.env_bindings := (ident,v)::old_bindings;
+ let res = eval_cexps env cl.let_body in
+ env.env_bindings := old_bindings;
+ res
| CEXP_src_mod {node=s; id=id} ->
let name = s.src_ident in
@@ -381,6 +382,7 @@ and eval_cexp (env:env) (exp:cexp) : cdir array =
ps.pstate_opaque_id
ps.pstate_sess
ps.pstate_get_mod
+ ps.pstate_get_cenv_tok
ps.pstate_infer_lib_name
env.env_required
env.env_required_syms
@@ -518,7 +520,7 @@ and eval_pexp (env:env) (exp:Pexp.pexp) : pval =
| Pexp.PEXP_lval (Pexp.PLVAL_ident ident) ->
begin
- match ltab_search env.env_bindings ident with
+ match ltab_search !(env.env_bindings) ident with
None -> raise (err (Printf.sprintf "no binding for '%s' found"
ident) env.env_ps)
| Some v -> v
@@ -622,11 +624,6 @@ let parse_crate_file
let oref = ref (Opaque 0) in
let required = Hashtbl.create 4 in
let required_syms = Hashtbl.create 4 in
- let ps =
- make_parser tref nref oref sess get_mod
- infer_lib_name required required_syms fname
- in
-
let files = Hashtbl.create 0 in
let items = Hashtbl.create 4 in
let target_bindings =
@@ -648,11 +645,23 @@ let parse_crate_file
("build_input", PVAL_str fname);
]
in
- let initial_bindings =
- target_bindings
- @ build_bindings
+ let bindings =
+ ref (target_bindings
+ @ build_bindings)
in
- let env = { env_bindings = initial_bindings;
+ let get_cenv_tok ps ident =
+ match ltab_search (!bindings) ident with
+ None -> raise (err (Printf.sprintf "no binding for '%s' found"
+ ident) ps)
+ | Some (PVAL_bool b) -> LIT_BOOL b
+ | Some (PVAL_str s) -> LIT_STR s
+ | Some (PVAL_num n) -> LIT_INT n
+ in
+ let ps =
+ make_parser tref nref oref sess get_mod get_cenv_tok
+ infer_lib_name required required_syms fname
+ in
+ let env = { env_bindings = bindings;
env_prefix = [Filename.dirname fname];
env_items = Hashtbl.create 0;
env_files = files;
@@ -720,8 +729,12 @@ let parse_src_file
let oref = ref (Opaque 0) in
let required = Hashtbl.create 0 in
let required_syms = Hashtbl.create 0 in
+ let get_cenv_tok ps ident =
+ raise (err (Printf.sprintf "no binding for '%s' found"
+ ident) ps)
+ in
let ps =
- make_parser tref nref oref sess get_mod
+ make_parser tref nref oref sess get_mod get_cenv_tok
infer_lib_name required required_syms fname
in
with_err_handling sess
diff --git a/src/boot/fe/item.ml b/src/boot/fe/item.ml
index 67a482a6..a47fca5a 100644
--- a/src/boot/fe/item.ml
+++ b/src/boot/fe/item.ml
@@ -556,7 +556,11 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
let stmts = expand_tags_to_stmts ps item in
spans ps stmts apos (Ast.STMT_decl decl)
- | _ ->
+ | token ->
+ if token = SPAWN then
+ prerr_endline ("warning: \"spawn\" with unused result spawns a " ^
+ "task that immediately dies");
+
let (lstmts, lval) = ctxt "stmt: lval" parse_lval ps in
let stmts =
match peek ps with
@@ -834,9 +838,17 @@ and parse_mod_item (ps:pstate) : (Ast.ident * Ast.mod_item) =
EQ ->
begin
bump ps;
- match peek ps with
- LIT_STR s -> (bump ps; s)
- | _ -> raise (unexpected ps)
+ let do_tok t =
+ bump ps;
+ match t with
+ LIT_STR s -> s
+ | _ -> raise (unexpected ps)
+ in
+ match peek ps with
+ IDENT i ->
+ do_tok (ps.pstate_get_cenv_tok ps i)
+ | t ->
+ do_tok t
end
| _ -> ps.pstate_infer_lib_name ident
in
@@ -888,14 +900,14 @@ and parse_mod_item (ps:pstate) : (Ast.ident * Ast.mod_item) =
| _ -> CONV_cdecl
in
expect ps MOD;
- let (ident, params) = parse_ident_and_params ps "native mod" in
+ let ident = Pexp.parse_ident ps in
let path = parse_lib_name ident in
let items = parse_mod_items_from_signature ps in
let bpos = lexpos ps in
let rlib = REQUIRED_LIB_c { required_libname = path;
required_prefix = ps.pstate_depth }
in
- let item = decl params (Ast.MOD_ITEM_mod items) in
+ let item = decl [||] (Ast.MOD_ITEM_mod items) in
let item = span ps apos bpos item in
note_required_mod ps {lo=apos; hi=bpos} conv rlib item;
(ident, item)
diff --git a/src/boot/fe/lexer.mll b/src/boot/fe/lexer.mll
index ed548b1e..af8eab6a 100644
--- a/src/boot/fe/lexer.mll
+++ b/src/boot/fe/lexer.mll
@@ -27,8 +27,12 @@
<- (bump_line lexbuf.Lexing.lex_curr_p)
;;
- let mach_suf_table = Hashtbl.create 0
+ let mach_suf_table = Hashtbl.create 10
;;
+
+ let reserved_suf_table = Hashtbl.create 10
+ ;;
+
let _ =
List.iter (fun (suf, ty) -> Common.htab_put mach_suf_table suf ty)
[ ("u8", Common.TY_u8);
@@ -43,8 +47,24 @@
("f64", Common.TY_f64); ]
;;
+ let _ =
+ List.iter (fun suf -> Common.htab_put reserved_suf_table suf ())
+ [ "f16"; (* IEEE 754-2008 'binary16' interchange format. *)
+ "f80"; (* IEEE 754-1985 'extended' *)
+ "f128"; (* IEEE 754-2008 'binary128' *)
+ "m32"; (* IEEE 754-2008 'decimal32' *)
+ "m64"; (* IEEE 754-2008 'decimal64' *)
+ "m128"; (* IEEE 754-2008 'decimal128' *)
+ "m"; (* One of m32, m64, m128. *)
+ ]
+ ;;
+
let keyword_table = Hashtbl.create 100
;;
+
+ let reserved_table = Hashtbl.create 10
+ ;;
+
let _ =
List.iter (fun (kwd, tok) -> Common.htab_put keyword_table kwd tok)
[ ("mod", MOD);
@@ -141,6 +161,19 @@
("f64", MACH TY_f64)
]
;;
+
+ let _ =
+ List.iter (fun kwd -> Common.htab_put reserved_table kwd ())
+ [ "f16"; (* IEEE 754-2008 'binary16' interchange format. *)
+ "f80"; (* IEEE 754-1985 'extended' *)
+ "f128"; (* IEEE 754-2008 'binary128' *)
+ "m32"; (* IEEE 754-2008 'decimal32' *)
+ "m64"; (* IEEE 754-2008 'decimal64' *)
+ "m128"; (* IEEE 754-2008 'decimal128' *)
+ "dec"; (* One of m32, m64, m128. *)
+ ];
+ ;;
+
}
let hexdig = ['0'-'9' 'a'-'f' 'A'-'F']
@@ -153,6 +186,7 @@ let flo = (dec '.' dec (exp?)) | (dec exp)
let mach_float_suf = "f32"|"f64"
let mach_int_suf = ['u''i']('8'|"16"|"32"|"64")
+let flo_suf = ['m''f']("16"|"32"|"64"|"80"|"128")
let ws = [ ' ' '\t' '\r' ]
@@ -218,26 +252,39 @@ rule token = parse
| ']' { RBRACKET }
| id as i
- { try
- Hashtbl.find keyword_table i
- with
- Not_found -> IDENT (i) }
+ {
+ match Common.htab_search keyword_table i with
+ Some tok -> tok
+ | None ->
+ if Hashtbl.mem reserved_table i
+ then fail lexbuf "reserved keyword"
+ else IDENT (i)
+ }
| (bin|hex|dec) as n { LIT_INT (Int64.of_string n) }
| ((bin|hex|dec) as n) 'u' { LIT_UINT (Int64.of_string n) }
| ((bin|hex|dec) as n)
- (mach_int_suf as s) { try
- let tm =
- Hashtbl.find mach_suf_table s
- in
- LIT_MACH_INT
- (tm, Int64.of_string n)
- with
- Not_found ->
- fail lexbuf
- "bad mach-int suffix" }
+ (mach_int_suf as s)
+ {
+ match Common.htab_search mach_suf_table s with
+ Some tm -> LIT_MACH_INT (tm, Int64.of_string n)
+ | None ->
+ if Hashtbl.mem reserved_suf_table s
+ then fail lexbuf "reserved mach-int suffix"
+ else fail lexbuf "bad mach-int suffix"
+ }
| flo as n { LIT_FLOAT (float_of_string n) }
+| flo 'm' { fail lexbuf "reseved mach-float suffix" }
+| (flo as n) (flo_suf as s)
+ {
+ match Common.htab_search mach_suf_table s with
+ Some tm -> LIT_MACH_FLOAT (tm, float_of_string n)
+ | None ->
+ if Hashtbl.mem reserved_suf_table s
+ then fail lexbuf "reserved mach-float suffix"
+ else fail lexbuf "bad mach-float suffix"
+ }
| '\'' { char lexbuf }
| '"' { let buf = Buffer.create 32 in
@@ -411,3 +458,13 @@ and comment depth = parse
comment depth lexbuf }
| _ { comment depth lexbuf }
+
+
+(*
+ * Local Variables:
+ * fill-column: 78;
+ * indent-tabs-mode: nil
+ * buffer-file-coding-system: utf-8-unix
+ * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+ * End:
+ *)
diff --git a/src/boot/fe/parser.ml b/src/boot/fe/parser.ml
index ab7ff56c..4add7b01 100644
--- a/src/boot/fe/parser.ml
+++ b/src/boot/fe/parser.ml
@@ -23,6 +23,7 @@ type pstate =
pstate_node_id : node_id ref;
pstate_opaque_id : opaque_id ref;
pstate_get_mod : get_mod_fn;
+ pstate_get_cenv_tok : pstate -> Ast.ident -> token;
pstate_infer_lib_name : (Ast.ident -> filename);
pstate_required : (node_id, (required_lib * nabi_conv)) Hashtbl.t;
pstate_required_syms : (node_id, string) Hashtbl.t; }
@@ -45,6 +46,7 @@ let make_parser
(oref:opaque_id ref)
(sess:Session.sess)
(get_mod:get_mod_fn)
+ (get_cenv_tok:pstate -> Ast.ident -> token)
(infer_lib_name:Ast.ident -> filename)
(required:(node_id, (required_lib * nabi_conv)) Hashtbl.t)
(required_syms:(node_id, string) Hashtbl.t)
@@ -68,6 +70,7 @@ let make_parser
pstate_node_id = nref;
pstate_opaque_id = oref;
pstate_get_mod = get_mod;
+ pstate_get_cenv_tok = get_cenv_tok;
pstate_infer_lib_name = infer_lib_name;
pstate_required = required;
pstate_required_syms = required_syms; }
diff --git a/src/boot/fe/pexp.ml b/src/boot/fe/pexp.ml
index 3e17e0e4..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
@@ -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/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..552b41e4 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
@@ -2176,14 +2176,8 @@ let dwarf_visitor
in
let addr_ranges (fix:fixup) : frag =
- let image_is_relocated =
- match cx.ctxt_sess.Session.sess_targ with
- Win32_x86_pe ->
- cx.ctxt_sess.Session.sess_library_mode
- | _ -> true
- in
let lo =
- if image_is_relocated
+ if cx.ctxt_sess.Session.sess_library_mode
then image_base_rel fix
else M_POS fix
in
@@ -2801,6 +2795,7 @@ let rec extract_meta
queue_to_arr meta
;;
+let external_opaques = Hashtbl.create 0;;
let rec extract_mod_items
(nref:node_id ref)
@@ -2822,7 +2817,6 @@ let rec extract_mod_items
id
in
- let external_opaques = Hashtbl.create 0 in
let get_opaque_of o =
htab_search_or_add external_opaques o
(fun _ -> next_opaque_id())
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/resolve.ml b/src/boot/me/resolve.ml
index bf11ad23..25eb544a 100644
--- a/src/boot/me/resolve.ml
+++ b/src/boot/me/resolve.ml
@@ -48,6 +48,7 @@ let stmt_collecting_visitor
: Walk.visitor =
let block_ids = Stack.create () in
let visit_block_pre (b:Ast.block) =
+ htab_put cx.ctxt_all_blocks b.id b.node;
Stack.push b.id block_ids;
inner.Walk.visit_block_pre b
in
diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml
index bcaec2b4..7d1b21ef 100644
--- a/src/boot/me/semant.ml
+++ b/src/boot/me/semant.ml
@@ -98,6 +98,7 @@ type ctxt =
ctxt_all_cast_types: (node_id,Ast.ty) Hashtbl.t;
ctxt_all_type_items: (node_id,Ast.ty) Hashtbl.t;
ctxt_all_stmts: (node_id,Ast.stmt) Hashtbl.t;
+ ctxt_all_blocks: (node_id,Ast.block') Hashtbl.t;
ctxt_item_files: (node_id,filename) Hashtbl.t;
ctxt_all_lvals: (node_id,Ast.lval) Hashtbl.t;
ctxt_call_lval_params: (node_id,Ast.ty array) Hashtbl.t;
@@ -183,6 +184,7 @@ let new_ctxt sess abi crate =
ctxt_all_cast_types = Hashtbl.create 0;
ctxt_all_type_items = Hashtbl.create 0;
ctxt_all_stmts = Hashtbl.create 0;
+ ctxt_all_blocks = Hashtbl.create 0;
ctxt_item_files = crate.Ast.crate_files;
ctxt_all_lvals = Hashtbl.create 0;
ctxt_all_defns = Hashtbl.create 0;
@@ -1012,7 +1014,8 @@ let type_is_unsigned_2s_complement t =
| Ast.TY_mach TY_u64
| Ast.TY_char
| Ast.TY_uint
- | Ast.TY_bool -> true
+ | Ast.TY_bool
+ | Ast.TY_native _ -> true
| _ -> false
;;
@@ -1822,24 +1825,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 +1852,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 +1919,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 +1931,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 +1961,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 +1973,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 +2009,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 +2063,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 b708bb26..03174b0a 100644
--- a/src/boot/me/trans.ml
+++ b/src/boot/me/trans.ml
@@ -88,6 +88,7 @@ let trans_visitor
let zero = imm 0L in
let imm_true = imm_of_ty 1L TY_u8 in
let imm_false = imm_of_ty 0L TY_u8 in
+ let zero_byte = imm_of_ty 0L TY_u8 in
let nil_ptr = Il.Mem ((Il.Abs (Asm.IMM 0L)), Il.NilTy) in
let wordptr_ty = Il.AddrTy (Il.ScalarTy word_sty) in
@@ -181,7 +182,7 @@ let trans_visitor
match q with
Il.Jmp _ -> flush_emitter_size_cache();
| _ -> ()
- end;
+ end;
Il.emit (emitter()) q
in
@@ -292,7 +293,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 =
@@ -330,11 +331,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)
@@ -453,13 +450,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)
@@ -469,11 +475,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 _ =
@@ -520,34 +558,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 =
@@ -721,7 +735,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
@@ -730,7 +744,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
@@ -931,7 +945,7 @@ let trans_visitor
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
@@ -1120,7 +1134,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)
@@ -1226,7 +1240,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
@@ -1394,7 +1408,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
@@ -1473,8 +1487,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 *)
@@ -2128,10 +2142,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 _ =
@@ -2165,7 +2181,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
[|
@@ -2177,7 +2193,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
[|
@@ -2243,8 +2259,17 @@ let trans_visitor
trans_void_upcall "upcall_join" [| trans_atom (Ast.ATOM_lval task) |]
and trans_send (chan:Ast.lval) (src:Ast.lval) : unit =
- let (srccell, _) = trans_lval src in
- aliasing false srccell
+ let (src_cell, src_ty) = trans_lval src in
+ begin
+ match (ty_mem_ctrl src_ty) with
+ | MEM_rc_opaque
+ | MEM_rc_struct
+ | MEM_gc ->
+ iflog (fun _ -> annotate "incr_refcount of src obj");
+ incr_refcount src_cell;
+ | _ -> ()
+ end;
+ aliasing false src_cell
begin
fun src_alias ->
trans_void_upcall "upcall_send"
@@ -2331,7 +2356,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
@@ -2377,12 +2402,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
@@ -2418,7 +2443,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
@@ -2435,7 +2460,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)
@@ -2532,7 +2557,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;
@@ -2932,6 +2957,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
@@ -4188,6 +4214,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
@@ -4290,7 +4335,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;
@@ -4345,18 +4390,18 @@ let trans_visitor
(src_ty:Ast.ty)
: unit =
let elt_ty = seq_unit_ty dst_ty in
- let trim_trailing_null = dst_ty = Ast.TY_str in
- assert (simplified_ty src_ty = simplified_ty dst_ty);
- match simplified_ty src_ty with
- Ast.TY_str
- | Ast.TY_vec _ ->
+ let trailing_null = simplified_ty dst_ty = Ast.TY_str in
+ match (simplified_ty dst_ty, simplified_ty src_ty) with
+ (Ast.TY_str, Ast.TY_str)
+ | (Ast.TY_vec _, Ast.TY_vec _)
+ when (simplified_ty dst_ty) = (simplified_ty src_ty) ->
let is_gc = if type_has_state src_ty then 1L else 0L in
let src_cell = need_cell src_oper in
let src_vec = deref src_cell in
let src_fill = get_element_ptr src_vec Abi.vec_elt_fill in
let dst_vec = deref dst_cell in
let dst_fill = get_element_ptr dst_vec Abi.vec_elt_fill in
- if trim_trailing_null
+ if trailing_null
then sub_from dst_fill (imm 1L);
trans_upcall "upcall_vec_grow"
dst_cell
@@ -4374,7 +4419,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
@@ -4413,9 +4458,53 @@ let trans_visitor
let v = next_vreg_cell word_sty in
mov v (Il.Cell src_fill);
add_to dst_fill (Il.Cell v);
- | t ->
+
+ | (Ast.TY_str, e)
+ | (Ast.TY_vec _, e)
+ when e = simplified_ty elt_ty ->
+
+ let dst_is_gc = if type_has_state dst_ty then 1L else 0L in
+ let elt_sz = ty_sz_in_current_frame elt_ty in
+ trans_upcall "upcall_vec_grow"
+ dst_cell
+ [| Il.Cell dst_cell;
+ elt_sz;
+ imm dst_is_gc |];
+
+ (*
+ * By now, dst_cell points to a vec/str with room for us
+ * to add to.
+ *)
+
+ (* Reload dst vec, fill; might have changed. *)
+ let dst_vec = deref dst_cell in
+ let dst_fill = get_element_ptr dst_vec Abi.vec_elt_fill in
+
+ let eltp_rty = Il.AddrTy (referent_type word_bits elt_ty) in
+ let dptr = next_vreg_cell eltp_rty in
+ let dst_data =
+ get_element_ptr_dyn_in_current_frame
+ dst_vec Abi.vec_elt_data
+ in
+ lea dptr (fst (need_mem_cell dst_data));
+ add_to dptr (Il.Cell dst_fill);
+ if trailing_null
+ then sub_from dptr elt_sz;
+ trans_copy_ty
+ (get_ty_params_of_current_frame()) true
+ (deref dptr) elt_ty
+ (Il.Mem (force_to_mem src_oper)) elt_ty
+ None;
+ add_to dptr elt_sz;
+ if trailing_null
+ then mov (deref dptr) zero_byte;
+ add_to dst_fill elt_sz;
+
+ | _ ->
begin
- bug () "unsupported vector-append type %a" Ast.sprintf_ty t
+ bug () "unsupported vector-append types %a += %a"
+ Ast.sprintf_ty dst_ty
+ Ast.sprintf_ty src_ty
end
@@ -4496,8 +4585,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
@@ -4693,6 +4783,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
@@ -4700,10 +4792,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
@@ -4751,7 +4852,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;
@@ -4765,7 +4866,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 ();
@@ -4789,8 +4890,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
@@ -4799,7 +4901,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
@@ -4818,7 +4920,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
@@ -4920,7 +5022,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 =
@@ -5058,7 +5160,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
@@ -5121,7 +5223,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
@@ -5155,7 +5257,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;
@@ -5165,7 +5267,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 23210ea1..17a4b38f 100644
--- a/src/boot/me/type.ml
+++ b/src/boot/me/type.ml
@@ -101,11 +101,11 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
if not (is_integer (fundamental_ty actual)) then
type_error "integer" actual
in
- let demand_bool_or_char_or_integer (actual:Ast.ty) : unit =
+ let demand_bool_or_char_or_integer_or_native (actual:Ast.ty) : unit =
match fundamental_ty actual with
- Ast.TY_bool | Ast.TY_char -> ()
+ Ast.TY_bool | Ast.TY_char | Ast.TY_native _ -> ()
| ty when is_integer ty -> ()
- | _ -> type_error "bool, char, or integer" actual
+ | _ -> type_error "bool, char, integer or native" actual
in
let demand_number (actual:Ast.ty) : unit =
match fundamental_ty actual with
@@ -634,9 +634,11 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
ty
| Ast.EXPR_unary (Ast.UNOP_cast dst_ty_id, atom) ->
(* TODO: probably we want to handle more cases here *)
- demand_bool_or_char_or_integer (check_atom atom);
- let dst_ty = dst_ty_id.Common.node in
- demand_bool_or_char_or_integer dst_ty;
+ demand_bool_or_char_or_integer_or_native (check_atom atom);
+ let dst_ty =
+ Hashtbl.find cx.Semant.ctxt_all_cast_types dst_ty_id.Common.id
+ in
+ demand_bool_or_char_or_integer_or_native dst_ty;
dst_ty
in
@@ -692,7 +694,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)
@@ -761,6 +763,27 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
| Ast.STMT_copy (dst, src) ->
infer_lval (check_expr src) dst
+ | Ast.STMT_copy_binop (dst, Ast.BINOP_add, src) ->
+ begin
+ let src_ty = check_atom ~deref:true src in
+ let dst_ty = check_lval dst in
+ match fundamental_ty dst_ty, fundamental_ty src_ty with
+ Ast.TY_vec elt1, Ast.TY_vec elt2
+ | Ast.TY_vec elt1, elt2 ->
+ if elt1 = elt2
+ then ()
+ else
+ Common.err None
+ "mismatched types in vec-append: %a += %a"
+ Ast.sprintf_ty dst_ty
+ Ast.sprintf_ty src_ty
+ | Ast.TY_str, (Ast.TY_mach Common.TY_u8)
+ | Ast.TY_str, Ast.TY_str -> ()
+ | _ ->
+ infer_lval src_ty dst;
+ demand src_ty (check_binop Ast.BINOP_add src_ty)
+ end
+
| Ast.STMT_copy_binop (dst, binop, src) ->
let ty = check_atom ~deref:true src in
infer_lval ty dst;
diff --git a/src/boot/me/typestate.ml b/src/boot/me/typestate.ml
index baf4a543..8f8d7179 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
@@ -697,7 +697,8 @@ let condition_assigning_visitor
| Ast.STMT_while sw ->
let (_, expr) = sw.Ast.while_lval in
let precond = slot_inits (expr_slots cx expr) in
- raise_pre_post_cond s.id precond
+ raise_precondition sw.Ast.while_body.id precond;
+ raise_postcondition sw.Ast.while_body.id precond
| Ast.STMT_alt_tag at ->
let precond = slot_inits (lval_slots cx at.Ast.alt_tag_lval) in
@@ -947,16 +948,17 @@ let graph_special_block_structure_building_visitor
let ts = tables () in
let graph = ts.ts_graph in
let cond_id = s.id in
+ let succ = Hashtbl.find graph cond_id in
let then_id = sif.Ast.if_then.id in
let then_end_id = last_id_or_block_id sif.Ast.if_then in
let show_node = show_node cx graph in
+ let succ = List.filter (fun x -> not (x = then_id)) succ in
show_node "initial cond" cond_id;
show_node "initial then" then_id;
show_node "initial then_end" then_end_id;
begin
match sif.Ast.if_else with
None ->
- let succ = Hashtbl.find graph then_end_id in
Hashtbl.replace graph cond_id (then_id :: succ);
(* Kill residual messed-up block wiring.*)
remove_flow_edges graph then_end_id [then_id];
@@ -966,8 +968,10 @@ let graph_special_block_structure_building_visitor
| Some e ->
let else_id = e.id in
+ let succ =
+ List.filter (fun x -> not (x = else_id)) succ
+ in
let else_end_id = last_id_or_block_id e in
- let succ = Hashtbl.find graph else_end_id in
show_node "initial else" else_id;
show_node "initial else_end" else_end_id;
Hashtbl.replace graph cond_id [then_id; else_id];
@@ -1049,19 +1053,23 @@ let graph_special_block_structure_building_visitor
;;
let find_roots
+ (cx:ctxt)
(graph:(node_id, (node_id list)) Hashtbl.t)
: (node_id,unit) Hashtbl.t =
let roots = Hashtbl.create 0 in
Hashtbl.iter (fun src _ -> Hashtbl.replace roots src ()) graph;
Hashtbl.iter (fun _ dsts ->
List.iter (fun d -> Hashtbl.remove roots d) dsts) graph;
+ iflog cx
+ (fun _ -> Hashtbl.iter
+ (fun k _ -> log cx "root: %d" (int_of_node k)) roots);
roots
;;
let run_dataflow (cx:ctxt) (ts:typestate_tables) : unit =
let graph = ts.ts_graph in
let idref = ts.ts_maxid in
- let roots = find_roots graph in
+ let roots = find_roots cx graph in
let nodes = Queue.create () in
let progress = ref true in
@@ -1138,9 +1146,17 @@ let run_dataflow (cx:ctxt) (ts:typestate_tables) : unit =
begin
fun _ ->
log cx "stmt %d: '%s'" (int_of_node node)
- (match htab_search cx.ctxt_all_stmts node with
- None -> "??"
- | Some stmt -> Fmt.fmt_to_str Ast.fmt_stmt stmt);
+ begin
+ match htab_search cx.ctxt_all_stmts node with
+ None ->
+ begin
+ match htab_search cx.ctxt_all_blocks node with
+ None -> "??"
+ | Some b ->
+ Fmt.fmt_to_str Ast.fmt_block b
+ end
+ | Some stmt -> Fmt.fmt_to_str Ast.fmt_stmt stmt
+ end;
log cx "stmt %d:" (int_of_node node);
log cx " prestate %s" (fmt_constr_bitv prestate);
@@ -1227,27 +1243,35 @@ let typestate_verify_visitor
let tables _ = Stack.top tables_stack in
- let visit_stmt_pre s =
+ let check_states id =
let ts = tables () in
- let prestate = Hashtbl.find ts.ts_prestates s.id in
- let precond = Hashtbl.find ts.ts_preconditions s.id in
+ let prestate = Hashtbl.find ts.ts_prestates id in
+ let precond = Hashtbl.find ts.ts_preconditions id in
List.iter
(fun i ->
if not (Bits.get prestate i)
then
let ckey = Hashtbl.find ts.ts_constrs (Constr i) in
let constr_str = fmt_constr_key cx ckey in
- err (Some s.id)
- "Unsatisfied precondition constraint %s at stmt %d: %s"
- constr_str
- (int_of_node s.id)
- (Fmt.fmt_to_str Ast.fmt_stmt
- (Hashtbl.find cx.ctxt_all_stmts s.id)))
- (Bits.to_list precond);
- inner.Walk.visit_stmt_pre s
+ err (Some id)
+ "Unsatisfied precondition constraint %s"
+ constr_str)
+ (Bits.to_list precond)
+ in
+
+ let visit_stmt_pre s =
+ check_states s.id;
+ inner.Walk.visit_stmt_pre s
+ in
+
+ let visit_block_pre b =
+ check_states b.id;
+ inner.Walk.visit_block_pre b
in
+
{ inner with
- Walk.visit_stmt_pre = visit_stmt_pre }
+ Walk.visit_stmt_pre = visit_stmt_pre;
+ Walk.visit_block_pre = visit_block_pre }
;;
let lifecycle_visitor
@@ -1350,7 +1374,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/boot/util/common.ml b/src/boot/util/common.ml
index 3a467f1c..d9b91856 100644
--- a/src/boot/util/common.ml
+++ b/src/boot/util/common.ml
@@ -717,7 +717,7 @@ let rec max_sz (a:size) (b:size) : size =
| (SIZE_rt_max (b, c), a) when a = c -> max_sz a b
| (SIZE_fixed a, SIZE_fixed b) -> SIZE_fixed (i64_max a b)
| (SIZE_fixed 0L, b) when no_negs b -> b
- | (a, SIZE_fixed 0L) when no_negs a -> b
+ | (a, SIZE_fixed 0L) when no_negs a -> a
| (a, SIZE_fixed b) -> max_sz (SIZE_fixed b) a
| (a, b) when a = b -> a
| (a, b) -> SIZE_rt_max (a, b)
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index e5a614ba..42bd91c5 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -1,6 +1,23 @@
// -*- rust -*-
-fn main(vec[str] args) -> () {
+import std._str;
+import lib.llvm.llvm;
+import lib.llvm.builder;
+import fe.parser;
+import fe.token;
+
+fn write_module() {
+ auto llmod =
+ llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
+ llvm.LLVMGetGlobalContext());
+
+ auto b = builder(llvm.LLVMCreateBuilder());
+
+ llvm.LLVMWriteBitcodeToFile(llmod, _str.buf("rust_out.bc"));
+ llvm.LLVMDisposeModule(llmod);
+}
+
+fn main(vec[str] args) {
log "This is the rust 'self-hosted' compiler.";
log "The one written in rust.";
@@ -10,13 +27,36 @@ fn main(vec[str] args) -> () {
auto i = 0;
for (str filename in args) {
if (i > 0) {
- auto br = std._io.new_buf_reader(filename);
- log "opened file: " + filename;
- for (u8 b in br.read()) {
- log b;
- }
+ auto p = parser.new_parser(filename);
+ log "opened file: " + filename;
+ auto tok = p.peek();
+ while (true) {
+ alt (tok) {
+ case (token.EOF()) { ret; }
+ case (_) {
+ log token.to_str(tok);
+ p.bump();
+ tok = p.peek();
+ }
+ }
+ }
}
i += 1;
}
+ // Test LLVM module-writing. Nothing interesting yet.
+ write_module();
+
}
+
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/fe/ast.rs b/src/comp/fe/ast.rs
new file mode 100644
index 00000000..3a329ded
--- /dev/null
+++ b/src/comp/fe/ast.rs
@@ -0,0 +1,58 @@
+
+import std.util.option;
+import std.map.hashmap;
+
+type ident = str;
+
+type crate = rec( str filename,
+ _mod module);
+
+type block = vec[stmt];
+
+type stmt = tag( stmt_block(block),
+ stmt_decl(@decl),
+ stmt_ret(option[@lval]) );
+
+type decl = tag( decl_local(ident, option[ty]),
+ decl_item(ident, @item) );
+
+type lval = tag( lval_ident(ident),
+ lval_ext(@lval, ident),
+ lval_idx(@lval, @atom) );
+
+type atom = tag( atom_lit(lit));
+
+type lit = tag( lit_char(char),
+ lit_int(int),
+ lit_nil(),
+ lit_bool(bool) );
+
+type ty = tag( ty_nil(),
+ ty_bool(),
+ ty_int(),
+ ty_char() );
+
+type mode = tag( local(), alias() );
+
+type slot = rec(ty ty, mode mode);
+
+type _fn = rec(vec[rec(slot slot, ident ident)] inputs,
+ slot output,
+ block body);
+
+type _mod = hashmap[ident,item];
+
+type item = tag( item_fn(@_fn),
+ item_mod(@_mod) );
+
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/fe/lexer.rs b/src/comp/fe/lexer.rs
index 87809b3b..b0ee557d 100644
--- a/src/comp/fe/lexer.rs
+++ b/src/comp/fe/lexer.rs
@@ -1,20 +1,103 @@
-import std._io.buf_reader;
+import std._io.stdio_reader;
-iter buffers(buf_reader rdr) -> vec[u8] {
- while (true) {
- let vec[u8] v = rdr.read();
- if (std._vec.len[u8](v) == 0u) {
- ret;
- }
- put v;
- }
+fn in_range(char c, char lo, char hi) -> bool {
+ ret lo <= c && c <= hi;
+}
+
+fn is_alpha(char c) -> bool {
+ ret in_range(c, 'a', 'z') ||
+ in_range(c, 'A', 'Z');
+}
+
+fn is_dec_digit(char c) -> bool {
+ ret in_range(c, '0', '9');
+}
+
+fn is_hex_digit(char c) -> bool {
+ ret in_range(c, '0', '9') ||
+ in_range(c, 'a', 'f') ||
+ in_range(c, 'A', 'F');
+}
+
+fn is_bin_digit(char c) -> bool {
+ ret c == '0' || c == '1';
+}
+
+fn is_whitespace(char c) -> bool {
+ ret c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
-iter bytes(buf_reader rdr) -> u8 {
- for each (vec[u8] buf in buffers(rdr)) {
- for (u8 b in buf) {
- // FIXME: doesn't compile at the moment.
- // put b;
+fn next_token(stdio_reader rdr) -> token.token {
+ auto eof = (-1) as char;
+ auto c = rdr.getc() as char;
+ auto accum_str = "";
+ auto accum_int = 0;
+
+ while (is_whitespace(c) && c != eof) {
+ c = rdr.getc() as char;
+ }
+
+ if (c == eof) { ret token.EOF(); }
+
+ if (is_alpha(c)) {
+ while (is_alpha(c)) {
+ accum_str += (c as u8);
+ c = rdr.getc() as char;
+ }
+ rdr.ungetc(c as int);
+ ret token.IDENT(accum_str);
+ }
+
+ if (is_dec_digit(c)) {
+ if (c == '0') {
+ } else {
+ while (is_dec_digit(c)) {
+ accum_int *= 10;
+ accum_int += (c as int) - ('0' as int);
+ c = rdr.getc() as char;
+ }
+ rdr.ungetc(c as int);
+ ret token.LIT_INT(accum_int);
+ }
}
- }
+
+ // One-byte structural symbols.
+ alt (c) {
+ case (';') { ret token.SEMI(); }
+ case (',') { ret token.COMMA(); }
+ case ('.') { ret token.DOT(); }
+ case ('(') { ret token.LPAREN(); }
+ case (')') { ret token.RPAREN(); }
+ case ('{') { ret token.LBRACE(); }
+ case ('}') { ret token.RBRACE(); }
+ case ('[') { ret token.LBRACKET(); }
+ case (']') { ret token.RBRACKET(); }
+ case ('@') { ret token.AT(); }
+ case ('#') { ret token.POUND(); }
+ case ('=') {
+ auto c2 = rdr.getc() as char;
+ if (c2 == '=') {
+ ret token.OP(token.EQEQ());
+ } else {
+ rdr.ungetc(c2 as int);
+ ret token.OP(token.EQ());
+ }
+ }
+ }
+
+ log "lexer stopping at ";
+ log c;
+ ret token.EOF();
}
+
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/fe/parser.rs b/src/comp/fe/parser.rs
index e69de29b..02de22a7 100644
--- a/src/comp/fe/parser.rs
+++ b/src/comp/fe/parser.rs
@@ -0,0 +1,33 @@
+import std._io;
+
+state type parser =
+ state obj {
+ state fn peek() -> token.token;
+ state fn bump();
+ };
+
+fn new_parser(str path) -> parser {
+ state obj stdio_parser(mutable token.token tok,
+ _io.stdio_reader rdr)
+ {
+ state fn peek() -> token.token {
+ ret tok;
+ }
+ state fn bump() {
+ tok = lexer.next_token(rdr);
+ }
+ }
+ auto rdr = _io.new_stdio_reader(path);
+ ret stdio_parser(lexer.next_token(rdr), rdr);
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/fe/token.rs b/src/comp/fe/token.rs
new file mode 100644
index 00000000..5e8171bc
--- /dev/null
+++ b/src/comp/fe/token.rs
@@ -0,0 +1,333 @@
+import util.common.ty_mach;
+import util.common.ty_mach_to_str;
+import std._int;
+import std._uint;
+
+type op = tag
+ (PLUS(),
+ MINUS(),
+ STAR(),
+ SLASH(),
+ PERCENT(),
+ EQ(),
+ LT(),
+ LE(),
+ EQEQ(),
+ NE(),
+ GE(),
+ GT(),
+ NOT(),
+ TILDE(),
+ CARET(),
+ AND(),
+ ANDAND(),
+ OR(),
+ OROR(),
+ LSL(),
+ LSR(),
+ ASR());
+
+type token = tag
+ (OP(op),
+ OPEQ(op),
+ AS(),
+ WITH(),
+
+ /* Structural symbols */
+ AT(),
+ DOT(),
+ COMMA(),
+ SEMI(),
+ COLON(),
+ RARROW(),
+ SEND(),
+ LARROW(),
+ LPAREN(),
+ RPAREN(),
+ LBRACKET(),
+ RBRACKET(),
+ LBRACE(),
+ RBRACE(),
+
+ /* Module and crate keywords */
+ MOD(),
+ USE(),
+ AUTH(),
+ META(),
+
+ /* Metaprogramming keywords */
+ SYNTAX(),
+ POUND(),
+
+ /* Statement keywords */
+ IF(),
+ ELSE(),
+ DO(),
+ WHILE(),
+ ALT(),
+ CASE(),
+
+ FAIL(),
+ DROP(),
+
+ IN(),
+ FOR(),
+ EACH(),
+ PUT(),
+ RET(),
+ BE(),
+
+ /* Type and type-state keywords */
+ TYPE(),
+ CHECK(),
+ CLAIM(),
+ PROVE(),
+
+ /* Effect keywords */
+ IO(),
+ STATE(),
+ UNSAFE(),
+
+ /* Type qualifiers */
+ NATIVE(),
+ AUTO(),
+ MUTABLE(),
+
+ /* Name management */
+ IMPORT(),
+ EXPORT(),
+
+ /* Value / stmt declarators */
+ LET(),
+
+ /* Magic runtime services */
+ LOG(),
+ SPAWN(),
+ BIND(),
+ THREAD(),
+ YIELD(),
+ JOIN(),
+
+ /* Literals */
+ LIT_INT(int),
+ LIT_UINT(uint),
+ LIT_MACH_INT(ty_mach, int),
+ LIT_STR(str),
+ LIT_CHAR(char),
+ LIT_BOOL(bool),
+
+ /* Name components */
+ IDENT(str),
+ IDX(int),
+ UNDERSCORE(),
+
+ /* Reserved type names */
+ BOOL(),
+ INT(),
+ UINT(),
+ FLOAT(),
+ CHAR(),
+ STR(),
+ MACH(ty_mach),
+
+ /* Algebraic type constructors */
+ REC(),
+ TUP(),
+ TAG(),
+ VEC(),
+ ANY(),
+
+ /* Callable type constructors */
+ FN(),
+ ITER(),
+
+ /* Object type */
+ OBJ(),
+
+ /* Comm and task types */
+ CHAN(),
+ PORT(),
+ TASK(),
+
+ BRACEQUOTE(str),
+ EOF());
+
+fn op_to_str(op o) -> str {
+ alt (o) {
+ case (PLUS()) { ret "+"; }
+ case (MINUS()) { ret "-"; }
+ case (STAR()) { ret "*"; }
+ case (SLASH()) { ret "/"; }
+ case (PERCENT()) { ret "%"; }
+ case (EQ()) { ret "="; }
+ case (LT()) { ret "<"; }
+ case (LE()) { ret "<="; }
+ case (EQEQ()) { ret "=="; }
+ case (NE()) { ret "!="; }
+ case (GE()) { ret ">="; }
+ case (GT()) { ret ">"; }
+ case (NOT()) { ret "!"; }
+ case (TILDE()) { ret "~"; }
+ case (CARET()) { ret "^"; }
+ case (AND()) { ret "&"; }
+ case (ANDAND()) { ret "&&"; }
+ case (OR()) { ret "|"; }
+ case (OROR()) { ret "||"; }
+ case (LSL()) { ret "<<"; }
+ case (LSR()) { ret ">>"; }
+ case (ASR()) { ret ">>>"; }
+ }
+}
+
+fn to_str(token t) -> str {
+ alt (t) {
+ case (OP(op)) { ret op_to_str(op); }
+ case (OPEQ(op)) { ret op_to_str(op) + "="; }
+ case (AS()) { ret "as"; }
+ case (WITH()) { ret "with"; }
+
+ /* Structural symbols */
+ case (AT()) { ret "@"; }
+ case (DOT()) { ret "."; }
+ case (COMMA()) { ret ","; }
+ case (SEMI()) { ret ";"; }
+ case (COLON()) { ret ":"; }
+ case (RARROW()) { ret "->"; }
+ case (SEND()) { ret "<|"; }
+ case (LARROW()) { ret "<-"; }
+ case (LPAREN()) { ret "("; }
+ case (RPAREN()) { ret ")"; }
+ case (LBRACKET()) { ret "["; }
+ case (RBRACKET()) { ret "]"; }
+ case (LBRACE()) { ret "{"; }
+ case (RBRACE()) { ret "}"; }
+
+ /* Module and crate keywords */
+ case (MOD()) { ret "mod"; }
+ case (USE()) { ret "use"; }
+ case (AUTH()) { ret "auth"; }
+ case (META()) { ret "meta"; }
+
+ /* Metaprogramming keywords */
+ case (SYNTAX()) { ret "syntax"; }
+ case (POUND()) { ret "#"; }
+
+ /* Statement keywords */
+ case (IF()) { ret "if"; }
+ case (ELSE()) { ret "else"; }
+ case (DO()) { ret "do"; }
+ case (WHILE()) { ret "while"; }
+ case (ALT()) { ret "alt"; }
+ case (CASE()) { ret "case"; }
+
+ case (FAIL()) { ret "fail"; }
+ case (DROP()) { ret "drop"; }
+
+ case (IN()) { ret "in"; }
+ case (FOR()) { ret "for"; }
+ case (EACH()) { ret "each"; }
+ case (PUT()) { ret "put"; }
+ case (RET()) { ret "ret"; }
+ case (BE()) { ret "be"; }
+
+ /* Type and type-state keywords */
+ case (TYPE()) { ret "type"; }
+ case (CHECK()) { ret "check"; }
+ case (CLAIM()) { ret "claim"; }
+ case (PROVE()) { ret "prove"; }
+
+ /* Effect keywords */
+ case (IO()) { ret "io"; }
+ case (STATE()) { ret "state"; }
+ case (UNSAFE()) { ret "unsafe"; }
+
+ /* Type qualifiers */
+ case (NATIVE()) { ret "native"; }
+ case (AUTO()) { ret "auto"; }
+ case (MUTABLE()) { ret "mutable"; }
+
+ /* Name management */
+ case (IMPORT()) { ret "import"; }
+ case (EXPORT()) { ret "export"; }
+
+ /* Value / stmt declarators */
+ case (LET()) { ret "let"; }
+
+ /* Magic runtime services */
+ case (LOG()) { ret "log"; }
+ case (SPAWN()) { ret "spawn"; }
+ case (BIND()) { ret "bind"; }
+ case (THREAD()) { ret "thread"; }
+ case (YIELD()) { ret "yield"; }
+ case (JOIN()) { ret "join"; }
+
+ /* Literals */
+ case (LIT_INT(i)) { ret _int.to_str(i, 10u); }
+ case (LIT_UINT(u)) { ret _uint.to_str(u, 10u); }
+ case (LIT_MACH_INT(tm, i)) {
+ ret _int.to_str(i, 10u)
+ + "_" + ty_mach_to_str(tm);
+ }
+
+ case (LIT_STR(s)) {
+ // FIXME: escape.
+ ret "\"" + s + "\"";
+ }
+ case (LIT_CHAR(c)) {
+ // FIXME: escape and encode.
+ auto tmp = "";
+ tmp += (c as u8);
+ ret tmp;
+ }
+
+ case (LIT_BOOL(b)) {
+ if (b) { ret "true"; } else { ret "false"; }
+ }
+
+ /* Name components */
+ case (IDENT(s)) { ret s; }
+ case (IDX(i)) { ret "_" + _int.to_str(i, 10u); }
+ case (UNDERSCORE()) { ret "_"; }
+
+ /* Reserved type names */
+ case (BOOL()) { ret "bool"; }
+ case (INT()) { ret "int"; }
+ case (UINT()) { ret "uint"; }
+ case (FLOAT()) { ret "float"; }
+ case (CHAR()) { ret "char"; }
+ case (STR()) { ret "str"; }
+ case (MACH(tm)) { ret ty_mach_to_str(tm); }
+
+ /* Algebraic type constructors */
+ case (REC()) { ret "rec"; }
+ case (TUP()) { ret "tup"; }
+ case (TAG()) { ret "tag"; }
+ case (VEC()) { ret "vec"; }
+ case (ANY()) { ret "any"; }
+
+ /* Callable type constructors */
+ case (FN()) { ret "fn"; }
+ case (ITER()) { ret "iter"; }
+
+ /* Object type */
+ case (OBJ()) { ret "obj"; }
+
+ /* Comm and task types */
+ case (CHAN()) { ret "chan"; }
+ case (PORT()) { ret "port"; }
+ case (TASK()) { ret "task"; }
+
+ case (BRACEQUOTE(_)) { ret "<bracequote>"; }
+ case (EOF()) { ret "<eof>"; }
+ }
+}
+
+
+
+// Local Variables:
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index da748bf3..9a31a193 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -1,277 +1,884 @@
import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;
+import llvm.ModuleRef;
+import llvm.ContextRef;
+import llvm.TypeRef;
+import llvm.TypeHandleRef;
+import llvm.ValueRef;
+import llvm.BasicBlockRef;
+import llvm.BuilderRef;
+import llvm.ModuleProviderRef;
+import llvm.MemoryBufferRef;
+import llvm.PassManagerRef;
+import llvm.UseRef;
+import llvm.Linkage;
+import llvm.Attribute;
+import llvm.Visibility;
+import llvm.CallConv;
+import llvm.IntPredicate;
+import llvm.RealPredicate;
+import llvm.Opcode;
+
type ULongLong = u64;
type LongLong = i64;
type Long = i32;
type Bool = int;
-native mod llvm = "libLLVM-2.7.so" {
-
- type ModuleRef;
- type ContextRef;
- type TypeRef;
- type TypeHandleRef;
- type ValueRef;
- type BasicBlockRef;
- type BuilderRef;
- type ModuleProviderRef;
- type MemoryBufferRef;
- type PassManagerRef;
- type UseRef;
-
-
- /* Create and destroy contexts. */
- fn ContextCreate() -> ContextRef;
- fn GetGlobalContext() -> ContextRef;
- fn ContextDispose(ContextRef C);
- fn GetMDKindIDInContext(ContextRef C, sbuf Name, uint SLen) -> uint;
- fn GetMDKindID(sbuf Name, uint SLen) -> uint;
-
- /* Create and destroy modules. */
- fn ModuleCreateWithName(sbuf ModuleID) -> ModuleRef;
- fn DisposeModule(ModuleRef M);
-
- /** Data layout. See Module::getDataLayout. */
- fn GetDataLayout(ModuleRef M) -> sbuf;
- fn SetDataLayout(ModuleRef M, sbuf Triple);
-
- /** Target triple. See Module::getTargetTriple. */
- fn GetTarget(ModuleRef M) -> sbuf;
- fn SetTarget(ModuleRef M, sbuf Triple);
-
- /** See Module::addTypeName. */
- fn AddTypeName(ModuleRef M, sbuf Name, TypeRef Ty) -> Bool;
- fn DeleteTypeName(ModuleRef M, sbuf Name);
- fn GetTypeByName(ModuleRef M, sbuf Name) -> TypeRef;
-
- /** See Module::dump. */
- fn DumpModule(ModuleRef M);
-
- /** See Module::setModuleInlineAsm. */
- fn SetModuleInlineAsm(ModuleRef M, sbuf Asm);
-
- /** See llvm::LLVMType::getContext. */
- fn GetTypeContext(TypeRef Ty) -> ContextRef;
-
- /* Operations on integer types */
- fn Int1TypeInContext(ContextRef C) -> TypeRef;
- fn Int8TypeInContext(ContextRef C) -> TypeRef;
- fn Int16TypeInContext(ContextRef C) -> TypeRef;
- fn Int32TypeInContext(ContextRef C) -> TypeRef;
- fn Int64TypeInContext(ContextRef C) -> TypeRef;
- fn IntTypeInContext(ContextRef C, uint NumBits) -> TypeRef;
-
- fn Int1Type() -> TypeRef;
- fn Int8Type() -> TypeRef;
- fn Int16Type() -> TypeRef;
- fn Int32Type() -> TypeRef;
- fn Int64Type() -> TypeRef;
- fn IntType(uint NumBits) -> TypeRef;
- fn GetIntTypeWidth(TypeRef IntegerTy) -> uint;
-
- /* Operations on real types */
- fn FloatTypeInContext(ContextRef C) -> TypeRef;
- fn DoubleTypeInContext(ContextRef C) -> TypeRef;
- fn X86FP80TypeInContext(ContextRef C) -> TypeRef;
- fn FP128TypeInContext(ContextRef C) -> TypeRef;
- fn PPCFP128TypeInContext(ContextRef C) -> TypeRef;
-
- fn FloatType() -> TypeRef;
- fn DoubleType() -> TypeRef;
- fn X86FP80Type() -> TypeRef;
- fn FP128Type() -> TypeRef;
- fn PPCFP128Type() -> TypeRef;
-
- /* Operations on function types */
- fn FunctionType(TypeRef ReturnType, vbuf ParamTypes,
- uint ParamCount, Bool IsVarArg) -> TypeRef;
- fn IsFunctionVarArg(TypeRef FunctionTy) -> Bool;
- fn GetReturnType(TypeRef FunctionTy) -> TypeRef;
- fn CountParamTypes(TypeRef FunctionTy) -> uint;
- fn GetParamTypes(TypeRef FunctionTy, vbuf Dest);
-
- /* Operations on struct types */
- fn StructTypeInContext(ContextRef C, vbuf ElementTypes,
- uint ElementCount, Bool Packed) -> TypeRef;
- fn StructType(vbuf ElementTypes, uint ElementCount,
- Bool Packed) -> TypeRef;
- fn CountStructElementTypes(TypeRef StructTy) -> uint;
- fn GetStructElementTypes(TypeRef StructTy, vbuf Dest);
- fn IsPackedStruct(TypeRef StructTy) -> Bool;
-
- /* Operations on union types */
- fn UnionTypeInContext(ContextRef C, vbuf ElementTypes,
- uint ElementCount) -> TypeRef;
- fn UnionType(vbuf ElementTypes, uint ElementCount) -> TypeRef;
- fn CountUnionElementTypes(TypeRef UnionTy) -> uint;
- fn GetUnionElementTypes(TypeRef UnionTy, vbuf Dest);
-
- /* Operations on array, pointer, and vector types (sequence types) */
- fn ArrayType(TypeRef ElementType, uint ElementCount) -> TypeRef;
- fn PointerType(TypeRef ElementType, uint AddressSpace) -> TypeRef;
- fn VectorType(TypeRef ElementType, uint ElementCount) -> TypeRef;
-
- fn GetElementType(TypeRef Ty) -> TypeRef;
- fn GetArrayLength(TypeRef ArrayTy) -> uint;
- fn GetPointerAddressSpace(TypeRef PointerTy) -> uint;
- fn GetVectorSize(TypeRef VectorTy) -> uint;
-
- /* Operations on other types */
- fn VoidTypeInContext(ContextRef C) -> TypeRef;
- fn LabelTypeInContext(ContextRef C) -> TypeRef;
- fn OpaqueTypeInContext(ContextRef C) -> TypeRef;
-
- fn VoidType() -> TypeRef;
- fn LabelType() -> TypeRef;
- fn OpaqueType() -> TypeRef;
-
- /* Operations on type handles */
- fn CreateTypeHandle(TypeRef PotentiallyAbstractTy) -> TypeHandleRef;
- fn RefineType(TypeRef AbstractTy, TypeRef ConcreteTy);
- fn ResolveTypeHandle(TypeHandleRef TypeHandle) -> TypeRef;
- fn DisposeTypeHandle(TypeHandleRef TypeHandle);
-
- /* Operations on all values */
- fn TypeOf(ValueRef Val) -> TypeRef;
- fn GetValueName(ValueRef Val) -> sbuf;
- fn SetValueName(ValueRef Val, sbuf Name);
- fn DumpValue(ValueRef Val);
- fn ReplaceAllUsesWith(ValueRef OldVal, ValueRef NewVal);
- fn HasMetadata(ValueRef Val) -> int;
- fn GetMetadata(ValueRef Val, uint KindID) -> ValueRef;
- fn SetMetadata(ValueRef Val, uint KindID, ValueRef Node);
-
- /* Operations on Uses */
- fn GetFirstUse(ValueRef Val) -> UseRef;
- fn GetNextUse(UseRef U) -> UseRef;
- fn GetUser(UseRef U) -> ValueRef;
- fn GetUsedValue(UseRef U) -> ValueRef;
-
- /* Operations on Users */
- fn GetOperand(ValueRef Val, uint Index) -> ValueRef;
-
- /* Operations on constants of any type */
- fn ConstNull(TypeRef Ty) -> ValueRef; /* all zeroes */
- fn ConstAllOnes(TypeRef Ty) -> ValueRef; /* only for int/vector */
- fn GetUndef(TypeRef Ty) -> ValueRef;
- fn IsConstant(ValueRef Val) -> Bool;
- fn IsNull(ValueRef Val) -> Bool;
- fn IsUndef(ValueRef Val) -> Bool;
- fn ConstPointerNull(TypeRef Ty) -> ValueRef;
-
- /* Operations on metadata */
- fn MDStringInContext(ContextRef C, sbuf Str, uint SLen) -> ValueRef;
- fn MDString(sbuf Str, uint SLen) -> ValueRef;
- fn MDNodeInContext(ContextRef C, vbuf Vals, uint Count) -> ValueRef;
- fn MDNode(vbuf Vals, uint Count) -> ValueRef;
-
- /* Operations on scalar constants */
- fn ConstInt(TypeRef IntTy, ULongLong N, Bool SignExtend) -> ValueRef;
- fn ConstIntOfString(TypeRef IntTy, sbuf Text, u8 Radix) -> ValueRef;
- fn ConstIntOfStringAndSize(TypeRef IntTy, sbuf Text,
- uint SLen, u8 Radix) -> ValueRef;
- fn ConstReal(TypeRef RealTy, f64 N) -> ValueRef;
- fn ConstRealOfString(TypeRef RealTy, sbuf Text) -> ValueRef;
- fn ConstRealOfStringAndSize(TypeRef RealTy, sbuf Text,
- uint SLen) -> ValueRef;
- fn ConstIntGetZExtValue(ValueRef ConstantVal) -> ULongLong;
- fn ConstIntGetSExtValue(ValueRef ConstantVal) -> LongLong;
-
-
- /* Operations on composite constants */
- fn ConstStringInContext(ContextRef C, sbuf Str,
- uint Length, Bool DontNullTerminate) -> ValueRef;
- fn ConstStructInContext(ContextRef C, vbuf ConstantVals,
- uint Count, Bool Packed) -> ValueRef;
-
- fn ConstString(sbuf Str, uint Length, Bool DontNullTerminate) -> ValueRef;
- fn ConstArray(TypeRef ElementTy,
- vbuf ConstantVals, uint Length) -> ValueRef;
- fn ConstStruct(vbuf ConstantVals, uint Count, Bool Packed) -> ValueRef;
- fn ConstVector(vbuf ScalarConstantVals, uint Size) -> ValueRef;
- fn ConstUnion(TypeRef Ty, ValueRef Val) -> ValueRef;
-
- /* Constant expressions */
- fn AlignOf(TypeRef Ty) -> ValueRef;
- fn SizeOf(TypeRef Ty) -> ValueRef;
- fn ConstNeg(ValueRef ConstantVal) -> ValueRef;
- fn ConstNSWNeg(ValueRef ConstantVal) -> ValueRef;
- fn ConstNUWNeg(ValueRef ConstantVal) -> ValueRef;
- fn ConstFNeg(ValueRef ConstantVal) -> ValueRef;
- fn ConstNot(ValueRef ConstantVal) -> ValueRef;
- fn ConstAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNSWAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNUWAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstFAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNSWSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNUWSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstFSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNSWMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstNUWMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstFMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstUDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstSDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstExactSDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstFDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstURem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstSRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstFRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstAnd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstOr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstXor(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstShl(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstLShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstAShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
- fn ConstGEP(ValueRef ConstantVal,
- vbuf ConstantIndices, uint NumIndices) -> ValueRef;
- fn ConstInBoundsGEP(ValueRef ConstantVal,
- vbuf ConstantIndices,
- uint NumIndices) -> ValueRef;
- fn ConstTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstSExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstZExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstFPTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstFPExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstUIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstSIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstFPToUI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstFPToSI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstPtrToInt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstIntToPtr(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstBitCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstZExtOrBitCast(ValueRef ConstantVal,
- TypeRef ToType) -> ValueRef;
- fn ConstSExtOrBitCast(ValueRef ConstantVal,
- TypeRef ToType) -> ValueRef;
- fn ConstTruncOrBitCast(ValueRef ConstantVal,
- TypeRef ToType) -> ValueRef;
- fn ConstPointerCast(ValueRef ConstantVal,
- TypeRef ToType) -> ValueRef;
- fn ConstIntCast(ValueRef ConstantVal, TypeRef ToType,
- Bool isSigned) -> ValueRef;
- fn ConstFPCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
- fn ConstSelect(ValueRef ConstantCondition,
- ValueRef ConstantIfTrue,
- ValueRef ConstantIfFalse) -> ValueRef;
- fn ConstExtractElement(ValueRef VectorConstant,
- ValueRef IndexConstant) -> ValueRef;
- fn ConstInsertElement(ValueRef VectorConstant,
- ValueRef ElementValueConstant,
- ValueRef IndexConstant) -> ValueRef;
- fn ConstShuffleVector(ValueRef VectorAConstant,
- ValueRef VectorBConstant,
- ValueRef MaskConstant) -> ValueRef;
- fn ConstExtractValue(ValueRef AggConstant, vbuf IdxList,
- uint NumIdx) -> ValueRef;
- fn ConstInsertValue(ValueRef AggConstant,
- ValueRef ElementValueConstant,
- vbuf IdxList, uint NumIdx) -> ValueRef;
- fn ConstInlineAsm(TypeRef Ty,
- sbuf AsmString, sbuf Constraints,
- Bool HasSideEffects, Bool IsAlignStack) -> ValueRef;
- fn BlockAddress(ValueRef F, BasicBlockRef BB) -> ValueRef;
-
-} \ No newline at end of file
+native mod llvm = llvm_lib {
+
+ type ModuleRef;
+ type ContextRef;
+ type TypeRef;
+ type TypeHandleRef;
+ type ValueRef;
+ type BasicBlockRef;
+ type BuilderRef;
+ type ModuleProviderRef;
+ type MemoryBufferRef;
+ type PassManagerRef;
+ type UseRef;
+
+ /* FIXME: These are enums in the C header. Represent them how, in rust? */
+ type Linkage;
+ type Attribute;
+ type Visibility;
+ type CallConv;
+ type IntPredicate;
+ type RealPredicate;
+ type Opcode;
+
+ /* Create and destroy contexts. */
+ fn LLVMContextCreate() -> ContextRef;
+ fn LLVMGetGlobalContext() -> ContextRef;
+ fn LLVMContextDispose(ContextRef C);
+ fn LLVMGetMDKindIDInContext(ContextRef C, sbuf Name, uint SLen) -> uint;
+ fn LLVMGetMDKindID(sbuf Name, uint SLen) -> uint;
+
+ /* Create and destroy modules. */
+ fn LLVMModuleCreateWithNameInContext(sbuf ModuleID,
+ ContextRef C)-> ModuleRef;
+ fn LLVMDisposeModule(ModuleRef M);
+
+ /** Data layout. See Module::getDataLayout. */
+ fn LLVMGetDataLayout(ModuleRef M) -> sbuf;
+ fn LLVMSetDataLayout(ModuleRef M, sbuf Triple);
+
+ /** Target triple. See Module::getTargetTriple. */
+ fn LLVMGetTarget(ModuleRef M) -> sbuf;
+ fn LLVMSetTarget(ModuleRef M, sbuf Triple);
+
+ /** See Module::addTypeName. */
+ fn LLVMAddTypeName(ModuleRef M, sbuf Name, TypeRef Ty) -> Bool;
+ fn LLVMDeleteTypeName(ModuleRef M, sbuf Name);
+ fn LLVMGetTypeByName(ModuleRef M, sbuf Name) -> TypeRef;
+
+ /** See Module::dump. */
+ fn LLVMDumpModule(ModuleRef M);
+
+ /** See Module::setModuleInlineAsm. */
+ fn LLVMSetModuleInlineAsm(ModuleRef M, sbuf Asm);
+
+ /** See llvm::LLVMType::getContext. */
+ fn LLVMGetTypeContext(TypeRef Ty) -> ContextRef;
+
+ /* Operations on integer types */
+ fn LLVMInt1TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMInt8TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMInt16TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMInt32TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMInt64TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMIntTypeInContext(ContextRef C, uint NumBits) -> TypeRef;
+
+ fn LLVMInt1Type() -> TypeRef;
+ fn LLVMInt8Type() -> TypeRef;
+ fn LLVMInt16Type() -> TypeRef;
+ fn LLVMInt32Type() -> TypeRef;
+ fn LLVMInt64Type() -> TypeRef;
+ fn LLVMIntType(uint NumBits) -> TypeRef;
+ fn LLVMGetIntTypeWidth(TypeRef IntegerTy) -> uint;
+
+ /* Operations on real types */
+ fn LLVMFloatTypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMDoubleTypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMX86FP80TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMFP128TypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMPPCFP128TypeInContext(ContextRef C) -> TypeRef;
+
+ fn LLVMFloatType() -> TypeRef;
+ fn LLVMDoubleType() -> TypeRef;
+ fn LLVMX86FP80Type() -> TypeRef;
+ fn LLVMFP128Type() -> TypeRef;
+ fn LLVMPPCFP128Type() -> TypeRef;
+
+ /* Operations on function types */
+ fn LLVMFunctionType(TypeRef ReturnType, vbuf ParamTypes,
+ uint ParamCount, Bool IsVarArg) -> TypeRef;
+ fn LLVMIsFunctionVarArg(TypeRef FunctionTy) -> Bool;
+ fn LLVMGetReturnType(TypeRef FunctionTy) -> TypeRef;
+ fn LLVMCountParamTypes(TypeRef FunctionTy) -> uint;
+ fn LLVMGetParamTypes(TypeRef FunctionTy, vbuf Dest);
+
+ /* Operations on struct types */
+ fn LLVMStructTypeInContext(ContextRef C, vbuf ElementTypes,
+ uint ElementCount, Bool Packed) -> TypeRef;
+ fn LLVMStructType(vbuf ElementTypes, uint ElementCount,
+ Bool Packed) -> TypeRef;
+ fn LLVMCountStructElementTypes(TypeRef StructTy) -> uint;
+ fn LLVMGetStructElementTypes(TypeRef StructTy, vbuf Dest);
+ fn LLVMIsPackedStruct(TypeRef StructTy) -> Bool;
+
+ /* Operations on union types */
+ fn LLVMUnionTypeInContext(ContextRef C, vbuf ElementTypes,
+ uint ElementCount) -> TypeRef;
+ fn LLVMUnionType(vbuf ElementTypes, uint ElementCount) -> TypeRef;
+ fn LLVMCountUnionElementTypes(TypeRef UnionTy) -> uint;
+ fn LLVMGetUnionElementTypes(TypeRef UnionTy, vbuf Dest);
+
+ /* Operations on array, pointer, and vector types (sequence types) */
+ fn LLVMArrayType(TypeRef ElementType, uint ElementCount) -> TypeRef;
+ fn LLVMPointerType(TypeRef ElementType, uint AddressSpace) -> TypeRef;
+ fn LLVMVectorType(TypeRef ElementType, uint ElementCount) -> TypeRef;
+
+ fn LLVMGetElementType(TypeRef Ty) -> TypeRef;
+ fn LLVMGetArrayLength(TypeRef ArrayTy) -> uint;
+ fn LLVMGetPointerAddressSpace(TypeRef PointerTy) -> uint;
+ fn LLVMGetVectorSize(TypeRef VectorTy) -> uint;
+
+ /* Operations on other types */
+ fn LLVMVoidTypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMLabelTypeInContext(ContextRef C) -> TypeRef;
+ fn LLVMOpaqueTypeInContext(ContextRef C) -> TypeRef;
+
+ fn LLVMVoidType() -> TypeRef;
+ fn LLVMLabelType() -> TypeRef;
+ fn LLVMOpaqueType() -> TypeRef;
+
+ /* Operations on type handles */
+ fn LLVMCreateTypeHandle(TypeRef PotentiallyAbstractTy) -> TypeHandleRef;
+ fn LLVMRefineType(TypeRef AbstractTy, TypeRef ConcreteTy);
+ fn LLVMResolveTypeHandle(TypeHandleRef TypeHandle) -> TypeRef;
+ fn LLVMDisposeTypeHandle(TypeHandleRef TypeHandle);
+
+ /* Operations on all values */
+ fn LLVMTypeOf(ValueRef Val) -> TypeRef;
+ fn LLVMGetValueName(ValueRef Val) -> sbuf;
+ fn LLVMSetValueName(ValueRef Val, sbuf Name);
+ fn LLVMDumpValue(ValueRef Val);
+ fn LLVMReplaceAllUsesWith(ValueRef OldVal, ValueRef NewVal);
+ fn LLVMHasMetadata(ValueRef Val) -> int;
+ fn LLVMGetMetadata(ValueRef Val, uint KindID) -> ValueRef;
+ fn LLVMSetMetadata(ValueRef Val, uint KindID, ValueRef Node);
+
+ /* Operations on Uses */
+ fn LLVMGetFirstUse(ValueRef Val) -> UseRef;
+ fn LLVMGetNextUse(UseRef U) -> UseRef;
+ fn LLVMGetUser(UseRef U) -> ValueRef;
+ fn LLVMGetUsedValue(UseRef U) -> ValueRef;
+
+ /* Operations on Users */
+ fn LLVMGetOperand(ValueRef Val, uint Index) -> ValueRef;
+
+ /* Operations on constants of any type */
+ fn LLVMConstNull(TypeRef Ty) -> ValueRef; /* all zeroes */
+ fn LLVMConstAllOnes(TypeRef Ty) -> ValueRef; /* only for int/vector */
+ fn LLVMGetUndef(TypeRef Ty) -> ValueRef;
+ fn LLVMIsConstant(ValueRef Val) -> Bool;
+ fn LLVMIsNull(ValueRef Val) -> Bool;
+ fn LLVMIsUndef(ValueRef Val) -> Bool;
+ fn LLVMConstPointerNull(TypeRef Ty) -> ValueRef;
+
+ /* Operations on metadata */
+ fn LLVMMDStringInContext(ContextRef C, sbuf Str, uint SLen) -> ValueRef;
+ fn LLVMMDString(sbuf Str, uint SLen) -> ValueRef;
+ fn LLVMMDNodeInContext(ContextRef C, vbuf Vals, uint Count) -> ValueRef;
+ fn LLVMMDNode(vbuf Vals, uint Count) -> ValueRef;
+
+ /* Operations on scalar constants */
+ fn LLVMConstInt(TypeRef IntTy, ULongLong N, Bool SignExtend) -> ValueRef;
+ fn LLVMConstIntOfString(TypeRef IntTy, sbuf Text, u8 Radix) -> ValueRef;
+ fn LLVMConstIntOfStringAndSize(TypeRef IntTy, sbuf Text,
+ uint SLen, u8 Radix) -> ValueRef;
+ fn LLVMConstReal(TypeRef RealTy, f64 N) -> ValueRef;
+ fn LLVMConstRealOfString(TypeRef RealTy, sbuf Text) -> ValueRef;
+ fn LLVMConstRealOfStringAndSize(TypeRef RealTy, sbuf Text,
+ uint SLen) -> ValueRef;
+ fn LLVMConstIntGetZExtValue(ValueRef ConstantVal) -> ULongLong;
+ fn LLVMConstIntGetSExtValue(ValueRef ConstantVal) -> LongLong;
+
+
+ /* Operations on composite constants */
+ fn LLVMConstStringInContext(ContextRef C, sbuf Str, uint Length,
+ Bool DontNullTerminate) -> ValueRef;
+ fn LLVMConstStructInContext(ContextRef C, vbuf ConstantVals,
+ uint Count, Bool Packed) -> ValueRef;
+
+ fn LLVMConstString(sbuf Str, uint Length,
+ Bool DontNullTerminate) -> ValueRef;
+ fn LLVMConstArray(TypeRef ElementTy,
+ vbuf ConstantVals, uint Length) -> ValueRef;
+ fn LLVMConstStruct(vbuf ConstantVals, uint Count,
+ Bool Packed) -> ValueRef;
+ fn LLVMConstVector(vbuf ScalarConstantVals, uint Size) -> ValueRef;
+ fn LLVMConstUnion(TypeRef Ty, ValueRef Val) -> ValueRef;
+
+ /* Constant expressions */
+ fn LLVMAlignOf(TypeRef Ty) -> ValueRef;
+ fn LLVMSizeOf(TypeRef Ty) -> ValueRef;
+ fn LLVMConstNeg(ValueRef ConstantVal) -> ValueRef;
+ fn LLVMConstNSWNeg(ValueRef ConstantVal) -> ValueRef;
+ fn LLVMConstNUWNeg(ValueRef ConstantVal) -> ValueRef;
+ fn LLVMConstFNeg(ValueRef ConstantVal) -> ValueRef;
+ fn LLVMConstNot(ValueRef ConstantVal) -> ValueRef;
+ fn LLVMConstAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNSWAdd(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNUWAdd(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstFAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNSWSub(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNUWSub(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstFSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNSWMul(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstNUWMul(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstFMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstUDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstSDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstExactSDiv(ValueRef LHSConstant,
+ ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstFDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstURem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstSRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstFRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstAnd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstOr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstXor(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstShl(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstLShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstAShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
+ fn LLVMConstGEP(ValueRef ConstantVal,
+ vbuf ConstantIndices, uint NumIndices) -> ValueRef;
+ fn LLVMConstInBoundsGEP(ValueRef ConstantVal,
+ vbuf ConstantIndices,
+ uint NumIndices) -> ValueRef;
+ fn LLVMConstTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstSExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstZExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstFPTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstFPExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstUIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstSIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstFPToUI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstFPToSI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstPtrToInt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstIntToPtr(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstBitCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstZExtOrBitCast(ValueRef ConstantVal,
+ TypeRef ToType) -> ValueRef;
+ fn LLVMConstSExtOrBitCast(ValueRef ConstantVal,
+ TypeRef ToType) -> ValueRef;
+ fn LLVMConstTruncOrBitCast(ValueRef ConstantVal,
+ TypeRef ToType) -> ValueRef;
+ fn LLVMConstPointerCast(ValueRef ConstantVal,
+ TypeRef ToType) -> ValueRef;
+ fn LLVMConstIntCast(ValueRef ConstantVal, TypeRef ToType,
+ Bool isSigned) -> ValueRef;
+ fn LLVMConstFPCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
+ fn LLVMConstSelect(ValueRef ConstantCondition,
+ ValueRef ConstantIfTrue,
+ ValueRef ConstantIfFalse) -> ValueRef;
+ fn LLVMConstExtractElement(ValueRef VectorConstant,
+ ValueRef IndexConstant) -> ValueRef;
+ fn LLVMConstInsertElement(ValueRef VectorConstant,
+ ValueRef ElementValueConstant,
+ ValueRef IndexConstant) -> ValueRef;
+ fn LLVMConstShuffleVector(ValueRef VectorAConstant,
+ ValueRef VectorBConstant,
+ ValueRef MaskConstant) -> ValueRef;
+ fn LLVMConstExtractValue(ValueRef AggConstant, vbuf IdxList,
+ uint NumIdx) -> ValueRef;
+ fn LLVMConstInsertValue(ValueRef AggConstant,
+ ValueRef ElementValueConstant,
+ vbuf IdxList, uint NumIdx) -> ValueRef;
+ fn LLVMConstInlineAsm(TypeRef Ty,
+ sbuf AsmString, sbuf Constraints,
+ Bool HasSideEffects, Bool IsAlignStack) -> ValueRef;
+ fn LLVMBlockAddress(ValueRef F, BasicBlockRef BB) -> ValueRef;
+
+
+
+ /* Operations on global variables, functions, and aliases (globals) */
+ fn LLVMGetGlobalParent(ValueRef Global) -> ModuleRef;
+ fn LLVMIsDeclaration(ValueRef Global) -> Bool;
+ fn LLVMGetLinkage(ValueRef Global) -> Linkage;
+ fn LLVMSetLinkage(ValueRef Global, Linkage Link);
+ fn LLVMGetSection(ValueRef Global) -> sbuf;
+ fn LLVMSetSection(ValueRef Global, sbuf Section);
+ fn LLVMGetVisibility(ValueRef Global) -> Visibility;
+ fn LLVMSetVisibility(ValueRef Global, Visibility Viz);
+ fn LLVMGetAlignment(ValueRef Global) -> uint;
+ fn LLVMSetAlignment(ValueRef Global, uint Bytes);
+
+
+ /* Operations on global variables */
+ fn LLVMAddGlobal(ModuleRef M, TypeRef Ty, sbuf Name) -> ValueRef;
+ fn LLVMAddGlobalInAddressSpace(ModuleRef M, TypeRef Ty,
+ sbuf Name,
+ uint AddressSpace) -> ValueRef;
+ fn LLVMGetNamedGlobal(ModuleRef M, sbuf Name) -> ValueRef;
+ fn LLVMGetFirstGlobal(ModuleRef M) -> ValueRef;
+ fn LLVMGetLastGlobal(ModuleRef M) -> ValueRef;
+ fn LLVMGetNextGlobal(ValueRef GlobalVar) -> ValueRef;
+ fn LLVMGetPreviousGlobal(ValueRef GlobalVar) -> ValueRef;
+ fn LLVMDeleteGlobal(ValueRef GlobalVar);
+ fn LLVMGetInitializer(ValueRef GlobalVar) -> ValueRef;
+ fn LLVMSetInitializer(ValueRef GlobalVar, ValueRef ConstantVal);
+ fn LLVMIsThreadLocal(ValueRef GlobalVar) -> Bool;
+ fn LLVMSetThreadLocal(ValueRef GlobalVar, Bool IsThreadLocal);
+ fn LLVMIsGlobalConstant(ValueRef GlobalVar) -> Bool;
+ fn LLVMSetGlobalConstant(ValueRef GlobalVar, Bool IsConstant);
+
+ /* Operations on aliases */
+ fn LLVMAddAlias(ModuleRef M, TypeRef Ty, ValueRef Aliasee,
+ sbuf Name) -> ValueRef;
+
+ /* Operations on functions */
+ fn LLVMAddFunction(ModuleRef M, sbuf Name,
+ TypeRef FunctionTy) -> ValueRef;
+ fn LLVMGetNamedFunction(ModuleRef M, sbuf Name) -> ValueRef;
+ fn LLVMGetFirstFunction(ModuleRef M) -> ValueRef;
+ fn LLVMGetLastFunction(ModuleRef M) -> ValueRef;
+ fn LLVMGetNextFunction(ValueRef Fn) -> ValueRef;
+ fn LLVMGetPreviousFunction(ValueRef Fn) -> ValueRef;
+ fn LLVMDeleteFunction(ValueRef Fn);
+ fn LLVMGetIntrinsicID(ValueRef Fn) -> uint;
+ fn LLVMGetFunctionCallConv(ValueRef Fn) -> uint;
+ fn LLVMSetFunctionCallConv(ValueRef Fn, uint CC);
+ fn LLVMGetGC(ValueRef Fn) -> sbuf;
+ fn LLVMSetGC(ValueRef Fn, sbuf Name);
+ fn LLVMAddFunctionAttr(ValueRef Fn, Attribute PA);
+ fn LLVMGetFunctionAttr(ValueRef Fn) -> Attribute;
+ fn LLVMRemoveFunctionAttr(ValueRef Fn, Attribute PA);
+
+ /* Operations on parameters */
+ fn LLVMCountParams(ValueRef Fn) -> uint;
+ fn LLVMGetParams(ValueRef Fn, vbuf Params);
+ fn LLVMGetParam(ValueRef Fn, uint Index) -> ValueRef;
+ fn LLVMGetParamParent(ValueRef Inst) -> ValueRef;
+ fn LLVMGetFirstParam(ValueRef Fn) -> ValueRef;
+ fn LLVMGetLastParam(ValueRef Fn) -> ValueRef;
+ fn LLVMGetNextParam(ValueRef Arg) -> ValueRef;
+ fn LLVMGetPreviousParam(ValueRef Arg) -> ValueRef;
+ fn LLVMAddAttribute(ValueRef Arg, Attribute PA);
+ fn LLVMRemoveAttribute(ValueRef Arg, Attribute PA);
+ fn LLVMGetAttribute(ValueRef Arg) -> Attribute;
+ fn LLVMSetParamAlignment(ValueRef Arg, uint align);
+
+ /* Operations on basic blocks */
+ fn LLVMBasicBlockAsValue(BasicBlockRef BB) -> ValueRef;
+ fn LLVMValueIsBasicBlock(ValueRef Val) -> Bool;
+ fn LLVMValueAsBasicBlock(ValueRef Val) -> BasicBlockRef;
+ fn LLVMGetBasicBlockParent(BasicBlockRef BB) -> ValueRef;
+ fn LLVMCountBasicBlocks(ValueRef Fn) -> uint;
+ fn LLVMGetBasicBlocks(ValueRef Fn, vbuf BasicBlocks);
+ fn LLVMGetFirstBasicBlock(ValueRef Fn) -> BasicBlockRef;
+ fn LLVMGetLastBasicBlock(ValueRef Fn) -> BasicBlockRef;
+ fn LLVMGetNextBasicBlock(BasicBlockRef BB) -> BasicBlockRef;
+ fn LLVMGetPreviousBasicBlock(BasicBlockRef BB) -> BasicBlockRef;
+ fn LLVMGetEntryBasicBlock(ValueRef Fn) -> BasicBlockRef;
+
+ fn LLVMAppendBasicBlockInContext(ContextRef C, ValueRef Fn,
+ sbuf Name) -> BasicBlockRef;
+ fn LLVMInsertBasicBlockInContext(ContextRef C, BasicBlockRef BB,
+ sbuf Name) -> BasicBlockRef;
+
+ fn LLVMAppendBasicBlock(ValueRef Fn, sbuf Name) -> BasicBlockRef;
+ fn LLVMInsertBasicBlock(BasicBlockRef InsertBeforeBB,
+ sbuf Name) -> BasicBlockRef;
+ fn LLVMDeleteBasicBlock(BasicBlockRef BB);
+
+ /* Operations on instructions */
+ fn LLVMGetInstructionParent(ValueRef Inst) -> BasicBlockRef;
+ fn LLVMGetFirstInstruction(BasicBlockRef BB) -> ValueRef;
+ fn LLVMGetLastInstruction(BasicBlockRef BB) -> ValueRef;
+ fn LLVMGetNextInstruction(ValueRef Inst) -> ValueRef;
+ fn LLVMGetPreviousInstruction(ValueRef Inst) -> ValueRef;
+
+ /* Operations on call sites */
+ fn LLVMSetInstructionCallConv(ValueRef Instr, uint CC);
+ fn LLVMGetInstructionCallConv(ValueRef Instr) -> uint;
+ fn LLVMAddInstrAttribute(ValueRef Instr, uint index, Attribute IA);
+ fn LLVMRemoveInstrAttribute(ValueRef Instr, uint index, Attribute IA);
+ fn LLVMSetInstrParamAlignment(ValueRef Instr, uint index, uint align);
+
+ /* Operations on call instructions (only) */
+ fn LLVMIsTailCall(ValueRef CallInst) -> Bool;
+ fn LLVMSetTailCall(ValueRef CallInst, Bool IsTailCall);
+
+ /* Operations on phi nodes */
+ fn LLVMAddIncoming(ValueRef PhiNode, vbuf IncomingValues,
+ vbuf IncomingBlocks, uint Count);
+ fn LLVMCountIncoming(ValueRef PhiNode) -> uint;
+ fn LLVMGetIncomingValue(ValueRef PhiNode, uint Index) -> ValueRef;
+ fn LLVMGetIncomingBlock(ValueRef PhiNode, uint Index) -> BasicBlockRef;
+
+ /* Instruction builders */
+ fn LLVMCreateBuilderInContext(ContextRef C) -> BuilderRef;
+ fn LLVMCreateBuilder() -> BuilderRef;
+ fn LLVMPositionBuilder(BuilderRef Builder, BasicBlockRef Block,
+ ValueRef Instr);
+ fn LLVMPositionBuilderBefore(BuilderRef Builder, ValueRef Instr);
+ fn LLVMPositionBuilderAtEnd(BuilderRef Builder, BasicBlockRef Block);
+ fn LLVMGetInsertBlock(BuilderRef Builder) -> BasicBlockRef;
+ fn LLVMClearInsertionPosition(BuilderRef Builder);
+ fn LLVMInsertIntoBuilder(BuilderRef Builder, ValueRef Instr);
+ fn LLVMInsertIntoBuilderWithName(BuilderRef Builder, ValueRef Instr,
+ sbuf Name);
+ fn LLVMDisposeBuilder(BuilderRef Builder);
+
+ /* Metadata */
+ fn LLVMSetCurrentDebugLocation(BuilderRef Builder, ValueRef L);
+ fn LLVMGetCurrentDebugLocation(BuilderRef Builder) -> ValueRef;
+ fn LLVMSetInstDebugLocation(BuilderRef Builder, ValueRef Inst);
+
+ /* Terminators */
+ fn LLVMBuildRetVoid(BuilderRef B) -> ValueRef;
+ fn LLVMBuildRet(BuilderRef B, ValueRef V) -> ValueRef;
+ fn LLVMBuildAggregateRet(BuilderRef B, vbuf RetVals,
+ uint N) -> ValueRef;
+ fn LLVMBuildBr(BuilderRef B, BasicBlockRef Dest) -> ValueRef;
+ fn LLVMBuildCondBr(BuilderRef B, ValueRef If,
+ BasicBlockRef Then, BasicBlockRef Else) -> ValueRef;
+ fn LLVMBuildSwitch(BuilderRef B, ValueRef V,
+ BasicBlockRef Else, uint NumCases) -> ValueRef;
+ fn LLVMBuildIndirectBr(BuilderRef B, ValueRef Addr,
+ uint NumDests) -> ValueRef;
+ fn LLVMBuildInvoke(BuilderRef B, ValueRef Fn,
+ vbuf Args, uint NumArgs,
+ BasicBlockRef Then, BasicBlockRef Catch,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildUnwind(BuilderRef B) -> ValueRef;
+ fn LLVMBuildUnreachable(BuilderRef B) -> ValueRef;
+
+ /* Add a case to the switch instruction */
+ fn LLVMAddCase(ValueRef Switch, ValueRef OnVal,
+ BasicBlockRef Dest);
+
+ /* Add a destination to the indirectbr instruction */
+ fn LLVMAddDestination(ValueRef IndirectBr, BasicBlockRef Dest);
+
+ /* Arithmetic */
+ fn LLVMBuildAdd(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNSWAdd(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNUWAdd(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFAdd(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildSub(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNSWSub(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNUWSub(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFSub(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildMul(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNSWMul(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNUWMul(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFMul(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildUDiv(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildSDiv(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildExactSDiv(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFDiv(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildURem(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildSRem(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFRem(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildShl(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildLShr(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildAShr(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildAnd(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildOr(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildXor(BuilderRef B, ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildBinOp(BuilderRef B, Opcode Op,
+ ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNeg(BuilderRef B, ValueRef V, sbuf Name) -> ValueRef;
+ fn LLVMBuildNSWNeg(BuilderRef B, ValueRef V,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildNUWNeg(BuilderRef B, ValueRef V,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFNeg(BuilderRef B, ValueRef V, sbuf Name) -> ValueRef;
+ fn LLVMBuildNot(BuilderRef B, ValueRef V, sbuf Name) -> ValueRef;
+
+ /* Memory */
+ fn LLVMBuildMalloc(BuilderRef B, TypeRef Ty, sbuf Name) -> ValueRef;
+ fn LLVMBuildArrayMalloc(BuilderRef B, TypeRef Ty,
+ ValueRef Val, sbuf Name) -> ValueRef;
+ fn LLVMBuildAlloca(BuilderRef B, TypeRef Ty, sbuf Name) -> ValueRef;
+ fn LLVMBuildArrayAlloca(BuilderRef B, TypeRef Ty,
+ ValueRef Val, sbuf Name) -> ValueRef;
+ fn LLVMBuildFree(BuilderRef B, ValueRef PointerVal) -> ValueRef;
+ fn LLVMBuildLoad(BuilderRef B, ValueRef PointerVal,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildStore(BuilderRef B, ValueRef Val, ValueRef Ptr) -> ValueRef;
+ fn LLVMBuildGEP(BuilderRef B, ValueRef Pointer,
+ vbuf Indices, uint NumIndices,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildInBoundsGEP(BuilderRef B, ValueRef Pointer,
+ vbuf Indices, uint NumIndices,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildStructGEP(BuilderRef B, ValueRef Pointer,
+ uint Idx, sbuf Name) -> ValueRef;
+ fn LLVMBuildGlobalString(BuilderRef B, sbuf Str,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildGlobalStringPtr(BuilderRef B, sbuf Str,
+ sbuf Name) -> ValueRef;
+
+ /* Casts */
+ fn LLVMBuildTrunc(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildZExt(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildSExt(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildFPToUI(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildFPToSI(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildUIToFP(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildSIToFP(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildFPTrunc(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildFPExt(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildPtrToInt(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildIntToPtr(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildBitCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildZExtOrBitCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildSExtOrBitCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildTruncOrBitCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildCast(BuilderRef B, Opcode Op, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildPointerCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildIntCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+ fn LLVMBuildFPCast(BuilderRef B, ValueRef Val,
+ TypeRef DestTy, sbuf Name) -> ValueRef;
+
+ /* Comparisons */
+ fn LLVMBuildICmp(BuilderRef B, IntPredicate Op,
+ ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildFCmp(BuilderRef B, RealPredicate Op,
+ ValueRef LHS, ValueRef RHS,
+ sbuf Name) -> ValueRef;
+
+ /* Miscellaneous instructions */
+ fn LLVMBuildPhi(BuilderRef B, TypeRef Ty, sbuf Name) -> ValueRef;
+ fn LLVMBuildCall(BuilderRef B, ValueRef Fn,
+ vbuf Args, uint NumArgs,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildSelect(BuilderRef B, ValueRef If,
+ ValueRef Then, ValueRef Else,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildVAArg(BuilderRef B, ValueRef List, TypeRef Ty,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildExtractElement(BuilderRef B, ValueRef VecVal,
+ ValueRef Index, sbuf Name) -> ValueRef;
+ fn LLVMBuildInsertElement(BuilderRef B, ValueRef VecVal,
+ ValueRef EltVal, ValueRef Index,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildShuffleVector(BuilderRef B, ValueRef V1,
+ ValueRef V2, ValueRef Mask,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildExtractValue(BuilderRef B, ValueRef AggVal,
+ uint Index, sbuf Name) -> ValueRef;
+ fn LLVMBuildInsertValue(BuilderRef B, ValueRef AggVal,
+ ValueRef EltVal, uint Index,
+ sbuf Name) -> ValueRef;
+
+ fn LLVMBuildIsNull(BuilderRef B, ValueRef Val,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildIsNotNull(BuilderRef B, ValueRef Val,
+ sbuf Name) -> ValueRef;
+ fn LLVMBuildPtrDiff(BuilderRef B, ValueRef LHS,
+ ValueRef RHS, sbuf Name) -> ValueRef;
+
+
+ /** Writes a module to the specified path. Returns 0 on success. */
+ fn LLVMWriteBitcodeToFile(ModuleRef M, sbuf Path) -> int;
+}
+
+/* Slightly more terse object-interface to LLVM's 'builder' functions. */
+
+obj builder(BuilderRef B) {
+
+ /* Terminators */
+ fn RetVoid() -> ValueRef {
+ ret llvm.LLVMBuildRetVoid(B);
+ }
+
+ fn Ret(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildRet(B, V);
+ }
+
+ fn AggregateRet(vbuf RetVals, uint N) -> ValueRef {
+ ret llvm.LLVMBuildAggregateRet(B, RetVals, N);
+ }
+
+ fn Br(BasicBlockRef Dest) -> ValueRef {
+ ret llvm.LLVMBuildBr(B, Dest);
+ }
+
+ fn CondBr(ValueRef If, BasicBlockRef Then,
+ BasicBlockRef Else) -> ValueRef {
+ ret llvm.LLVMBuildCondBr(B, If, Then, Else);
+ }
+
+ fn Switch(ValueRef V, BasicBlockRef Else, uint NumCases) -> ValueRef {
+ ret llvm.LLVMBuildSwitch(B, V, Else, NumCases);
+ }
+
+ fn IndirectBr(ValueRef Addr, uint NumDests) -> ValueRef {
+ ret llvm.LLVMBuildIndirectBr(B, Addr, NumDests);
+ }
+
+ fn Invoke(ValueRef Fn, vbuf Args, uint NumArgs,
+ BasicBlockRef Then, BasicBlockRef Catch,
+ sbuf Name) -> ValueRef {
+ ret llvm.LLVMBuildInvoke(B, Fn, Args, NumArgs,
+ Then, Catch, Name);
+ }
+
+ fn Unwind() -> ValueRef {
+ ret llvm.LLVMBuildUnwind(B);
+ }
+
+ fn Unreachable() -> ValueRef {
+ ret llvm.LLVMBuildUnreachable(B);
+ }
+
+ /* Arithmetic */
+ fn Add(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildAdd(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NSWAdd(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNSWAdd(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NUWAdd(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNUWAdd(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn FAdd(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildFAdd(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Sub(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildSub(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NSWSub(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNSWSub(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NUWSub(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNUWSub(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn FSub(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildFSub(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Mul(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildMul(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NSWMul(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNSWMul(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn NUWMul(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildNUWMul(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn FMul(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildFMul(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn UDiv(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildUDiv(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn SDiv(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildSDiv(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn ExactSDiv(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildExactSDiv(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn FDiv(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildFDiv(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn URem(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildURem(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn SRem(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildSRem(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn FRem(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildFRem(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Shl(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildShl(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn LShr(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildLShr(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn AShr(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildAShr(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn And(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildAnd(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Or(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildOr(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Xor(ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildXor(B, LHS, RHS, 0 as sbuf);
+ }
+
+ fn BinOp(Opcode Op, ValueRef LHS, ValueRef RHS) -> ValueRef {
+ ret llvm.LLVMBuildBinOp(B, Op, LHS, RHS, 0 as sbuf);
+ }
+
+ fn Neg(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildNeg(B, V, 0 as sbuf);
+ }
+
+ fn NSWNeg(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildNSWNeg(B, V, 0 as sbuf);
+ }
+
+ fn NUWNeg(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildNUWNeg(B, V, 0 as sbuf);
+ }
+ fn FNeg(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildFNeg(B, V, 0 as sbuf);
+ }
+ fn Not(ValueRef V) -> ValueRef {
+ ret llvm.LLVMBuildNot(B, V, 0 as sbuf);
+ }
+
+ /* Memory */
+ fn Malloc(TypeRef Ty) -> ValueRef {
+ ret llvm.LLVMBuildMalloc(B, Ty, 0 as sbuf);
+ }
+
+ fn ArrayMalloc(TypeRef Ty, ValueRef Val) -> ValueRef {
+ ret llvm.LLVMBuildArrayMalloc(B, Ty, Val, 0 as sbuf);
+ }
+
+ fn Alloca(TypeRef Ty) -> ValueRef {
+ ret llvm.LLVMBuildAlloca(B, Ty, 0 as sbuf);
+ }
+
+ fn ArrayAlloca(TypeRef Ty, ValueRef Val) -> ValueRef {
+ ret llvm.LLVMBuildArrayAlloca(B, Ty, Val, 0 as sbuf);
+ }
+
+ fn Free(ValueRef PointerVal) -> ValueRef {
+ ret llvm.LLVMBuildFree(B, PointerVal);
+ }
+
+ fn Load(ValueRef PointerVal) -> ValueRef {
+ ret llvm.LLVMBuildLoad(B, PointerVal, 0 as sbuf);
+ }
+
+ fn Store(ValueRef Val, ValueRef Ptr) -> ValueRef {
+ ret llvm.LLVMBuildStore(B, Val, Ptr);
+ }
+
+ fn GEP(ValueRef Pointer, vbuf Indices, uint NumIndices,
+ sbuf Name) -> ValueRef {
+ ret llvm.LLVMBuildGEP(B, Pointer, Indices, NumIndices, 0 as sbuf);
+ }
+
+ fn InBoundsGEP(ValueRef Pointer, vbuf Indices, uint NumIndices,
+ sbuf Name) -> ValueRef {
+ ret llvm.LLVMBuildInBoundsGEP(B, Pointer, Indices,
+ NumIndices, 0 as sbuf);
+ }
+
+ fn StructGEP(ValueRef Pointer, uint Idx) -> ValueRef {
+ ret llvm.LLVMBuildStructGEP(B, Pointer, Idx, 0 as sbuf);
+ }
+
+ fn GlobalString(sbuf Str) -> ValueRef {
+ ret llvm.LLVMBuildGlobalString(B, Str, 0 as sbuf);
+ }
+
+ fn GlobalStringPtr(sbuf Str) -> ValueRef {
+ ret llvm.LLVMBuildGlobalStringPtr(B, Str, 0 as sbuf);
+ }
+
+ drop {
+ llvm.LLVMDisposeBuilder(B);
+ }
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 7b1f9236..4e186b17 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -4,21 +4,47 @@
use std;
mod fe {
+ mod ast;
mod lexer;
mod parser;
+ mod token;
}
mod driver {
mod rustc;
}
+mod util {
+ mod common;
+}
+
+auth driver.rustc.main = state;
+auth driver.rustc.write_module = unsafe;
+
mod lib {
- mod llvm;
+ alt (target_os) {
+ case ("win32") {
+ let (llvm_lib = "LLVM-2.8svn.dll") {
+ mod llvm;
+ }
+ }
+ case ("macos") {
+ let (llvm_lib = "libLLVM-2.8svn.dylib") {
+ mod llvm;
+ }
+ }
+ else {
+ let (llvm_lib = "libLLVM-2.8svn.so") {
+ mod llvm;
+ }
+ }
+ }
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
+// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs
new file mode 100644
index 00000000..3089c2c1
--- /dev/null
+++ b/src/comp/util/common.rs
@@ -0,0 +1,28 @@
+
+type ty_mach = tag( ty_i8(), ty_i16(), ty_i32(), ty_i64(),
+ ty_u8(), ty_u16(), ty_u32(), ty_u64(),
+ ty_f32(), ty_f16() );
+
+fn ty_mach_to_str(ty_mach tm) -> str {
+ alt (tm) {
+ case (ty_u8()) { ret "u8"; }
+ case (ty_i8()) { ret "i8"; }
+ case (ty_u16()) { ret "u16"; }
+ case (ty_i16()) { ret "i16"; }
+ case (ty_u32()) { ret "u32"; }
+ case (ty_i32()) { ret "i32"; }
+ case (ty_u64()) { ret "u64"; }
+ case (ty_i64()) { ret "i64"; }
+ }
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/etc/tidy.py b/src/etc/tidy.py
index eff967bf..057f5c2b 100644
--- a/src/etc/tidy.py
+++ b/src/etc/tidy.py
@@ -1,10 +1,18 @@
-#!/usr/bin/python
+#!/usr/bin/env python
-import sys, fileinput
+import sys, fileinput, subprocess
err=0
cols=78
+# Be careful to support Python 2.4, 2.6, and 3.x here!
+config_proc=subprocess.Popen([ "git", "config", "core.autocrlf" ],
+ stdout=subprocess.PIPE)
+result=config_proc.communicate()[0]
+
+true="true".encode('utf8')
+autocrlf=result.strip() == true if result is not None else False
+
def report_err(s):
global err
print("%s:%d: %s" % (fileinput.filename(), fileinput.filelineno(), s))
@@ -14,10 +22,11 @@ for line in fileinput.input(openhook=fileinput.hook_encoded("utf-8")):
if line.find('\t') != -1 and fileinput.filename().find("Makefile") == -1:
report_err("tab character")
- if line.find('\r') != -1:
+ if not autocrlf and line.find('\r') != -1:
report_err("CR character")
- if len(line)-1 > cols:
+ line_len = len(line)-2 if autocrlf else len(line)-1
+ if line_len > cols:
report_err("line longer than %d chars" % cols)
diff --git a/src/lib/_int.rs b/src/lib/_int.rs
index e76c2bf5..396dd331 100644
--- a/src/lib/_int.rs
+++ b/src/lib/_int.rs
@@ -25,66 +25,12 @@ iter range(mutable int lo, int hi) -> int {
}
}
-iter urange(mutable uint lo, uint hi) -> uint {
- while (lo < hi) {
- put lo;
- lo += 1u;
- }
-}
-
-fn next_power_of_two(uint n) -> uint {
- // FIXME change |* uint(4)| below to |* uint(8) / uint(2)| and watch the
- // world explode.
- let uint halfbits = sys.rustrt.size_of[uint]() * 4u;
- let uint tmp = n - 1u;
- let uint shift = 1u;
- while (shift <= halfbits) {
- tmp |= tmp >> shift;
- shift <<= 1u;
- }
- 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);
+ ret "-" + _uint.to_str((-n) as uint, radix);
} else {
- ret uto_str(n as uint, radix);
+ ret _uint.to_str(n as uint, radix);
}
}
diff --git a/src/lib/_io.rs b/src/lib/_io.rs
index 93d06d41..0d968c5c 100644
--- a/src/lib/_io.rs
+++ b/src/lib/_io.rs
@@ -1,132 +1,182 @@
-import std.os;
+import std.os.libc;
import std._str;
import std._vec;
+
+type stdio_reader = unsafe obj {
+ fn getc() -> int;
+ fn ungetc(int i);
+};
+
+fn new_stdio_reader(str path) -> stdio_reader {
+ unsafe obj stdio_FILE_reader(os.libc.FILE f) {
+ fn getc() -> int {
+ ret os.libc.fgetc(f);
+ }
+ fn ungetc(int i) {
+ os.libc.ungetc(i, f);
+ }
+ drop {
+ os.libc.fclose(f);
+ }
+ }
+ ret stdio_FILE_reader(os.libc.fopen(_str.buf(path),
+ _str.buf("r")));
+}
+
+
type buf_reader = unsafe obj {
- fn read() -> vec[u8];
+ fn read() -> vec[u8];
};
type buf_writer = unsafe obj {
- fn write(vec[u8] v);
+ fn write(vec[u8] v);
};
fn default_bufsz() -> uint {
- ret 4096u;
+ ret 4096u;
}
fn new_buf() -> vec[u8] {
- ret _vec.alloc[u8](default_bufsz());
+ ret _vec.alloc[u8](default_bufsz());
}
fn new_buf_reader(str path) -> buf_reader {
- unsafe obj fd_buf_reader(int fd, mutable vec[u8] buf) {
+ unsafe obj fd_buf_reader(int fd, mutable vec[u8] buf) {
- fn read() -> vec[u8] {
+ fn read() -> vec[u8] {
- // Ensure our buf is singly-referenced.
- if (_vec.rustrt.refcount[u8](buf) != 1u) {
- buf = new_buf();
- }
+ // Ensure our buf is singly-referenced.
+ if (_vec.rustrt.refcount[u8](buf) != 1u) {
+ buf = new_buf();
+ }
- auto len = _vec.len[u8](buf);
- auto vbuf = _vec.buf[u8](buf);
- auto count = os.libc.read(fd, vbuf, len);
+ auto len = default_bufsz();
+ auto vbuf = _vec.buf[u8](buf);
+ auto count = os.libc.read(fd, vbuf, len);
- if (count < 0) {
- log "error filling buffer";
- log sys.rustrt.last_os_error();
- fail;
- } else {
- ret buf;
- }
+ if (count < 0) {
+ log "error filling buffer";
+ log sys.rustrt.last_os_error();
+ fail;
+ }
+
+ _vec.len_set[u8](buf, count as uint);
+ ret buf;
+ }
+
+ drop {
+ os.libc.close(fd);
+ }
}
- drop {
- os.libc.close(fd);
+ auto fd = os.libc.open(_str.buf(path),
+ os.libc_constants.O_RDONLY() |
+ os.libc_constants.O_BINARY(),
+ 0u);
+
+ if (fd < 0) {
+ log "error opening file for reading";
+ log sys.rustrt.last_os_error();
+ fail;
}
- }
-
- auto fd = os.libc.open(_str.buf(path),
- os.libc_constants.O_RDONLY() |
- os.libc_constants.O_BINARY(),
- 0u);
-
- if (fd < 0) {
- log "error opening file for reading";
- log sys.rustrt.last_os_error();
- fail;
- }
- ret fd_buf_reader(fd, new_buf());
+ ret fd_buf_reader(fd, new_buf());
}
-type fileflag = tag(append(), create(), truncate());
+/**
+ * FIXME (issue #150): This should be
+ *
+ * type fileflag = tag(append(), create(), truncate());
+ *
+ * but then the tag value ctors are not found from crate-importers of std, so
+ * we manually simulate the enum below.
+ */
+type fileflag = uint;
+fn append() -> uint { ret 0u; }
+fn create() -> uint { ret 1u; }
+fn truncate() -> uint { ret 2u; }
fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
- unsafe obj fd_buf_writer(int fd) {
-
- fn write(vec[u8] v) {
- auto len = _vec.len[u8](v);
- auto count = 0u;
- auto vbuf;
- while (count < len) {
- vbuf = _vec.buf_off[u8](v, count);
- auto nout = os.libc.write(fd, vbuf, len);
- if (nout < 0) {
- log "error dumping buffer";
- log sys.rustrt.last_os_error();
- fail;
+ unsafe obj fd_buf_writer(int fd) {
+
+ fn write(vec[u8] v) {
+ auto len = _vec.len[u8](v);
+ auto count = 0u;
+ auto vbuf;
+ while (count < len) {
+ vbuf = _vec.buf_off[u8](v, count);
+ auto nout = os.libc.write(fd, vbuf, len);
+ if (nout < 0) {
+ log "error dumping buffer";
+ log sys.rustrt.last_os_error();
+ fail;
+ }
+ count += nout as uint;
+ }
+ }
+
+ drop {
+ os.libc.close(fd);
}
- count += nout as uint;
- }
}
- drop {
- os.libc.close(fd);
+ let int fflags =
+ os.libc_constants.O_WRONLY() |
+ os.libc_constants.O_BINARY();
+
+ for (fileflag f in flags) {
+ alt (f) {
+ // FIXME (issue #150): cf comment above defn of fileflag type
+ //case (append()) { fflags |= os.libc_constants.O_APPEND(); }
+ //case (create()) { fflags |= os.libc_constants.O_CREAT(); }
+ //case (truncate()) { fflags |= os.libc_constants.O_TRUNC(); }
+ case (0u) { fflags |= os.libc_constants.O_APPEND(); }
+ case (1u) { fflags |= os.libc_constants.O_CREAT(); }
+ case (2u) { fflags |= os.libc_constants.O_TRUNC(); }
+ }
}
- }
- let int fflags =
- os.libc_constants.O_WRONLY() |
- os.libc_constants.O_BINARY();
+ auto fd = os.libc.open(_str.buf(path),
+ fflags,
+ os.libc_constants.S_IRUSR() |
+ os.libc_constants.S_IWUSR());
- for (fileflag f in flags) {
- alt (f) {
- case (append()) { fflags |= os.libc_constants.O_APPEND(); }
- case (create()) { fflags |= os.libc_constants.O_CREAT(); }
- case (truncate()) { fflags |= os.libc_constants.O_TRUNC(); }
+ if (fd < 0) {
+ log "error opening file for writing";
+ log sys.rustrt.last_os_error();
+ fail;
}
- }
-
- auto fd = os.libc.open(_str.buf(path),
- fflags,
- os.libc_constants.S_IRUSR() |
- os.libc_constants.S_IWUSR());
-
- if (fd < 0) {
- log "error opening file for writing";
- log sys.rustrt.last_os_error();
- fail;
- }
- ret fd_buf_writer(fd);
+ ret fd_buf_writer(fd);
}
type writer =
- unsafe obj {
- fn write_str(str s);
- fn write_int(int n);
- fn write_uint(uint n);
- };
+ 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
+ -> 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));
+ 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(_uint.to_str(n, 10u))); }
+ }
+ ret fw(new_buf_writer(path, flags));
}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
diff --git a/src/lib/_str.rs b/src/lib/_str.rs
index a607c7d5..a29e1daa 100644
--- a/src/lib/_str.rs
+++ b/src/lib/_str.rs
@@ -1,13 +1,32 @@
import rustrt.sbuf;
+import std._vec.rustrt.vbuf;
+
native "rust" mod rustrt {
type sbuf;
fn str_buf(str s) -> sbuf;
fn str_byte_len(str s) -> uint;
fn str_alloc(uint n_bytes) -> str;
+ fn str_from_vec(vec[u8] b) -> str;
fn refcount[T](str s) -> uint;
}
+fn eq(str a, str b) -> bool {
+ let uint i = byte_len(a);
+ if (byte_len(b) != i) {
+ ret false;
+ }
+ while (i > 0u) {
+ i -= 1u;
+ auto cha = a.(i);
+ auto chb = b.(i);
+ if (cha != chb) {
+ ret false;
+ }
+ }
+ ret true;
+}
+
fn is_utf8(vec[u8] v) -> bool {
fail; // FIXME
}
@@ -40,9 +59,33 @@ 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);
+fn bytes(str s) -> vec[u8] {
+ /* FIXME (issue #58):
+ * Should be...
+ *
+ * fn ith(str s, uint i) -> u8 {
+ * ret s.(i);
+ * }
+ * ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
+ *
+ * but we do not correctly decrement refcount of s when
+ * the binding dies, so we have to do this manually.
+ */
+ let uint n = _str.byte_len(s);
+ let vec[u8] v = _vec.alloc[u8](n);
+ let uint i = 0u;
+ while (i < n) {
+ v += vec(s.(i));
+ i += 1u;
}
- ret _vec.init_fn[u8](bind ith(s, _), _str.byte_len(s));
+ ret v;
+}
+
+fn from_bytes(vec[u8] v) : is_utf8(v) -> str {
+ ret rustrt.str_from_vec(v);
+}
+
+fn refcount(str s) -> uint {
+ // -1 because calling this function incremented the refcount.
+ ret rustrt.refcount[u8](s) - 1u;
}
diff --git a/src/lib/_task.rs b/src/lib/_task.rs
new file mode 100644
index 00000000..a12c2f27
--- /dev/null
+++ b/src/lib/_task.rs
@@ -0,0 +1,12 @@
+native "rust" mod rustrt {
+ fn task_sleep(uint time_in_us);
+}
+
+/**
+ * Hints the scheduler to yield this task for a specified ammount of time.
+ *
+ * arg: time_in_us maximum number of microseconds to yield control for
+ */
+fn sleep(uint time_in_us) {
+ ret rustrt.task_sleep(time_in_us);
+} \ No newline at end of file
diff --git a/src/lib/_uint.rs b/src/lib/_uint.rs
new file mode 100644
index 00000000..897f0da6
--- /dev/null
+++ b/src/lib/_uint.rs
@@ -0,0 +1,86 @@
+import std.sys;
+
+fn add(uint x, uint y) -> uint { ret x + y; }
+fn sub(uint x, uint y) -> uint { ret x - y; }
+fn mul(uint x, uint y) -> uint { ret x * y; }
+fn div(uint x, uint y) -> uint { ret x / y; }
+fn rem(uint x, uint y) -> uint { ret x % y; }
+
+fn lt(uint x, uint y) -> bool { ret x < y; }
+fn le(uint x, uint y) -> bool { ret x <= y; }
+fn eq(uint x, uint y) -> bool { ret x == y; }
+fn ne(uint x, uint y) -> bool { ret x != y; }
+fn ge(uint x, uint y) -> bool { ret x >= y; }
+fn gt(uint x, uint y) -> bool { ret x > y; }
+
+iter range(mutable uint lo, uint hi) -> uint {
+ while (lo < hi) {
+ put lo;
+ lo += 1u;
+ }
+}
+
+fn next_power_of_two(uint n) -> uint {
+ // FIXME change |* uint(4)| below to |* uint(8) / uint(2)| and watch the
+ // world explode.
+ let uint halfbits = sys.rustrt.size_of[uint]() * 4u;
+ let uint tmp = n - 1u;
+ let uint shift = 1u;
+ while (shift <= halfbits) {
+ tmp |= tmp >> shift;
+ shift <<= 1u;
+ }
+ ret tmp + 1u;
+}
+
+fn to_str(mutable uint n, uint radix) -> str
+{
+ check (0u < radix && radix <= 16u);
+ fn digit(uint n) -> char {
+ 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 uint r = 1u;
+ if (n > r) {
+ while ((r*radix) < n) {
+ r *= radix;
+ }
+ }
+
+ let str s = "";
+ while (n > 0u) {
+
+ auto i = n/r;
+
+ n -= (i * r);
+ r /= radix;
+
+ s += digit(i) as u8;
+ }
+
+ while (r > 0u) {
+ s += '0' as u8;
+ r /= radix;
+ }
+
+ ret s;
+}
diff --git a/src/lib/_vec.rs b/src/lib/_vec.rs
index e374bf52..5f1d2baa 100644
--- a/src/lib/_vec.rs
+++ b/src/lib/_vec.rs
@@ -3,13 +3,26 @@ import op = util.operator;
native "rust" mod rustrt {
type vbuf;
+
fn vec_buf[T](vec[T] v, uint offset) -> vbuf;
+
fn vec_len[T](vec[T] v) -> uint;
- /* The T in vec_alloc[T, U] is the type of the vec to allocate. The
+ /**
+ * Sometimes we modify the vec internal data via vec_buf and need to update
+ * the vec's fill length accordingly.
+ */
+ fn vec_len_set[T](vec[T] v, uint n);
+
+ /**
+ * The T in vec_alloc[T, U] is the type of the vec to allocate. The
* U is the type of an element in the vec. So to allocate a vec[U] we
- * want to invoke this as vec_alloc[vec[U], U]. */
+ * want to invoke this as vec_alloc[vec[U], U].
+ */
fn vec_alloc[T, U](uint n_elts) -> vec[U];
+
fn refcount[T](vec[T] v) -> uint;
+
+ fn vec_print_debug_info[T](vec[T] v);
}
fn alloc[T](uint n_elts) -> vec[T] {
@@ -20,10 +33,10 @@ type init_op[T] = fn(uint i) -> T;
fn init_fn[T](&init_op[T] op, uint n_elts) -> vec[T] {
let vec[T] v = alloc[T](n_elts);
- let uint i = n_elts;
- while (i > 0u) {
- i -= 1u;
+ let uint i = 0u;
+ while (i < n_elts) {
v += vec(op(i));
+ i += 1u;
}
ret v;
}
@@ -45,12 +58,16 @@ fn init_elt[T](&T t, uint n_elts) -> vec[T] {
ret v;
}
+fn buf[T](vec[T] v) -> vbuf {
+ ret rustrt.vec_buf[T](v, 0u);
+}
+
fn len[T](vec[T] v) -> uint {
ret rustrt.vec_len[T](v);
}
-fn buf[T](vec[T] v) -> vbuf {
- ret rustrt.vec_buf[T](v, 0u);
+fn len_set[T](vec[T] v, uint n) {
+ rustrt.vec_len_set[T](v, n);
}
fn buf_off[T](vec[T] v, uint offset) -> vbuf {
@@ -58,14 +75,17 @@ fn buf_off[T](vec[T] v, uint offset) -> vbuf {
ret rustrt.vec_buf[T](v, offset);
}
+fn print_debug_info[T](vec[T] v) {
+ rustrt.vec_print_debug_info[T](v);
+}
+
// Returns elements from [start..end) from v.
fn slice[T](vec[T] v, int start, int end) -> vec[T] {
- check(0 <= start);
- check(start <= end);
- // FIXME #108: This doesn't work yet.
- //check(end <= int(len[T](v)));
+ check (0 <= start);
+ check (start <= end);
+ check (end <= (len[T](v) as int));
auto result = alloc[T]((end - start) as uint);
- let mutable int i = start;
+ let int i = start;
while (i < end) {
result += vec(v.(i));
i += 1;
diff --git a/src/lib/deque.rs b/src/lib/deque.rs
index bf7acb53..54dca00b 100644
--- a/src/lib/deque.rs
+++ b/src/lib/deque.rs
@@ -42,12 +42,12 @@ fn create[T]() -> t[T] {
}
}
- let uint nalloc = _int.next_power_of_two(nelts + 1u);
+ let uint nalloc = _uint.next_power_of_two(nelts + 1u);
let _vec.init_op[cell[T]] copy_op = bind fill[T](_, nelts, lo, elts);
ret _vec.init_fn[cell[T]](copy_op, nalloc);
}
- fn get[T](&vec[cell[T]] elts, uint i) -> T {
+ fn get[T](vec[cell[T]] elts, uint i) -> T {
alt (elts.(i)) {
case (util.some[T](t)) { ret t; }
case (_) { fail; }
@@ -100,6 +100,7 @@ fn create[T]() -> t[T] {
let T t = get[T](elts, lo);
elts.(lo) = util.none[T]();
lo = (lo + 1u) % _vec.len[cell[T]](elts);
+ nelts -= 1u;
ret t;
}
@@ -112,6 +113,7 @@ fn create[T]() -> t[T] {
let T t = get[T](elts, hi);
elts.(hi) = util.none[T]();
+ nelts -= 1u;
ret t;
}
diff --git a/src/lib/linux_os.rs b/src/lib/linux_os.rs
index 3f096e99..dd5d8bfc 100644
--- a/src/lib/linux_os.rs
+++ b/src/lib/linux_os.rs
@@ -8,6 +8,12 @@ native mod libc = "libc.so.6" {
fn write(int fd, vbuf buf, uint count) -> int;
fn close(int fd) -> int;
+ type FILE;
+ fn fopen(sbuf path, sbuf mode) -> FILE;
+ fn fclose(FILE f);
+ fn fgetc(FILE f) -> int;
+ fn ungetc(int c, FILE f);
+
type dir;
// readdir is a mess; handle via wrapper function in rustrt.
fn opendir(sbuf d) -> dir;
diff --git a/src/lib/macos_os.rs b/src/lib/macos_os.rs
index 2ada5c07..22ab3a79 100644
--- a/src/lib/macos_os.rs
+++ b/src/lib/macos_os.rs
@@ -8,6 +8,12 @@ native mod libc = "libc.dylib" {
fn write(int fd, vbuf buf, uint count) -> int;
fn close(int fd) -> int;
+ type FILE;
+ fn fopen(sbuf path, sbuf mode) -> FILE;
+ fn fclose(FILE f);
+ fn fgetc(FILE f) -> int;
+ fn ungetc(int c, FILE f);
+
type dir;
// readdir is a mess; handle via wrapper function in rustrt.
fn opendir(sbuf d) -> dir;
diff --git a/src/lib/map.rs b/src/lib/map.rs
index ff7b4411..786e5ba1 100644
--- a/src/lib/map.rs
+++ b/src/lib/map.rs
@@ -145,7 +145,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
fn insert(&K key, &V val) -> bool {
let util.rational load = rec(num=(nelts + 1u) as int, den=nbkts as int);
if (!util.rational_leq(load, lf)) {
- let uint nnewbkts = _int.next_power_of_two(nbkts + 1u);
+ let uint nnewbkts = _uint.next_power_of_two(nbkts + 1u);
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
diff --git a/src/lib/std.rc b/src/lib/std.rc
index 8c956691..ea8e50eb 100644
--- a/src/lib/std.rc
+++ b/src/lib/std.rc
@@ -7,6 +7,7 @@ meta (name = "std",
// Built-in types support modules.
mod _int;
+mod _uint;
mod _u8;
mod _vec;
mod _str;
@@ -15,6 +16,7 @@ mod _str;
mod _io;
mod sys;
+mod _task;
// Utility modules.
@@ -25,8 +27,9 @@ mod util;
auth _io = unsafe;
auth _str = unsafe;
auth _vec = unsafe;
+auth _task = unsafe;
-auth _int.next_power_of_two = unsafe;
+auth _uint.next_power_of_two = unsafe;
auth map.mk_hashmap = unsafe;
auth rand.mk_rng = unsafe;
diff --git a/src/lib/win32_os.rs b/src/lib/win32_os.rs
index 3d8e5f3a..3a6da60f 100644
--- a/src/lib/win32_os.rs
+++ b/src/lib/win32_os.rs
@@ -6,6 +6,12 @@ native mod libc = "msvcrt.dll" {
fn read(int fd, vbuf buf, uint count) -> int = "_read";
fn write(int fd, vbuf buf, uint count) -> int = "_write";
fn close(int fd) -> int = "_close";
+
+ type FILE;
+ fn fopen(sbuf path, sbuf mode) -> FILE;
+ fn fclose(FILE f);
+ fn fgetc(FILE f) -> int;
+ fn ungetc(int c, FILE f);
}
mod libc_constants {
diff --git a/src/rt/circular_buffer.cpp b/src/rt/circular_buffer.cpp
index a93f2572..b2eab97e 100644
--- a/src/rt/circular_buffer.cpp
+++ b/src/rt/circular_buffer.cpp
@@ -31,11 +31,10 @@ 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.");
+ W(dom, _unread == 0,
+ "freeing circular_buffer with %d unread bytes", _unread);
dom->free(_buffer);
}
@@ -144,3 +143,8 @@ bool
circular_buffer::is_empty() {
return _unread == 0;
}
+
+size_t
+circular_buffer::size() {
+ return _unread;
+}
diff --git a/src/rt/circular_buffer.h b/src/rt/circular_buffer.h
index 732ba329..9ddaba42 100644
--- a/src/rt/circular_buffer.h
+++ b/src/rt/circular_buffer.h
@@ -21,6 +21,7 @@ public:
void dequeue(void *dst);
uint8_t *peek();
bool is_empty();
+ size_t size();
private:
// Size of the buffer in bytes, should always be a power of two so that
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/memory.h b/src/rt/memory.h
new file mode 100644
index 00000000..22bc15d3
--- /dev/null
+++ b/src/rt/memory.h
@@ -0,0 +1,60 @@
+/*
+ *
+ */
+
+#ifndef MEMORY_H
+#define MEMORY_H
+
+
+inline void *operator new(size_t size, void *mem) {
+ return mem;
+}
+
+inline void *operator new(size_t size, rust_dom *dom) {
+ return dom->malloc(size, memory_region::LOCAL);
+}
+
+inline void *operator new[](size_t size, rust_dom *dom) {
+ return dom->malloc(size, memory_region::LOCAL);
+}
+
+inline void *operator new(size_t size, rust_dom &dom) {
+ return dom.malloc(size, memory_region::LOCAL);
+}
+
+inline void *operator new[](size_t size, rust_dom &dom) {
+ return dom.malloc(size, memory_region::LOCAL);
+}
+
+inline void *operator new(size_t size, rust_dom *dom,
+ memory_region::memory_region_type type) {
+ return dom->malloc(size, type);
+}
+
+inline void *operator new[](size_t size, rust_dom *dom,
+ memory_region::memory_region_type type) {
+ return dom->malloc(size, type);
+}
+
+inline void *operator new(size_t size, rust_dom &dom,
+ memory_region::memory_region_type type) {
+ return dom.malloc(size, type);
+}
+
+inline void *operator new[](size_t size, rust_dom &dom,
+ memory_region::memory_region_type type) {
+ return dom.malloc(size, type);
+}
+
+inline void operator delete(void *mem, rust_dom *dom) {
+ dom->free(mem, memory_region::LOCAL);
+ return;
+}
+
+inline void operator delete(void *mem, rust_dom *dom,
+ memory_region::memory_region_type type) {
+ dom->free(mem, type);
+ return;
+}
+
+#endif /* MEMORY_H */
diff --git a/src/rt/memory_region.cpp b/src/rt/memory_region.cpp
new file mode 100644
index 00000000..797a7c1d
--- /dev/null
+++ b/src/rt/memory_region.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ */
+
+#include "rust_internal.h"
+#include "memory_region.h"
+
+#define TRACK_ALLOCATIONS
+
+memory_region::memory_region(rust_srv *srv, bool synchronized) :
+ _srv(srv), _parent(NULL), _live_allocations(0),
+ _synchronized(synchronized) {
+ // Nop.
+}
+
+memory_region::memory_region(memory_region *parent) :
+ _srv(parent->_srv), _parent(parent), _live_allocations(0),
+ _synchronized(parent->_synchronized) {
+ // Nop.
+}
+
+void memory_region::free(void *mem) {
+ if (_synchronized) { _lock.lock(); }
+#ifdef TRACK_ALLOCATIONS
+ if (_allocation_list.replace(mem, NULL) == false) {
+ printf("free: ptr 0x%" PRIxPTR " is not in allocation_list\n",
+ (uintptr_t) mem);
+ _srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
+ }
+#endif
+ if (_live_allocations < 1) {
+ _srv->fatal("live_allocs < 1", __FILE__, __LINE__, "");
+ }
+ _live_allocations--;
+ _srv->free(mem);
+ if (_synchronized) { _lock.unlock(); }
+
+}
+
+void *
+memory_region::realloc(void *mem, size_t size) {
+ if (_synchronized) { _lock.lock(); }
+ if (!mem) {
+ _live_allocations++;
+ }
+ void *newMem = _srv->realloc(mem, size);
+#ifdef TRACK_ALLOCATIONS
+ if (_allocation_list.replace(mem, newMem) == false) {
+ printf("realloc: ptr 0x%" PRIxPTR " is not in allocation_list\n",
+ (uintptr_t) mem);
+ _srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
+ }
+#endif
+ if (_synchronized) { _lock.unlock(); }
+ return newMem;
+}
+
+void *
+memory_region::malloc(size_t size) {
+ if (_synchronized) { _lock.lock(); }
+ _live_allocations++;
+ void *mem = _srv->malloc(size);
+#ifdef TRACK_ALLOCATIONS
+ _allocation_list.append(mem);
+#endif
+ if (_synchronized) { _lock.unlock(); }
+ return mem;
+}
+
+void *
+memory_region::calloc(size_t size) {
+ if (_synchronized) { _lock.lock(); }
+ _live_allocations++;
+ void *mem = _srv->malloc(size);
+ memset(mem, 0, size);
+#ifdef TRACK_ALLOCATIONS
+ _allocation_list.append(mem);
+#endif
+ if (_synchronized) { _lock.unlock(); }
+ return mem;
+}
+
+memory_region::~memory_region() {
+ if (_live_allocations == 0) {
+ return;
+ }
+ char msg[128];
+ snprintf(msg, sizeof(msg),
+ "leaked memory in rust main loop (%" PRIuPTR " objects)",
+ _live_allocations);
+#ifdef TRACK_ALLOCATIONS
+ for (size_t i = 0; i < _allocation_list.size(); i++) {
+ if (_allocation_list[i] != NULL) {
+ printf("allocation 0x%" PRIxPTR " was not freed\n",
+ (uintptr_t) _allocation_list[i]);
+ }
+ }
+#endif
+ _srv->fatal(msg, __FILE__, __LINE__, "%d objects", _live_allocations);
+}
diff --git a/src/rt/memory_region.h b/src/rt/memory_region.h
new file mode 100644
index 00000000..3411d867
--- /dev/null
+++ b/src/rt/memory_region.h
@@ -0,0 +1,37 @@
+/*
+ * The Rust runtime uses memory regions to provide a primitive level of
+ * memory management and isolation between tasks, and domains.
+ *
+ * TODO: Implement a custom lock-free malloc / free instead of relying solely
+ * on the standard malloc / free.
+ */
+
+#ifndef MEMORY_REGION_H
+#define MEMORY_REGION_H
+
+#include "sync/spin_lock.h"
+
+class rust_srv;
+
+class memory_region {
+private:
+ rust_srv *_srv;
+ memory_region *_parent;
+ size_t _live_allocations;
+ array_list<void *> _allocation_list;
+ const bool _synchronized;
+ spin_lock _lock;
+public:
+ enum memory_region_type {
+ LOCAL = 0x1, SYNCHRONIZED = 0x2
+ };
+ memory_region(rust_srv *srv, bool synchronized);
+ memory_region(memory_region *parent);
+ void *malloc(size_t size);
+ void *calloc(size_t size);
+ void *realloc(void *mem, size_t size);
+ void free(void *mem);
+ virtual ~memory_region();
+};
+
+#endif /* MEMORY_REGION_H */
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index 9cc2fe41..905b0c8a 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -1,108 +1,5 @@
#include "rust_internal.h"
-#define TRACK_ALLOCATIONS
-
-rust_srv::rust_srv() :
- live_allocs(0)
-{
-}
-
-rust_srv::~rust_srv()
-{
- if (live_allocs != 0) {
- char msg[128];
- snprintf(msg, sizeof(msg),
- "leaked memory in rust main loop (%" PRIuPTR " objects)",
- live_allocs);
-#ifdef TRACK_ALLOCATIONS
- for (size_t i = 0; i < allocation_list.size(); i++) {
- if (allocation_list[i] != NULL) {
- printf("allocation 0x%" PRIxPTR " was not freed\n",
- (uintptr_t) allocation_list[i]);
- }
- }
-#endif
- fatal(msg, __FILE__, __LINE__);
- }
-}
-
-void
-rust_srv::log(char const *str)
-{
- printf("rt: %s\n", str);
-}
-
-
-
-void *
-rust_srv::malloc(size_t bytes)
-{
- ++live_allocs;
- void * val = ::malloc(bytes);
-#ifdef TRACK_ALLOCATIONS
- allocation_list.append(val);
-#endif
- return val;
-}
-
-void *
-rust_srv::realloc(void *p, size_t bytes)
-{
- if (!p) {
- live_allocs++;
- }
- void * val = ::realloc(p, bytes);
-#ifdef TRACK_ALLOCATIONS
- if (allocation_list.replace(p, val) == NULL) {
- fatal("not in allocation_list", __FILE__, __LINE__);
- }
-#endif
- return val;
-}
-
-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",
- (uintptr_t) p);
- fatal("not in allocation_list", __FILE__, __LINE__);
- }
-#endif
- if (live_allocs < 1) {
- fatal("live_allocs < 1", __FILE__, __LINE__);
- }
- live_allocs--;
- ::free(p);
-}
-
-void
-rust_srv::fatal(char const *expr, char const *file, size_t line)
-{
- char buf[1024];
- snprintf(buf, sizeof(buf),
- "fatal, '%s' failed, %s:%d",
- expr, file, (int)line);
- log(buf);
- exit(1);
-}
-
-void
-rust_srv::warning(char const *expr, char const *file, size_t line)
-{
- char buf[1024];
- snprintf(buf, sizeof(buf),
- "warning: '%s', at: %s:%d",
- expr, file, (int)line);
- log(buf);
-}
-
-rust_srv *
-rust_srv::clone()
-{
- return new rust_srv();
-}
struct
command_line_args
@@ -182,7 +79,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.h b/src/rt/rust.h
index 9a61dca7..3c534c94 100644
--- a/src/rt/rust.h
+++ b/src/rt/rust.h
@@ -19,26 +19,7 @@
#include "util/array_list.h"
-struct rust_srv {
- size_t live_allocs;
- array_list<void *> allocation_list;
-
- virtual void log(char const *);
- virtual void fatal(char const *, char const *, size_t);
- virtual void warning(char const *, char const *, size_t);
- virtual void *malloc(size_t);
- virtual void *realloc(void *, size_t);
- virtual void free(void *);
- virtual rust_srv *clone();
-
- rust_srv();
- virtual ~rust_srv();
-};
-
-inline void *operator new(size_t size, rust_srv *srv)
-{
- return srv->malloc(size);
-}
+#include "rust_srv.h"
/*
* Local Variables:
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index d8d9b8d6..d2bad054 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -2,19 +2,6 @@
#include "rust_internal.h"
/* Native builtins. */
-extern "C" CDECL rust_str*
-str_alloc(rust_task *task, size_t n_bytes)
-{
- rust_dom *dom = task->dom;
- size_t alloc = next_power_of_two(sizeof(rust_str) + n_bytes);
- void *mem = dom->malloc(alloc);
- if (!mem) {
- task->fail(2);
- return NULL;
- }
- rust_str *st = new (mem) rust_str(dom, alloc, 1, (uint8_t const *)"");
- return st;
-}
extern "C" CDECL rust_str*
last_os_error(rust_task *task) {
@@ -51,7 +38,7 @@ last_os_error(rust_task *task) {
#endif
size_t fill = strlen(buf) + 1;
size_t alloc = next_power_of_two(sizeof(rust_str) + fill);
- void *mem = dom->malloc(alloc);
+ void *mem = dom->malloc(alloc, memory_region::LOCAL);
if (!mem) {
task->fail(1);
return NULL;
@@ -95,7 +82,7 @@ extern "C" CDECL rust_vec*
vec_alloc(rust_task *task, type_desc *t, type_desc *elem_t, size_t n_elts)
{
rust_dom *dom = task->dom;
- task->log(rust_log::MEM,
+ task->log(rust_log::MEM | rust_log::STDLIB,
"vec_alloc %" PRIdPTR " elements of size %" PRIdPTR,
n_elts, elem_t->size);
size_t fill = n_elts * elem_t->size;
@@ -109,6 +96,85 @@ vec_alloc(rust_task *task, type_desc *t, type_desc *elem_t, size_t n_elts)
return vec;
}
+extern "C" CDECL void *
+vec_buf(rust_task *task, type_desc *ty, rust_vec *v, size_t offset)
+{
+ return (void *)&v->data[ty->size * offset];
+}
+
+extern "C" CDECL size_t
+vec_len(rust_task *task, type_desc *ty, rust_vec *v)
+{
+ return v->fill / ty->size;
+}
+
+extern "C" CDECL void
+vec_len_set(rust_task *task, type_desc *ty, rust_vec *v, size_t len)
+{
+ task->log(rust_log::STDLIB,
+ "vec_len_set(0x%" PRIxPTR ", %" PRIdPTR ") on vec with "
+ "alloc = %" PRIdPTR
+ ", fill = %" PRIdPTR
+ ", len = %" PRIdPTR
+ ". New fill is %" PRIdPTR,
+ v, len, v->alloc, v->fill, v->fill / ty->size, len * ty->size);
+ v->fill = len * ty->size;
+}
+
+extern "C" CDECL void
+vec_print_debug_info(rust_task *task, type_desc *ty, rust_vec *v)
+{
+ task->log(rust_log::STDLIB,
+ "vec_print_debug_info(0x%" PRIxPTR ")"
+ " with tydesc 0x%" PRIxPTR
+ " (size = %" PRIdPTR ", align = %" PRIdPTR ")"
+ " alloc = %" PRIdPTR ", fill = %" PRIdPTR ", len = %" PRIdPTR
+ " , data = ...",
+ v,
+ ty,
+ ty->size,
+ ty->align,
+ v->alloc,
+ v->fill,
+ v->fill / ty->size);
+
+ for (size_t i = 0; i < v->fill; ++i) {
+ task->log(rust_log::STDLIB,
+ " %" PRIdPTR ": 0x%" PRIxPTR,
+ i, v->data[i]);
+ }
+}
+
+/* Helper for str_alloc and str_from_vec. Returns NULL as failure. */
+static rust_str *
+str_alloc_with_data(rust_task *task,
+ size_t n_bytes,
+ size_t fill,
+ uint8_t const *d)
+{
+ rust_dom *dom = task->dom;
+ size_t alloc = next_power_of_two(sizeof(rust_str) + n_bytes);
+ void *mem = dom->malloc(alloc, memory_region::LOCAL);
+ if (!mem)
+ return NULL;
+ rust_str *st = new (mem) rust_str(dom, alloc, fill, d);
+ return st;
+}
+
+extern "C" CDECL rust_str*
+str_alloc(rust_task *task, size_t n_bytes)
+{
+ rust_str *st = str_alloc_with_data(task,
+ n_bytes + 1, // +1 to fit at least ""
+ 1,
+ (uint8_t const *)"");
+ if (!st) {
+ task->fail(2);
+ return NULL;
+ }
+ return st;
+}
+
extern "C" CDECL char const *
str_buf(rust_task *task, rust_str *s)
{
@@ -121,16 +187,20 @@ 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)
-{
- return (void *)&v->data[ty->size * offset];
-}
-
-extern "C" CDECL size_t
-vec_len(rust_task *task, type_desc *ty, rust_vec *v)
+extern "C" CDECL rust_str *
+str_from_vec(rust_task *task, rust_vec *v)
{
- return v->fill / ty->size;
+ rust_str *st =
+ str_alloc_with_data(task,
+ v->fill + 1, // +1 to fit at least '\0'
+ v->fill,
+ v->fill ? (uint8_t const *)v->data : NULL);
+ if (!st) {
+ task->fail(2);
+ return NULL;
+ }
+ st->data[st->fill++] = '\0';
+ return st;
}
extern "C" CDECL void *
@@ -158,6 +228,13 @@ rand_free(rust_task *task, randctx *rctx)
task->free(rctx);
}
+extern "C" CDECL void upcall_sleep(rust_task *task, size_t time_in_us);
+
+extern "C" CDECL void
+task_sleep(rust_task *task, size_t time_in_us) {
+ upcall_sleep(task, time_in_us);
+}
+
//
// Local Variables:
// mode: C++
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..ce6bebf3 100644
--- a/src/rt/rust_dom.cpp
+++ b/src/rt/rust_dom.cpp
@@ -4,12 +4,18 @@
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),
+ local_region(&srv->local_region),
+ synchronized_region(&srv->synchronized_region),
+ name(name),
running_tasks(this),
blocked_tasks(this),
dead_tasks(this),
@@ -25,14 +31,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 +53,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 +86,8 @@ rust_dom::~rust_dom() {
#endif
while (caches.length())
delete caches.pop();
+
+ _live_domains.replace(this, NULL);
}
void
@@ -124,41 +139,72 @@ 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;
}
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);
- return p;
+rust_dom::malloc(size_t size) {
+ return malloc(size, memory_region::LOCAL);
}
void *
-rust_dom::calloc(size_t sz) {
- void *p = this->malloc(sz);
- memset(p, 0, sz);
- return p;
+rust_dom::malloc(size_t size, memory_region::memory_region_type type) {
+ if (type == memory_region::LOCAL) {
+ return local_region.malloc(size);
+ } else if (type == memory_region::SYNCHRONIZED) {
+ return synchronized_region.malloc(size);
+ }
+ return NULL;
}
void *
-rust_dom::realloc(void *p, size_t sz) {
- void *p1 = srv->realloc(p, sz);
- I(this, p1);
- log(rust_log::MEM, "rust_dom::realloc(0x%" PRIxPTR ", %d) -> 0x%" PRIxPTR,
- p, sz, p1);
- return p1;
+rust_dom::calloc(size_t size) {
+ return calloc(size, memory_region::LOCAL);
+}
+
+void *
+rust_dom::calloc(size_t size, memory_region::memory_region_type type) {
+ if (type == memory_region::LOCAL) {
+ return local_region.calloc(size);
+ } else if (type == memory_region::SYNCHRONIZED) {
+ return synchronized_region.calloc(size);
+ }
+ return NULL;
+}
+
+void *
+rust_dom::realloc(void *mem, size_t size) {
+ return realloc(mem, size, memory_region::LOCAL);
+}
+
+void *
+rust_dom::realloc(void *mem, size_t size,
+ memory_region::memory_region_type type) {
+ if (type == memory_region::LOCAL) {
+ return local_region.realloc(mem, size);
+ } else if (type == memory_region::SYNCHRONIZED) {
+ return synchronized_region.realloc(mem, size);
+ }
+ return NULL;
+}
+
+void
+rust_dom::free(void *mem) {
+ free(mem, memory_region::LOCAL);
}
void
-rust_dom::free(void *p) {
- log(rust_log::MEM, "rust_dom::free(0x%" PRIxPTR ")", p);
- I(this, p);
- srv->free(p);
+rust_dom::free(void *mem, memory_region::memory_region_type type) {
+ log(rust_log::MEM, "rust_dom::free(0x%" PRIxPTR ")", mem);
+ if (type == memory_region::LOCAL) {
+ local_region.free(mem);
+ } else if (type == memory_region::SYNCHRONIZED) {
+ synchronized_region.free(mem);
+ }
+ return;
}
#ifdef __WIN32__
@@ -190,8 +236,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 +246,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 +272,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 +289,13 @@ 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);
- A(this, message->dom == this, "Message owned by non-local domain.");
+ &_incoming_message_queue,
+ this);
_incoming_message_queue.enqueue(message);
- _incoming_message_pending.signal();
- _progress.signal();
}
/**
@@ -262,7 +307,8 @@ void rust_dom::drain_incoming_message_queue() {
log(rust_log::COMM, "<== processing incoming message \"%s\" 0x%"
PRIxPTR, message->label, message);
message->process();
- delete message;
+ message->~rust_message();
+ this->synchronized_region.free(message);
}
}
@@ -272,7 +318,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;
@@ -307,27 +353,64 @@ rust_dom::get_port_proxy_synchronized(rust_port *port) {
* Returns NULL if no tasks can be scheduled.
*/
rust_task *
-rust_dom::schedule_task()
-{
+rust_dom::schedule_task() {
I(this, this);
// FIXME: in the face of failing tasks, this is not always right.
// I(this, n_live_tasks() > 0);
if (running_tasks.length() > 0) {
size_t i = rand(&rctx);
i %= running_tasks.length();
- return (rust_task *)running_tasks[i];
+ if (running_tasks[i]->yield_timer.has_timed_out()) {
+ return (rust_task *)running_tasks[i];
+ }
}
// log(rust_log::DOM|rust_log::TASK, "no schedulable tasks");
return NULL;
}
+/**
+ * Checks for simple deadlocks.
+ */
+bool
+rust_dom::is_deadlocked() {
+ if (_live_domains.size() != 1) {
+ // We cannot tell if we are deadlocked if other domains exists.
+ return false;
+ }
+
+ if (running_tasks.length() != 0) {
+ // We are making progress and therefore we are not deadlocked.
+ return false;
+ }
+
+ if (_incoming_message_queue.is_empty() && blocked_tasks.length() > 0) {
+ // We have no messages to process, no running tasks to schedule
+ // and some blocked tasks therefore we are likely in a deadlock.
+ log_state();
+ return true;
+ }
+
+ return false;
+}
+
+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
+ " timeout: %d",
+ running_tasks[i]->name,
+ running_tasks[i],
+ running_tasks[i]->yield_timer.get_timeout());
}
}
@@ -335,15 +418,19 @@ 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
+ " '%s'",
+ blocked_tasks[i]->name, blocked_tasks[i],
+ blocked_tasks[i]->cond, blocked_tasks[i]->cond_name);
}
}
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]->name, dead_tasks[i],
+ dead_tasks[i]->ref_count);
}
}
}
@@ -360,42 +447,54 @@ 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) {
+ A(this, is_deadlocked() == false, "deadlock");
+
drain_incoming_message_queue();
rust_task *scheduled_task = schedule_task();
- // If we cannot schedule a task because all other live tasks
- // are blocked, wait on a condition variable which is signaled
- // if progress is made in other domains.
+ // The scheduler busy waits until a task is available for scheduling.
+ // Eventually we'll want a smarter way to do this, perhaps sleep
+ // for a minimum amount of time.
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 +509,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..34d8c694 100644
--- a/src/rt/rust_dom.h
+++ b/src/rt/rust_dom.h
@@ -25,6 +25,9 @@ struct rust_dom
rust_crate const *root_crate;
rust_log _log;
rust_srv *srv;
+ memory_region local_region;
+ memory_region synchronized_region;
+ const char *const name;
ptr_vec<rust_task> running_tasks;
ptr_vec<rust_task> blocked_tasks;
ptr_vec<rust_task> dead_tasks;
@@ -34,20 +37,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);
@@ -58,10 +60,15 @@ struct rust_dom
template<typename T>
void logptr(char const *msg, T* ptrval);
void fail();
- void *malloc(size_t sz);
- void *calloc(size_t sz);
- void *realloc(void *data, size_t sz);
- void free(void *p);
+ void *malloc(size_t size);
+ void *malloc(size_t size, memory_region::memory_region_type type);
+ void *calloc(size_t size);
+ void *calloc(size_t size, memory_region::memory_region_type type);
+ void *realloc(void *mem, size_t size);
+ void *realloc(void *mem, size_t size,
+ memory_region::memory_region_type type);
+ void free(void *mem);
+ void free(void *mem, memory_region::memory_region_type type);
void send_message(rust_message *message);
void drain_incoming_message_queue();
@@ -81,9 +88,11 @@ struct rust_dom
void reap_dead_tasks();
rust_task *schedule_task();
+ bool is_deadlocked();
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..d6618873 100644
--- a/src/rt/rust_internal.h
+++ b/src/rt/rust_internal.h
@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@@ -38,19 +39,22 @@ extern "C" {
#error "Platform not supported."
#endif
+#include "sync/sync.h"
+#include "sync/timer.h"
#include "sync/condition_variable.h"
#ifndef __i386__
#error "Target CPU not supported."
#endif
-#define I(dom, e) ((e) ? (void)0 : \
- (dom)->srv->fatal(#e, __FILE__, __LINE__))
-#define W(dom, e, s) ((e) ? (void)0 : \
- (dom)->srv->warning(#e " : " #s, __FILE__, __LINE__))
+#define I(dom, e) ((e) ? (void)0 : \
+ (dom)->srv->fatal(#e, __FILE__, __LINE__, ""))
-#define A(dom, e, s) ((e) ? (void)0 : \
- (dom)->srv->fatal(#e " : " #s, __FILE__, __LINE__))
+#define W(dom, e, s, ...) ((e) ? (void)0 : \
+ (dom)->srv->warning(#e, __FILE__, __LINE__, s, ## __VA_ARGS__))
+
+#define A(dom, e, s, ...) ((e) ? (void)0 : \
+ (dom)->srv->fatal(#e, __FILE__, __LINE__, s, ## __VA_ARGS__))
struct rust_task;
struct rust_port;
@@ -75,7 +79,7 @@ template <typename T>
struct
rc_base
{
- size_t ref_count;
+ intptr_t ref_count;
void ref() {
++ref_count;
@@ -151,6 +155,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);
};
@@ -161,32 +166,14 @@ template <typename T> inline T
check_null(rust_dom *dom, T value, char const *expr,
char const *file, size_t line) {
if (value == NULL) {
- dom->srv->fatal(expr, file, line);
+ dom->srv->fatal(expr, file, line, "is null");
}
return value;
}
#define CHECK_NULL(dom, e) (check_null(dom, e, #e, __FILE__, __LINE__))
-inline void *operator new(size_t sz, void *mem) {
- return mem;
-}
-
-inline void *operator new(size_t sz, rust_dom *dom) {
- return dom->malloc(sz);
-}
-
-inline void *operator new[](size_t sz, rust_dom *dom) {
- return dom->malloc(sz);
-}
-
-inline void *operator new(size_t sz, rust_dom &dom) {
- return dom.malloc(sz);
-}
-
-inline void *operator new[](size_t sz, rust_dom &dom) {
- return dom.malloc(sz);
-}
+#include "memory.h"
struct
rust_timer
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 48fcd0f1..e72a62fa 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -26,7 +26,10 @@ read_type_bit_mask() {
bits |= strstr(env_str, "cache") ? rust_log::CACHE : 0;
bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0;
bits |= strstr(env_str, "gc") ? rust_log::GC : 0;
+ bits |= strstr(env_str, "stdlib") ? rust_log::STDLIB : 0;
+ bits |= strstr(env_str, "special") ? rust_log::SPECIAL : 0;
bits |= strstr(env_str, "all") ? rust_log::ALL : 0;
+ bits = strstr(env_str, "none") ? 0 : bits;
}
return bits;
}
@@ -144,13 +147,22 @@ rust_log::trace_ln(rust_task *task, char *message) {
#if defined(__WIN32__)
uint32_t thread_id = 0;
#else
- uint32_t thread_id = (uint32_t) pthread_self();
+ uint32_t thread_id = hash((uint32_t) pthread_self());
#endif
char prefix[1024] = "";
- append_string(prefix, "0x%08" PRIxPTR ":0x%08" PRIxPTR ":",
- thread_id, (uintptr_t) _dom);
+ if (_dom->name) {
+ append_string(prefix, "%04" PRIxPTR ":%.10s:",
+ thread_id, _dom->name);
+ } else {
+ append_string(prefix, "%04" PRIxPTR ":0x%08" PRIxPTR ":",
+ thread_id, (uintptr_t) _dom);
+ }
if (task) {
- append_string(prefix, "0x%08" PRIxPTR ":", (uintptr_t) task);
+ if (task->name) {
+ append_string(prefix, "%.10s:", task->name);
+ } else {
+ append_string(prefix, "0x%08" PRIxPTR ":", (uintptr_t) task);
+ }
}
trace_ln(thread_id, prefix, message);
}
diff --git a/src/rt/rust_log.h b/src/rt/rust_log.h
index 29c85e70..5155cb48 100644
--- a/src/rt/rust_log.h
+++ b/src/rt/rust_log.h
@@ -41,6 +41,8 @@ public:
UPCALL = 0x200,
TIMER = 0x400,
GC = 0x800,
+ STDLIB = 0x1000,
+ SPECIAL = 0x2000,
ALL = 0xffffffff
};
diff --git a/src/rt/rust_message.cpp b/src/rt/rust_message.cpp
index 8b396b4d..b6b7fbf0 100644
--- a/src/rt/rust_message.cpp
+++ b/src/rt/rust_message.cpp
@@ -3,7 +3,8 @@
rust_message::
rust_message(const char* label, rust_task *source, rust_task *target) :
- dom(target->dom), label(label),
+ label(label),
+ _dom(target->dom),
_source(source),
_target(target) {
}
@@ -12,12 +13,12 @@ rust_message::~rust_message() {
}
void rust_message::process() {
- I(dom, false);
+ I(_dom, false);
}
rust_proxy<rust_task> *
rust_message::get_source_proxy() {
- return dom->get_task_proxy(_source);
+ return _dom->get_task_proxy(_source);
}
notify_message::
@@ -50,8 +51,9 @@ send(notification_type type, const char* label, rust_task *source,
rust_proxy<rust_task> *target) {
rust_task *target_task = target->delegate();
rust_dom *target_domain = target_task->dom;
- notify_message *message = new (target_domain)
- notify_message(type, label, source, target_task);
+ notify_message *message =
+ new (target_domain, memory_region::SYNCHRONIZED) notify_message(type,
+ label, source, target_task);
target_domain->send_message(message);
}
@@ -83,15 +85,15 @@ send(uint8_t *buffer, size_t buffer_sz, const char* label, rust_task *source,
rust_task *target_task = target->delegate();
rust_port *target_port = port->delegate();
rust_dom *target_domain = target_task->dom;
- data_message *message = new (target_domain)
- data_message(buffer, buffer_sz, label, source,
- target_task, target_port);
+ data_message *message =
+ new (target_domain, memory_region::SYNCHRONIZED)
+ data_message(buffer, buffer_sz, label, source,
+ target_task, target_port);
target_domain->send_message(message);
}
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_message.h b/src/rt/rust_message.h
index b7b8568a..6d986acf 100644
--- a/src/rt/rust_message.h
+++ b/src/rt/rust_message.h
@@ -9,12 +9,11 @@
/**
* Abstract base class for all message types.
*/
-class rust_message : public lock_free_queue_node,
- public dom_owned<rust_message> {
+class rust_message : public lock_free_queue_node {
public:
- rust_dom *dom;
const char* label;
private:
+ rust_dom *_dom;
rust_task *_source;
protected:
rust_task *_target;
@@ -70,7 +69,7 @@ public:
data_message(uint8_t *buffer, size_t buffer_sz, const char* label,
rust_task *source, rust_task *target, rust_port *port);
- ~data_message();
+ virtual ~data_message();
void process();
/**
diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp
index 0a5b7ee7..458283fb 100644
--- a/src/rt/rust_port.cpp
+++ b/src/rt/rust_port.cpp
@@ -17,16 +17,49 @@ 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();
+
+ if (chan->ref_count == 0) {
+ task->log(rust_log::COMM,
+ "chan: 0x%" PRIxPTR " is dormant, freeing", chan);
+ delete chan;
+ }
}
- // 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);
+ 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 ", size: %d, remote: %s",
+ chan,
+ chan->buffer.size(),
+ 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_srv.cpp b/src/rt/rust_srv.cpp
new file mode 100644
index 00000000..f2dfef63
--- /dev/null
+++ b/src/rt/rust_srv.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ */
+
+#include "rust_internal.h"
+#include "rust_srv.h"
+
+rust_srv::rust_srv() :
+ local_region(this, false),
+ synchronized_region(this, true) {
+ // Nop.
+}
+
+rust_srv::~rust_srv() {
+ // Nop.
+}
+
+void
+rust_srv::free(void *p) {
+ ::free(p);
+}
+
+void *
+rust_srv::malloc(size_t bytes) {
+ return ::malloc(bytes);
+}
+
+void *
+rust_srv::realloc(void *p, size_t bytes) {
+ return ::realloc(p, bytes);
+}
+
+void
+rust_srv::log(char const *msg) {
+ printf("rt: %s\n", msg);
+}
+
+void
+rust_srv::fatal(const char *expression,
+ const char *file,
+ size_t line,
+ const char *format,
+ ...) {
+ char buf[1024];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+
+ char msg[1024];
+ snprintf(msg, sizeof(msg),
+ "fatal, '%s' failed, %s:%d %s",
+ expression, file, (int)line, buf);
+ log(msg);
+ exit(1);
+}
+
+void
+rust_srv::warning(char const *expression,
+ char const *file,
+ size_t line,
+ const char *format,
+ ...) {
+ char buf[1024];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+
+ char msg[1024];
+ snprintf(msg, sizeof(msg),
+ "warning: '%s', at: %s:%d %s",
+ expression, file, (int)line, buf);
+ log(msg);
+}
+
+rust_srv *
+rust_srv::clone() {
+ return new rust_srv();
+}
diff --git a/src/rt/rust_srv.h b/src/rt/rust_srv.h
new file mode 100644
index 00000000..e617c002
--- /dev/null
+++ b/src/rt/rust_srv.h
@@ -0,0 +1,34 @@
+/*
+ *
+ */
+
+#ifndef RUST_SRV_H
+#define RUST_SRV_H
+
+#include "sync/spin_lock.h"
+#include "memory_region.h"
+
+class rust_srv {
+public:
+ memory_region local_region;
+ memory_region synchronized_region;
+ virtual void log(char const *msg);
+ virtual void fatal(char const *expression,
+ char const *file,
+ size_t line,
+ char const *format,
+ ...);
+ virtual void warning(char const *expression,
+ char const *file,
+ size_t line,
+ char const *format,
+ ...);
+ virtual void free(void *);
+ virtual void *malloc(size_t);
+ virtual void *realloc(void *, size_t);
+ rust_srv();
+ virtual ~rust_srv();
+ virtual rust_srv *clone();
+};
+
+#endif /* RUST_SRV_H */
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 9f4fa611..9497645b 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -6,7 +6,9 @@
// Stacks
-static size_t const min_stk_bytes = 0x300;
+// FIXME (issue #151): This should be 0x300; the change here is for
+// practicality's sake until stack growth is working.
+static size_t const min_stk_bytes = 0x300000;
// Task stack segments. Heap allocated and chained together.
@@ -52,7 +54,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,8 +62,10 @@ 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),
+ cond_name("none"),
supervisor(spawner),
idx(0),
rendezvous_ptr(0),
@@ -77,8 +81,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)) {
@@ -198,6 +202,12 @@ rust_task::start(uintptr_t exit_task_glue,
void
rust_task::grow(size_t n_frame_bytes)
{
+ // FIXME (issue #151): Just fail rather than almost certainly crashing
+ // mysteriously later. The commented-out logic below won't work at all in
+ // the presence of non-word-aligned pointers.
+ abort();
+
+#if 0
stk_seg *old_stk = this->stk;
uintptr_t old_top = (uintptr_t) old_stk->limit;
uintptr_t old_bottom = (uintptr_t) &old_stk->data[0];
@@ -252,6 +262,7 @@ rust_task::grow(size_t n_frame_bytes)
"processed %d relocations", n_relocs);
del_stk(dom, old_stk);
dom->logptr("grown stk limit", new_top);
+#endif
}
void
@@ -308,10 +319,16 @@ rust_task::run_on_resume(uintptr_t glue)
}
void
-rust_task::yield(size_t nargs)
-{
+rust_task::yield(size_t nargs) {
+ yield(nargs, 0);
+}
+
+void
+rust_task::yield(size_t nargs, size_t time_in_us) {
log(rust_log::TASK,
- "task 0x%" PRIxPTR " yielding", this);
+ "task %s @0x%" PRIxPTR " yielding for %d us",
+ name, this, time_in_us);
+ yield_timer.reset(time_in_us);
run_after_return(nargs, dom->root_crate->get_yield_glue());
}
@@ -323,23 +340,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 +370,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 +381,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 +389,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 +492,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 +513,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 +533,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));
@@ -531,7 +562,7 @@ rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst)
}
void
-rust_task::block(rust_cond *on)
+rust_task::block(rust_cond *on, const char* name)
{
log(rust_log::TASK, "Blocking on 0x%" PRIxPTR ", cond: 0x%" PRIxPTR,
(uintptr_t) on, (uintptr_t) cond);
@@ -540,6 +571,7 @@ rust_task::block(rust_cond *on)
transition(&dom->running_tasks, &dom->blocked_tasks);
cond = on;
+ cond_name = name;
}
void
@@ -551,11 +583,9 @@ 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;
+ cond_name = "none";
}
void
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index b657592a..9a4e0c7b 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -21,13 +21,18 @@ 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;
+ const char *cond_name;
rust_task *supervisor; // Parent-link for failure propagation.
size_t idx;
size_t gc_alloc_thresh;
size_t gc_alloc_accum;
+ // Keeps track of the last time this task yielded.
+ timer yield_timer;
+
// Rendezvous pointer for receiving data when blocked on a port. If we're
// trying to read data and no data is available on any incoming channel,
// we block on the port, and yield control to the scheduler. Since, we
@@ -41,8 +46,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,
@@ -64,7 +71,7 @@ rust_task : public maybe_proxy<rust_task>,
const char *state_str();
void transition(ptr_vec<rust_task> *svec, ptr_vec<rust_task> *dvec);
- void block(rust_cond *on);
+ void block(rust_cond *on, const char* name);
void wakeup(rust_cond *from);
void die();
void unblock();
@@ -85,6 +92,9 @@ rust_task : public maybe_proxy<rust_task>,
// Save callee-saved registers and return to the main loop.
void yield(size_t nargs);
+ // Yields for a specified duration of time.
+ void yield(size_t nargs, size_t time_in_ms);
+
// Fail this task (assuming caller-on-stack is different task).
void kill();
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 574cb703..a3373870 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,55 @@ 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);
+ // Nop.
+}
+
+/**
* 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()) {
+ // We're trying to delete a channel that another task may be reading
+ // from. We have two options:
+ //
+ // 1. We can flush the channel by blocking in upcall_flush_chan()
+ // and resuming only when the channel is flushed. The problem
+ // here is that we can get ourselves in a deadlock if the parent
+ // task tries to join us.
+ //
+ // 2. We can leave the channel in a "dormnat" state by not freeing
+ // it and letting the receiver task delete it for us instead.
+ if (chan->buffer.is_empty() == false) {
+ return;
+ }
+ chan->disassociate();
+ }
delete chan;
}
@@ -133,24 +172,32 @@ extern "C" CDECL void upcall_yield(rust_task *task) {
task->yield(1);
}
+extern "C" CDECL void upcall_sleep(rust_task *task, size_t time_in_us) {
+ LOG_UPCALL_ENTRY(task);
+ task->log(rust_log::UPCALL | rust_log::TASK, "elapsed %d",
+ task->yield_timer.get_elapsed_time());
+ task->log(rust_log::UPCALL | rust_log::TASK, "sleep %d us", time_in_us);
+ task->yield(2, time_in_us);
+}
+
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());
- task->block(target_task);
+ task->block(target_task, "joining remote task");
task->yield(2);
} else {
// If the other task is already dying, we don't have to wait for it.
if (target_task->dead() == false) {
target_task->tasks_waiting_to_join.push(task);
- task->block(target_task);
+ task->block(target_task, "joining local task");
task->yield(2);
}
}
@@ -168,8 +215,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 +228,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
@@ -201,7 +238,7 @@ upcall_recv(rust_task *task, uintptr_t *dptr, rust_port *port) {
task->log(rust_log::COMM, "<=== waiting for rendezvous data ===");
task->rendezvous_ptr = dptr;
- task->block(port);
+ task->block(port, "waiting for rendezvous data");
task->yield(3);
}
@@ -219,11 +256,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 +282,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 +538,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 +556,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/lock_free_queue.cpp b/src/rt/sync/lock_free_queue.cpp
index 69241ece..3f859862 100644
--- a/src/rt/sync/lock_free_queue.cpp
+++ b/src/rt/sync/lock_free_queue.cpp
@@ -18,6 +18,7 @@ lock_free_queue::lock_free_queue() : _tail(this) {
void
lock_free_queue::enqueue(lock_free_queue_node *item) {
+ lock.lock();
item->next = (lock_free_queue_node *) NULL;
lock_free_queue_node *last = _tail;
_tail = item;
@@ -25,10 +26,12 @@ lock_free_queue::enqueue(lock_free_queue_node *item) {
last = last->next;
}
last->next = item;
+ lock.unlock();
}
lock_free_queue_node *
lock_free_queue::dequeue() {
+ lock.lock();
lock_free_queue_node *item = next;
if (item && !(next = item->next)) {
_tail = (lock_free_queue_node *) this;
@@ -41,6 +44,7 @@ lock_free_queue::dequeue() {
} while ((lost = help) != (lock_free_queue_node *) NULL);
}
}
+ lock.unlock();
return item;
}
diff --git a/src/rt/sync/lock_free_queue.h b/src/rt/sync/lock_free_queue.h
index 1f09ec52..c1a309b8 100644
--- a/src/rt/sync/lock_free_queue.h
+++ b/src/rt/sync/lock_free_queue.h
@@ -1,6 +1,8 @@
#ifndef LOCK_FREE_QUEUE_H
#define LOCK_FREE_QUEUE_H
+#include "spin_lock.h"
+
class lock_free_queue_node {
public:
lock_free_queue_node *next;
@@ -8,6 +10,7 @@ public:
};
class lock_free_queue : lock_free_queue_node {
+ spin_lock lock;
lock_free_queue_node *_tail;
public:
lock_free_queue();
diff --git a/src/rt/sync/sync.cpp b/src/rt/sync/sync.cpp
new file mode 100644
index 00000000..09a6f291
--- /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__
+ Sleep(1);
+#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/sync/timer.cpp b/src/rt/sync/timer.cpp
new file mode 100644
index 00000000..0487b397
--- /dev/null
+++ b/src/rt/sync/timer.cpp
@@ -0,0 +1,61 @@
+#include "../globals.h"
+#include "timer.h"
+
+#if defined(__APPLE__)
+#include <mach/mach_time.h>
+#endif
+
+timer::timer() {
+#if __WIN32__
+ uint64_t ticks_per_second;
+ QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second);
+ _ticks_per_us = ticks_per_second / 1000000;
+#endif
+ reset(0);
+}
+
+void
+timer::reset(uint64_t timeout) {
+ _start = get_time();
+ _timeout = timeout;
+}
+
+uint64_t
+timer::get_elapsed_time() {
+ return get_time() - _start;
+}
+
+int64_t
+timer::get_timeout() {
+ return _timeout - get_elapsed_time();
+}
+
+bool
+timer::has_timed_out() {
+ return get_timeout() <= 0;
+}
+
+uint64_t
+timer::get_time() {
+#ifdef __APPLE__
+ uint64_t time = mach_absolute_time();
+ mach_timebase_info_data_t info = {0, 0};
+ if (info.denom == 0) {
+ mach_timebase_info(&info);
+ }
+ uint64_t time_nano = time * (info.numer / info.denom);
+ return time_nano / 1000;
+#elif __WIN32__
+ uint64_t ticks;
+ QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+ return ticks / _ticks_per_us;
+#else
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (ts.tv_sec * 1000000000LL + ts.tv_nsec) / 1000;
+#endif
+}
+
+timer::~timer() {
+ // Nop.
+}
diff --git a/src/rt/sync/timer.h b/src/rt/sync/timer.h
new file mode 100644
index 00000000..509fd22c
--- /dev/null
+++ b/src/rt/sync/timer.h
@@ -0,0 +1,25 @@
+/*
+ * Utility class to measure time in a platform independent way.
+ */
+
+#ifndef TIMER_H
+#define TIMER_H
+
+class timer {
+private:
+ uint64_t _start;
+ uint64_t _timeout;
+ uint64_t get_time();
+#if __WIN32__
+ uint64_t _ticks_per_us;
+#endif
+public:
+ timer();
+ void reset(uint64_t timeout);
+ uint64_t get_elapsed_time();
+ int64_t get_timeout();
+ bool has_timed_out();
+ virtual ~timer();
+};
+
+#endif /* TIMER_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 100755
index 00000000..47a46ce9
--- /dev/null
+++ b/src/run.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+
+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("-l", dest="log", default="",
+ help="rust log")
+parser.add_option("-v", action="store_true", dest="valgrind", default=False,
+ help="runs under valgrind")
+parser.add_option("-t", action="store_true", dest="terminate", default=False,
+ help="terminate on first failure")
+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.log != ""):
+ os.putenv("RUST_LOG", options.log);
+
+if (options.quiet):
+ os.putenv("RUST_LOG", "none");
+
+# Rut
+totalPassed = 0;
+repetitions = 1;
+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));
+ command = rustProgram.replace(".rs", ".x86");
+ if (options.valgrind):
+ command = "valgrind --leak-check=full " + \
+ "--quiet --vex-iropt-level=0 " + \
+ "--suppressions=etc/x86.supp " + \
+ command;
+ print "Running Command: " + command;
+ result = os.system(command);
+ exitStatus = result >> 8;
+ signalNumber = result & 0xF;
+ if (result == 0):
+ passed += 1;
+ elif (options.terminate):
+ sys.exit(1);
+ print "Result for: " + rustProgram + " " + str(passed) + \
+ " of " + str(repetitions) + " passed.";
+ totalPassed += passed;
+print "Total: " + str(totalPassed) + " of " + \
+ str(len(tests) * repetitions) + " passed."
diff --git a/src/test/run-pass/acyclic-unwind.rs b/src/test/run-pass/acyclic-unwind.rs
index c9ed2ae3..38de9082 100644
--- a/src/test/run-pass/acyclic-unwind.rs
+++ b/src/test/run-pass/acyclic-unwind.rs
@@ -13,6 +13,11 @@ io fn f(chan[int] c)
while (true) {
// spin waiting for the parent to kill us.
log "child waiting to die...";
+
+ // while waiting to die, the messages we are
+ // sending to the channel are never received
+ // by the parent, therefore this test cases drops
+ // messages on the floor
c <| 1;
}
}
diff --git a/src/test/run-pass/append-units.rs b/src/test/run-pass/append-units.rs
new file mode 100644
index 00000000..05b3478b
--- /dev/null
+++ b/src/test/run-pass/append-units.rs
@@ -0,0 +1,15 @@
+fn main() {
+ auto v = vec(1,2,3);
+ v += 4;
+ v += 5;
+ check (v.(3) == 4);
+ check (v.(4) == 5);
+
+ auto s = "hello";
+ log s;
+ s += 'z' as u8;
+ s += 'y' as u8;
+ log s;
+ check (s.(5) == 'z' as u8);
+ check (s.(6) == 'y' as u8);
+}
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/arithmetic-interference.rs b/src/test/run-pass/arithmetic-interference.rs
deleted file mode 100644
index 588148bb..00000000
--- a/src/test/run-pass/arithmetic-interference.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Testcase for issue #131.
-
-fn main() -> () {
- let int a = 10;
- log a;
- check (a * (a - 1) == 90);
-}
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/lib-deque.rs b/src/test/run-pass/lib-deque.rs
index c7516e3d..ecd8bc44 100644
--- a/src/test/run-pass/lib-deque.rs
+++ b/src/test/run-pass/lib-deque.rs
@@ -35,8 +35,25 @@ fn test_simple() {
log i;
check (i == 17);
- /* FIXME (issue #138): Test d.get() once it no longer causes
- * segfault. */
+ check (d.size() == 0u);
+ d.add_back(3);
+ check (d.size() == 1u);
+ d.add_front(2);
+ check (d.size() == 2u);
+ d.add_back(4);
+ check (d.size() == 3u);
+ d.add_front(1);
+ check (d.size() == 4u);
+
+ log d.get(0);
+ log d.get(1);
+ log d.get(2);
+ log d.get(3);
+
+ check (d.get(0) == 1);
+ check (d.get(1) == 2);
+ check (d.get(2) == 3);
+ check (d.get(3) == 4);
}
fn test_boxes(@int a, @int b, @int c, @int d) {
@@ -57,13 +74,25 @@ fn test_boxes(@int a, @int b, @int c, @int d) {
check (deq.pop_back() == c);
check (deq.pop_back() == a);
- /* FIXME (issue #138): Test d.get() once it no longer causes
- * segfault. */
+ check (deq.size() == 0u);
+ deq.add_back(c);
+ check (deq.size() == 1u);
+ deq.add_front(b);
+ check (deq.size() == 2u);
+ deq.add_back(d);
+ check (deq.size() == 3u);
+ deq.add_front(a);
+ check (deq.size() == 4u);
+
+ check (deq.get(0) == a);
+ check (deq.get(1) == b);
+ check (deq.get(2) == c);
+ check (deq.get(3) == d);
}
-type eqfn[T] = fn(&T a, &T b) -> bool;
+type eqfn[T] = fn(T a, T b) -> bool;
-fn test_parameterized[T](eqfn[T] e, &T a, &T b, &T c, &T d) {
+fn test_parameterized[T](eqfn[T] e, T a, T b, T c, T d) {
let deque.t[T] deq = deque.create[T]();
check (deq.size() == 0u);
deq.add_front(a);
@@ -81,8 +110,20 @@ fn test_parameterized[T](eqfn[T] e, &T a, &T b, &T c, &T d) {
check (e(deq.pop_back(), c));
check (e(deq.pop_back(), a));
- /* FIXME (issue #138): Test d.get() once it no longer causes
- * segfault. */
+ check (deq.size() == 0u);
+ deq.add_back(c);
+ check (deq.size() == 1u);
+ deq.add_front(b);
+ check (deq.size() == 2u);
+ deq.add_back(d);
+ check (deq.size() == 3u);
+ deq.add_front(a);
+ check (deq.size() == 4u);
+
+ check (e(deq.get(0), a));
+ check (e(deq.get(1), b));
+ check (e(deq.get(2), c));
+ check (e(deq.get(3), d));
}
type taggy = tag(one(int), two(int, int), three(int, int, int));
@@ -94,15 +135,15 @@ type taggypar[T] = tag(onepar(int),
type reccy = rec(int x, int y, taggy t);
fn main() {
- fn inteq(&int a, &int b) -> bool {
+ fn inteq(int a, int b) -> bool {
ret a == b;
}
- fn intboxeq(&@int a, &@int b) -> bool {
+ fn intboxeq(@int a, @int b) -> bool {
ret a == b;
}
- fn taggyeq(&taggy a, &taggy b) -> bool {
+ fn taggyeq(taggy a, taggy b) -> bool {
alt (a) {
case (one(a1)) {
alt (b) {
@@ -125,7 +166,7 @@ fn main() {
}
}
- fn taggypareq[T](&taggypar[T] a, &taggypar[T] b) -> bool {
+ fn taggypareq[T](taggypar[T] a, taggypar[T] b) -> bool {
alt (a) {
case (onepar[T](a1)) {
alt (b) {
@@ -150,65 +191,68 @@ fn main() {
}
}
- fn reccyeq(&reccy a, &reccy b) -> bool {
+ fn reccyeq(reccy a, reccy b) -> bool {
ret (a.x == b.x && a.y == b.y && taggyeq(a.t, b.t));
}
- log "test simple";
+ log "*** starting";
+
+ log "*** test simple";
test_simple();
+ log "*** end test simple";
/*
* FIXME: Causes "Invalid read of size 4" under valgrind.
- log "test boxes";
+ log "*** test boxes";
test_boxes(@5, @72, @64, @175);
+ log "*** end test boxes";
*/
log "test parameterized: int";
- let eqfn[int] eq1 = bind inteq(_, _);
+ let eqfn[int] eq1 = inteq;
test_parameterized[int](eq1, 5, 72, 64, 175);
/*
* FIXME: Appears to segfault after an upcall_grow_task
- log "test parameterized: @int";
- let eqfn[@int] eq2 = bind intboxeq(_, _);
+ log "*** test parameterized: @int";
+ let eqfn[@int] eq2 = intboxeq;
test_parameterized[@int](eq2, @5, @72, @64, @175);
+ log "*** end test parameterized @int";
- */
+ */
log "test parameterized: taggy";
- let eqfn[taggy] eq3 = bind taggyeq(_, _);
+ let eqfn[taggy] eq3 = taggyeq;
test_parameterized[taggy](eq3,
one(1), two(1, 2), three(1, 2, 3), two(17, 42));
/*
- * FIXME: Segfault.
+ * FIXME: Segfault. Also appears to be caused only after upcall_grow_task
- log "test parameterized: taggypar[int]";
- let eqfn[taggypar[int]] eq4 = bind taggypareq[int](_, _);
+ log "*** test parameterized: taggypar[int]";
+ let eqfn[taggypar[int]] eq4 = taggypareq[int];
test_parameterized[taggypar[int]](eq4,
onepar[int](1),
twopar[int](1, 2),
threepar[int](1, 2, 3),
twopar[int](17, 42));
+ log "*** end test parameterized: taggypar[int]";
*/
- /*
- * FIXME: Segfault.
-
- log "test parameterized: reccy";
+ log "*** test parameterized: reccy";
let reccy reccy1 = rec(x=1, y=2, t=one(1));
let reccy reccy2 = rec(x=345, y=2, t=two(1, 2));
let reccy reccy3 = rec(x=1, y=777, t=three(1, 2, 3));
let reccy reccy4 = rec(x=19, y=252, t=two(17, 42));
- let eqfn[reccy] eq5 = bind reccyeq(_, _);
+ let eqfn[reccy] eq5 = reccyeq;
test_parameterized[reccy](eq5,
reccy1, reccy2, reccy3, reccy4);
+ log "*** end test parameterized: reccy";
- */
- log "done";
+ log "*** done";
}
diff --git a/src/test/run-pass/lib-io.rs b/src/test/run-pass/lib-io.rs
new file mode 100644
index 00000000..66394435
--- /dev/null
+++ b/src/test/run-pass/lib-io.rs
@@ -0,0 +1,26 @@
+// -*- rust -*-
+
+use std;
+import std._io;
+import std._str;
+
+fn test_simple(str tmpfilebase) {
+ let str tmpfile = tmpfilebase + ".tmp";
+ log tmpfile;
+ let str frood = "A hoopy frood who really knows where his towel is.";
+ log frood;
+
+ {
+ let _io.buf_writer out = _io.new_buf_writer(tmpfile, vec(_io.create()));
+ out.write(_str.bytes(frood));
+ }
+
+ let _io.buf_reader inp = _io.new_buf_reader(tmpfile);
+ let str frood2 = _str.from_bytes(inp.read());
+ log frood2;
+ check (_str.eq(frood, frood2));
+}
+
+fn main(vec[str] argv) {
+ test_simple(argv.(0));
+}
diff --git a/src/test/run-pass/lib-vec-str-conversions.rs b/src/test/run-pass/lib-vec-str-conversions.rs
new file mode 100644
index 00000000..1d6b61a1
--- /dev/null
+++ b/src/test/run-pass/lib-vec-str-conversions.rs
@@ -0,0 +1,41 @@
+// -*- rust -*-
+
+use std;
+import std._str;
+import std._vec;
+
+fn test_simple() {
+ let str s1 = "All mimsy were the borogoves";
+
+ /*
+ * FIXME from_bytes(vec[u8] v) has constraint is_utf(v), which is
+ * unimplemented and thereby just fails. This doesn't stop us from
+ * using from_bytes for now since the constraint system isn't fully
+ * working, but we should implement is_utf8 before that happens.
+ */
+
+ let vec[u8] v = _str.bytes(s1);
+ let str s2 = _str.from_bytes(v);
+
+ let uint i = 0u;
+ let uint n1 = _str.byte_len(s1);
+ let uint n2 = _vec.len[u8](v);
+
+ check (n1 == n2);
+
+ while (i < n1) {
+ let u8 a = s1.(i);
+ let u8 b = s2.(i);
+ log a;
+ log b;
+ check (a == b);
+ i += 1u;
+ }
+
+ log "refcnt is";
+ log _str.refcount(s1);
+}
+
+fn main() {
+ test_simple();
+}
diff --git a/src/test/run-pass/size-and-align.rs b/src/test/run-pass/size-and-align.rs
new file mode 100644
index 00000000..4da22558
--- /dev/null
+++ b/src/test/run-pass/size-and-align.rs
@@ -0,0 +1,15 @@
+// -*- rust -*-
+
+type clam[T] = tag(a(T, int), b());
+
+fn uhoh[T](vec[clam[T]] v) {
+ alt (v.(1)) {
+ case (a[T](t, u)) { log "incorrect"; log u; fail; }
+ case (b[T]()) { log "correct"; }
+ }
+}
+
+fn main() {
+ let vec[clam[int]] v = vec(b[int](), b[int](), a[int](42, 17));
+ uhoh[int](v);
+}
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-10.rs b/src/test/run-pass/task-comm-10.rs
new file mode 100644
index 00000000..4cdcf18b
--- /dev/null
+++ b/src/test/run-pass/task-comm-10.rs
@@ -0,0 +1,15 @@
+io fn start(chan[chan[str]] c) {
+ let port[str] p = port();
+ c <| chan(p);
+ auto a <- p;
+ // auto b <- p; // Never read the second string.
+}
+
+io fn main() {
+ let port[chan[str]] p = port();
+ auto child = spawn "start" start(chan(p));
+ auto c <- p;
+ c <| "A";
+ c <| "B";
+ yield;
+} \ No newline at end of file
diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs
new file mode 100644
index 00000000..519eb699
--- /dev/null
+++ b/src/test/run-pass/task-comm-11.rs
@@ -0,0 +1,10 @@
+io fn start(chan[chan[str]] c) {
+ let port[str] p = port();
+ c <| chan(p);
+}
+
+io fn main() {
+ let port[chan[str]] p = port();
+ auto child = spawn "child" start(chan(p));
+ auto c <- p;
+} \ No newline at end of file
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;
diff --git a/src/test/run-pass/task-lib.rs b/src/test/run-pass/task-lib.rs
new file mode 100644
index 00000000..18499f4e
--- /dev/null
+++ b/src/test/run-pass/task-lib.rs
@@ -0,0 +1,6 @@
+use std;
+import std._task;
+
+fn main() {
+ _task.sleep(1000000u);
+} \ No newline at end of file
diff --git a/src/test/run-pass/task-life-0.rs b/src/test/run-pass/task-life-0.rs
new file mode 100644
index 00000000..f15792fb
--- /dev/null
+++ b/src/test/run-pass/task-life-0.rs
@@ -0,0 +1,7 @@
+fn main() -> () {
+ spawn child("Hello");
+}
+
+fn child(str s) {
+
+} \ No newline at end of file
diff --git a/src/test/run-pass/while-flow-graph.rs b/src/test/run-pass/while-flow-graph.rs
new file mode 100644
index 00000000..49e7810a
--- /dev/null
+++ b/src/test/run-pass/while-flow-graph.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let int x = 10;
+ while (x == 10 && x == 11) { auto y = 0xf00; }
+} \ No newline at end of file