summaryrefslogtreecommitdiff
path: root/byterun
diff options
context:
space:
mode:
Diffstat (limited to 'byterun')
-rw-r--r--byterun/.depend121
-rw-r--r--byterun/Makefile84
-rw-r--r--byterun/alloc.c131
-rw-r--r--byterun/alloc.h19
-rw-r--r--byterun/array.c45
-rw-r--r--byterun/compare.c110
-rw-r--r--byterun/config.h121
-rw-r--r--byterun/crc.c91
-rw-r--r--byterun/exec.h27
-rw-r--r--byterun/extern.c245
-rw-r--r--byterun/fail.c108
-rw-r--r--byterun/fail.h36
-rw-r--r--byterun/fix_code.c66
-rw-r--r--byterun/fix_code.h15
-rw-r--r--byterun/floats.c226
-rw-r--r--byterun/freelist.c234
-rw-r--r--byterun/freelist.h16
-rw-r--r--byterun/gc.h42
-rw-r--r--byterun/gc_ctrl.c212
-rw-r--r--byterun/gc_ctrl.h17
-rw-r--r--byterun/hash.c103
-rw-r--r--byterun/instrtrace.c52
-rw-r--r--byterun/instrtrace.h16
-rw-r--r--byterun/instruct.h33
-rw-r--r--byterun/intern.c230
-rw-r--r--byterun/interp.c865
-rw-r--r--byterun/interp.h14
-rw-r--r--byterun/intext.h54
-rw-r--r--byterun/ints.c81
-rw-r--r--byterun/io.c393
-rw-r--r--byterun/io.h52
-rw-r--r--byterun/main.c229
-rw-r--r--byterun/major_gc.c305
-rw-r--r--byterun/major_gc.h42
-rw-r--r--byterun/memory.c205
-rw-r--r--byterun/memory.h88
-rw-r--r--byterun/meta.c93
-rw-r--r--byterun/minor_gc.c156
-rw-r--r--byterun/minor_gc.h19
-rw-r--r--byterun/misc.c166
-rw-r--r--byterun/misc.h90
-rw-r--r--byterun/mlvalues.h213
-rw-r--r--byterun/oldlexing.c36
-rw-r--r--byterun/parsing.c205
-rw-r--r--byterun/prims.h11
-rw-r--r--byterun/reverse.h54
-rw-r--r--byterun/roots.c49
-rw-r--r--byterun/roots.h9
-rw-r--r--byterun/signals.c158
-rw-r--r--byterun/signals.h13
-rw-r--r--byterun/stacks.c60
-rw-r--r--byterun/stacks.h26
-rw-r--r--byterun/str.c81
-rw-r--r--byterun/str.h11
-rw-r--r--byterun/sys.c186
-rw-r--r--byterun/sys.h10
-rw-r--r--byterun/terminfo.c126
57 files changed, 6500 insertions, 0 deletions
diff --git a/byterun/.depend b/byterun/.depend
new file mode 100644
index 0000000000..d43a9d1d88
--- /dev/null
+++ b/byterun/.depend
@@ -0,0 +1,121 @@
+alloc.o : alloc.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ major_gc.h freelist.h memory.h gc.h minor_gc.h stacks.h
+array.o : array.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+compare.o : compare.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ memory.h gc.h major_gc.h freelist.h minor_gc.h str.h
+crc.o : crc.c io.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h
+extern.o : extern.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h intext.h io.h memory.h major_gc.h freelist.h minor_gc.h reverse.h str.h
+fail.o : fail.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h gc.h memory.h major_gc.h freelist.h minor_gc.h signals.h stacks.h
+fix_code.o : fix_code.c config.h ../config/m.h ../config/s.h fix_code.h misc.h \
+ mlvalues.h instruct.h reverse.h
+floats.o : floats.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h stacks.h
+freelist.o : freelist.c config.h ../config/m.h ../config/s.h freelist.h misc.h \
+ mlvalues.h gc.h gc_ctrl.h major_gc.h
+gc_ctrl.o : gc_ctrl.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h gc_ctrl.h major_gc.h freelist.h minor_gc.h
+hash.o : hash.c mlvalues.h config.h ../config/m.h ../config/s.h misc.h memory.h \
+ gc.h major_gc.h freelist.h minor_gc.h str.h
+instrtrace.o : instrtrace.c
+intern.o : intern.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h intext.h io.h memory.h major_gc.h freelist.h minor_gc.h reverse.h
+interp.o : interp.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h fix_code.h instruct.h interp.h memory.h gc.h major_gc.h freelist.h minor_gc.h \
+ prims.h signals.h stacks.h str.h instrtrace.h jumptbl.h
+ints.o : ints.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+io.o : io.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h fail.h \
+ io.h memory.h gc.h major_gc.h freelist.h minor_gc.h signals.h sys.h
+lexing.o : lexing.c interp.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h str.h
+main.o : main.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ exec.h fail.h gc_ctrl.h interp.h intext.h io.h stacks.h memory.h gc.h major_gc.h \
+ freelist.h minor_gc.h sys.h
+major_gc.o : major_gc.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ freelist.h gc.h gc_ctrl.h major_gc.h roots.h
+memory.o : memory.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ freelist.h gc.h gc_ctrl.h major_gc.h memory.h minor_gc.h
+meta.o : meta.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ interp.h major_gc.h freelist.h memory.h gc.h minor_gc.h prims.h
+minor_gc.o : minor_gc.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ gc.h gc_ctrl.h major_gc.h freelist.h memory.h minor_gc.h roots.h
+misc.o : misc.c config.h ../config/m.h ../config/s.h misc.h
+parsing.o : parsing.c config.h ../config/m.h ../config/s.h mlvalues.h misc.h \
+ memory.h gc.h major_gc.h freelist.h minor_gc.h alloc.h
+prims.o : prims.c mlvalues.h config.h ../config/m.h ../config/s.h misc.h prims.h
+roots.o : roots.c memory.h config.h ../config/m.h ../config/s.h gc.h mlvalues.h \
+ misc.h major_gc.h freelist.h minor_gc.h roots.h stacks.h
+signals.o : signals.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h interp.h memory.h gc.h major_gc.h freelist.h minor_gc.h roots.h signals.h
+stacks.o : stacks.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+str.o : str.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h
+sys.o : sys.c config.h ../config/m.h ../config/s.h alloc.h misc.h mlvalues.h \
+ fail.h instruct.h signals.h stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+terminfo.o : terminfo.c config.h ../config/m.h ../config/s.h alloc.h misc.h \
+ mlvalues.h fail.h io.h
+alloc.d.o : alloc.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ major_gc.h freelist.h memory.h gc.h minor_gc.h stacks.h
+array.d.o : array.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+compare.d.o : compare.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ memory.h gc.h major_gc.h freelist.h minor_gc.h str.h
+crc.d.o : crc.c io.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h
+extern.d.o : extern.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h intext.h io.h memory.h major_gc.h freelist.h minor_gc.h reverse.h str.h
+fail.d.o : fail.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h gc.h memory.h major_gc.h freelist.h minor_gc.h signals.h stacks.h
+fix_code.d.o : fix_code.c config.h ../config/m.h ../config/s.h fix_code.h misc.h \
+ mlvalues.h instruct.h reverse.h
+floats.d.o : floats.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h stacks.h
+freelist.d.o : freelist.c config.h ../config/m.h ../config/s.h freelist.h misc.h \
+ mlvalues.h gc.h gc_ctrl.h major_gc.h
+gc_ctrl.d.o : gc_ctrl.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h gc_ctrl.h major_gc.h freelist.h minor_gc.h
+hash.d.o : hash.c mlvalues.h config.h ../config/m.h ../config/s.h misc.h memory.h \
+ gc.h major_gc.h freelist.h minor_gc.h str.h
+instrtrace.d.o : instrtrace.c instruct.h misc.h config.h ../config/m.h ../config/s.h \
+ mlvalues.h opnames.h
+intern.d.o : intern.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ gc.h intext.h io.h memory.h major_gc.h freelist.h minor_gc.h reverse.h
+interp.d.o : interp.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h fix_code.h instruct.h interp.h memory.h gc.h major_gc.h freelist.h minor_gc.h \
+ prims.h signals.h stacks.h str.h instrtrace.h
+ints.d.o : ints.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+io.d.o : io.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h fail.h \
+ io.h memory.h gc.h major_gc.h freelist.h minor_gc.h signals.h sys.h
+lexing.d.o : lexing.c interp.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h str.h
+main.d.o : main.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ exec.h fail.h gc_ctrl.h interp.h intext.h io.h stacks.h memory.h gc.h major_gc.h \
+ freelist.h minor_gc.h sys.h
+major_gc.d.o : major_gc.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ freelist.h gc.h gc_ctrl.h major_gc.h roots.h
+memory.d.o : memory.c fail.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ freelist.h gc.h gc_ctrl.h major_gc.h memory.h minor_gc.h
+meta.d.o : meta.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ interp.h major_gc.h freelist.h memory.h gc.h minor_gc.h prims.h
+minor_gc.d.o : minor_gc.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ gc.h gc_ctrl.h major_gc.h freelist.h memory.h minor_gc.h roots.h
+misc.d.o : misc.c config.h ../config/m.h ../config/s.h misc.h
+parsing.d.o : parsing.c config.h ../config/m.h ../config/s.h mlvalues.h misc.h \
+ memory.h gc.h major_gc.h freelist.h minor_gc.h alloc.h
+prims.d.o : prims.c mlvalues.h config.h ../config/m.h ../config/s.h misc.h prims.h
+roots.d.o : roots.c memory.h config.h ../config/m.h ../config/s.h gc.h mlvalues.h \
+ misc.h major_gc.h freelist.h minor_gc.h roots.h stacks.h
+signals.d.o : signals.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h interp.h memory.h gc.h major_gc.h freelist.h minor_gc.h roots.h signals.h
+stacks.d.o : stacks.c config.h ../config/m.h ../config/s.h fail.h misc.h mlvalues.h \
+ stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+str.d.o : str.c alloc.h misc.h config.h ../config/m.h ../config/s.h mlvalues.h \
+ fail.h
+sys.d.o : sys.c config.h ../config/m.h ../config/s.h alloc.h misc.h mlvalues.h \
+ fail.h instruct.h signals.h stacks.h memory.h gc.h major_gc.h freelist.h minor_gc.h
+terminfo.d.o : terminfo.c config.h ../config/m.h ../config/s.h alloc.h misc.h \
+ mlvalues.h fail.h io.h
diff --git a/byterun/Makefile b/byterun/Makefile
new file mode 100644
index 0000000000..2ac4f0ef3a
--- /dev/null
+++ b/byterun/Makefile
@@ -0,0 +1,84 @@
+include ../config/Makefile.h
+include ../Makefile.config
+
+CFLAGS=-O $(CCCOMPOPTS)
+DFLAGS=-g -DDEBUG $(CCCOMPOPTS)
+
+OBJS=interp.o misc.o stacks.o fix_code.o main.o fail.o signals.o \
+ freelist.o major_gc.o minor_gc.o memory.o alloc.o roots.o \
+ compare.o ints.o floats.o str.o array.o io.o extern.o intern.o \
+ hash.o sys.o meta.o parsing.o lexing.o gc_ctrl.o terminfo.o crc.o
+
+DOBJS=$(OBJS:.o=.d.o) instrtrace.d.o
+
+PRIMS=array.c compare.c crc.c extern.c floats.c gc_ctrl.c hash.c \
+ intern.c interp.c ints.c io.c lexing.c meta.c parsing.c \
+ signals.c str.c sys.c terminfo.c
+
+all: camlrun camlrund libcaml.a
+
+camlrun: $(OBJS) prims.o
+ $(CC) $(CCCOMPOPTS) $(CCLINKOPTS) $(LOWADDRESSES) -o camlrun prims.o $(OBJS) $(CCLIBS)
+
+camlrund: $(DOBJS) prims.o
+ $(CC) -g $(CCCOMPOPTS) $(CCLINKOPTS) $(LOWADDRESSES) -o camlrund prims.o $(DOBJS) $(CCLIBS)
+
+libcaml.a: $(OBJS)
+ rm -f libcaml.a
+ ar rc libcaml.a $(OBJS)
+ $(RANLIB) libcaml.a
+
+install:
+ cp camlrun $(BINDIR)/cslrun
+ cp libcaml.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcaml.a
+ test -d $(LIBDIR)/caml || mkdir $(LIBDIR)/caml
+ cp mlvalues.h alloc.h misc.h $(LIBDIR)/caml
+ sed -e '/#include ".*\/m.h/r ../config/m.h' \
+ -e '/#include ".*\/s.h/r ../config/s.h' \
+ -e '/#include "/d' config.h > $(LIBDIR)/caml/config.h
+ sed -e '/#include ".*gc\.h"/d' \
+ -e '/#define Alloc_small/,/^}/d' \
+ -e '/Modify/,/^}/d' memory.h > $(LIBDIR)/caml/memory.h
+
+clean:
+ rm -f camlrun camlrund *.o *.a
+ rm -f primitives prims.c opnames.h jumptbl.h
+
+primitives : $(PRIMS)
+ sed -n -e '/\/\* ML \*\//s/.* \([a-z0-9_]*\)(.*/\1/p' \
+ $(PRIMS) > primitives
+
+prims.c : primitives
+ (echo '#include "mlvalues.h"'; \
+ echo '#include "prims.h"'; \
+ sed -e 's/.*/extern value &();/' primitives; \
+ echo 'c_primitive cprim[] = {'; \
+ sed -e 's/.*/ &,/' primitives; \
+ echo ' 0 };'; \
+ echo 'char * names_of_cprim[] = {'; \
+ sed -e 's/.*/ "&",/' primitives; \
+ echo ' 0 };') > prims.c
+
+opnames.h : instruct.h
+ sed -e '/\/\*/d' \
+ -e 's/enum /char * names_of_/' \
+ -e 's/{$$/[] = {/' \
+ -e 's/\([A-Z][A-Z_0-9]*\)/"\1"/g' instruct.h > opnames.h
+
+# jumptbl.h is required only if you have GCC 2.0 or later
+jumptbl.h : instruct.h
+ sed -n -e '/^ /s/ \([A-Z]\)/ \&\&lbl_\1/gp' \
+ -e '/^}/q' instruct.h > jumptbl.h
+
+.SUFFIXES: .d.o
+
+.c.d.o:
+ cd .debugobj; $(CC) -c $(DFLAGS) -I.. ../$<
+ mv .debugobj/$*.o $*.d.o
+
+depend : prims.c opnames.h jumptbl.h
+ gcc -MM $(CFLAGS) *.c > .depend
+ gcc -MM $(DFLAGS) *.c | sed -e 's/\.o/.d.o/' >> .depend
+
+include .depend
diff --git a/byterun/alloc.c b/byterun/alloc.c
new file mode 100644
index 0000000000..afe0892cee
--- /dev/null
+++ b/byterun/alloc.c
@@ -0,0 +1,131 @@
+/* 1. Allocation functions doing the same work as the macros in the
+ case where [Setup_for_gc] and [Restore_after_gc] are no-ops.
+ 2. Convenience functions related to allocation.
+*/
+
+#include <string.h>
+#include "alloc.h"
+#include "major_gc.h"
+#include "memory.h"
+#include "mlvalues.h"
+#include "stacks.h"
+
+#define Setup_for_gc
+#define Restore_after_gc
+
+value alloc (wosize, tag)
+ mlsize_t wosize;
+ tag_t tag;
+{
+ value result;
+
+ Assert (wosize > 0 && wosize <= Max_young_wosize);
+ Alloc_small (result, wosize, tag);
+ return result;
+}
+
+value alloc_tuple(n)
+ mlsize_t n;
+{
+ return alloc(n, 0);
+}
+
+value alloc_string (len)
+ mlsize_t len;
+{
+ value result;
+ mlsize_t offset_index;
+ mlsize_t wosize = (len + sizeof (value)) / sizeof (value);
+
+ if (wosize <= Max_young_wosize) {
+ Alloc_small (result, wosize, String_tag);
+ }else{
+ result = alloc_shr (wosize, String_tag);
+ }
+ Field (result, wosize - 1) = 0;
+ offset_index = Bsize_wsize (wosize) - 1;
+ Byte (result, offset_index) = offset_index - len;
+ return result;
+}
+
+value alloc_final (len, fun, mem, max)
+ mlsize_t len;
+ final_fun fun;
+ mlsize_t mem, max;
+{
+ value result = alloc_shr (len, Final_tag);
+
+ Field (result, 0) = (value) fun;
+ adjust_gc_speed (mem, max);
+ return result;
+}
+
+value copy_double(d)
+ double d;
+{
+ value res;
+
+ Alloc_small(res, Double_wosize, Double_tag);
+ Store_double_val(res, d);
+ return res;
+}
+
+value copy_string(s)
+ char * s;
+{
+ int len;
+ value res;
+
+ len = strlen(s);
+ res = alloc_string(len);
+ bcopy(s, String_val(res), len);
+ return res;
+}
+
+value alloc_array(funct, arr)
+ value (*funct) P((char *));
+ char ** arr;
+{
+ mlsize_t nbr, n;
+ value v;
+
+ nbr = 0;
+ while (arr[nbr] != 0) nbr++;
+ if (nbr == 0) {
+ v = Atom(0);
+ } else {
+ while (extern_sp - nbr <= stack_low)
+ realloc_stack();
+ for (n = 0; n < nbr; n++)
+ *--extern_sp = funct(arr[n]);
+ if (nbr < Max_young_wosize) {
+ v = alloc(nbr, 0);
+ n = nbr;
+ while (n-- > 0) Field (v, n) = *extern_sp++;
+ } else {
+ v = alloc_shr(nbr, 0);
+ n = nbr;
+ while (n-- > 0) initialize (&Field(v, n), *extern_sp++);
+ }
+ }
+ return v;
+}
+
+value copy_string_array(arr)
+ char ** arr;
+{
+ return alloc_array(copy_string, arr);
+}
+
+int convert_flag_list(list, flags)
+ value list;
+ int * flags;
+{
+ int res;
+ res = 0;
+ while (Tag_val(list) == 1) {
+ res |= flags[Tag_val(Field(list, 0))];
+ list = Field(list, 1);
+ }
+ return res;
+}
diff --git a/byterun/alloc.h b/byterun/alloc.h
new file mode 100644
index 0000000000..5b0a1029a0
--- /dev/null
+++ b/byterun/alloc.h
@@ -0,0 +1,19 @@
+#ifndef _alloc_
+#define _alloc_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+value alloc P((mlsize_t, tag_t));
+value alloc_tuple P((mlsize_t));
+value alloc_string P((mlsize_t));
+value alloc_final P((mlsize_t, final_fun, mlsize_t, mlsize_t));
+value copy_string P((char *));
+value copy_string_array P((char **));
+value copy_double P((double));
+value alloc_array P((value (*funct) P((char *)), char ** array));
+int convert_flag_list P((value, int *));
+
+
+#endif /* _alloc_ */
diff --git a/byterun/array.c b/byterun/array.c
new file mode 100644
index 0000000000..471bfa1541
--- /dev/null
+++ b/byterun/array.c
@@ -0,0 +1,45 @@
+/* Operations on arrays */
+
+#include "alloc.h"
+#include "fail.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+
+value make_vect(len, init) /* ML */
+ value len, init;
+{
+ value res;
+ mlsize_t size, i;
+ Push_roots(root, 1);
+
+ size = Long_val(len);
+ if (size > Max_wosize) {
+ Pop_roots();
+ invalid_argument("Array.new");
+ }
+ if (size == 0) {
+ res = Atom(0);
+ }
+ else if (size < Max_young_wosize) {
+ root[0] = init;
+ res = alloc(size, 0);
+ init = root[0];
+ for (i = 0; i < size; i++) Field(res, i) = init;
+ }
+ else if (Is_block(init) && Is_young(init)) {
+ root[0] = init;
+ minor_collection();
+ res = alloc_shr(size, 0);
+ init = root[0];
+ for (i = 0; i < size; i++) Field(res, i) = init;
+ }
+ else {
+ root[0] = init;
+ res = alloc_shr(size, 0);
+ init = root[0];
+ for (i = 0; i < size; i++) initialize(&Field(res, i), init);
+ }
+ Pop_roots();
+ return res;
+}
diff --git a/byterun/compare.c b/byterun/compare.c
new file mode 100644
index 0000000000..a42fe7664d
--- /dev/null
+++ b/byterun/compare.c
@@ -0,0 +1,110 @@
+#include "fail.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "str.h"
+
+/* Structural comparison on trees.
+ May loop on cyclic structures. */
+
+static long compare_val(v1, v2)
+ value v1,v2;
+{
+ tag_t t1, t2;
+
+ tailcall:
+ if (v1 == v2) return 0;
+ if (Is_long(v1) || Is_long(v2)) return Long_val(v1) - Long_val(v2);
+ /* If one of the objects is outside the heap (but is not an atom),
+ use address comparison. */
+ if ((!Is_atom(v1) && !Is_young(v1) && !Is_in_heap(v1)) ||
+ (!Is_atom(v2) && !Is_young(v2) && !Is_in_heap(v2)))
+ return v1 - v2;
+ t1 = Tag_val(v1);
+ t2 = Tag_val(v2);
+ if (t1 != t2) return (long)t1 - (long)t2;
+ switch(t1) {
+ case String_tag: {
+ mlsize_t len1, len2, len;
+ unsigned char * p1, * p2;
+ len1 = string_length(v1);
+ len2 = string_length(v2);
+ for (len = (len1 <= len2 ? len1 : len2),
+ p1 = (unsigned char *) String_val(v1),
+ p2 = (unsigned char *) String_val(v2);
+ len > 0;
+ len--, p1++, p2++)
+ if (*p1 != *p2) return (long)*p1 - (long)*p2;
+ return len1 - len2;
+ }
+ case Double_tag: {
+ double d1 = Double_val(v1);
+ double d2 = Double_val(v2);
+ if (d1 == d2) return 0; else if (d1 < d2) return -1; else return 1;
+ }
+ case Abstract_tag:
+ case Final_tag:
+ invalid_argument("equal: abstract value");
+ case Closure_tag:
+ invalid_argument("equal: functional value");
+ default: {
+ mlsize_t sz1 = Wosize_val(v1);
+ mlsize_t sz2 = Wosize_val(v2);
+ value * p1, * p2;
+ long res;
+ if (sz1 != sz2) return sz1 - sz2;
+ for(p1 = Op_val(v1), p2 = Op_val(v2);
+ sz1 > 1;
+ sz1--, p1++, p2++) {
+ res = compare_val(*p1, *p2);
+ if (res != 0) return res;
+ }
+ v1 = *p1;
+ v2 = *p2;
+ goto tailcall;
+ }
+ }
+}
+
+value compare(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Val_long(compare_val(v1, v2));
+}
+
+value equal(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) == 0);
+}
+
+value notequal(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) != 0);
+}
+
+value lessthan(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) < 0);
+}
+
+value lessequal(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) <= 0);
+}
+
+value greaterthan(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) > 0);
+}
+
+value greaterequal(v1, v2) /* ML */
+ value v1, v2;
+{
+ return Atom(compare_val(v1, v2) >= 0);
+}
+
diff --git a/byterun/config.h b/byterun/config.h
new file mode 100644
index 0000000000..c3a8a78b91
--- /dev/null
+++ b/byterun/config.h
@@ -0,0 +1,121 @@
+#ifndef _config_
+#define _config_
+
+
+#include "../config/m.h"
+#include "../config/s.h"
+
+/* Library dependencies */
+
+#ifdef HAS_MEMMOVE
+#define bcopy(src,dst,len) memmove((dst), (src), (len))
+#else
+#ifdef HAS_BCOPY
+/* Nothing to do */
+#else
+#ifdef HAS_MEMCPY
+#define bcopy(src,dst,len) memcpy((dst), (src), (len))
+#else
+#define bcopy(src,dst,len) memmov((dst), (src), (len))
+#define USING_MEMMOV
+#endif
+#endif
+#endif
+
+#ifndef HAS__SETJMP
+#define _setjmp setjmp
+#define _longjmp longjmp
+#endif
+
+/* We use threaded code interpretation if the compiler provides labels
+ as first-class values (GCC 2.x). */
+
+#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(DEBUG)
+#define THREADED_CODE
+#endif
+
+/* Do not change this definition. */
+#define Page_size (1 << Page_log)
+
+/* Memory model parameters */
+
+#ifndef SMALL
+
+/* The size of a page for memory management (in bytes) is [1 << Page_log].
+ It must be a multiple of [sizeof (long)]. */
+#define Page_log 12 /* A page is 4 kilobytes. */
+
+/* Initial sizes of stack (bytes). */
+#define Stack_size 16384
+
+/* Minimum free size of stack (bytes); below that, it is reallocated. */
+#define Stack_threshold 1024
+
+/* Maximum sizes for the stack (bytes). */
+
+#ifdef MINIMIZE_MEMORY
+#define Max_stack_size 131072
+#else
+#define Max_stack_size 524288
+#endif
+
+/* Maximum size of a block allocated in the young generation (words). */
+/* Must be > 4 */
+#define Max_young_wosize 256
+
+
+/* Minimum size of the minor zone (words).
+ This must be at least [Max_young_wosize + 1]. */
+#define Minor_heap_min 4096
+
+/* Maximum size of the minor zone (words).
+ Must be greater than or equal to [Minor_heap_min].
+*/
+#define Minor_heap_max (1 << 28)
+
+/* Default size of the minor zone. (words) */
+#define Minor_heap_def 32768
+
+
+/* Minimum size increment when growing the heap (words).
+ Must be a multiple of [Page_size / sizeof (value)]. */
+#define Heap_chunk_min (2 * Page_size / sizeof (value))
+
+/* Maximum size of a contiguous piece of the heap (words).
+ Must be greater than or equal to [Heap_chunk_min].
+ Must be greater than or equal to [Bhsize_wosize (Max_wosize)]. */
+#define Heap_chunk_max (Bhsize_wosize (Max_wosize))
+
+/* Default size increment when growing the heap. (bytes)
+ Must be a multiple of [Page_size / sizeof (value)]. */
+#define Heap_chunk_def (62 * Page_size / sizeof (value))
+
+
+/* Default speed setting for the major GC. The heap will grow until
+ the dead objects and the free list represent this percentage of the
+ heap size. The rest of the heap is live objects. */
+#define Percent_free_def 30
+
+#else
+/* Scaled-down parameters for small memory */
+
+#define Page_log 10
+#define Arg_stack_size 16384
+#define Ret_stack_size 16384
+#define Arg_stack_threshold 1024
+#define Ret_stack_threshold 1024
+#define Max_arg_stack_size 524288
+#define Max_ret_stack_size 524288
+#define Max_young_wosize 256
+#define Minor_heap_min 1024
+#define Minor_heap_max (1 << 28)
+#define Minor_heap_def 16384
+#define Heap_chunk_min (2 * Page_size / sizeof (value))
+#define Heap_chunk_max (1 << 28)
+#define Heap_chunk_def (126 * Page_size / sizeof (value))
+#define Percent_free_def 20
+
+#endif
+
+
+#endif /* _config_ */
diff --git a/byterun/crc.c b/byterun/crc.c
new file mode 100644
index 0000000000..0e961b3493
--- /dev/null
+++ b/byterun/crc.c
@@ -0,0 +1,91 @@
+/* CRC computation */
+
+#include "io.h"
+#include "mlvalues.h"
+
+static uint32 crc32tab[] = { /* CRC polynomial 0xedb88320 */
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d };
+
+#define START 0xFFFFFFFF
+#define MASK_RESULT 0x7FFFFFFF
+
+/* This macro assumes that crc is an unsigned integer */
+#define ADDCRC(ch, crc) (crc32tab[((ch) ^ crc) & 0xff] ^ (crc >> 8))
+
+value crc_string(str, ofs, len) /* ML */
+ value str, ofs, len;
+{
+ unsigned char * p;
+ mlsize_t n;
+ uint32 crc;
+
+ for (crc = START, p = &Byte_u(str, Long_val(ofs)), n = Long_val(len);
+ n > 0;
+ n--, p++)
+ crc = ADDCRC(*p, crc);
+ return Val_int(crc & MASK_RESULT);
+}
+
+value crc_chan(chan, len) /* ML */
+ struct channel * chan;
+ value len;
+{
+ mlsize_t n;
+ uint32 crc;
+
+ for (crc = START, n = Long_val(len); n > 0; n--)
+ crc = ADDCRC(getch(chan), crc);
+ return Val_int(crc & MASK_RESULT);
+}
+
diff --git a/byterun/exec.h b/byterun/exec.h
new file mode 100644
index 0000000000..1590dc0a4a
--- /dev/null
+++ b/byterun/exec.h
@@ -0,0 +1,27 @@
+/* exec.h : format of executable bytecode files */
+
+/* offset 0 ---> initial junk
+ code block
+ data block
+ symbol table
+ debug infos
+ trailer
+ end of file --->
+*/
+
+/* Structure of the trailer: four 32-bit, unsigned integers, big endian */
+
+#define TRAILER_SIZE (4*4+12)
+
+struct exec_trailer {
+ unsigned long code_size; /* Size of the code block (in bytes) */
+ unsigned long data_size; /* Size of the global data table (bytes) */
+ unsigned long symbol_size; /* Size of the symbol table (bytes) */
+ unsigned long debug_size; /* Size of the debug infos (bytes) */
+ char magic[12]; /* A magic string */
+};
+
+/* Magic number for this release */
+
+#define EXEC_MAGIC "Caml1999X001"
+
diff --git a/byterun/extern.c b/byterun/extern.c
new file mode 100644
index 0000000000..ea05d35e76
--- /dev/null
+++ b/byterun/extern.c
@@ -0,0 +1,245 @@
+/* Structured output */
+
+#include "fail.h"
+#include "gc.h"
+#include "intext.h"
+#include "io.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "reverse.h"
+#include "str.h"
+
+/* To keep track of sharing in externed objects */
+
+typedef unsigned long byteoffset_t;
+
+struct extern_obj {
+ value obj;
+ byteoffset_t ofs;
+};
+
+static struct extern_obj * extern_table;
+static asize_t extern_table_size;
+
+#ifdef SIXTYFOUR
+#define Hash(v) (((asize_t) ((v) >> 3)) % extern_table_size)
+#else
+#define Hash(v) (((asize_t) ((v) >> 2)) % extern_table_size)
+#endif
+
+static void alloc_extern_table()
+{
+ asize_t i;
+
+ extern_table = (struct extern_obj *)
+ stat_alloc(extern_table_size * sizeof(struct extern_obj));
+ for (i = 0; i < extern_table_size; i++)
+ extern_table[i].obj = 0;
+}
+
+static void resize_extern_table()
+{
+ asize_t oldsize;
+ struct extern_obj * oldtable;
+ asize_t i, h;
+
+ oldsize = extern_table_size;
+ oldtable = extern_table;
+ extern_table_size = 2 * extern_table_size;
+ alloc_extern_table();
+ for (i = 0; i < oldsize; i++) {
+ h = Hash(oldtable[i].obj);
+ while (extern_table[h].obj != 0) {
+ h++;
+ if (h >= extern_table_size) h = 0;
+ }
+ extern_table[h].obj = oldtable[i].obj;
+ extern_table[h].ofs = oldtable[i].ofs;
+ }
+ stat_free((char *) oldtable);
+}
+
+/* Write integers on a channel */
+
+static void output8(chan, code, val)
+ struct channel * chan;
+ int code;
+ long val;
+{
+ putch(chan, code); putch(chan, val);
+}
+
+static void output16(chan, code, val)
+ struct channel * chan;
+ int code;
+ long val;
+{
+ putch(chan, code); putch(chan, val >> 8); putch(chan, val);
+}
+
+static void output32(chan, code, val)
+ struct channel * chan;
+ int code;
+ long val;
+{
+ putch(chan, code);
+ putch(chan, val >> 24); putch(chan, val >> 16);
+ putch(chan, val >> 8); putch(chan, val);
+}
+
+#ifdef SIXTYFOUR
+static void output64(chan, code, val)
+ struct channel * chan;
+ int code;
+ long val;
+{
+ int i;
+ putch(chan, code);
+ for (i = 64 - 8; i >= 0; i -= 8) putch(chan, val >> i);
+}
+#endif
+
+static byteoffset_t obj_counter; /* Number of objects emitted so far */
+static unsigned long size_32; /* Size in words of 32-bit block for struct. */
+static unsigned long size_64; /* Size in words of 64-bit block for struct. */
+
+static void emit_compact(chan, v)
+ struct channel * chan;
+ value v;
+{
+ tailcall:
+ if (Is_long(v)) {
+ long n = Long_val(v);
+ if (n >= 0 && n < 0x40) {
+ putch(chan, PREFIX_SMALL_INT + n);
+ } else if (n >= -(1 << 7) && n < (1 << 7)) {
+ output8(chan, CODE_INT8, n);
+ } else if (n >= -(1 << 15) && n < (1 << 15)) {
+ output16(chan, CODE_INT16, n);
+#ifdef SIXTYFOUR
+ } else if (n < -(1L << 31) || n >= (1L << 31)) {
+ output64(chan, CODE_INT64, n);
+#endif
+ } else
+ output32(chan, CODE_INT32, n);
+ } else {
+ header_t hd = Hd_val(v);
+ tag_t tag = Tag_hd(hd);
+ mlsize_t sz = Wosize_hd(hd);
+ asize_t h;
+ /* Atoms are treated specially for two reasons: they are not allocated
+ in the externed block, and they are automatically shared. */
+ if (sz == 0) {
+ if (tag < 16) {
+ putch(chan, PREFIX_SMALL_BLOCK + tag);
+ } else {
+ output32(chan, CODE_BLOCK32, hd);
+ }
+ } else {
+ /* Check if already seen */
+ if (2 * obj_counter >= extern_table_size) resize_extern_table();
+ h = Hash(v);
+ while (extern_table[h].obj != 0) {
+ if (extern_table[h].obj == v) {
+ byteoffset_t d = obj_counter - extern_table[h].ofs;
+ if (d < 0x100) {
+ output8(chan, CODE_SHARED8, d);
+ } else if (d < 0x10000) {
+ output16(chan, CODE_SHARED16, d);
+ } else {
+ output32(chan, CODE_SHARED32, d);
+ }
+ return;
+ }
+ h++;
+ if (h >= extern_table_size) h = 0;
+ }
+ /* Not seen yet. Record the object and output its contents. */
+ extern_table[h].obj = v;
+ extern_table[h].ofs = obj_counter;
+ obj_counter++;
+ switch(tag) {
+ case String_tag: {
+ mlsize_t len = string_length(v);
+ if (len < 0x20) {
+ putch(chan, PREFIX_SMALL_STRING + len);
+ } else if (len < 0x100) {
+ output8(chan, CODE_STRING8, len);
+ } else {
+ output32(chan, CODE_STRING32, len);
+ }
+ putblock(chan, String_val(v), len);
+ size_32 += 1 + (len + 4) / 4;
+ size_64 += 1 + (len + 8) / 8;
+ break;
+ }
+ case Double_tag: {
+ double buffer;
+ if (sizeof(double) != 8)
+ invalid_argument("output_value: non-standard floats");
+ putch(chan, CODE_DOUBLE_NATIVE);
+ buffer = Double_val(v);
+ putblock(chan, (char *) &buffer, 8);
+ size_32 += 1 + sizeof(double) / 4;
+ size_64 += 1 + sizeof(double) / 8;
+ break;
+ }
+ case Abstract_tag:
+ case Final_tag:
+ invalid_argument("output_value: abstract value");
+ break;
+ case Closure_tag:
+ invalid_argument("output_value: functional value");
+ break;
+ default: {
+ mlsize_t i;
+ if (tag < 16 && sz < 8) {
+ putch(chan, PREFIX_SMALL_BLOCK + tag + (sz << 4));
+ } else {
+ output32(chan, CODE_BLOCK32, hd);
+ }
+ size_32 += 1 + sz;
+ size_64 += 1 + sz;
+ for (i = 0; i < sz - 1; i++) emit_compact(chan, Field(v, i));
+ v = Field(v, i);
+ goto tailcall;
+ }
+ }
+ }
+ }
+}
+
+value output_value(chan, v) /* ML */
+ struct channel * chan;
+ value v;
+{
+ value start_loc, final_loc;
+ putword(chan, Compact_magic_number);
+ start_loc = pos_out(chan);
+ putword(chan, 0);
+ putword(chan, 0);
+ putword(chan, 0);
+ extern_table_size = INITIAL_EXTERN_TABLE_SIZE;
+ alloc_extern_table();
+ obj_counter = 0;
+ size_32 = 0;
+ size_64 = 0;
+ emit_compact(chan, v);
+#ifdef SIXTYFOUR
+ if (size_32 >= (1L << 32) || size_64 >= (1L << 32)) {
+ /* The object is so big its size cannot be written in the header.
+ Besides, some of the block sizes or string lengths or shared offsets
+ it contains may have overflowed the 32 bits used to write them. */
+ failwith("output_value: object too big");
+ }
+#endif
+ final_loc = pos_out(chan);
+ seek_out(chan, start_loc);
+ putword(chan, obj_counter);
+ putword(chan, size_32);
+ putword(chan, size_64);
+ seek_out(chan, final_loc);
+ stat_free((char *) extern_table);
+ return Val_unit;
+}
diff --git a/byterun/fail.c b/byterun/fail.c
new file mode 100644
index 0000000000..8b56034beb
--- /dev/null
+++ b/byterun/fail.c
@@ -0,0 +1,108 @@
+/* Raising exceptions from C. */
+
+#include "alloc.h"
+#include "fail.h"
+#include "gc.h"
+#include "memory.h"
+#include "mlvalues.h"
+#include "signals.h"
+#include "stacks.h"
+
+struct longjmp_buffer * external_raise;
+value exn_bucket;
+
+static void mlraise P((value)) Noreturn;
+
+static void mlraise(v)
+ value v;
+{
+ leave_blocking_section();
+ exn_bucket = v;
+ longjmp(external_raise->buf, 1);
+}
+
+void raise_constant(tag)
+ value tag;
+{
+ value bucket;
+ Push_roots (a, 1);
+ a[0] = tag;
+ bucket = alloc (1, 0);
+ Field(bucket, 0) = a[0];
+ Pop_roots ();
+ mlraise(bucket);
+}
+
+void raise_with_arg(tag, arg)
+ value tag;
+ value arg;
+{
+ value bucket;
+ Push_roots (a, 2);
+ a[0] = tag;
+ a[1] = arg;
+ bucket = alloc (2, 0);
+ Field(bucket, 0) = a[0];
+ Field(bucket, 1) = a[1];
+ Pop_roots ();
+ mlraise(bucket);
+}
+
+void raise_with_string(tag, msg)
+ value tag;
+ char * msg;
+{
+ raise_with_arg(tag, copy_string(msg));
+}
+
+void failwith (msg)
+ char * msg;
+{
+ raise_with_string(Field(global_data, FAILURE_EXN), msg);
+}
+
+void invalid_argument (msg)
+ char * msg;
+{
+ raise_with_string(Field(global_data, INVALID_EXN), msg);
+}
+
+/* Problem: we can't use raise_constant, because it allocates and
+ we're out of memory... The following is a terrible hack that works
+ because global_data[OUT_OF_MEMORY_EXN] is in the old generation
+ (because global_data was read with intern_val), hence stays at
+ a fixed address */
+
+static struct {
+ header_t hdr;
+ value exn;
+} out_of_memory_bucket;
+
+void raise_out_of_memory()
+{
+ out_of_memory_bucket.hdr = Make_header(1, 0, White);
+ out_of_memory_bucket.exn = Field(global_data, OUT_OF_MEMORY_EXN);
+ mlraise((value) &(out_of_memory_bucket.exn));
+}
+
+void raise_sys_error(msg)
+ value msg;
+{
+ raise_with_arg(Field(global_data, SYS_ERROR_EXN), msg);
+}
+
+void raise_end_of_file()
+{
+ raise_constant(Field(global_data, END_OF_FILE_EXN));
+}
+
+void raise_zero_divide()
+{
+ raise_constant(Field(global_data, ZERO_DIVIDE_EXN));
+}
+
+void raise_not_found()
+{
+ raise_constant(Field(global_data, NOT_FOUND_EXN));
+}
+
diff --git a/byterun/fail.h b/byterun/fail.h
new file mode 100644
index 0000000000..0a0be89706
--- /dev/null
+++ b/byterun/fail.h
@@ -0,0 +1,36 @@
+#ifndef _fail_
+#define _fail_
+
+
+#include <setjmp.h>
+#include "misc.h"
+#include "mlvalues.h"
+
+#define OUT_OF_MEMORY_EXN 0 /* "Out_of_memory" */
+#define SYS_ERROR_EXN 1 /* "Sys_error" */
+#define FAILURE_EXN 2 /* "Failure" */
+#define INVALID_EXN 3 /* "Invalid_argument" */
+#define END_OF_FILE_EXN 4 /* "End_of_file" */
+#define ZERO_DIVIDE_EXN 5 /* "Division_by_zero" */
+#define NOT_FOUND_EXN 6 /* "Not_found" */
+#define MATCH_FAILURE_EXN 7 /* "Match_failure" */
+
+struct longjmp_buffer {
+ jmp_buf buf;
+};
+
+extern struct longjmp_buffer * external_raise;
+extern value exn_bucket;
+
+void raise_constant P((value tag)) Noreturn;
+void raise_with_arg P((value tag, value arg)) Noreturn;
+void raise_with_string P((value tag, char * msg)) Noreturn;
+void failwith P((char *)) Noreturn;
+void invalid_argument P((char *)) Noreturn;
+void raise_out_of_memory P((void)) Noreturn;
+void raise_sys_error P((value)) Noreturn;
+void raise_end_of_file P((void)) Noreturn;
+void raise_zero_divide P((void)) Noreturn;
+void raise_not_found P((void)) Noreturn;
+
+#endif /* _fail_ */
diff --git a/byterun/fix_code.c b/byterun/fix_code.c
new file mode 100644
index 0000000000..9c24de180e
--- /dev/null
+++ b/byterun/fix_code.c
@@ -0,0 +1,66 @@
+/* Translate a block of bytecode (endianness switch, threading). */
+
+#include "config.h"
+#include "fix_code.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "instruct.h"
+#include "reverse.h"
+
+/* This code is needed only if the processor is big endian */
+
+#ifdef BIG_ENDIAN
+
+void fixup_endianness(code, len)
+ code_t code;
+ asize_t len;
+{
+ code_t p;
+ len /= sizeof(opcode_t);
+ for (p = code; p < code + len; p++) {
+ Reverse_int32(p);
+ }
+}
+
+#endif
+
+/* This code is needed only if we're using threaded code */
+
+#ifdef THREADED_CODE
+
+void thread_code(code, len, instr_table)
+ code_t code;
+ asize_t len;
+ void * instr_table[];
+{
+ code_t p;
+ len /= sizeof(opcode_t);
+ for (p = code; p < code + len; /*nothing*/) {
+ opcode_t instr = *p;
+ Assert(instr >= 0 && instr <= STOP);
+ *p++ = (opcode_t)((unsigned long)(instr_table[instr]));
+ switch(instr) {
+ /* Instructions with one operand */
+ case PUSHACC: case ACC: case POP: case ASSIGN:
+ case PUSHENVACC: case ENVACC: case PUSH_RETADDR: case APPLY:
+ case APPTERM1: case APPTERM2: case APPTERM3: case RETURN:
+ case GRAB: case PUSHGETGLOBAL: case GETGLOBAL: case SETGLOBAL:
+ case PUSHATOM: case ATOM: case MAKEBLOCK1: case MAKEBLOCK2:
+ case MAKEBLOCK3: case GETFIELD: case SETFIELD: case DUMMY:
+ case BRANCH: case BRANCHIF: case BRANCHIFNOT: case PUSHTRAP:
+ case C_CALL1: case C_CALL2: case C_CALL3: case C_CALL4:
+ case CONSTINT: case PUSHCONSTINT: case OFFSETINT: case OFFSETREF:
+ p += 1; break;
+ /* Instructions with two operands */
+ case APPTERM: case CLOSURE: case CLOSUREREC: case PUSHGETGLOBALFIELD:
+ case GETGLOBALFIELD: case MAKEBLOCK: case C_CALLN:
+ p += 2; break;
+ /* Instructions with N+1 operands */
+ case SWITCH: case TRANSLATE:
+ p += *p + 1; break;
+ }
+ }
+ Assert(p = code + len);
+}
+
+#endif
diff --git a/byterun/fix_code.h b/byterun/fix_code.h
new file mode 100644
index 0000000000..c754fad278
--- /dev/null
+++ b/byterun/fix_code.h
@@ -0,0 +1,15 @@
+/* Translate a block of bytecode (endianness switch, threading). */
+
+#ifndef _fix_code_
+#define _fix_code_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+void fixup_endianness P((code_t code, asize_t len));
+void thread_code P((code_t code, asize_t len, void * instr_table[]));
+
+
+#endif
+
diff --git a/byterun/floats.c b/byterun/floats.c
new file mode 100644
index 0000000000..f5b4864737
--- /dev/null
+++ b/byterun/floats.c
@@ -0,0 +1,226 @@
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "alloc.h"
+#include "fail.h"
+#include "memory.h"
+#include "mlvalues.h"
+#include "misc.h"
+#include "stacks.h"
+
+#ifdef ALIGN_DOUBLE
+
+double Double_val(val)
+ value val;
+{
+ union { value v[2]; double d; } buffer;
+
+ Assert(sizeof(double) == 2 * sizeof(value));
+ buffer.v[0] = Field(val, 0);
+ buffer.v[1] = Field(val, 1);
+ return buffer.d;
+}
+
+void Store_double_val(val, dbl)
+ value val;
+ double dbl;
+{
+ union { value v[2]; double d; } buffer;
+
+ Assert(sizeof(double) == 2 * sizeof(value));
+ buffer.d = dbl;
+ Field(val, 0) = buffer.v[0];
+ Field(val, 1) = buffer.v[1];
+}
+
+#endif
+
+value format_float(fmt, arg) /* ML */
+ value fmt, arg;
+{
+ char format_buffer[64];
+ int prec, i;
+ char * p;
+ char * dest;
+ value res;
+
+ prec = 64;
+ for (p = String_val(fmt); *p != 0; p++) {
+ if (*p >= '0' && *p <= '9') {
+ i = atoi(p) + 15;
+ if (i > prec) prec = i;
+ break;
+ }
+ }
+ for( ; *p != 0; p++) {
+ if (*p == '.') {
+ i = atoi(p+1) + 15;
+ if (i > prec) prec = i;
+ break;
+ }
+ }
+ if (prec <= sizeof(format_buffer)) {
+ dest = format_buffer;
+ } else {
+ dest = stat_alloc(prec);
+ }
+ sprintf(dest, String_val(fmt), Double_val(arg));
+ res = copy_string(dest);
+ if (dest != format_buffer) {
+ stat_free(dest);
+ }
+ return res;
+}
+
+value float_of_string(s) /* ML */
+ value s;
+{
+ return copy_double(atof(String_val(s)));
+}
+
+value int_of_float(f) /* ML */
+ value f;
+{
+ return Val_long((long) Double_val(f));
+}
+
+value float_of_int(n) /* ML */
+ value n;
+{
+ return copy_double((double) Long_val(n));
+}
+
+value neg_float(f) /* ML */
+ value f;
+{
+ return copy_double(- Double_val(f));
+}
+
+value add_float(f, g) /* ML */
+ value f, g;
+{
+ return copy_double(Double_val(f) + Double_val(g));
+}
+
+value sub_float(f, g) /* ML */
+ value f, g;
+{
+ return copy_double(Double_val(f) - Double_val(g));
+}
+
+value mul_float(f, g) /* ML */
+ value f, g;
+{
+ return copy_double(Double_val(f) * Double_val(g));
+}
+
+value div_float(f, g) /* ML */
+ value f, g;
+{
+ double dg = Double_val(g);
+ if (dg == 0.0) raise_zero_divide();
+ return copy_double(Double_val(f) / dg);
+}
+
+value exp_float(f) /* ML */
+ value f;
+{
+ return copy_double(exp(Double_val(f)));
+}
+
+value log_float(f) /* ML */
+ value f;
+{
+ return copy_double(log(Double_val(f)));
+}
+
+value sqrt_float(f) /* ML */
+ value f;
+{
+ return copy_double(sqrt(Double_val(f)));
+}
+
+value power_float(f, g) /* ML */
+ value f, g;
+{
+ return copy_double(pow(Double_val(f), Double_val(g)));
+}
+
+value sin_float(f) /* ML */
+ value f;
+{
+ return copy_double(sin(Double_val(f)));
+}
+
+value cos_float(f) /* ML */
+ value f;
+{
+ return copy_double(cos(Double_val(f)));
+}
+
+value tan_float(f) /* ML */
+ value f;
+{
+ return copy_double(tan(Double_val(f)));
+}
+
+value asin_float(f) /* ML */
+ value f;
+{
+ return copy_double(asin(Double_val(f)));
+}
+
+value acos_float(f) /* ML */
+ value f;
+{
+ return copy_double(acos(Double_val(f)));
+}
+
+value atan_float(f) /* ML */
+ value f;
+{
+ return copy_double(atan(Double_val(f)));
+}
+
+value atan2_float(f, g) /* ML */
+ value f, g;
+{
+ return copy_double(atan2(Double_val(f), Double_val(g)));
+}
+
+value eq_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) == Double_val(g));
+}
+
+value neq_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) != Double_val(g));
+}
+
+value le_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) <= Double_val(g));
+}
+
+value lt_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) < Double_val(g));
+}
+
+value ge_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) >= Double_val(g));
+}
+
+value gt_float(f, g) /* ML */
+ value f, g;
+{
+ return Val_bool(Double_val(f) > Double_val(g));
+}
+
diff --git a/byterun/freelist.c b/byterun/freelist.c
new file mode 100644
index 0000000000..0b348fd205
--- /dev/null
+++ b/byterun/freelist.c
@@ -0,0 +1,234 @@
+#include "config.h"
+#include "freelist.h"
+#include "gc.h"
+#include "gc_ctrl.h"
+#include "major_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+
+/* The free-list is kept sorted by increasing addresses.
+ This makes the merging of adjacent free blocks possible.
+ (See [fl_merge_block].)
+*/
+
+typedef struct {
+ char *next_bp; /* Pointer to the first byte of the next block. */
+} block;
+
+/* The sentinel can be located anywhere in memory, but it must not be
+ adjacent to any heap object. */
+static struct {
+ value filler1; /* Make sure the sentinel is never adjacent to any block. */
+ header_t h;
+ value first_bp;
+ value filler2; /* Make sure the sentinel is never adjacent to any block. */
+} sentinel = {0, Make_header (0, 0, Blue), 0, 0};
+
+#define Fl_head ((char *) (&(sentinel.first_bp)))
+static char *fl_prev = Fl_head; /* Current allocation pointer. */
+static char *fl_last = NULL; /* Last block in the list. Only valid
+ just after fl_allocate returned NULL. */
+char *fl_merge = Fl_head; /* Current insertion pointer. Managed
+ jointly with [sweep_slice]. */
+
+#define Next(b) (((block *) (b))->next_bp)
+
+#ifdef DEBUG
+void fl_verify ()
+{
+ char *cur, *prev;
+ int prev_found = 0, merge_found = 0;
+
+ prev = Fl_head;
+ cur = Next (prev);
+ while (cur != NULL){
+ Assert (Is_in_heap (cur));
+ if (cur == fl_prev) prev_found = 1;
+ if (cur == fl_merge) merge_found = 1;
+ prev = cur;
+ cur = Next (prev);
+ }
+ Assert (prev_found || fl_prev == Fl_head);
+ Assert (merge_found || fl_merge == Fl_head);
+}
+#endif
+
+/* [allocate_block] is called by [fl_allocate]. Given a suitable free
+ block and the desired size, it allocates a new block from the free
+ block. There are three cases:
+ 0. The free block has the desired size. Detach the block from the
+ free-list and return it.
+ 1. The free block is 1 word longer than the desired size. Detach
+ the block from the free list. The remaining word cannot be linked:
+ turn it into an empty block (header only), and return the rest.
+ 2. The free block is big enough. Split it in two and return the right
+ block.
+ In all cases, the allocated block is right-justified in the free block:
+ it is located in the high-address words of the free block. This way,
+ the linking of the free-list does not change in case 2.
+*/
+static char *allocate_block (wh_sz, prev, cur)
+ mlsize_t wh_sz;
+ char *prev, *cur;
+{
+ header_t h = Hd_bp (cur);
+ Assert (Whsize_hd (h) >= wh_sz);
+ if (Wosize_hd (h) < wh_sz + 1){ /* Cases 0 and 1. */
+ Next (prev) = Next (cur);
+ Assert (Is_in_heap (Next (prev)) || Next (prev) == NULL);
+ if (fl_merge == cur) fl_merge = prev;
+#ifdef DEBUG
+ fl_last = NULL;
+#endif
+ /* In case 1, the following creates the empty block correctly.
+ In case 0, it gives an invalid header to the block. The function
+ calling [fl_allocate] will overwrite it. */
+ Hd_op (cur) = Make_header (0, 0, White);
+ }else{ /* Case 2. */
+ Hd_op (cur) = Make_header (Wosize_hd (h) - wh_sz, 0, Blue);
+ }
+ fl_prev = prev;
+ return cur + Bosize_hd (h) - Bsize_wsize (wh_sz);
+}
+
+/* [fl_allocate] does not set the header of the newly allocated block.
+ The calling function must do it before any GC function gets called.
+ [fl_allocate] returns a head pointer.
+*/
+char *fl_allocate (wo_sz)
+ mlsize_t wo_sz;
+{
+ char *cur, *prev;
+ Assert (sizeof (char *) == sizeof (value));
+ Assert (fl_prev != NULL);
+ Assert (wo_sz >= 1);
+ /* Search from [fl_prev] to the end of the list. */
+ prev = fl_prev;
+ cur = Next (prev);
+ while (cur != NULL){ Assert (Is_in_heap (cur));
+ if (Wosize_bp (cur) >= wo_sz){
+ return allocate_block (Whsize_wosize (wo_sz), prev, cur);
+ }
+ prev = cur;
+ cur = Next (prev);
+ }
+ fl_last = prev;
+ /* Search from the start of the list to [fl_prev]. */
+ prev = Fl_head;
+ cur = Next (prev);
+ while (prev != fl_prev){
+ if (Wosize_bp (cur) >= wo_sz){
+ return allocate_block (Whsize_wosize (wo_sz), prev, cur);
+ }
+ prev = cur;
+ cur = Next (prev);
+ }
+ /* No suitable block was found. */
+ return NULL;
+}
+
+void fl_init_merge ()
+{
+ fl_merge = Fl_head;
+}
+
+/* [fl_merge_block] returns the head pointer of the next block after [bp],
+ because merging blocks may change the size of [bp]. */
+char *fl_merge_block (bp)
+ char *bp;
+{
+ char *prev, *cur, *adj;
+ header_t hd = Hd_bp (bp);
+
+#ifdef DEBUG
+ {
+ mlsize_t i;
+ for (i = 0; i < Wosize_hd (hd); i++){
+ Field (Val_bp (bp), i) = not_random ();
+ }
+ }
+#endif
+ prev = fl_merge;
+ cur = Next (prev);
+ /* The sweep code makes sure that this is the right place to insert
+ this block: */
+ Assert (prev < bp || prev == Fl_head);
+ Assert (cur > bp || cur == NULL);
+
+ /* If [bp] and [cur] are adjacent, remove [cur] from the free-list
+ and merge them. */
+ adj = bp + Bosize_hd (hd);
+ if (adj == Hp_bp (cur)){
+ char *next_cur = Next (cur);
+ long cur_whsz = Whsize_bp (cur);
+
+ Next (prev) = next_cur;
+ if (fl_prev == cur) fl_prev = prev;
+ hd = Make_header (Wosize_hd (hd) + cur_whsz, 0, Blue);
+ Hd_bp (bp) = hd;
+ adj = bp + Bosize_hd (hd);
+#ifdef DEBUG
+ fl_last = NULL;
+ Next (cur) = (char *) not_random ();
+ Hd_bp (cur) = not_random ();
+#endif
+ cur = next_cur;
+ }
+ /* If [prev] and [bp] are adjacent merge them, else insert [bp] into
+ the free-list if it is big enough. */
+ if (prev + Bosize_bp (prev) == Hp_bp (bp)){
+ Hd_bp (prev) = Make_header (Wosize_bp (prev) + Whsize_hd (hd), 0, Blue);
+#ifdef DEBUG
+ Hd_bp (bp) = not_random ();
+#endif
+ Assert (fl_merge == prev);
+ }else if (Wosize_hd (hd) > 0){
+ Hd_bp (bp) = Bluehd_hd (hd);
+ Next (bp) = cur;
+ Next (prev) = bp;
+ fl_merge = bp;
+ } /* Else leave it in white. */
+ return adj;
+}
+
+/* This is a heap extension. We have to insert it in the right place
+ in the free-list.
+ [fl_add_block] can only be called just after a call to [fl_allocate]
+ that returned NULL.
+ Most of the heap extensions are expected to be at the end of the
+ free list. (This depends on the implementation of [malloc].)
+*/
+void fl_add_block (bp)
+ char *bp;
+{
+ Assert (fl_last != NULL);
+ Assert (Next (fl_last) == NULL);
+#ifdef DEBUG
+ {
+ mlsize_t i;
+ for (i = 0; i < Wosize_bp (bp); i++){
+ Field (Val_bp (bp), i) = not_random ();
+ }
+ }
+#endif
+ if (bp > fl_last){
+ Next (fl_last) = bp;
+ Next (bp) = NULL;
+ }else{
+ char *cur, *prev;
+
+ prev = Fl_head;
+ cur = Next (prev);
+ while (cur != NULL && cur < bp){ Assert (prev < bp || prev == Fl_head);
+ prev = cur;
+ cur = Next (prev);
+ } Assert (prev < bp || prev == Fl_head);
+ Assert (cur > bp || cur == NULL);
+ Next (bp) = cur;
+ Next (prev) = bp;
+ /* When inserting a block between fl_merge and gc_sweep_hp, we must
+ advance fl_merge to the new block, so that fl_merge is always the
+ last free-list block before gc_sweep_hp. */
+ if (prev == fl_merge && bp <= gc_sweep_hp) fl_merge = bp;
+ }
+}
diff --git a/byterun/freelist.h b/byterun/freelist.h
new file mode 100644
index 0000000000..1f1aef9a7f
--- /dev/null
+++ b/byterun/freelist.h
@@ -0,0 +1,16 @@
+/* Free lists of heap blocks. */
+
+#ifndef _freelist_
+#define _freelist_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+char *fl_allocate P((mlsize_t));
+void fl_init_merge P((void));
+char *fl_merge_block P((char *));
+void fl_add_block P((char *));
+
+
+#endif /* _freelist_ */
diff --git a/byterun/gc.h b/byterun/gc.h
new file mode 100644
index 0000000000..b772f2f28d
--- /dev/null
+++ b/byterun/gc.h
@@ -0,0 +1,42 @@
+#ifndef _gc_
+#define _gc_
+
+
+#include "mlvalues.h"
+
+/* Defined in [major_gc.c]. */
+extern unsigned free_mem_percent_min, free_mem_percent_max;
+
+#define White (0 << 8)
+#define Gray (1 << 8)
+#define Blue (2 << 8)
+#define Black (3 << 8)
+
+#define Color_hd(hd) ((color_t) ((hd) & Black))
+#define Color_hp(hp) Color_hd (Hd_hp (hp))
+
+#define Is_white_hd(hd) (Color_hd (hd) == White)
+#define Is_gray_hd(hd) (Color_hd (hd) == Gray)
+#define Is_blue_hd(hd) (Color_hd (hd) == Blue)
+#define Is_black_hd(hd) (Color_hd (hd) == Black)
+
+#define Whitehd_hd(hd) ((hd) & ~Black)
+#define Grayhd_hd(hd) (((hd) & ~Black) | Gray)
+#define Blackhd_hd(hd) ((hd) | Black)
+#define Bluehd_hd(hd) (((hd) & ~Black) | Blue)
+
+/* This depends on the layout of the header. See [mlvalues.h]. */
+#define Make_header(wosize, tag, color) \
+ ((header_t) (((header_t) (wosize) << 10) \
+ + (color) \
+ + (tag_t) (tag)))
+
+#define Color_val(val) (Color_hd (Hd_val (val)))
+
+#define Is_white_val(val) (Color_val(val) == White)
+#define Is_gray_val(val) (Color_val(val) == Gray)
+#define Is_blue_val(val) (Color_val(val) == Blue)
+#define Is_black_val(val) (Color_val(val) == Black)
+
+
+#endif /* _gc_ */
diff --git a/byterun/gc_ctrl.c b/byterun/gc_ctrl.c
new file mode 100644
index 0000000000..facd9f30f7
--- /dev/null
+++ b/byterun/gc_ctrl.c
@@ -0,0 +1,212 @@
+#include "alloc.h"
+#include "gc.h"
+#include "gc_ctrl.h"
+#include "major_gc.h"
+#include "minor_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+
+long stat_minor_words = 0,
+ stat_promoted_words = 0,
+ stat_major_words = 0,
+ stat_minor_collections = 0,
+ stat_major_collections = 0,
+ stat_heap_size = 0; /* bytes */
+
+extern asize_t major_heap_increment; /* bytes; cf. major_gc.c */
+extern int percent_free; /* cf. major_gc.c */
+extern int verb_gc; /* cf. misc.c */
+
+#define Chunk_size(c) (((heap_chunk_head *) (c)) [-1]).size
+#define Chunk_next(c) (((heap_chunk_head *) (c)) [-1]).next
+#define Next(hp) ((hp) + Bhsize_hp (hp))
+
+/* This will also thoroughly verify the heap if compiled in DEBUG mode. */
+
+value gc_stat(v) /* ML */
+ value v;
+{
+ value res;
+ long live_words = 0, live_blocks = 0,
+ free_words = 0, free_blocks = 0, largest_free = 0,
+ fragments = 0, heap_chunks = 0;
+ char *chunk = heap_start, *chunk_end;
+ char *cur_hp, *prev_hp;
+ header_t cur_hd;
+
+ Assert (v == Atom (0));
+
+ while (chunk != NULL){
+ ++ heap_chunks;
+ chunk_end = chunk + Chunk_size (chunk);
+ prev_hp = NULL;
+ cur_hp = chunk;
+ while (cur_hp < chunk_end){
+ cur_hd = Hd_hp (cur_hp);
+ switch (Color_hd (cur_hd)){
+ case White:
+ if (Wosize_hd (cur_hd) == 0){
+ ++fragments;
+ Assert (prev_hp == NULL
+ || (Color_hp (prev_hp) != Blue
+ && Wosize_hp (prev_hp) > 0));
+ Assert (Next (cur_hp) == chunk_end
+ || (Color_hp (Next (cur_hp)) != Blue
+ && Wosize_hp (Next (cur_hp)) > 0));
+ break;
+ }
+ /* FALLTHROUGH */
+ case Gray: case Black:
+ Assert (Wosize_hd (cur_hd) > 0);
+ ++ live_blocks;
+ live_words += Whsize_hd (cur_hd);
+ break;
+ case Blue:
+ Assert (Wosize_hd (cur_hd) > 0);
+ ++ free_blocks;
+ free_words += Whsize_hd (cur_hd);
+ if (Whsize_hd (cur_hd) > largest_free){
+ largest_free = Whsize_hd (cur_hd);
+ }
+ Assert (prev_hp == NULL
+ || (Color_hp (prev_hp) != Blue
+ && Wosize_hp (prev_hp) > 0));
+ Assert (Next (cur_hp) == chunk_end
+ || (Color_hp (Next (cur_hp)) != Blue
+ && Wosize_hp (Next (cur_hp)) > 0));
+ break;
+ }
+ prev_hp = cur_hp;
+ cur_hp = Next (cur_hp);
+ } Assert (cur_hp == chunk_end);
+ chunk = Chunk_next (chunk);
+ }
+
+ Assert (live_words + free_words + fragments == Wsize_bsize (stat_heap_size));
+
+ res = alloc (13, 0);
+ Field (res, 0) = Val_long (stat_minor_words
+ + Wsize_bsize (young_ptr - young_start));
+ Field (res, 1) = Val_long (stat_promoted_words);
+ Field (res, 2) = Val_long (stat_major_words + allocated_words);
+ Field (res, 3) = Val_long (stat_minor_collections);
+ Field (res, 4) = Val_long (stat_major_collections);
+ Field (res, 5) = Val_long (Wsize_bsize (stat_heap_size));
+ Field (res, 6) = Val_long (heap_chunks);
+ Field (res, 7) = Val_long (live_words);
+ Field (res, 8) = Val_long (live_blocks);
+ Field (res, 9) = Val_long (free_words);
+ Field (res, 10) = Val_long (free_blocks);
+ Field (res, 11) = Val_long (largest_free);
+ Field (res, 12) = Val_long (fragments);
+ return res;
+}
+
+value gc_get(v) /* ML */
+ value v;
+{
+ value res;
+
+ Assert (v == Atom (0));
+ res = alloc (4, 0);
+ Field (res, 0) = Wsize_bsize (Val_long (minor_heap_size));
+ Field (res, 1) = Wsize_bsize (Val_long (major_heap_increment));
+ Field (res, 2) = Val_long (percent_free);
+ Field (res, 3) = Val_bool (verb_gc);
+ return res;
+}
+
+static int norm_pfree (p)
+ int p;
+{
+ if (p < 1) return p = 1;
+ return p;
+}
+
+static long norm_heapincr (i)
+ long i;
+{
+ i = ((i + (1 << Page_log) - 1) >> Page_log) << Page_log;
+ if (i < Heap_chunk_min) i = Heap_chunk_min;
+ if (i > Heap_chunk_max) i = Heap_chunk_max;
+ return i;
+}
+
+static long norm_minsize (s)
+ long s;
+{
+ if (s < Minor_heap_min) s = Minor_heap_min;
+ if (s > Minor_heap_max) s = Minor_heap_max;
+ return s;
+}
+
+value gc_set(v) /* ML */
+ value v;
+{
+ int newpf;
+
+ verb_gc = Bool_val (Field (v, 3));
+
+ newpf = norm_pfree (Long_val (Field (v, 2)));
+ if (newpf != percent_free){
+ percent_free = newpf;
+ gc_message ("New space overhead: %d%%\n", percent_free);
+ }
+
+ if (Bsize_wsize (Long_val (Field (v, 1))) != major_heap_increment){
+ major_heap_increment = norm_heapincr (Bsize_wsize (Long_val (Field(v,1))));
+ gc_message ("New heap increment size: %ldk\n", major_heap_increment/1024);
+ }
+
+ /* Minor heap size comes last because it will trigger a minor collection
+ (thus invalidating [v]) and it can raise [Out_of_memory]. */
+ if (Bsize_wsize (Long_val (Field (v, 0))) != minor_heap_size){
+ long new_size = norm_minsize (Bsize_wsize (Long_val (Field (v, 0))));
+ gc_message ("New minor heap size: %ldk\n", new_size/1024);
+ set_minor_heap_size (new_size);
+ }
+ return Atom (0);
+}
+
+value gc_minor(v) /* ML */
+ value v;
+{ Assert (v == Atom (0));
+ minor_collection ();
+ return Atom (0);
+}
+
+value gc_major(v) /* ML */
+ value v;
+{ Assert (v == Atom (0));
+ minor_collection ();
+ finish_major_cycle ();
+ return Atom (0);
+}
+
+value gc_full_major(v) /* ML */
+ value v;
+{ Assert (v == Atom (0));
+ minor_collection ();
+ finish_major_cycle ();
+ finish_major_cycle ();
+ return Atom (0);
+}
+
+void init_gc (minor_size, major_incr, percent_fr, verb)
+ long minor_size;
+ long major_incr;
+ int percent_fr;
+ int verb;
+{
+#ifdef DEBUG
+ gc_message ("*** camlrun: debug mode ***\n", 0);
+#endif
+ verb_gc = verb;
+ set_minor_heap_size (Bsize_wsize (norm_minsize (minor_size)));
+ major_heap_increment = Bsize_wsize (norm_heapincr (major_incr));
+ percent_free = norm_pfree (percent_fr);
+ init_major_heap (major_heap_increment);
+ gc_message ("Initial space overhead: %d%%\n", percent_free);
+ gc_message ("Initial heap increment: %ldk\n", major_heap_increment / 1024);
+ gc_message ("Initial minor heap size: %ldk\n", minor_heap_size / 1024);
+}
diff --git a/byterun/gc_ctrl.h b/byterun/gc_ctrl.h
new file mode 100644
index 0000000000..5a88a9ab61
--- /dev/null
+++ b/byterun/gc_ctrl.h
@@ -0,0 +1,17 @@
+#ifndef _gc_ctrl_
+#define _gc_ctrl_
+
+#include "misc.h"
+
+extern long
+ stat_minor_words,
+ stat_promoted_words,
+ stat_major_words,
+ stat_minor_collections,
+ stat_major_collections,
+ stat_heap_size;
+
+void init_gc P((long, long, int, int));
+
+
+#endif /* _gc_ctrl_ */
diff --git a/byterun/hash.c b/byterun/hash.c
new file mode 100644
index 0000000000..944bfac985
--- /dev/null
+++ b/byterun/hash.c
@@ -0,0 +1,103 @@
+/* The generic hashing primitive */
+
+#include "mlvalues.h"
+#include "memory.h"
+#include "str.h"
+
+static unsigned long hash_accu;
+static long hash_univ_limit, hash_univ_count;
+
+static void hash_aux();
+
+value hash_univ_param(count, limit, obj) /* ML */
+ value obj, count, limit;
+{
+ hash_univ_limit = Long_val(limit);
+ hash_univ_count = Long_val(count);
+ hash_accu = 0;
+ hash_aux(obj);
+ return Val_long(hash_accu & 0x3FFFFFFF);
+ /* The & has two purposes: ensure that the return value is positive
+ and give the same result on 32 bit and 64 bit architectures. */
+}
+
+#define Alpha 65599
+#define Beta 19
+#define Combine(new) (hash_accu = hash_accu * Alpha + (new))
+#define Combine_small(new) (hash_accu = hash_accu * Beta + (new))
+
+static void hash_aux(obj)
+ value obj;
+{
+ unsigned char * p;
+ mlsize_t i;
+ tag_t tag;
+
+ hash_univ_limit--;
+ if (hash_univ_count < 0 || hash_univ_limit < 0) return;
+
+ if (Is_long(obj)) {
+ hash_univ_count--;
+ Combine(Long_val(obj));
+ return;
+ }
+
+ /* Atoms are not in the heap, but it's better to hash their tag
+ than to do nothing. */
+
+ if (Is_atom(obj)) {
+ tag = Tag_val(obj);
+ hash_univ_count--;
+ Combine_small(tag);
+ return;
+ }
+
+ /* Pointers into the heap are well-structured blocks.
+ We can inspect the block contents. */
+
+ if (Is_in_heap(obj) || Is_young(obj)) {
+ tag = Tag_val(obj);
+ switch (tag) {
+ case String_tag:
+ hash_univ_count--;
+ i = string_length(obj);
+ for (p = &Byte_u(obj, 0); i > 0; i--, p++)
+ Combine_small(*p);
+ break;
+ case Double_tag:
+ /* For doubles, we inspect their binary representation, LSB first.
+ The results are consistent among all platforms with IEEE floats. */
+ hash_univ_count--;
+#ifdef BIG_ENDIAN
+ for (p = &Byte_u(obj, sizeof(double) - 1), i = sizeof(double);
+ i > 0;
+ p--, i--)
+#else
+ for (p = &Byte_u(obj, 0), i = sizeof(double);
+ i > 0;
+ p++, i--)
+#endif
+ Combine_small(*p);
+ break;
+ case Abstract_tag:
+ case Final_tag:
+ /* We don't know anything about the contents of the block.
+ Better do nothing. */
+ break;
+ default:
+ hash_univ_count--;
+ Combine_small(tag);
+ i = Wosize_val(obj);
+ while (i != 0) {
+ i--;
+ hash_aux(Field(obj, i));
+ }
+ break;
+ }
+ return;
+ }
+
+ /* Otherwise, obj is a pointer outside the heap, to an object with
+ a priori unknown structure. Use its physical address as hash key. */
+ Combine((long) obj);
+}
diff --git a/byterun/instrtrace.c b/byterun/instrtrace.c
new file mode 100644
index 0000000000..5e3133565f
--- /dev/null
+++ b/byterun/instrtrace.c
@@ -0,0 +1,52 @@
+/* Trace the instructions executed */
+
+#ifdef DEBUG
+
+#include <stdio.h>
+#include "instruct.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "opnames.h"
+
+extern code_t start_code;
+extern char * names_of_cprim[];
+
+long icount = 0;
+
+void stop_here () {}
+
+int trace_flag = 0;
+
+void disasm_instr(pc)
+ code_t pc;
+{
+ int instr = *pc;
+ printf("%6d %s", pc - start_code,
+ instr < 0 || instr > STOP ? "???" : names_of_instructions[instr]);
+ pc++;
+ switch(instr) {
+ /* Instructions with one integer operand */
+ case PUSHACC: case ACC: case POP: case ASSIGN:
+ case PUSHENVACC: case ENVACC: case PUSH_RETADDR: case APPLY:
+ case APPTERM1: case APPTERM2: case APPTERM3: case RETURN:
+ case GRAB: case PUSHGETGLOBAL: case GETGLOBAL: case SETGLOBAL:
+ case PUSHATOM: case ATOM: case MAKEBLOCK1: case MAKEBLOCK2:
+ case MAKEBLOCK3: case GETFIELD: case SETFIELD: case DUMMY:
+ case BRANCH: case BRANCHIF: case BRANCHIFNOT: case PUSHTRAP:
+ case CONSTINT: case PUSHCONSTINT: case OFFSETINT: case OFFSETREF:
+ printf(" %d\n", pc[0]); break;
+ /* Instructions with two operands */
+ case APPTERM: case CLOSURE: case CLOSUREREC: case PUSHGETGLOBALFIELD:
+ case GETGLOBALFIELD: case MAKEBLOCK:
+ printf(" %d, %d\n", pc[0], pc[1]); break;
+ /* Instructions with a C primitive as operand */
+ case C_CALL1: case C_CALL2: case C_CALL3: case C_CALL4:
+ printf(" %s\n", names_of_cprim[pc[0]]); break;
+ case C_CALLN:
+ printf(" %d, %s\n", pc[0], names_of_cprim[pc[1]]); break;
+ default:
+ printf("\n");
+ }
+}
+
+#endif
diff --git a/byterun/instrtrace.h b/byterun/instrtrace.h
new file mode 100644
index 0000000000..c47b39781c
--- /dev/null
+++ b/byterun/instrtrace.h
@@ -0,0 +1,16 @@
+/* Trace the instructions executed */
+
+#ifndef _instrtrace_
+#define _instrtrace_
+
+
+#include "mlvalues.h"
+#include "misc.h"
+
+extern int trace_flag;
+extern long icount;
+void stop_here P((void));
+void disasm_instr P((code_t pc));
+
+
+#endif
diff --git a/byterun/instruct.h b/byterun/instruct.h
new file mode 100644
index 0000000000..43cb8dcdf0
--- /dev/null
+++ b/byterun/instruct.h
@@ -0,0 +1,33 @@
+/* The instruction set. */
+
+enum instructions {
+ ACC0, ACC1, ACC2, ACC3, ACC4, ACC5, ACC6, ACC7,
+ ACC, PUSH,
+ PUSHACC0, PUSHACC1, PUSHACC2, PUSHACC3,
+ PUSHACC4, PUSHACC5, PUSHACC6, PUSHACC7,
+ PUSHACC, POP, ASSIGN,
+ ENVACC0, ENVACC1, ENVACC2, ENVACC3, ENVACC,
+ PUSHENVACC0, PUSHENVACC1, PUSHENVACC2, PUSHENVACC3, PUSHENVACC,
+ PUSH_RETADDR, APPLY, APPLY1, APPLY2, APPLY3,
+ APPTERM, APPTERM1, APPTERM2, APPTERM3,
+ RETURN, RESTART, GRAB,
+ CLOSURE, CLOSUREREC,
+ GETGLOBAL, PUSHGETGLOBAL, GETGLOBALFIELD, PUSHGETGLOBALFIELD, SETGLOBAL,
+ ATOM0, ATOM1, ATOM2, ATOM3, ATOM,
+ PUSHATOM0, PUSHATOM1, PUSHATOM2, PUSHATOM3, PUSHATOM,
+ MAKEBLOCK, MAKEBLOCK1, MAKEBLOCK2, MAKEBLOCK3,
+ GETFIELD0, GETFIELD1, GETFIELD2, GETFIELD3, GETFIELD,
+ SETFIELD0, SETFIELD1, SETFIELD2, SETFIELD3, SETFIELD,
+ TAGOF, DUMMY, UPDATE,
+ VECTLENGTH, GETVECTITEM, SETVECTITEM,
+ GETSTRINGCHAR, SETSTRINGCHAR,
+ BRANCH, BRANCHIF, BRANCHIFNOT, SWITCH, TRANSLATE, BOOLNOT,
+ PUSHTRAP, POPTRAP, RAISE, CHECK_SIGNALS,
+ C_CALL1, C_CALL2, C_CALL3, C_CALL4, C_CALLN,
+ CONSTINT, PUSHCONSTINT,
+ NEGINT, ADDINT, SUBINT, MULINT, DIVINT, MODINT,
+ ANDINT, ORINT, XORINT, LSLINT, LSRINT, ASRINT,
+ EQ, NEQ, LTINT, LEINT, GTINT, GEINT,
+ OFFSETINT, OFFSETREF,
+ STOP
+};
diff --git a/byterun/intern.c b/byterun/intern.c
new file mode 100644
index 0000000000..4fb438b44a
--- /dev/null
+++ b/byterun/intern.c
@@ -0,0 +1,230 @@
+/* Structured input, compact format */
+
+#include "fail.h"
+#include "gc.h"
+#include "intext.h"
+#include "io.h"
+#include "memory.h"
+#include "mlvalues.h"
+#include "misc.h"
+#include "reverse.h"
+
+static header_t * intern_ptr;
+static asize_t obj_counter;
+static value * intern_obj_table;
+static unsigned int intern_color;
+static header_t intern_header;
+static value intern_block;
+
+#define Sign_extend_shift ((sizeof(long) - 1) * 8)
+#define Sign_extend(x) (((long)(x) << Sign_extend_shift) >> Sign_extend_shift)
+
+static long input8u(chan)
+ struct channel * chan;
+{
+ return getch(chan);
+}
+
+static long input8s(chan)
+ struct channel * chan;
+{
+ long b1 = getch(chan);
+ return Sign_extend(b1);
+}
+
+static long input16u(chan)
+ struct channel * chan;
+{
+ long b1 = getch(chan);
+ long b2 = getch(chan);
+ return (b1 << 8) + b2;
+}
+
+static long input16s(chan)
+ struct channel * chan;
+{
+ long b1 = getch(chan);
+ long b2 = getch(chan);
+ return (Sign_extend(b1) << 8) + b2;
+}
+
+static long input32u(chan)
+ struct channel * chan;
+{
+ long b1 = getch(chan);
+ long b2 = getch(chan);
+ long b3 = getch(chan);
+ long b4 = getch(chan);
+ return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
+}
+
+static long input32s(chan)
+ struct channel * chan;
+{
+ long b1 = getch(chan);
+ long b2 = getch(chan);
+ long b3 = getch(chan);
+ long b4 = getch(chan);
+ return (Sign_extend(b1) << 24) + (b2 << 16) + (b3 << 8) + b4;
+}
+
+#ifdef SIXTYFOUR
+static long input64s(chan)
+ struct channel * chan;
+{
+ long res;
+ int i;
+ res = 0;
+ for (i = 0; i < 8; i++) res = (res << 8) + getch(chan);
+ return res;
+}
+#endif
+
+static void read_compact(chan, dest)
+ struct channel * chan;
+ value * dest;
+{
+ unsigned int code;
+ tag_t tag;
+ mlsize_t size, len, ofs_ind;
+ value v;
+ asize_t ofs;
+ header_t header;
+
+ tailcall:
+ code = getch(chan);
+ if (code >= PREFIX_SMALL_INT) {
+ if (code >= PREFIX_SMALL_BLOCK) {
+ /* Small block */
+ tag = code & 0xF;
+ size = (code >> 4) & 0x7;
+ read_block:
+ if (size == 0) {
+ v = Atom(tag);
+ } else {
+ v = Val_hp(intern_ptr);
+ *dest = v;
+ intern_obj_table[obj_counter++] = v;
+ dest = (value *) (intern_ptr + 1);
+ *intern_ptr = Make_header(size, tag, intern_color);
+ intern_ptr += 1 + size;
+ for(/*nothing*/; size > 1; size--, dest++)
+ read_compact(chan, dest);
+ goto tailcall;
+ }
+ } else {
+ /* Small integer */
+ v = Val_int(code & 0x3F);
+ }
+ } else {
+ if (code >= PREFIX_SMALL_STRING) {
+ /* Small string */
+ len = (code & 0x1F);
+ read_string:
+ size = (len + sizeof(value)) / sizeof(value);
+ v = Val_hp(intern_ptr);
+ intern_obj_table[obj_counter++] = v;
+ *intern_ptr = Make_header(size, String_tag, intern_color);
+ intern_ptr += 1 + size;
+ Field(v, size - 1) = 0;
+ ofs_ind = Bsize_wsize(size) - 1;
+ Byte(v, ofs_ind) = ofs_ind - len;
+ really_getblock(chan, String_val(v), len);
+ } else {
+ switch(code) {
+ case CODE_INT8:
+ v = Val_long(input8s(chan));
+ break;
+ case CODE_INT16:
+ v = Val_long(input16s(chan));
+ break;
+ case CODE_INT32:
+ v = Val_long(input32s(chan));
+ break;
+ case CODE_INT64:
+#ifdef SIXTYFOUR
+ v = Val_long(input64s(chan));
+ break;
+#else
+ stat_free((char *) intern_obj_table);
+ Hd_val(intern_block) = intern_header; /* Don't confuse the GC */
+ failwith("input_value: integer too large");
+ break;
+#endif
+ case CODE_SHARED8:
+ ofs = input8u(chan);
+ read_shared:
+ Assert(ofs > 0 && ofs <= obj_counter);
+ v = intern_obj_table[obj_counter - ofs];
+ break;
+ case CODE_SHARED16:
+ ofs = input16u(chan);
+ goto read_shared;
+ case CODE_SHARED32:
+ ofs = input32u(chan);
+ goto read_shared;
+ case CODE_BLOCK32:
+ header = (header_t) input32u(chan);
+ tag = Tag_hd(header);
+ size = Wosize_hd(header);
+ goto read_block;
+ case CODE_STRING8:
+ len = input8u(chan);
+ goto read_string;
+ case CODE_STRING32:
+ len = input32u(chan);
+ goto read_string;
+ case CODE_DOUBLE_LITTLE:
+ case CODE_DOUBLE_BIG:
+ if (sizeof(double) != 8) {
+ stat_free((char *) intern_obj_table);
+ Hd_val(intern_block) = intern_header; /* Don't confuse the GC */
+ invalid_argument("input_value: non-standard floats");
+ }
+ v = Val_hp(intern_ptr);
+ intern_obj_table[obj_counter++] = v;
+ *intern_ptr = Make_header(Double_wosize, Double_tag, intern_color);
+ intern_ptr += 1 + Double_wosize;
+ really_getblock(chan, (char *) v, 8);
+ if (code != CODE_DOUBLE_NATIVE) Reverse_double(v);
+ break;
+ }
+ }
+ }
+ *dest = v;
+}
+
+value input_value(chan) /* ML */
+ struct channel * chan;
+{
+ uint32 magic;
+ mlsize_t num_objects, size_32, size_64, whsize;
+ value res;
+
+ magic = getword(chan);
+ if (magic != Compact_magic_number) failwith("input_value: bad object");
+ num_objects = getword(chan);
+ size_32 = getword(chan);
+ size_64 = getword(chan);
+#ifdef SIXTYFOUR
+ whsize = size_64;
+#else
+ whsize = size_32;
+#endif
+ if (whsize == 0) {
+ read_compact(chan, &res);
+ } else {
+ if (Wosize_whsize(whsize) > Max_wosize)
+ failwith("intern: structure too big");
+ intern_block = alloc_shr(Wosize_whsize(whsize), String_tag);
+ intern_header = Hd_val(intern_block);
+ intern_color = Color_hd(intern_header);
+ Assert (intern_color == White || intern_color == Black);
+ intern_ptr = (header_t *) Hp_val(intern_block);
+ obj_counter = 0;
+ intern_obj_table = (value *) stat_alloc(num_objects * sizeof(value));
+ read_compact(chan, &res);
+ stat_free((char *) intern_obj_table);
+ }
+ return res;
+}
diff --git a/byterun/interp.c b/byterun/interp.c
new file mode 100644
index 0000000000..2a5babc5a7
--- /dev/null
+++ b/byterun/interp.c
@@ -0,0 +1,865 @@
+/* The bytecode interpreter */
+
+#include "alloc.h"
+#include "fail.h"
+#include "fix_code.h"
+#include "instruct.h"
+#include "interp.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "prims.h"
+#include "signals.h"
+#include "stacks.h"
+#include "str.h"
+#include "instrtrace.h"
+
+/* Registers for the abstract machine:
+ pc the code pointer
+ sp the stack pointer (grows downward)
+ accu the accumulator
+ env heap-allocated environment
+ trapsp pointer to the current trap frame
+ extra_args number of extra arguments provided by the caller
+
+sp is a local copy of the global variable extern_sp. */
+
+extern value global_data;
+extern code_t start_code;
+
+/* Instruction decoding */
+
+#ifdef THREADED_CODE
+# define Instruct(name) lbl_##name
+# ifdef DEBUG
+# define Next goto next_instr
+# else
+# define Next goto *((void *)((unsigned long)(*pc++)))
+# endif
+#else
+# define Instruct(name) case name
+# define Next break
+#endif
+
+/* GC interface */
+
+#define Setup_for_gc { sp -= 2; sp[0] = accu; sp[1] = env; extern_sp = sp; }
+#define Restore_after_gc { accu = sp[0]; env = sp[1]; sp += 2; }
+#define Setup_for_c_call { *--sp = env; extern_sp = sp; }
+#define Restore_after_c_call { sp = extern_sp; env = *sp++; }
+
+/* Register optimization.
+ Many compilers underestimate the use of the local variables representing
+ the abstract machine registers, and don't put them in hardware registers,
+ which slows down the interpreter considerably.
+ For GCC, I have hand-assigned hardware registers for several architectures.
+*/
+
+#if defined(__GNUC__) && !defined(DEBUG)
+#ifdef __mips__
+#define PC_REG asm("$16")
+#define SP_REG asm("$17")
+#define ACCU_REG asm("$18")
+#endif
+#ifdef __sparc__
+#define PC_REG asm("%l0")
+#define SP_REG asm("%l1")
+#define ACCU_REG asm("%l2")
+#endif
+#ifdef __alpha__
+#define PC_REG asm("$9")
+#define SP_REG asm("$10")
+#define ACCU_REG asm("$11")
+#endif
+#ifdef __i386__
+#define PC_REG asm("%esi")
+#define SP_REG asm("%edi")
+#define ACCU_REG
+#endif
+#endif
+
+/* The interpreter itself */
+
+value interprete(prog, prog_size)
+ code_t prog;
+ asize_t prog_size;
+{
+#ifdef PC_REG
+ register code_t pc PC_REG;
+ register value * sp SP_REG;
+ register value accu ACCU_REG;
+#else
+ register code_t pc;
+ register value * sp;
+ register value accu;
+#endif
+ value env;
+ long extra_args;
+ struct longjmp_buffer * initial_external_raise;
+ int initial_sp_offset;
+ value * initial_local_roots;
+ struct longjmp_buffer raise_buf;
+ value * modify_dest, modify_newval;
+
+#ifdef THREADED_CODE
+ static void * jumptable[] = {
+# include "jumptbl.h"
+ };
+#endif
+
+#ifdef THREADED_CODE
+ if (prog[0] <= STOP) thread_code(prog, prog_size, jumptable);
+#endif
+
+ sp = extern_sp;
+ pc = prog;
+ extra_args = 0;
+ env = Atom(0);
+ accu = Val_long(0);
+ initial_local_roots = local_roots;
+ initial_sp_offset = stack_high - sp;
+ initial_external_raise = external_raise;
+ if (setjmp(raise_buf.buf)) {
+ local_roots = initial_local_roots;
+ accu = exn_bucket;
+ goto raise_exception;
+ }
+ external_raise = &raise_buf;
+
+#ifdef THREADED_CODE
+#ifdef DEBUG
+ next_instr:
+ if (icount-- == 0) stop_here ();
+ Assert(sp >= stack_low);
+ Assert(sp <= stack_high);
+ goto *((void *)((unsigned long)(*pc++)));
+#else
+ Next; /* Jump to the first instruction */
+#endif
+#else
+ while(1) {
+#ifdef DEBUG
+ if (icount-- == 0) stop_here ();
+ if (trace_flag) disasm_instr(pc);
+ Assert(sp >= stack_low);
+ Assert(sp <= stack_high);
+#endif
+ switch(*pc++) {
+#endif
+
+/* Basic stack operations */
+
+ Instruct(ACC0):
+ accu = sp[0]; Next;
+ Instruct(ACC1):
+ accu = sp[1]; Next;
+ Instruct(ACC2):
+ accu = sp[2]; Next;
+ Instruct(ACC3):
+ accu = sp[3]; Next;
+ Instruct(ACC4):
+ accu = sp[4]; Next;
+ Instruct(ACC5):
+ accu = sp[5]; Next;
+ Instruct(ACC6):
+ accu = sp[6]; Next;
+ Instruct(ACC7):
+ accu = sp[7]; Next;
+
+ Instruct(PUSH): Instruct(PUSHACC0):
+ *--sp = accu; Next;
+ Instruct(PUSHACC1):
+ *--sp = accu; accu = sp[1]; Next;
+ Instruct(PUSHACC2):
+ *--sp = accu; accu = sp[2]; Next;
+ Instruct(PUSHACC3):
+ *--sp = accu; accu = sp[3]; Next;
+ Instruct(PUSHACC4):
+ *--sp = accu; accu = sp[4]; Next;
+ Instruct(PUSHACC5):
+ *--sp = accu; accu = sp[5]; Next;
+ Instruct(PUSHACC6):
+ *--sp = accu; accu = sp[6]; Next;
+ Instruct(PUSHACC7):
+ *--sp = accu; accu = sp[7]; Next;
+
+ Instruct(PUSHACC):
+ *--sp = accu;
+ /* Fallthrough */
+ Instruct(ACC):
+ accu = sp[*pc++];
+ Next;
+
+ Instruct(POP):
+ sp += *pc++;
+ Next;
+ Instruct(ASSIGN):
+ sp[*pc++] = accu;
+ Next;
+
+/* Access in heap-allocated environment */
+
+ Instruct(ENVACC0):
+ accu = Field(env, 0); Next;
+ Instruct(ENVACC1):
+ accu = Field(env, 1); Next;
+ Instruct(ENVACC2):
+ accu = Field(env, 2); Next;
+ Instruct(ENVACC3):
+ accu = Field(env, 3); Next;
+
+ Instruct(PUSHENVACC0):
+ *--sp = accu; accu = Field(env, 0); Next;
+ Instruct(PUSHENVACC1):
+ *--sp = accu; accu = Field(env, 1); Next;
+ Instruct(PUSHENVACC2):
+ *--sp = accu; accu = Field(env, 2); Next;
+ Instruct(PUSHENVACC3):
+ *--sp = accu; accu = Field(env, 3); Next;
+
+ Instruct(PUSHENVACC):
+ *--sp = accu;
+ /* Fallthrough */
+ Instruct(ENVACC):
+ accu = Field(env, *pc++);
+ Next;
+
+/* Function application */
+
+ Instruct(PUSH_RETADDR): {
+ sp -= 3;
+ sp[0] = (value) (pc + *pc);
+ sp[1] = env;
+ sp[2] = Val_long(extra_args);
+ pc++;
+ Next;
+ }
+ Instruct(APPLY): {
+ extra_args = *pc++ - 1;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ goto check_stacks;
+ }
+ Instruct(APPLY1): {
+ value arg1 = sp[0];
+ sp -= 3;
+ sp[0] = arg1;
+ sp[1] = (value)pc;
+ sp[2] = env;
+ sp[3] = Val_long(extra_args);
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args = 0;
+ goto check_stacks;
+ }
+ Instruct(APPLY2): {
+ value arg1 = sp[0];
+ value arg2 = sp[1];
+ sp -= 3;
+ sp[0] = arg1;
+ sp[1] = arg2;
+ sp[2] = (value)pc;
+ sp[3] = env;
+ sp[4] = Val_long(extra_args);
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args = 1;
+ goto check_stacks;
+ }
+ Instruct(APPLY3): {
+ value arg1 = sp[0];
+ value arg2 = sp[1];
+ value arg3 = sp[2];
+ sp -= 3;
+ sp[0] = arg1;
+ sp[1] = arg2;
+ sp[2] = arg3;
+ sp[3] = (value)pc;
+ sp[4] = env;
+ sp[5] = Val_long(extra_args);
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args = 2;
+ goto check_stacks;
+ }
+
+ Instruct(APPTERM): {
+ int nargs = *pc++;
+ int slotsize = *pc++;
+ value * newsp;
+ int i;
+ /* Slide the nargs bottom words of the current frame to the top
+ of the frame, and discard the remainder of the frame */
+ newsp = sp + slotsize - nargs;
+ for (i = nargs - 1; i >= 0; i--) newsp[i] = sp[i];
+ sp = newsp;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args += nargs - 1;
+ goto check_stacks;
+ }
+ Instruct(APPTERM1): {
+ value arg1 = sp[0];
+ sp = sp + *pc++ - 1;
+ sp[0] = arg1;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ goto check_stacks;
+ }
+ Instruct(APPTERM2): {
+ value arg1 = sp[0];
+ value arg2 = sp[1];
+ sp = sp + *pc++ - 2;
+ sp[0] = arg1;
+ sp[1] = arg2;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args += 1;
+ goto check_stacks;
+ }
+ Instruct(APPTERM3): {
+ value arg1 = sp[0];
+ value arg2 = sp[1];
+ value arg3 = sp[2];
+ sp = sp + *pc++ - 3;
+ sp[0] = arg1;
+ sp[1] = arg2;
+ sp[2] = arg3;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ extra_args += 2;
+ goto check_stacks;
+ }
+
+ Instruct(RETURN): {
+ sp += *pc++;
+ if (extra_args > 0) {
+ extra_args--;
+ pc = Code_val(accu);
+ env = Env_val(accu);
+ } else {
+ pc = (code_t)(sp[0]);
+ env = sp[1];
+ extra_args = Long_val(sp[2]);
+ sp += 3;
+ }
+ Next;
+ }
+
+ Instruct(RESTART): {
+ int num_args = Wosize_val(env) - 1;
+ int i;
+ sp -= num_args;
+ for (i = 0; i < num_args; i++) sp[i] = Field(env, i);
+ env = Field(env, num_args);
+ extra_args += num_args;
+ Next;
+ }
+
+ Instruct(GRAB): {
+ int required = *pc++;
+ if (extra_args >= required) {
+ extra_args -= required;
+ } else {
+ value clos;
+ mlsize_t num_args, i;
+ num_args = 1 + extra_args; /* arg1 + extra args */
+ Alloc_small(accu, num_args + 1, 0);
+ for (i = 0; i < num_args; i++) Field(accu, i) = sp[i];
+ Field(accu, num_args) = env;
+ sp += num_args;
+ Alloc_small(clos, Closure_wosize, Closure_tag);
+ Code_val(clos) = pc - 3; /* Point to the preceding RESTART instr. */
+ Env_val(clos) = accu;
+ pc = (code_t)(sp[0]);
+ env = sp[1];
+ extra_args = Long_val(sp[2]);
+ sp += 3;
+ accu = clos;
+ }
+ Next;
+ }
+
+ Instruct(CLOSURE): {
+ int nvars = *pc++;
+ value clos;
+ int i;
+ if (nvars == 0) {
+ accu = Val_int(0);
+ } else {
+ *--sp = accu;
+ Alloc_small(accu, nvars, 0);
+ for (i = 0; i < nvars; i++) Field(accu, i) = sp[i];
+ sp += nvars;
+ }
+ Alloc_small(clos, Closure_wosize, Closure_tag);
+ Code_val(clos) = pc + *pc;
+ Env_val(clos) = accu;
+ accu = clos;
+ pc++;
+ Next;
+ }
+
+ Instruct(CLOSUREREC): {
+ int nvars = *pc++;
+ value fun_clos, fun_env;
+ int i;
+ Alloc_small(fun_env, nvars + 1, 0);
+ Field(fun_env, 0) = Val_int(0);
+ if (nvars > 0) {
+ *--sp = accu;
+ for (i = 0; i < nvars; i++) Field(fun_env, i+1) = sp[i];
+ sp += nvars;
+ }
+ accu = fun_env;
+ Alloc_small(fun_clos, Closure_wosize, Closure_tag);
+ Code_val(fun_clos) = pc + *pc;
+ Env_val(fun_clos) = accu;
+ modify(&Field(accu, 0), fun_clos);
+ accu = fun_clos;
+ pc++;
+ Next;
+ }
+
+ Instruct(PUSHGETGLOBAL):
+ *--sp = accu;
+ /* Fallthrough */
+ Instruct(GETGLOBAL):
+ accu = Field(global_data, *pc);
+ pc++;
+ Next;
+
+ Instruct(PUSHGETGLOBALFIELD):
+ *--sp = accu;
+ /* Fallthrough */
+ Instruct(GETGLOBALFIELD): {
+ accu = Field(global_data, *pc);
+ pc++;
+ accu = Field(accu, *pc);
+ pc++;
+ Next;
+ }
+
+ Instruct(SETGLOBAL):
+ modify(&Field(global_data, *pc), accu);
+ accu = Val_unit;
+ pc++;
+ Next;
+
+/* Allocation of blocks */
+
+ Instruct(ATOM0):
+ accu = Atom(0); Next;
+ Instruct(ATOM1):
+ accu = Atom(1); Next;
+ Instruct(ATOM2):
+ accu = Atom(2); Next;
+ Instruct(ATOM3):
+ accu = Atom(3); Next;
+
+ Instruct(PUSHATOM0):
+ *--sp = accu; accu = Atom(0); Next;
+ Instruct(PUSHATOM1):
+ *--sp = accu; accu = Atom(1); Next;
+ Instruct(PUSHATOM2):
+ *--sp = accu; accu = Atom(2); Next;
+ Instruct(PUSHATOM3):
+ *--sp = accu; accu = Atom(3); Next;
+
+ Instruct(PUSHATOM):
+ *--sp = accu;
+ /* Fallthrough */
+ Instruct(ATOM):
+ accu = Atom(*pc);
+ pc++;
+ Next;
+
+ Instruct(MAKEBLOCK): {
+ mlsize_t wosize = *pc++;
+ tag_t tag = *pc++;
+ mlsize_t i;
+ value block;
+ Alloc_small(block, wosize, tag);
+ Field(block, 0) = accu;
+ for (i = 1; i < wosize; i++) Field(block, i) = *sp++;
+ accu = block;
+ Next;
+ }
+ Instruct(MAKEBLOCK1): {
+ tag_t tag = *pc++;
+ value block;
+ Alloc_small(block, 1, tag);
+ Field(block, 0) = accu;
+ accu = block;
+ Next;
+ }
+ Instruct(MAKEBLOCK2): {
+ tag_t tag = *pc++;
+ value block;
+ Alloc_small(block, 2, tag);
+ Field(block, 0) = accu;
+ Field(block, 1) = sp[0];
+ sp += 1;
+ accu = block;
+ Next;
+ }
+ Instruct(MAKEBLOCK3): {
+ tag_t tag = *pc++;
+ value block;
+ Alloc_small(block, 3, tag);
+ Field(block, 0) = accu;
+ Field(block, 1) = sp[0];
+ Field(block, 2) = sp[1];
+ sp += 2;
+ accu = block;
+ Next;
+ }
+
+/* Access to components of blocks */
+
+ Instruct(GETFIELD0):
+ accu = Field(accu, 0); Next;
+ Instruct(GETFIELD1):
+ accu = Field(accu, 1); Next;
+ Instruct(GETFIELD2):
+ accu = Field(accu, 2); Next;
+ Instruct(GETFIELD3):
+ accu = Field(accu, 3); Next;
+ Instruct(GETFIELD):
+ accu = Field(accu, *pc); pc++; Next;
+
+ Instruct(SETFIELD0):
+ modify_dest = &Field(accu, 0);
+ modify_newval = *sp++;
+ modify:
+ Modify(modify_dest, modify_newval);
+ accu = Val_unit;
+ Next;
+ Instruct(SETFIELD1):
+ modify_dest = &Field(accu, 1);
+ modify_newval = *sp++;
+ goto modify;
+ Instruct(SETFIELD2):
+ modify_dest = &Field(accu, 2);
+ modify_newval = *sp++;
+ goto modify;
+ Instruct(SETFIELD3):
+ modify_dest = &Field(accu, 3);
+ modify_newval = *sp++;
+ goto modify;
+ Instruct(SETFIELD):
+ modify_dest = &Field(accu, *pc);
+ pc++;
+ modify_newval = *sp++;
+ goto modify;
+
+ Instruct(TAGOF):
+ accu = Val_int(Tag_val(accu));
+ Next;
+
+/* For recursive definitions */
+
+ Instruct(DUMMY): {
+ int size = *pc++;
+ Alloc_small(accu, size, 0);
+ while (size--) Field(accu, size) = Val_long(0);
+ Next;
+ }
+ Instruct(UPDATE): {
+ value newval = *sp++;
+ mlsize_t size, n;
+ Tag_val(accu) = Tag_val(newval);
+ size = Wosize_val(newval);
+ for (n = 0; n < size; n++) {
+ modify(&Field(accu, n), Field(newval, n));
+ }
+ accu = Val_unit;
+ Next;
+ }
+
+/* Array operations */
+
+ Instruct(VECTLENGTH):
+ accu = Val_long(Wosize_val(accu));
+ Next;
+ Instruct(GETVECTITEM):
+ accu = Field(accu, Long_val(sp[0]));
+ sp += 1;
+ Next;
+ Instruct(SETVECTITEM):
+ modify_dest = &Field(accu, Long_val(sp[0]));
+ modify_newval = sp[1];
+ sp += 2;
+ goto modify;
+
+/* String operations */
+
+ Instruct(GETSTRINGCHAR):
+ accu = Val_int(Byte_u(accu, Long_val(sp[0])));
+ sp += 1;
+ Next;
+ Instruct(SETSTRINGCHAR):
+ Byte_u(accu, Long_val(sp[0])) = Int_val(sp[1]);
+ sp += 2;
+ Next;
+
+/* Branches and conditional branches */
+
+ Instruct(BRANCH):
+ pc += *pc;
+ Next;
+ Instruct(BRANCHIF):
+ if (Tag_val(accu) != 0) pc += *pc; else pc++;
+ Next;
+ Instruct(BRANCHIFNOT):
+ if (Tag_val(accu) == 0) pc += *pc; else pc++;
+ Next;
+ Instruct(SWITCH): {
+ long index = Long_val(accu);
+ Assert(index >= 0 && index < *pc);
+ pc++;
+ pc += pc[index];
+ Next;
+ }
+ Instruct(TRANSLATE): {
+ long arg = Long_val(accu);
+ int num_cases = *pc++;
+ int low, high, i;
+ uint32 interv;
+ for (low = 0, high = num_cases - 1, accu = Val_int(0);
+ low <= high;
+ /*nothing*/) {
+ i = (low + high) / 2;
+ interv = pc[i];
+ if (arg < (interv & 0xFF))
+ high = i - 1;
+ else if (arg > ((interv >> 8) & 0xFF))
+ low = i + 1;
+ else {
+ accu = Val_long(arg + (interv >> 16) - (interv & 0xFF));
+ break;
+ }
+ }
+ pc += num_cases;
+ Next;
+ }
+ Instruct(BOOLNOT):
+ accu = Atom(Tag_val(accu) == 0);
+ Next;
+
+/* Exceptions */
+
+ Instruct(PUSHTRAP):
+ sp -= 4;
+ Trap_pc(sp) = pc + *pc;
+ Trap_link(sp) = trapsp;
+ sp[2] = env;
+ sp[3] = Val_long(extra_args);
+ trapsp = sp;
+ pc++;
+ Next;
+
+ Instruct(POPTRAP):
+ /* We should check here if a signal is pending, to preserve the
+ semantics of the program w.r.t. exceptions. Unfortunately,
+ process_signal destroys the accumulator, and there is no
+ convenient way to preserve it... */
+ trapsp = Trap_link(sp);
+ sp += 4;
+ Next;
+
+ Instruct(RAISE): /* arg */
+ raise_exception:
+ sp = trapsp;
+ if (sp >= stack_high - initial_sp_offset) {
+ exn_bucket = accu;
+ external_raise = initial_external_raise;
+ longjmp(external_raise->buf, 1);
+ }
+ pc = Trap_pc(sp);
+ trapsp = Trap_link(sp);
+ env = sp[2];
+ extra_args = Long_val(sp[3]);
+ sp += 4;
+ Next;
+
+/* Stack checks */
+
+ check_stacks:
+ if (sp < stack_threshold) {
+ extern_sp = sp;
+ realloc_stack();
+ sp = extern_sp;
+ }
+ /* Fall through CHECK_SIGNALS */
+
+/* Signal handling */
+
+ Instruct(CHECK_SIGNALS): /* accu not preserved */
+ if (something_to_do) goto process_signal;
+ Next;
+
+ process_signal:
+ something_to_do = 0;
+ if (force_minor_flag){
+ force_minor_flag = 0;
+ Setup_for_gc;
+ minor_collection ();
+ Restore_after_gc;
+ }
+ /* If a signal arrives between the following two instructions,
+ it will be lost. */
+ { int signal_number = pending_signal;
+ pending_signal = 0;
+ if (signal_number) {
+ /* Push a return frame to the current code location */
+ sp -= 4;
+ sp[0] = (value) pc;
+ sp[1] = env;
+ sp[2] = Val_long(extra_args);
+ sp[3] = Val_int(signal_number);
+ pc = Code_val(Field(signal_handlers, signal_number));
+ env = Env_val(Field(signal_handlers, signal_number));
+ extra_args = 0;
+ }
+ }
+ Next;
+
+/* Calling C functions */
+
+ Instruct(C_CALL1):
+ Setup_for_c_call;
+ accu = cprim[*pc](accu);
+ Restore_after_c_call;
+ pc++;
+ Next;
+ Instruct(C_CALL2):
+ Setup_for_c_call;
+ accu = cprim[*pc](accu, sp[1]);
+ Restore_after_c_call;
+ sp += 1;
+ pc++;
+ Next;
+ Instruct(C_CALL3):
+ Setup_for_c_call;
+ accu = cprim[*pc](accu, sp[1], sp[2]);
+ Restore_after_c_call;
+ sp += 2;
+ pc++;
+ Next;
+ Instruct(C_CALL4):
+ Setup_for_c_call;
+ accu = cprim[*pc](accu, sp[1], sp[2], sp[3]);
+ Restore_after_c_call;
+ sp += 3;
+ pc++;
+ Next;
+ Instruct(C_CALLN): {
+ int nargs = *pc++;
+ *--sp = accu;
+ Setup_for_c_call;
+ accu = cprim[*pc](sp + 1, nargs);
+ Restore_after_c_call;
+ sp += nargs;
+ pc++;
+ Next;
+ }
+
+/* Integer arithmetic */
+
+ Instruct(CONSTINT):
+ accu = Val_int(*pc);
+ pc++;
+ Next;
+ Instruct(PUSHCONSTINT):
+ *--sp = accu;
+ accu = Val_int(*pc);
+ pc++;
+ Next;
+ Instruct(NEGINT):
+ accu = (value)(2 - (long)accu); Next;
+ Instruct(ADDINT):
+ accu = (value)((long) accu + (long) *sp++ - 1); Next;
+ Instruct(SUBINT):
+ accu = (value)((long) accu - (long) *sp++ + 1); Next;
+ Instruct(MULINT):
+ accu = Val_long(Long_val(accu) * Long_val(*sp++)); Next;
+ Instruct(DIVINT): {
+ value div = *sp++;
+ if (div == Val_long(0)) {
+ accu = Field(global_data, ZERO_DIVIDE_EXN);
+ goto raise_exception;
+ }
+ accu = Val_long(Long_val(accu) / Long_val(div));
+ Next;
+ }
+ Instruct(MODINT): {
+ value div = *sp++;
+ if (div == Val_long(0)) {
+ accu = Field(global_data, ZERO_DIVIDE_EXN);
+ goto raise_exception;
+ }
+ accu = Val_long(Long_val(accu) % Long_val(div));
+ Next;
+ }
+ Instruct(ANDINT):
+ accu = (value)((long) accu & (long) *sp++); Next;
+ Instruct(ORINT):
+ accu = (value)((long) accu | (long) *sp++); Next;
+ Instruct(XORINT):
+ accu = (value)(((long) accu ^ (long) *sp++) | 1); Next;
+ Instruct(LSLINT):
+ accu = (value)((((long) accu - 1) << Long_val(*sp++)) + 1); Next;
+ Instruct(LSRINT):
+ accu = (value)((((long) accu - 1) >> Long_val(*sp++)) | 1); Next;
+ Instruct(ASRINT):
+ accu = (value)((((unsigned long) accu - 1) >> Long_val(*sp++)) | 1);
+ Next;
+
+#define Integer_comparison(opname,tst) \
+ Instruct(opname): \
+ accu = Atom((long) accu tst (long) *sp++); Next;
+
+ Integer_comparison(EQ, ==)
+ Integer_comparison(NEQ, !=)
+ Integer_comparison(LTINT, <)
+ Integer_comparison(LEINT, <=)
+ Integer_comparison(GTINT, >)
+ Integer_comparison(GEINT, >=)
+
+ Instruct(OFFSETINT):
+ accu += *pc << 1;
+ pc++;
+ Next;
+ Instruct(OFFSETREF):
+ Field(accu, 0) += *pc << 1;
+ pc++;
+ Next;
+
+/* Machine control */
+
+ Instruct(STOP):
+ external_raise = initial_external_raise;
+ extern_sp = sp;
+ return accu;
+
+#ifndef THREADED_CODE
+ default:
+ fatal_error("bad opcode");
+ }
+ }
+#endif
+}
+
+static opcode_t callback_code[] = {
+ ACC1, APPLY1, POP, 1, STOP
+};
+
+value callback(closure, argument)
+ value closure, argument;
+{
+ extern_sp -= 2;
+ extern_sp[0] = argument;
+ extern_sp[1] = closure;
+ return interprete(callback_code, sizeof(callback_code));
+}
diff --git a/byterun/interp.h b/byterun/interp.h
new file mode 100644
index 0000000000..e652331d8a
--- /dev/null
+++ b/byterun/interp.h
@@ -0,0 +1,14 @@
+/* The bytecode interpreter */
+
+#ifndef _interp_
+#define _interp_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+value interprete P((code_t prog, asize_t prog_size));
+value callback P((value closure, value argument));
+
+
+#endif _interp_
diff --git a/byterun/intext.h b/byterun/intext.h
new file mode 100644
index 0000000000..7b1a26c414
--- /dev/null
+++ b/byterun/intext.h
@@ -0,0 +1,54 @@
+/* Structured input/output */
+
+#ifndef __intext__
+#define __intext__
+
+#include "misc.h"
+#include "mlvalues.h"
+#include "io.h"
+
+/* Magic number */
+
+#define Base_magic_number 0x8495A6B9
+#define Compact_magic_number (Base_magic_number + 4)
+
+/* Codes for the compact format */
+
+#define PREFIX_SMALL_BLOCK 0x80
+#define PREFIX_SMALL_INT 0x40
+#define PREFIX_SMALL_STRING 0x20
+#define CODE_INT8 0x0
+#define CODE_INT16 0x1
+#define CODE_INT32 0x2
+#define CODE_INT64 0x3
+#define CODE_SHARED8 0x4
+#define CODE_SHARED16 0x5
+#define CODE_SHARED32 0x6
+#define CODE_BLOCK32 0x8
+#define CODE_STRING8 0x9
+#define CODE_STRING32 0xA
+#define CODE_DOUBLE_BIG 0xB
+#define CODE_DOUBLE_LITTLE 0xC
+#ifdef BIG_ENDIAN
+#define CODE_DOUBLE_NATIVE CODE_DOUBLE_BIG
+#else
+#define CODE_DOUBLE_NATIVE CODE_DOUBLE_LITTLE
+#endif
+
+/* Initial sizes of data structures for extern */
+
+#ifndef INITIAL_EXTERN_SIZE
+#define INITIAL_EXTERN_SIZE 4096
+#endif
+#ifndef INITIAL_EXTERN_TABLE_SIZE
+#define INITIAL_EXTERN_TABLE_SIZE 2039
+#endif
+
+/* The entry points */
+
+value output_value P((struct channel *, value));
+value input_value P((struct channel *));
+
+
+#endif
+
diff --git a/byterun/ints.c b/byterun/ints.c
new file mode 100644
index 0000000000..4a4f767225
--- /dev/null
+++ b/byterun/ints.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include "alloc.h"
+#include "fail.h"
+#include "memory.h"
+#include "mlvalues.h"
+
+value int_of_string(s) /* ML */
+ value s;
+{
+ long res;
+ int sign;
+ int base;
+ char * p;
+ int c, d;
+
+ p = String_val(s);
+ if (*p == 0) failwith("int_of_string");
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ }
+ base = 10;
+ if (*p == '0') {
+ switch (p[1]) {
+ case 'x': case 'X':
+ base = 16; p += 2; break;
+ case 'o': case 'O':
+ base = 8; p += 2; break;
+ case 'b': case 'B':
+ base = 2; p += 2; break;
+ }
+ }
+ res = 0;
+ while (1) {
+ c = *p;
+ if (c >= '0' && c <= '9')
+ d = c - '0';
+ else if (c >= 'A' && c <= 'F')
+ d = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ d = c - 'a' + 10;
+ else
+ break;
+ if (d >= base) break;
+ res = base * res + d;
+ p++;
+ }
+ if (*p != 0)
+ failwith("int_of_string");
+ return Val_long(sign < 0 ? -res : res);
+}
+
+value format_int(fmt, arg) /* ML */
+ value fmt, arg;
+{
+ char format_buffer[32];
+ int prec;
+ char * p;
+ char * dest;
+ value res;
+
+ prec = 32;
+ for (p = String_val(fmt); *p != 0; p++) {
+ if (*p >= '0' && *p <= '9') {
+ prec = atoi(p) + 5;
+ break;
+ }
+ }
+ if (prec <= sizeof(format_buffer)) {
+ dest = format_buffer;
+ } else {
+ dest = stat_alloc(prec);
+ }
+ sprintf(dest, String_val(fmt), Long_val(arg));
+ res = copy_string(dest);
+ if (dest != format_buffer) {
+ stat_free(dest);
+ }
+ return res;
+}
diff --git a/byterun/io.c b/byterun/io.c
new file mode 100644
index 0000000000..67bc961f78
--- /dev/null
+++ b/byterun/io.c
@@ -0,0 +1,393 @@
+/* Buffered input/output. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include "alloc.h"
+#include "fail.h"
+#include "io.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "signals.h"
+#include "sys.h"
+#ifdef HAS_UI
+#include "ui.h"
+#endif
+
+/* Common functions. */
+
+struct channel * open_descr(fd)
+ int fd;
+{
+ struct channel * channel;
+
+ channel = (struct channel *) stat_alloc(sizeof(struct channel));
+ channel->fd = fd;
+ channel->offset = 0;
+ channel->curr = channel->max = channel->buff;
+ channel->end = channel->buff + IO_BUFFER_SIZE;
+ return channel;
+}
+
+value open_descriptor(fd) /* ML */
+ value fd;
+{
+ return (value) open_descr(Int_val(fd));
+}
+
+value channel_descriptor(channel) /* ML */
+ struct channel * channel;
+{
+ return Val_long(channel->fd);
+}
+
+value channel_size(channel) /* ML */
+ struct channel * channel;
+{
+ long end;
+
+ end = lseek(channel->fd, 0, 2);
+ if (end == -1) sys_error(NULL);
+ if (lseek(channel->fd, channel->offset, 0) != channel->offset)
+ sys_error(NULL);
+ return Val_long(end);
+}
+
+/* Output */
+
+static void really_write(fd, p, n)
+ int fd;
+ char * p;
+ int n;
+{
+ int retcode;
+ while (n > 0) {
+#ifdef HAS_UI
+ retcode = ui_write(fd, p, n);
+#else
+#ifdef EINTR
+ do { retcode = write(fd, p, n); } while (retcode == -1 && errno == EINTR);
+#else
+ retcode = write(fd, p, n);
+#endif
+#endif
+ if (retcode == -1) sys_error(NULL);
+ p += retcode;
+ n -= retcode;
+ }
+}
+
+value flush(channel) /* ML */
+ struct channel * channel;
+{
+ int n;
+ n = channel->max - channel->buff;
+ if (n > 0) {
+ really_write(channel->fd, channel->buff, n);
+ channel->offset += n;
+ channel->curr = channel->buff;
+ channel->max = channel->buff;
+ }
+ return Atom(0);
+}
+
+value output_char(channel, ch) /* ML */
+ struct channel * channel;
+ value ch;
+{
+ putch(channel, Long_val(ch));
+ return Atom(0);
+}
+
+void putword(channel, w)
+ struct channel * channel;
+ uint32 w;
+{
+ putch(channel, w >> 24);
+ putch(channel, w >> 16);
+ putch(channel, w >> 8);
+ putch(channel, w);
+}
+
+value output_int(channel, w) /* ML */
+ struct channel * channel;
+ value w;
+{
+ putword(channel, Long_val(w));
+ return Atom(0);
+}
+
+void putblock(channel, p, n)
+ struct channel * channel;
+ char * p;
+ unsigned n;
+{
+ unsigned m;
+
+ m = channel->end - channel->curr;
+ if (channel->curr == channel->buff && n >= m) {
+ really_write(channel->fd, p, n);
+ channel->offset += n;
+ } else if (n <= m) {
+ bcopy(p, channel->curr, n);
+ channel->curr += n;
+ if (channel->curr > channel->max) channel->max = channel->curr;
+ } else {
+ bcopy(p, channel->curr, m);
+ p += m;
+ n -= m;
+ m = channel->end - channel->buff;
+ really_write(channel->fd, channel->buff, m);
+ channel->offset += m;
+ if (n <= m) {
+ bcopy(p, channel->buff, n);
+ channel->curr = channel->max = channel->buff + n;
+ } else {
+ really_write(channel->fd, p, n);
+ channel->offset += n;
+ channel->curr = channel->max = channel->buff;
+ }
+ }
+}
+
+value output(channel, buff, start, length) /* ML */
+ value channel, buff, start, length;
+{
+ putblock((struct channel *) channel,
+ &Byte(buff, Long_val(start)),
+ (unsigned) Long_val(length));
+ return Atom(0);
+}
+
+value seek_out(channel, pos) /* ML */
+ struct channel * channel;
+ value pos;
+{
+ long dest;
+
+ dest = Long_val(pos);
+ if (dest >= channel->offset &&
+ dest <= channel->offset + channel->max - channel->buff) {
+ channel->curr = channel->buff + dest - channel->offset;
+ } else {
+ flush(channel);
+ if (lseek(channel->fd, dest, 0) != dest) sys_error(NULL);
+ channel->offset = dest;
+ }
+ return Atom(0);
+}
+
+value pos_out(channel) /* ML */
+ struct channel * channel;
+{
+ return Val_long(channel->offset + channel->curr - channel->buff);
+}
+
+value close_out(channel) /* ML */
+ struct channel * channel;
+{
+ flush(channel);
+ close(channel->fd);
+ stat_free((char *) channel);
+ return Atom(0);
+}
+
+/* Input */
+
+static int really_read(fd, p, n)
+ int fd;
+ char * p;
+ unsigned n;
+{
+ int retcode;
+
+ enter_blocking_section();
+#ifdef HAS_UI
+ retcode = ui_read(fd, p, n);
+#else
+#ifdef EINTR
+ do { retcode = read(fd, p, n); } while (retcode == -1 && errno == EINTR);
+#else
+ retcode = read(fd, p, n);
+#endif
+#endif
+ leave_blocking_section();
+ if (retcode == -1) sys_error(NULL);
+ return retcode;
+}
+
+unsigned char refill(channel)
+ struct channel * channel;
+{
+ int n;
+
+ n = really_read(channel->fd, channel->buff, IO_BUFFER_SIZE);
+ if (n == 0) raise_end_of_file();
+ channel->offset += n;
+ channel->max = channel->buff + n;
+ channel->curr = channel->buff + 1;
+ return (unsigned char)(channel->buff[0]);
+}
+
+value input_char(channel) /* ML */
+ struct channel * channel;
+{
+ unsigned char c;
+ c = getch(channel);
+ return Val_long(c);
+}
+
+uint32 getword(channel)
+ struct channel * channel;
+{
+ int i;
+ uint32 res;
+
+ res = 0;
+ for(i = 0; i < 4; i++) {
+ res = (res << 8) + getch(channel);
+ }
+ return res;
+}
+
+value input_int(channel) /* ML */
+ struct channel * channel;
+{
+ long i;
+ i = getword(channel);
+#ifdef SIXTYFOUR
+ i = (i << 32) >> 32; /* Force sign extension */
+#endif
+ return Val_long(i);
+}
+
+unsigned getblock(channel, p, n)
+ struct channel * channel;
+ char * p;
+ unsigned n;
+{
+ unsigned m, l;
+
+ m = channel->max - channel->curr;
+ if (n <= m) {
+ bcopy(channel->curr, p, n);
+ channel->curr += n;
+ return n;
+ } else if (m > 0) {
+ bcopy(channel->curr, p, m);
+ channel->curr += m;
+ return m;
+ } else if (n < IO_BUFFER_SIZE) {
+ l = really_read(channel->fd, channel->buff, IO_BUFFER_SIZE);
+ channel->offset += l;
+ channel->max = channel->buff + l;
+ if (n > l) n = l;
+ bcopy(channel->buff, p, n);
+ channel->curr = channel->buff + n;
+ return n;
+ } else {
+ channel->curr = channel->buff;
+ channel->max = channel->buff;
+ l = really_read(channel->fd, p, n);
+ channel->offset += l;
+ return l;
+ }
+}
+
+int really_getblock(chan, p, n)
+ struct channel * chan;
+ char * p;
+ unsigned long n;
+{
+ unsigned r;
+ while (n > 0) {
+ r = getblock(chan, p, (unsigned) n);
+ if (r == 0) return 0;
+ p += r;
+ n -= r;
+ }
+ return 1;
+}
+
+value input(channel, buff, start, length) /* ML */
+ value channel, buff, start, length;
+{
+ return Val_long(getblock((struct channel *) channel,
+ &Byte(buff, Long_val(start)),
+ (unsigned) Long_val(length)));
+}
+
+value seek_in(channel, pos) /* ML */
+ struct channel * channel;
+ value pos;
+{
+ long dest;
+
+ dest = Long_val(pos);
+ if (dest >= channel->offset - (channel->max - channel->buff) &&
+ dest <= channel->offset) {
+ channel->curr = channel->max - (channel->offset - dest);
+ } else {
+ if (lseek(channel->fd, dest, 0) != dest) sys_error(NULL);
+ channel->offset = dest;
+ channel->curr = channel->max = channel->buff;
+ }
+ return Atom(0);
+}
+
+value pos_in(channel) /* ML */
+ struct channel * channel;
+{
+ return Val_long(channel->offset - (channel->max - channel->curr));
+}
+
+value close_in(channel) /* ML */
+ struct channel * channel;
+{
+ close(channel->fd);
+ stat_free((char *) channel);
+ return Atom(0);
+}
+
+value input_scan_line(channel) /* ML */
+ struct channel * channel;
+{
+ char * p;
+ int n;
+
+ p = channel->curr;
+ do {
+ if (p >= channel->max) {
+ /* No more characters available in the buffer */
+ if (channel->curr > channel->buff) {
+ /* Try to make some room in the buffer by shifting the unread
+ portion at the beginning */
+ bcopy(channel->curr, channel->buff, channel->max - channel->curr);
+ n = channel->curr - channel->buff;
+ channel->curr -= n;
+ channel->max -= n;
+ p -= n;
+ }
+ if (channel->max >= channel->end) {
+ /* Buffer is full, no room to read more characters from the input.
+ Return the number of characters in the buffer, with negative
+ sign to indicate that no newline was encountered. */
+ return Val_long(-(channel->max - channel->curr));
+ }
+ /* Fill the buffer as much as possible */
+ n = really_read(channel->fd, channel->max, channel->end - channel->max);
+ if (n == 0) {
+ /* End-of-file encountered. Return the number of characters in the
+ buffer, with negative sign since we haven't encountered
+ a newline. */
+ return Val_long(-(channel->max - channel->curr));
+ }
+ channel->offset += n;
+ channel->max += n;
+ }
+ } while (*p++ != '\n');
+ /* Found a newline. Return the length of the line, newline included. */
+ return Val_long(p - channel->curr);
+}
diff --git a/byterun/io.h b/byterun/io.h
new file mode 100644
index 0000000000..d679886cbc
--- /dev/null
+++ b/byterun/io.h
@@ -0,0 +1,52 @@
+/* Buffered input/output */
+
+#ifndef _io_
+#define _io_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+#ifndef IO_BUFFER_SIZE
+#define IO_BUFFER_SIZE 4096
+#endif
+
+struct channel {
+ int fd; /* Unix file descriptor */
+ long offset; /* Absolute position of fd in the file */
+ char * curr; /* Current position in the buffer */
+ char * max; /* Logical end of the buffer */
+ char * end; /* Physical end of the buffer */
+ char buff[IO_BUFFER_SIZE]; /* The buffer itself */
+};
+
+/* For an output channel:
+ [offset] is the absolute position of the beginning of the buffer [buff].
+ For an input channel:
+ [offset] is the absolute position of the logical end of the buffer [max].
+*/
+
+#define putch(channel, ch) \
+ { if ((channel)->curr >= (channel)->end) flush(channel); \
+ *((channel)->curr)++ = (ch); \
+ if ((channel)->curr > (channel)->max) (channel)->max = (channel)->curr; }
+
+#define getch(channel) \
+ ((channel)->curr >= (channel)->max \
+ ? refill(channel) \
+ : (unsigned char) *((channel))->curr++)
+
+struct channel * open_descr P((int));
+value flush P((struct channel *));
+void putword P((struct channel *, uint32));
+void putblock P((struct channel *, char *, unsigned));
+unsigned char refill P((struct channel *));
+value pos_out P((struct channel *));
+value seek_out P((struct channel *, value));
+uint32 getword P((struct channel *));
+unsigned getblock P((struct channel *, char *, unsigned));
+int really_getblock P((struct channel *, char *, unsigned long));
+value close_in P((struct channel *));
+
+
+#endif /* _io_ */
diff --git a/byterun/main.c b/byterun/main.c
new file mode 100644
index 0000000000..f91ada34c2
--- /dev/null
+++ b/byterun/main.c
@@ -0,0 +1,229 @@
+/* Start-up code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "alloc.h"
+#include "exec.h"
+#include "fail.h"
+#include "gc_ctrl.h"
+#include "interp.h"
+#include "intext.h"
+#include "io.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "stacks.h"
+#include "sys.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+header_t first_atoms[256];
+code_t start_code;
+asize_t code_size;
+
+static void init_atoms()
+{
+ int i;
+ for(i = 0; i < 256; i++) first_atoms[i] = Make_header(0, i, White);
+}
+
+static unsigned long read_size(p)
+ unsigned char * p;
+{
+ return ((unsigned long) p[0] << 24) + ((unsigned long) p[1] << 16) +
+ ((unsigned long) p[2] << 8) + p[3];
+}
+
+#define FILE_NOT_FOUND (-1)
+#define TRUNCATED_FILE (-2)
+#define BAD_MAGIC_NUM (-3)
+
+static int read_trailer(fd, trail)
+ int fd;
+ struct exec_trailer * trail;
+{
+ char buffer[TRAILER_SIZE];
+
+ lseek(fd, (long) -TRAILER_SIZE, 2);
+ if (read(fd, buffer, TRAILER_SIZE) < TRAILER_SIZE) return TRUNCATED_FILE;
+ trail->code_size = read_size(buffer);
+ trail->data_size = read_size(buffer+4);
+ trail->symbol_size = read_size(buffer+8);
+ trail->debug_size = read_size(buffer+12);
+ if (strncmp(buffer + 16, EXEC_MAGIC, 12) == 0)
+ return 0;
+ else
+ return BAD_MAGIC_NUM;
+}
+
+extern char * searchpath();
+
+int attempt_open(name, trail, do_open_script)
+ char ** name;
+ struct exec_trailer * trail;
+ int do_open_script;
+{
+ char * truename;
+ int fd;
+ int err;
+ char buf [2];
+
+ truename = searchpath(*name);
+ if (truename == 0) truename = *name; else *name = truename;
+ fd = open(truename, O_RDONLY | O_BINARY);
+ if (fd == -1) return FILE_NOT_FOUND;
+ if (!do_open_script){
+ err = read (fd, buf, 2);
+ if (err < 2) return TRUNCATED_FILE;
+ if (buf [0] == '#' && buf [1] == '!') return BAD_MAGIC_NUM;
+ }
+ err = read_trailer(fd, trail);
+ if (err != 0) { close(fd); return err; }
+ return fd;
+}
+
+/* Invocation of camlrun: 4 cases.
+
+ 1. runtime + bytecode
+ user types: camlrun [options] bytecode args...
+ arguments: camlrun [options] bytecode args...
+
+ 2. bytecode script
+ user types: bytecode args...
+ 2a (kernel 1) arguments: camlrun ./bytecode args...
+ 2b (kernel 2) arguments: bytecode bytecode args...
+
+ 3. concatenated runtime and bytecode
+ user types: composite args...
+ arguments: composite args...
+
+Algorithm:
+ 1- If argument 0 is a valid byte-code file that does not start with #!,
+ then we are in case 3 and we pass the same command line to the
+ Caml Light program.
+ 2- In all other cases, we parse the command line as:
+ (whatever) [options] bytecode args...
+ and we strip "(whatever) [options]" from the command line.
+
+*/
+
+#ifdef HAS_UI
+int caml_main(argc, argv)
+#else
+int main(argc, argv)
+#endif
+ int argc;
+ char * argv[];
+{
+ int fd;
+ struct exec_trailer trail;
+ int i;
+ struct longjmp_buffer raise_buf;
+ struct channel * chan;
+ int verbose_init = 0, percent_free_init = Percent_free_def;
+ long minor_heap_init = Minor_heap_def, heap_chunk_init = Heap_chunk_def;
+
+#ifdef DEBUG
+ verbose_init = 1;
+#endif
+
+ i = 0;
+ fd = attempt_open(&argv[0], &trail, 0);
+
+ if (fd < 0) {
+
+ for(i = 1; i < argc && argv[i][0] == '-'; i++) {
+ switch(argv[i][1]) {
+#ifdef DEBUG
+ case 't': {
+ extern int trace_flag;
+ trace_flag = 1;
+ break;
+ }
+#endif
+ case 'v':
+ verbose_init = 1;
+ break;
+ case 'V':
+ fprintf(stderr, "The Caml 1999 runtime system, version %s\n",
+ "1");
+ exit(0);
+ default:
+ fatal_error_arg("Unknown option %s.\n", argv[i]);
+ }
+ }
+
+ if (argv[i] == 0)
+ fatal_error("No bytecode file specified.\n");
+
+ fd = attempt_open(&argv[i], &trail, 1);
+
+ switch(fd) {
+ case FILE_NOT_FOUND:
+ fatal_error_arg("Fatal error: cannot find file %s\n", argv[i]);
+ break;
+ case TRUNCATED_FILE:
+ case BAD_MAGIC_NUM:
+ fatal_error_arg(
+ "Fatal error: the file %s is not a bytecode executable file\n",
+ argv[i]);
+ break;
+ }
+ }
+
+ /* Runtime options. The option letter is the first letter of the
+ last word of the ML name of the option (see [lib/gc.mli]). */
+
+ { char *opt = getenv ("CAMLRUNPARAM");
+ if (opt != NULL){
+ while (*opt != '\0'){
+ switch (*opt++){
+ case 's': sscanf (opt, "=%ld", &minor_heap_init); break;
+ case 'i': sscanf (opt, "=%ld", &heap_chunk_init); break;
+ case 'o': sscanf (opt, "=%d", &percent_free_init); break;
+ case 'v': sscanf (opt, "=%d", &verbose_init); break;
+ }
+ }
+ }
+ }
+
+ if (setjmp(raise_buf.buf) == 0) {
+
+ external_raise = &raise_buf;
+
+ init_gc (minor_heap_init, heap_chunk_init, percent_free_init,
+ verbose_init);
+ init_stack();
+ init_atoms();
+
+ lseek(fd, - (long) (TRAILER_SIZE + trail.code_size + trail.data_size
+ + trail.symbol_size + trail.debug_size), 2);
+
+ code_size = trail.code_size;
+ start_code = (code_t) stat_alloc(code_size);
+ if (read(fd, (char *) start_code, code_size) != code_size)
+ fatal_error("Fatal error: truncated bytecode file.\n");
+
+#ifdef BIG_ENDIAN
+ fixup_endianness(start_code, code_size);
+#endif
+
+ chan = open_descr(fd);
+ global_data = input_value(chan);
+ close_in(chan);
+
+ sys_init(argv + i);
+ interprete(start_code, code_size);
+ sys_exit(Val_int(0));
+
+ } else {
+
+ fatal_error_arg("Fatal error: uncaught exception %s.\n",
+ String_val(Field(Field(exn_bucket, 0), 0)));
+ }
+}
+
diff --git a/byterun/major_gc.c b/byterun/major_gc.c
new file mode 100644
index 0000000000..11dd32b790
--- /dev/null
+++ b/byterun/major_gc.c
@@ -0,0 +1,305 @@
+#include "config.h"
+#include "fail.h"
+#include "freelist.h"
+#include "gc.h"
+#include "gc_ctrl.h"
+#include "major_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "roots.h"
+
+#ifdef __STDC__
+#include <limits.h>
+#else
+#ifdef SIXTYFOUR
+#define LONG_MAX 0x7FFFFFFFFFFFFFFF
+#else
+#define LONG_MAX 0x7FFFFFFF
+#endif
+#endif
+
+int percent_free;
+long major_heap_increment;
+char *heap_start, *heap_end;
+char *page_table;
+asize_t page_table_size;
+char *gc_sweep_hp;
+int gc_phase;
+static value *gray_vals;
+value *gray_vals_cur, *gray_vals_end;
+static asize_t gray_vals_size;
+static int heap_is_pure; /* The heap is pure if the only gray objects
+ below [markhp] are also in [gray_vals]. */
+unsigned long allocated_words;
+unsigned long extra_heap_memory;
+extern char *fl_merge; /* Defined in freelist.c. */
+
+static char *markhp, *chunk, *limit;
+
+static void realloc_gray_vals ()
+{
+ value *new;
+
+ Assert (gray_vals_cur == gray_vals_end);
+ if (gray_vals_size < stat_heap_size / 128){
+ gc_message ("Growing gray_vals to %ldk\n",
+ (long) gray_vals_size * sizeof (value) / 512);
+ new = (value *) realloc ((char *) gray_vals,
+ 2 * gray_vals_size * sizeof (value));
+ if (new == NULL){
+ gc_message ("No room for growing gray_vals\n", 0);
+ gray_vals_cur = gray_vals;
+ heap_is_pure = 0;
+ }else{
+ gray_vals = new;
+ gray_vals_cur = gray_vals + gray_vals_size;
+ gray_vals_size *= 2;
+ gray_vals_end = gray_vals + gray_vals_size;
+ }
+ }else{
+ gray_vals_cur = gray_vals + gray_vals_size / 2;
+ heap_is_pure = 0;
+ }
+}
+
+void darken (v)
+ value v;
+{
+ if (Is_block (v) && Is_in_heap (v) && Is_white_val (v)){
+ Hd_val (v) = Grayhd_hd (Hd_val (v));
+ *gray_vals_cur++ = v;
+ if (gray_vals_cur >= gray_vals_end) realloc_gray_vals ();
+ }
+}
+
+static void darken_root (p, v)
+ value *p;
+ value v;
+{
+ darken (v);
+}
+
+static void start_cycle ()
+{
+ Assert (gray_vals_cur == gray_vals);
+ Assert (Is_white_val (global_data));
+ darken (global_data);
+ scan_local_roots (darken_root);
+ gc_phase = Phase_mark;
+ markhp = NULL;
+}
+
+static void mark_slice (work)
+ long work;
+{
+ value v, child;
+ mlsize_t i;
+
+ while (work > 0){
+ if (gray_vals_cur > gray_vals){
+ v = *--gray_vals_cur;
+ Assert (Is_gray_val (v));
+ Hd_val (v) = Blackhd_hd (Hd_val (v));
+ if (Tag_val (v) < No_scan_tag){
+ for (i = Wosize_val (v); i > 0;){
+ --i;
+ child = Field (v, i);
+ darken (child);
+ }
+ }
+ work -= Whsize_val (v);
+ }else if (markhp != NULL){
+ if (markhp == limit){
+ chunk = (((heap_chunk_head *) chunk) [-1]).next;
+ if (chunk == NULL){
+ markhp = NULL;
+ }else{
+ markhp = chunk;
+ limit = chunk + (((heap_chunk_head *) chunk) [-1]).size;
+ }
+ }else{
+ if (Is_gray_val (Val_hp (markhp))){
+ Assert (gray_vals_cur == gray_vals);
+ *gray_vals_cur++ = Val_hp (markhp);
+ }
+ markhp += Bhsize_hp (markhp);
+ }
+ }else if (!heap_is_pure){
+ heap_is_pure = 1;
+ chunk = heap_start;
+ markhp = chunk;
+ limit = chunk + (((heap_chunk_head *) chunk) [-1]).size;
+ }else{
+ /* Marking is done. */
+ gc_sweep_hp = heap_start;
+ fl_init_merge ();
+ gc_phase = Phase_sweep;
+ chunk = heap_start;
+ gc_sweep_hp = chunk;
+ limit = chunk + (((heap_chunk_head *) chunk) [-1]).size;
+ work = 0;
+ }
+ }
+}
+
+static void sweep_slice (work)
+ long work;
+{
+ char *hp;
+ header_t hd;
+
+ while (work > 0){
+ if (gc_sweep_hp < limit){
+ hp = gc_sweep_hp;
+ hd = Hd_hp (hp);
+ work -= Whsize_hd (hd);
+ gc_sweep_hp += Bhsize_hd (hd);
+ switch (Color_hd (hd)){
+ case White:
+ if (Tag_hd (hd) == Final_tag){
+ Final_fun (Val_hp (hp)) (Val_hp (hp));
+ }
+ gc_sweep_hp = fl_merge_block (Bp_hp (hp));
+ break;
+ case Gray:
+ Assert (0); /* Fall through to Black when not in debug mode. */
+ case Black:
+ Hd_hp (hp) = Whitehd_hd (hd);
+ break;
+ case Blue:
+ /* Only the blocks of the free-list are blue. See [freelist.c]. */
+ fl_merge = Bp_hp (hp);
+ break;
+ }
+ Assert (gc_sweep_hp <= limit);
+ }else{
+ chunk = (((heap_chunk_head *) chunk) [-1]).next;
+ if (chunk == NULL){
+ /* Sweeping is done. Start the next cycle. */
+ ++ stat_major_collections;
+ work = 0;
+ start_cycle ();
+ }else{
+ gc_sweep_hp = chunk;
+ limit = chunk + (((heap_chunk_head *) chunk) [-1]).size;
+ }
+ }
+ }
+}
+
+void major_collection_slice ()
+{
+ /* Free memory at the start of the GC cycle:
+ FM = stat_heap_size * percent_free / 100 * 2/3
+ Proportion of free memory consumed since the previous slice:
+ PH = allocated_words / FM
+ Proportion of extra-heap memory consumed since the previous slice:
+ PE = extra_heap_memory / stat_heap_size
+ Proportion of total work to do in this slice:
+ P = PH + PE
+ Amount of marking work for the GC cycle:
+ MW = stat_heap_size * (100 - percent_free) / 100
+ Amount of sweeping work for the GC cycle:
+ SW = stat_heap_size
+ Amount of marking work for this slice:
+ MS = MW * 2 * P
+ MS = 2 * (100 - percent_free)
+ * (allocated_words * 3 / percent_free / 2
+ + 100 * extra_heap_memory)
+ Amount of sweeping work for this slice:
+ SS = SW * 2 * P
+ SS = 2 * 100
+ * (allocated_words * 3 / percent_free / 2
+ + 100 * extra_heap_memory)
+ This slice will either mark MS words or sweep SS words.
+ */
+
+#define Margin 100 /* Make it a little faster to be on the safe side. */
+
+ if (gc_phase == Phase_mark){
+ mark_slice (2 * (100 - percent_free)
+ * (allocated_words * 3 / percent_free / 2
+ + 100 * extra_heap_memory)
+ + Margin);
+ gc_message ("!", 0);
+ }else{
+ Assert (gc_phase == Phase_sweep);
+ sweep_slice (200 * (allocated_words * 3 / percent_free / 2
+ + 100 * extra_heap_memory)
+ + Margin);
+ gc_message ("$", 0);
+ }
+ stat_major_words += allocated_words;
+ allocated_words = 0;
+ extra_heap_memory = 0;
+}
+
+/* The minor heap must be empty when this function is called. */
+void finish_major_cycle ()
+{
+ if (gc_phase == Phase_mark) mark_slice (LONG_MAX);
+ Assert (gc_phase == Phase_sweep);
+ sweep_slice (LONG_MAX);
+ stat_major_words += allocated_words;
+ allocated_words = 0;
+}
+
+asize_t round_heap_chunk_size (request)
+ asize_t request;
+{ Assert (major_heap_increment >= Heap_chunk_min);
+ if (request < major_heap_increment){
+ Assert (major_heap_increment % Page_size == 0);
+ return major_heap_increment;
+ }else if (request <= Heap_chunk_max){
+ return ((request + Page_size - 1) >> Page_log) << Page_log;
+ }else{
+ raise_out_of_memory ();
+ }
+}
+
+void init_major_heap (heap_size)
+ asize_t heap_size;
+{
+ asize_t i;
+
+ stat_heap_size = round_heap_chunk_size (heap_size);
+ Assert (stat_heap_size % Page_size == 0);
+ heap_start = aligned_malloc (stat_heap_size + sizeof (heap_chunk_head),
+ sizeof (heap_chunk_head));
+ if (heap_start == NULL)
+ fatal_error ("Fatal error: not enough memory for the initial heap.\n");
+ heap_start += sizeof (heap_chunk_head);
+ Assert ((unsigned long) heap_start % Page_size == 0);
+ (((heap_chunk_head *) heap_start) [-1]).size = stat_heap_size;
+ (((heap_chunk_head *) heap_start) [-1]).next = NULL;
+ heap_end = heap_start + stat_heap_size;
+ Assert ((unsigned long) heap_end % Page_size == 0);
+#ifdef SIXTEEN
+ page_table_size = 640L * 1024L / Page_size + 1;
+#else
+ page_table_size = 4 * stat_heap_size / Page_size;
+#endif
+ page_table = (char *) malloc (page_table_size);
+ if (page_table == NULL){
+ fatal_error ("Fatal error: not enough memory for the initial heap.\n");
+ }
+ for (i = 0; i < page_table_size; i++){
+ page_table [i] = Not_in_heap;
+ }
+ for (i = Page (heap_start); i < Page (heap_end); i++){
+ page_table [i] = In_heap;
+ }
+ Hd_hp (heap_start) = Make_header (Wosize_bhsize (stat_heap_size), 0, Blue);
+ fl_init_merge ();
+ fl_merge_block (Bp_hp (heap_start));
+ /* We start the major GC in the marking phase, just after the roots have been
+ darkened. (Since there are no roots, we don't have to darken anything.) */
+ gc_phase = Phase_mark;
+ gray_vals_size = 2048;
+ gray_vals = (value *) malloc (gray_vals_size * sizeof (value));
+ gray_vals_cur = gray_vals;
+ gray_vals_end = gray_vals + gray_vals_size;
+ heap_is_pure = 1;
+ allocated_words = 0;
+ extra_heap_memory = 0;
+}
diff --git a/byterun/major_gc.h b/byterun/major_gc.h
new file mode 100644
index 0000000000..0c39a87de1
--- /dev/null
+++ b/byterun/major_gc.h
@@ -0,0 +1,42 @@
+#ifndef _major_gc_
+#define _major_gc_
+
+
+#include "freelist.h"
+#include "misc.h"
+
+typedef struct {
+ asize_t size;
+ char *next;
+} heap_chunk_head;
+
+extern int gc_phase;
+extern unsigned long allocated_words;
+extern unsigned long extra_heap_memory;
+
+#define Phase_mark 0
+#define Phase_sweep 1
+
+extern char *heap_start;
+extern char *heap_end;
+extern unsigned long total_heap_size;
+extern char *page_table;
+extern asize_t page_table_size;
+extern char *gc_sweep_hp;
+
+#define In_heap 1
+#define Not_in_heap 0
+#define Page(p) (((addr) (p) - (addr) heap_start) >> Page_log)
+#define Is_in_heap(p) \
+ ((addr)(p) >= (addr)heap_start && (addr)(p) < (addr)heap_end \
+ && page_table [Page (p)] == In_heap)
+
+void init_major_heap P((asize_t));
+asize_t round_heap_chunk_size P((asize_t));
+void darken P((value));
+void major_collection_slice P((void));
+void major_collection P((void));
+void finish_major_cycle P((void));
+
+
+#endif /* _major_gc_ */
diff --git a/byterun/memory.c b/byterun/memory.c
new file mode 100644
index 0000000000..aacf05eba7
--- /dev/null
+++ b/byterun/memory.c
@@ -0,0 +1,205 @@
+#include <string.h>
+#include "fail.h"
+#include "freelist.h"
+#include "gc.h"
+#include "gc_ctrl.h"
+#include "major_gc.h"
+#include "memory.h"
+#include "minor_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+
+/* Allocate more memory from malloc for the heap.
+ Return a block of at least the requested size (in words).
+ Return NULL when out of memory.
+*/
+static char *expand_heap (request)
+ mlsize_t request;
+{
+ char *mem;
+ char *new_page_table;
+ asize_t new_page_table_size;
+ asize_t malloc_request;
+ asize_t i, more_pages;
+
+ malloc_request = round_heap_chunk_size (Bhsize_wosize (request));
+ gc_message ("Growing heap to %ldk\n",
+ (stat_heap_size + malloc_request) / 1024);
+ mem = aligned_malloc (malloc_request + sizeof (heap_chunk_head),
+ sizeof (heap_chunk_head));
+ if (mem == NULL){
+ gc_message ("No room for growing heap\n", 0);
+ return NULL;
+ }
+ mem += sizeof (heap_chunk_head);
+ (((heap_chunk_head *) mem) [-1]).size = malloc_request;
+ Assert (Wosize_bhsize (malloc_request) >= request);
+ Hd_hp (mem) = Make_header (Wosize_bhsize (malloc_request), 0, Blue);
+
+ if (mem < heap_start){
+ more_pages = -Page (mem);
+ }else if (Page (mem + malloc_request) > page_table_size){
+ Assert (mem >= heap_end);
+ more_pages = Page (mem + malloc_request) - page_table_size;
+ }else{
+ more_pages = 0;
+ }
+
+ if (more_pages != 0){
+ new_page_table_size = page_table_size + more_pages;
+ new_page_table = (char *) malloc (new_page_table_size);
+ if (new_page_table == NULL){
+ gc_message ("No room for growing page table\n", 0);
+ free (mem);
+ return NULL;
+ }
+ } else {
+ new_page_table = NULL;
+ new_page_table_size = 0;
+ }
+
+ if (mem < heap_start){
+ Assert (more_pages != 0);
+ for (i = 0; i < more_pages; i++){
+ new_page_table [i] = Not_in_heap;
+ }
+ bcopy (page_table, new_page_table + more_pages, page_table_size);
+ (((heap_chunk_head *) mem) [-1]).next = heap_start;
+ heap_start = mem;
+ }else{
+ char **last;
+ char *cur;
+
+ if (mem >= heap_end) heap_end = mem + malloc_request;
+ if (more_pages != 0){
+ for (i = page_table_size; i < new_page_table_size; i++){
+ new_page_table [i] = Not_in_heap;
+ }
+ bcopy (page_table, new_page_table, page_table_size);
+ }
+ last = &heap_start;
+ cur = *last;
+ while (cur != NULL && cur < mem){
+ last = &((((heap_chunk_head *) cur) [-1]).next);
+ cur = *last;
+ }
+ (((heap_chunk_head *) mem) [-1]).next = cur;
+ *last = mem;
+ }
+
+ if (more_pages != 0){
+ free (page_table);
+ page_table = new_page_table;
+ page_table_size = new_page_table_size;
+ }
+
+ for (i = Page (mem); i < Page (mem + malloc_request); i++){
+ page_table [i] = In_heap;
+ }
+ stat_heap_size += malloc_request;
+ return Bp_hp (mem);
+}
+
+value alloc_shr (wosize, tag)
+ mlsize_t wosize;
+ tag_t tag;
+{
+ char *hp, *new_block;
+
+ hp = fl_allocate (wosize);
+ if (hp == NULL){
+ new_block = expand_heap (wosize);
+ if (new_block == NULL) raise_out_of_memory ();
+ fl_add_block (new_block);
+ hp = fl_allocate (wosize);
+ }
+
+ Assert (Is_in_heap (Val_hp (hp)));
+
+ if (gc_phase == Phase_mark || (addr)hp >= (addr)gc_sweep_hp){
+ Hd_hp (hp) = Make_header (wosize, tag, Black);
+ }else{
+ Hd_hp (hp) = Make_header (wosize, tag, White);
+ }
+ allocated_words += Whsize_wosize (wosize);
+ if (allocated_words > Wsize_bsize (minor_heap_size)) force_minor_gc ();
+ return Val_hp (hp);
+}
+
+/* Use this function to tell the major GC to speed up when you use
+ finalized objects to automatically deallocate extra-heap objects.
+ The GC will do at least one cycle every [max] allocated words;
+ [mem] is the number of words allocated this time.
+ Note that only [mem/max] is relevant. You can use numbers of bytes
+ (or kilobytes, ...) instead of words. You can change units between
+ calls to [adjust_collector_speed].
+*/
+void adjust_gc_speed (mem, max)
+ mlsize_t mem, max;
+{
+ if (max == 0) max = 1;
+ if (mem > max) mem = max;
+ extra_heap_memory += ((float) mem / max) * stat_heap_size;
+ if (extra_heap_memory > stat_heap_size){
+ extra_heap_memory = stat_heap_size;
+ }
+ if (extra_heap_memory > Wsize_bsize (minor_heap_size) / 2) force_minor_gc ();
+}
+
+/* You must use [initialize] to store the initial value in a field of
+ a shared block, unless you are sure the value is not a young block.
+ A block value [v] is a shared block if and only if [Is_in_heap (v)]
+ is true.
+*/
+/* [initialize] never calls the GC, so you may call it while an object is
+ unfinished (i.e. just after a call to [alloc_shr].) */
+void initialize (fp, val)
+ value *fp;
+ value val;
+{
+ *fp = val;
+ Assert (Is_in_heap (fp));
+ if (Is_block (val) && Is_young (val)){
+ *ref_table_ptr++ = fp;
+ if (ref_table_ptr >= ref_table_limit){
+ realloc_ref_table ();
+ }
+ }
+}
+
+/* You must use [modify] to change a field of an existing shared block,
+ unless you are sure the value being overwritten is not a shared block and
+ the value being written is not a young block. */
+/* [modify] never calls the GC. */
+void modify (fp, val)
+ value *fp;
+ value val;
+{
+ Modify (fp, val);
+}
+
+char *stat_alloc (sz)
+ asize_t sz;
+{
+ char *result = (char *) malloc (sz);
+
+ if (result == NULL) raise_out_of_memory ();
+ return result;
+}
+
+void stat_free (blk)
+ char * blk;
+{
+ free (blk);
+}
+
+char *stat_resize (blk, sz)
+ char *blk;
+ asize_t sz;
+{
+ char *result = (char *) realloc (blk, sz);
+
+ if (result == NULL) raise_out_of_memory ();
+ return result;
+}
+
diff --git a/byterun/memory.h b/byterun/memory.h
new file mode 100644
index 0000000000..5df199e02e
--- /dev/null
+++ b/byterun/memory.h
@@ -0,0 +1,88 @@
+/* Allocation macros and functions */
+
+#ifndef _memory_
+#define _memory_
+
+
+#include "config.h"
+#include "gc.h"
+#include "major_gc.h"
+#include "minor_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+
+value alloc_shr P((mlsize_t, tag_t));
+void adjust_gc_speed P((mlsize_t, mlsize_t));
+void modify P((value *, value));
+void initialize P((value *, value));
+char * stat_alloc P((asize_t)); /* Size in bytes. */
+void stat_free P((char *));
+char * stat_resize P((char *, asize_t)); /* Size in bytes. */
+
+
+#define Alloc_small(result, wosize, tag) { \
+ char *_res_ = young_ptr; \
+ young_ptr += Bhsize_wosize (wosize); \
+ if (young_ptr > young_end){ \
+ Setup_for_gc; \
+ minor_collection (); \
+ Restore_after_gc; \
+ _res_ = young_ptr; \
+ young_ptr += Bhsize_wosize (wosize); \
+ } \
+ Hd_hp (_res_) = Make_header ((wosize), (tag), Black); \
+ (result) = Val_hp (_res_); \
+}
+
+/* You must use [Modify] to change a field of an existing shared block,
+ unless you are sure the value being overwritten is not a shared block and
+ the value being written is not a young block. */
+/* [Modify] never calls the GC. */
+
+#define Modify(fp, val) { \
+ value _old_ = *(fp); \
+ *(fp) = (val); \
+ if (Is_in_heap (fp)){ \
+ if (gc_phase == Phase_mark) darken (_old_); \
+ if (Is_block (val) && Is_young (val) \
+ && ! (Is_block (_old_) && Is_young (_old_))){ \
+ *ref_table_ptr++ = (fp); \
+ if (ref_table_ptr >= ref_table_limit){ \
+ Assert (ref_table_ptr == ref_table_limit); \
+ realloc_ref_table (); \
+ } \
+ } \
+ } \
+} \
+
+/* [Push_roots] and [Pop_roots] are used for C variables that are GC roots.
+ * It must contain all values in C local variables at the time the minor GC is
+ * called.
+ * Usage:
+ * At the end of the declarations of your C local variables, add
+ * [ Push_roots (variable_name, size); ]
+ * The size is the number of declared roots. They are accessed as
+ * [ variable_name [0] ... variable_name [size - 1] ].
+ * The [variable_name] and the [size] must not be [ _ ].
+ * Just before the function return, add a call to [Pop_roots].
+ */
+
+extern value *local_roots;
+
+#define Push_roots(name, size) \
+ value name [(size) + 2]; \
+ { long _; for (_ = 0; _ < (size); name [_++] = Val_long (0)); } \
+ name [(size)] = (value) (size); \
+ name [(size) + 1] = (value) local_roots; \
+ local_roots = &(name [(size)]);
+
+#define Pop_roots() {local_roots = (value *) local_roots [1]; }
+
+/* [register_global_root] registers a global C variable as a memory root
+ for the duration of the program. */
+
+void register_global_root P((value *));
+
+
+#endif /* _memory_ */
+
diff --git a/byterun/meta.c b/byterun/meta.c
new file mode 100644
index 0000000000..2da8c15c91
--- /dev/null
+++ b/byterun/meta.c
@@ -0,0 +1,93 @@
+/* Primitives for the toplevel */
+
+#include "alloc.h"
+#include "interp.h"
+#include "major_gc.h"
+#include "memory.h"
+#include "minor_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "prims.h"
+
+value get_global_data(unit) /* ML */
+ value unit;
+{
+ return global_data;
+}
+
+value execute_bytecode(prog, len) /* ML */
+ value prog, len;
+{
+#if defined(BIG_ENDIAN)
+ fixup_endianness((code_t) prog, (asize_t) Long_val(len));
+#endif
+ return interprete((code_t) prog, (asize_t) Long_val(len));
+}
+
+value realloc_global(size) /* ML */
+ value size;
+{
+ mlsize_t requested_size, actual_size, i;
+ value new_global_data;
+
+ requested_size = Long_val(size);
+ actual_size = Wosize_val(global_data);
+ if (requested_size >= actual_size) {
+ requested_size = (requested_size + 0x100) & 0xFFFFFF00;
+ new_global_data = alloc_shr(requested_size, 0);
+ for (i = 0; i < actual_size; i++)
+ initialize(&Field(new_global_data, i), Field(global_data, i));
+ for (i = actual_size; i < requested_size; i++){
+ Field (new_global_data, i) = Val_long (0);
+ }
+ global_data = new_global_data;
+ }
+ return Atom(0);
+}
+
+value static_alloc(size) /* ML */
+ value size;
+{
+ return (value) stat_alloc((asize_t) Long_val(size));
+}
+
+value static_free(blk) /* ML */
+ value blk;
+{
+ stat_free((char *) blk);
+ return Atom(0);
+}
+
+value static_resize(blk, new_size) /* ML */
+ value blk, new_size;
+{
+ return (value) stat_resize((char *) blk, (asize_t) Long_val(new_size));
+}
+
+value obj_is_block(arg) /* ML */
+ value arg;
+{
+ return Atom(Is_block(arg));
+}
+
+value obj_block(tag, size) /* ML */
+ value tag, size;
+{
+ value res;
+ mlsize_t sz, i;
+ tag_t tg;
+
+ sz = Long_val(size);
+ tg = Long_val(tag);
+ if (sz == 0) return Atom(tg);
+ res = alloc(sz, tg);
+ for (i = 0; i < sz; i++)
+ Field(res, i) = Val_long(0);
+
+ return res;
+}
+
+value available_primitives() /* ML */
+{
+ return copy_string_array(names_of_cprim);
+}
diff --git a/byterun/minor_gc.c b/byterun/minor_gc.c
new file mode 100644
index 0000000000..f2fd8fbd31
--- /dev/null
+++ b/byterun/minor_gc.c
@@ -0,0 +1,156 @@
+#include <string.h>
+#include "config.h"
+#include "fail.h"
+#include "gc.h"
+#include "gc_ctrl.h"
+#include "major_gc.h"
+#include "memory.h"
+#include "minor_gc.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "roots.h"
+
+asize_t minor_heap_size;
+char *young_start = NULL, *young_end, *young_ptr = NULL;
+static value **ref_table = NULL, **ref_table_end, **ref_table_threshold;
+value **ref_table_ptr = NULL, **ref_table_limit;
+static asize_t ref_table_size, ref_table_reserve;
+
+void set_minor_heap_size (size)
+ asize_t size;
+{
+ char *new_heap;
+ value **new_table;
+
+ Assert (size >= Minor_heap_min);
+ Assert (size <= Minor_heap_max);
+ Assert (size % sizeof (value) == 0);
+ if (young_ptr != young_start) minor_collection ();
+ Assert (young_ptr == young_start);
+ new_heap = (char *) stat_alloc (size);
+ if (young_start != NULL){
+ stat_free ((char *) young_start);
+ }
+ young_start = new_heap;
+ young_end = new_heap + size;
+ young_ptr = young_start;
+ minor_heap_size = size;
+
+ ref_table_size = minor_heap_size / sizeof (value) / 8;
+ ref_table_reserve = 256;
+ new_table = (value **) stat_alloc ((ref_table_size + ref_table_reserve)
+ * sizeof (value *));
+ if (ref_table != NULL) stat_free ((char *) ref_table);
+ ref_table = new_table;
+ ref_table_ptr = ref_table;
+ ref_table_threshold = ref_table + ref_table_size;
+ ref_table_limit = ref_table_threshold;
+ ref_table_end = ref_table + ref_table_size + ref_table_reserve;
+}
+
+static void oldify (p, v)
+ value *p;
+ value v;
+{
+ value result;
+ mlsize_t i;
+
+ tail_call:
+ if (Is_block (v) && Is_young (v)){
+ Assert (Hp_val (v) < young_ptr);
+ if (Is_blue_val (v)){ /* Already forwarded ? */
+ *p = Field (v, 0); /* Then the forward pointer is the first field. */
+ }else if (Tag_val (v) >= No_scan_tag){
+ result = alloc_shr (Wosize_val (v), Tag_val (v));
+ bcopy (Bp_val (v), Bp_val (result), Bosize_val (v));
+ Hd_val (v) = Bluehd_hd (Hd_val (v)); /* Put the forward flag. */
+ Field (v, 0) = result; /* And the forward pointer. */
+ *p = result;
+ }else{
+ /* We can do recursive calls before all the fields are filled, because
+ we will not be calling the major GC. */
+ value field0 = Field (v, 0);
+ mlsize_t sz = Wosize_val (v);
+
+ result = alloc_shr (sz, Tag_val (v));
+ *p = result;
+ Hd_val (v) = Bluehd_hd (Hd_val (v)); /* Put the forward flag. */
+ Field (v, 0) = result; /* And the forward pointer. */
+ if (sz == 1){
+ p = &Field (result, 0);
+ v = field0;
+ goto tail_call;
+ }else{
+ oldify (&Field (result, 0), field0);
+ for (i = 1; i < sz - 1; i++){
+ oldify (&Field (result, i), Field (v, i));
+ }
+ p = &Field (result, i);
+ v = Field (v, i);
+ goto tail_call;
+ }
+ }
+ }else{
+ *p = v;
+ }
+}
+
+void minor_collection ()
+{
+ value **r;
+ struct longjmp_buffer raise_buf;
+ struct longjmp_buffer *old_external_raise;
+ long prev_alloc_words = allocated_words;
+
+ if (setjmp(raise_buf.buf)) {
+ fatal_error ("Fatal error: out of memory.\n");
+ }
+ old_external_raise = external_raise;
+ external_raise = &raise_buf;
+
+ gc_message ("<", 0);
+ scan_local_roots (oldify);
+ for (r = ref_table; r < ref_table_ptr; r++) oldify (*r, **r);
+ stat_minor_words += Wsize_bsize (young_ptr - young_start);
+ young_ptr = young_start;
+ ref_table_ptr = ref_table;
+ ref_table_limit = ref_table_threshold;
+ gc_message (">", 0);
+
+ external_raise = old_external_raise;
+
+ stat_promoted_words += allocated_words - prev_alloc_words;
+ ++ stat_minor_collections;
+ major_collection_slice ();
+ force_minor_flag = 0;
+}
+
+void realloc_ref_table ()
+{ Assert (ref_table_ptr == ref_table_limit);
+ Assert (ref_table_limit <= ref_table_end);
+ Assert (ref_table_limit >= ref_table_threshold);
+
+ if (ref_table_limit == ref_table_threshold){
+ gc_message ("ref_table threshold crossed\n", 0);
+ ref_table_limit = ref_table_end;
+ force_minor_gc ();
+ }else{ /* This will never happen. */
+ asize_t sz;
+ asize_t cur_ptr = ref_table_ptr - ref_table;
+ Assert (force_minor_flag);
+ Assert (something_to_do);
+ ref_table_reserve += 1024;
+ sz = (ref_table_size + ref_table_reserve) * sizeof (value *);
+ gc_message ("Growing ref_table to %ldk\n", (long) sz / 1024);
+#ifdef MAX_MALLOC_SIZE
+ if (sz > MAX_MALLOC_SIZE) ref_table = NULL;
+ else
+#endif
+ ref_table = (value **) realloc ((char *) ref_table, sz);
+ if (ref_table == NULL) fatal_error ("Fatal error: ref_table overflow\n");
+ ref_table_end = ref_table + ref_table_size + ref_table_reserve;
+ ref_table_threshold = ref_table + ref_table_size;
+ ref_table_ptr = ref_table + cur_ptr;
+ ref_table_limit = ref_table_end;
+ }
+}
diff --git a/byterun/minor_gc.h b/byterun/minor_gc.h
new file mode 100644
index 0000000000..112ba58a97
--- /dev/null
+++ b/byterun/minor_gc.h
@@ -0,0 +1,19 @@
+#ifndef _minor_gc_
+#define _minor_gc_
+
+
+#include "misc.h"
+
+extern char *young_start, *young_ptr, *young_end;
+extern value **ref_table_ptr, **ref_table_limit;
+extern asize_t minor_heap_size;
+
+#define Is_young(val) \
+ ((addr)(val) > (addr)young_start && (addr)(val) < (addr)young_end)
+
+extern void set_minor_heap_size P((asize_t));
+extern void minor_collection P((void));
+extern void realloc_ref_table P((void));
+
+
+#endif /* _minor_gc_ */
diff --git a/byterun/misc.c b/byterun/misc.c
new file mode 100644
index 0000000000..c53452acd0
--- /dev/null
+++ b/byterun/misc.c
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include "config.h"
+#include "misc.h"
+#ifdef HAS_UI
+#include "ui.h"
+#endif
+
+#ifdef DEBUG
+
+void failed_assert (expr, file, line)
+ char *expr, *file;
+ int line;
+{
+ fprintf (stderr, "Assertion failed: %s; file %s; line %d\n",
+ expr, file, line);
+ exit (100);
+}
+
+static unsigned long seed = 0x12345;
+
+unsigned long not_random ()
+{
+ seed = seed * 65537 + 12345;
+ return seed;
+}
+
+#endif
+
+int verb_gc;
+int Volatile something_to_do = 0;
+int Volatile force_minor_flag = 0;
+
+void force_minor_gc ()
+{
+ force_minor_flag = 1;
+ something_to_do = 1;
+}
+
+void gc_message (msg, arg)
+ char *msg;
+ unsigned long arg;
+{
+ if (verb_gc){
+#ifdef HAS_UI
+ ui_gc_message(msg, arg);
+#else
+ fprintf (stderr, msg, arg);
+ fflush (stderr);
+#endif
+ }
+}
+
+void fatal_error (msg)
+ char * msg;
+{
+#ifdef HAS_UI
+ ui_fatal_error("%s", msg);
+#else
+ fprintf (stderr, "%s", msg);
+ exit(2);
+#endif
+}
+
+void fatal_error_arg (fmt, arg)
+ char * fmt, * arg;
+{
+#ifdef HAS_UI
+ ui_fatal_error(fmt, arg);
+#else
+ fprintf (stderr, fmt, arg);
+ exit(2);
+#endif
+}
+
+#ifdef USING_MEMMOV
+
+/* This should work on 64-bit machines as well as 32-bit machines.
+ It assumes a long is the natural size for memory reads and writes.
+*/
+void memmov (dst, src, length)
+ char *dst, *src;
+ unsigned long length;
+{
+ unsigned long i;
+
+ if ((unsigned long) dst <= (unsigned long) src){
+
+ /* Copy in ascending order. */
+ if (((unsigned long) src - (unsigned long) dst) % sizeof (long) != 0){
+
+ /* The pointers are not equal modulo sizeof (long).
+ Copy byte by byte. */
+ for (; length != 0; length--){
+ *dst++ = *src++;
+ }
+ }else{
+
+ /* Copy the first few bytes. */
+ i = (unsigned long) dst % sizeof (long);
+ if (i != 0){
+ i = sizeof (long) - i; /* Number of bytes to copy. */
+ if (i > length) i = length; /* Never copy more than length.*/
+ for (; i != 0; i--){
+ *dst++ = *src++; --length;
+ }
+ } Assert ((unsigned long) dst % sizeof (long) == 0);
+ Assert ((unsigned long) src % sizeof (long) == 0);
+
+ /* Then copy as many entire words as possible. */
+ for (i = length / sizeof (long); i > 0; i--){
+ *(long *) dst = *(long *) src;
+ dst += sizeof (long); src += sizeof (long);
+ }
+
+ /* Then copy the last few bytes. */
+ for (i = length % sizeof (long); i > 0; i--){
+ *dst++ = *src++;
+ }
+ }
+ }else{ /* Copy in descending order. */
+ src += length; dst += length;
+ if (((unsigned long) dst - (unsigned long) src) % sizeof (long) != 0){
+
+ /* The pointers are not equal modulo sizeof (long).
+ Copy byte by byte. */
+ for (; length > 0; length--){
+ *--dst = *--src;
+ }
+ }else{
+
+ /* Copy the first few bytes. */
+ i = (unsigned long) dst % sizeof (long);
+ if (i > length) i = length; /* Never copy more than length. */
+ for (; i > 0; i--){
+ *--dst = *--src; --length;
+ }
+
+ /* Then copy as many entire words as possible. */
+ for (i = length / sizeof (long); i > 0; i--){
+ dst -= sizeof (long); src -= sizeof (long);
+ *(long *) dst = *(long *) src;
+ }
+
+ /* Then copy the last few bytes. */
+ for (i = length % sizeof (long); i > 0; i--){
+ *--dst = *--src;
+ }
+ }
+ }
+}
+
+#endif /* USING_MEMMOV */
+
+char *aligned_malloc (size, modulo)
+ asize_t size;
+ int modulo;
+{
+ char *raw_mem;
+ unsigned long aligned_mem;
+ Assert (modulo < Page_size);
+ raw_mem = (char *) malloc (size + Page_size);
+ if (raw_mem == NULL) return NULL;
+ raw_mem += modulo; /* Address to be aligned */
+ aligned_mem = (((unsigned long) raw_mem / Page_size + 1) * Page_size);
+ return (char *) (aligned_mem - modulo);
+}
diff --git a/byterun/misc.h b/byterun/misc.h
new file mode 100644
index 0000000000..14c7bb3385
--- /dev/null
+++ b/byterun/misc.h
@@ -0,0 +1,90 @@
+/* Miscellaneous macros and variables. */
+
+#ifndef _misc_
+#define _misc_
+
+
+#include "config.h"
+
+/* Standard definitions */
+
+#ifdef __STDC__
+#include <stddef.h>
+#include <stdlib.h>
+#endif
+
+/* Function prototypes */
+
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
+/* Basic types and constants */
+
+#ifdef __STDC__
+typedef size_t asize_t;
+#else
+typedef int asize_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef char * addr;
+
+/* Volatile stuff */
+
+#ifdef __STDC__
+#define Volatile volatile
+#else
+#define Volatile
+#endif
+
+#ifdef __GNUC__
+/* Works only in GCC 2.5 and later */
+#define Noreturn __attribute ((noreturn))
+#else
+#define Noreturn
+#endif
+
+/* Assertions */
+
+#ifdef DEBUG
+#ifdef __STDC__
+#define Assert(x) if (!(x)) failed_assert ( #x , __FILE__, __LINE__)
+#else
+#ifndef __LINE__
+#define __LINE__ 0
+#endif
+#ifndef __FILE__
+#define __FILE__ "(?)"
+#endif
+#define Assert(x) if (!(x)) failed_assert ("(?)" , __FILE__, __LINE__)
+#endif
+#else
+#define Assert(x)
+#endif
+
+void failed_assert P((char *, char *, int)) Noreturn;
+void fatal_error P((char *)) Noreturn;
+void fatal_error_arg P((char *, char *)) Noreturn;
+
+/* GC flags and messages */
+
+extern int verb_gc;
+extern int Volatile something_to_do;
+extern int Volatile force_minor_flag;
+
+void force_minor_gc P((void));
+void gc_message P((char *, unsigned long));
+
+/* Memory routines */
+
+void memmov P((char *, char *, unsigned long));
+char * aligned_malloc P((asize_t, int));
+unsigned long not_random P((void));
+
+#endif /* _misc_ */
diff --git a/byterun/mlvalues.h b/byterun/mlvalues.h
new file mode 100644
index 0000000000..f820f289a6
--- /dev/null
+++ b/byterun/mlvalues.h
@@ -0,0 +1,213 @@
+#ifndef _mlvalues_
+#define _mlvalues_
+
+
+#include "config.h"
+#include "misc.h"
+
+/* Definitions
+
+ word: Four bytes on 32 and 16 bit architectures,
+ eight bytes on 64 bit architectures.
+ long: A C long integer.
+ val: The ML representation of something. A long or a block or a pointer
+ outside the heap. If it is a block, it is the (encoded) address
+ of an object. If it is a long, it is encoded as well.
+ object: Something allocated. It always has a header and some
+ fields or some number of bytes (a multiple of the word size).
+ field: A word-sized val which is part of an object.
+ bp: Pointer to the first byte of an object. (a char *)
+ op: Pointer to the first field of an object. (a value *)
+ hp: Pointer to the header of an object. (a char *)
+ int32: Four bytes on all architectures.
+
+ Remark: An object size is always a multiple of the word size, and at least
+ one word plus the header.
+
+ bosize: Size (in bytes) of the "bytes" part.
+ wosize: Size (in words) of the "fields" part.
+ bhsize: Size (in bytes) of the object with its header.
+ whsize: Size (in words) of the object with its header.
+
+ hd: A header.
+ tag: The value of the tag field of the header.
+ color: The value of the color field of the header.
+ This is for use only by the GC.
+*/
+
+typedef long value;
+typedef unsigned long header_t;
+typedef unsigned long mlsize_t;
+typedef unsigned int tag_t; /* Actually, an unsigned char */
+typedef unsigned long color_t;
+typedef unsigned long mark_t;
+
+typedef int int32; /* Not portable, but checked by autoconf. */
+typedef unsigned int uint32; /* Seems like a reasonable assumption anyway. */
+
+/* Longs vs blocks. */
+#define Is_long(x) (((x) & 1) == 1)
+#define Is_block(x) (((x) & 1) == 0)
+
+/* Conversion macro names are always of the form "to_from". */
+/* Example: Val_long as in "Val from long" or "Val of long". */
+#define Val_long(x) (((long)(x) << 1) + 1)
+#define Long_val(x) ((x) >> 1)
+#define Max_long ((1L << (8 * sizeof(value) - 2)) - 1)
+#define Min_long (-(1L << (8 * sizeof(value) - 2)))
+#define Val_int Val_long
+#define Int_val(x) ((int) Long_val(x))
+
+/* Structure of the header:
+
+For 16-bit and 32-bit architectures:
+ +--------+-------+-----+
+ | wosize | color | tag |
+ +--------+-------+-----+
+bits 31 10 9 8 7 0
+
+For 64-bit architectures:
+
+ +--------+-------+-----+
+ | wosize | color | tag |
+ +--------+-------+-----+
+bits 63 10 9 8 7 0
+
+*/
+
+#define Tag_hd(hd) ((tag_t) ((hd) & 0xFF))
+#define Wosize_hd(hd) ((mlsize_t) ((hd) >> 10))
+
+#define Hd_val(val) (((header_t *) (val)) [-1]) /* Also an l-value. */
+#define Hd_op(op) (Hd_val (op)) /* Also an l-value. */
+#define Hd_bp(bp) (Hd_val (bp)) /* Also an l-value. */
+#define Hd_hp(hp) (* ((header_t *) (hp))) /* Also an l-value. */
+#define Hp_val(val) ((char *) (((header_t *) (val)) - 1))
+#define Hp_op(op) (Hp_val (op))
+#define Hp_bp(bp) (Hp_val (bp))
+#define Val_op(op) ((value) (op))
+#define Val_hp(hp) ((value) (((header_t *) (hp)) + 1))
+#define Op_hp(hp) ((value *) Val_hp (hp))
+#define Bp_hp(hp) ((char *) Val_hp (hp))
+
+#define Num_tags (1 << 8)
+#ifdef SIXTYFOUR
+#define Max_wosize ((1L << 54) - 1)
+#else
+#define Max_wosize ((1 << 22) - 1)
+#endif
+
+#define Wosize_val(val) (Wosize_hd (Hd_val (val)))
+#define Wosize_op(op) (Wosize_val (op))
+#define Wosize_bp(bp) (Wosize_val (bp))
+#define Wosize_hp(hp) (Wosize_hd (Hd_hp (hp)))
+#define Whsize_wosize(sz) ((sz) + 1)
+#define Wosize_whsize(sz) ((sz) - 1)
+#define Wosize_bhsize(sz) ((sz) / sizeof (value) - 1)
+#define Bsize_wsize(sz) ((sz) * sizeof (value))
+#define Wsize_bsize(sz) ((sz) / sizeof (value))
+#define Bhsize_wosize(sz) (Bsize_wsize (Whsize_wosize (sz)))
+#define Bhsize_bosize(sz) ((sz) + sizeof (header_t))
+#define Bosize_val(val) (Bsize_wsize (Wosize_val (val)))
+#define Bosize_op(op) (Bosize_val (Val_op (op)))
+#define Bosize_bp(bp) (Bosize_val (Val_bp (bp)))
+#define Bosize_hd(hd) (Bsize_wsize (Wosize_hd (hd)))
+#define Whsize_hp(hp) (Whsize_wosize (Wosize_hp (hp)))
+#define Whsize_val(val) (Whsize_hp (Hp_val (val)))
+#define Whsize_bp(bp) (Whsize_val (Val_bp (bp)))
+#define Whsize_hd(hd) (Whsize_wosize (Wosize_hd (hd)))
+#define Bhsize_hp(hp) (Bsize_wsize (Whsize_hp (hp)))
+#define Bhsize_hd(hd) (Bsize_wsize (Whsize_hd (hd)))
+
+#ifdef BIG_ENDIAN
+#define Tag_val(val) (((unsigned char *) (val)) [-1])
+ /* Also an l-value. */
+#define Tag_hp(hp) (((unsigned char *) (hp)) [sizeof(value)-1])
+ /* Also an l-value. */
+#else
+#define Tag_val(val) (((unsigned char *) (val)) [-sizeof(value)])
+ /* Also an l-value. */
+#define Tag_hp(hp) (((unsigned char *) (hp)) [0])
+ /* Also an l-value. */
+#endif
+
+/* The Lowest tag for blocks containing no value. */
+#define No_scan_tag (Num_tags - 4)
+
+
+/* 1- If tag < No_scan_tag : a tuple of fields. */
+
+/* Pointer to the first field. */
+#define Op_val(x) ((value *) (x))
+/* Fields are numbered from 0. */
+#define Field(x, i) (((value *)(x)) [i]) /* Also an l-value. */
+
+typedef int32 opcode_t;
+typedef opcode_t * code_t;
+
+#define Closure_wosize 2
+#define Closure_tag (No_scan_tag - 1)
+#define Code_val(val) (((code_t *) (val)) [0]) /* Also an l-value. */
+#define Env_val(val) (Field(val, 1)) /* Also an l-value. */
+
+
+/* 2- If tag >= No_scan_tag : a sequence of bytes. */
+
+/* Pointer to the first byte */
+#define Bp_val(v) ((char *) (v))
+#define Val_bp(p) ((value) (p))
+/* Bytes are numbered from 0. */
+#define Byte(x, i) (((char *) (x)) [i]) /* Also an l-value. */
+#define Byte_u(x, i) (((unsigned char *) (x)) [i]) /* Also an l-value. */
+
+/* Abstract things. Their contents is not traced by the GC; therefore they
+ must not contain any [value].
+*/
+#define Abstract_tag No_scan_tag
+
+/* Strings. */
+#define String_tag (No_scan_tag + 1)
+#define String_val(x) ((char *) Bp_val(x))
+
+/* Floating-point numbers. */
+#define Double_tag (No_scan_tag + 2)
+#define Double_wosize ((sizeof(double) / sizeof(value)))
+#ifndef ALIGN_DOUBLE
+#define Double_val(v) (* (double *) (v))
+#define Store_double_val(v,d) (* (double *) (v) = (d))
+#else
+double Double_val P((value));
+void Store_double_val P((value,double));
+#endif
+
+/* Finalized things. Just like abstract things, but the GC will call the
+ [Final_fun] before deallocation.
+*/
+#define Final_tag (No_scan_tag + 3)
+typedef void (*final_fun) P((value));
+#define Final_fun(val) (((final_fun *) (val)) [0]) /* Also an l-value. */
+
+
+/* 3- Atoms are 0-tuples. They are statically allocated once and for all. */
+
+extern header_t first_atoms[];
+#define Atom(tag) (Val_hp (&(first_atoms [tag])))
+#define Is_atom(v) (v >= Atom(0) && v <= Atom(255))
+
+/* Booleans are atoms tagged 0 or 1 */
+
+#define Val_bool(x) Atom((x) != 0)
+#define Bool_val(x) Tag_val(x)
+#define Val_false Atom(0)
+#define Val_true Atom(1)
+
+/* The unit value is the atom tagged 0 */
+
+#define Val_unit Atom(0)
+
+/* The table of global identifiers */
+
+extern value global_data;
+
+
+#endif /* _mlvalues_ */
diff --git a/byterun/oldlexing.c b/byterun/oldlexing.c
new file mode 100644
index 0000000000..3d5d4a0903
--- /dev/null
+++ b/byterun/oldlexing.c
@@ -0,0 +1,36 @@
+/* The "get_next_char" routine for lexers generated by camllex. */
+
+#include "interp.h"
+#include "mlvalues.h"
+#include "stacks.h"
+#include "str.h"
+
+struct lexer_buffer {
+ value refill_buff;
+ value lex_buffer;
+ value lex_abs_pos;
+ value lex_start_pos;
+ value lex_curr_pos;
+ value lex_last_pos;
+ value lex_last_action;
+};
+
+value get_next_char(lexbuf) /* ML */
+ struct lexer_buffer * lexbuf;
+{
+ mlsize_t buffer_len, curr_pos;
+
+ buffer_len = string_length(lexbuf->lex_buffer);
+ curr_pos = Long_val(lexbuf->lex_curr_pos);
+ if (curr_pos >= buffer_len) {
+ Push_roots (r, 1);
+ r[0] = (value) lexbuf;
+ callback(lexbuf->refill_buff, (value) lexbuf);
+ lexbuf = (struct lexer_buffer *) r[0];
+ curr_pos = Long_val(lexbuf->lex_curr_pos);
+ Pop_roots ();
+ }
+ lexbuf->lex_curr_pos += 2;
+ return Val_int(Byte_u(lexbuf->lex_buffer, curr_pos));
+}
+
diff --git a/byterun/parsing.c b/byterun/parsing.c
new file mode 100644
index 0000000000..f051ffed7b
--- /dev/null
+++ b/byterun/parsing.c
@@ -0,0 +1,205 @@
+/* The PDA automaton for parsers generated by camlyacc */
+
+#include <stdio.h>
+#include "config.h"
+#include "mlvalues.h"
+#include "memory.h"
+#include "alloc.h"
+
+struct parser_tables { /* Mirrors parse_tables in ../stdlib/parsing.mli */
+ value actions;
+ value transl;
+ char * lhs;
+ char * len;
+ char * defred;
+ char * dgoto;
+ char * sindex;
+ char * rindex;
+ char * gindex;
+ value tablesize;
+ char * table;
+ char * check;
+};
+
+struct parser_env { /* Mirrors parser_env in ../stdlib/parsing.ml */
+ value s_stack;
+ value v_stack;
+ value symb_start_stack;
+ value symb_end_stack;
+ value stacksize;
+ value curr_char;
+ value lval;
+ value symb_start;
+ value symb_end;
+ value asp;
+ value rule_len;
+ value rule_number;
+ value sp;
+ value state;
+};
+
+#ifdef BIG_ENDIAN
+#define Short(tbl,n) \
+ (*((unsigned char *)((tbl) + (n) * sizeof(short))) + \
+ (*((schar *)((tbl) + (n) * sizeof(short) + 1)) << 8))
+#else
+#define Short(tbl,n) (((short *)(tbl))[n])
+#endif
+
+#ifdef DEBUG
+int parser_trace = 0;
+#define Trace(act) if(parser_trace) act
+#else
+#define Trace(act)
+#endif
+
+/* Input codes */
+
+#define START 0 /* Mirrors parser_input in ../stdlib/parsing.ml */
+#define TOKEN_READ 1
+#define STACKS_GROWN_1 2
+#define STACKS_GROWN_2 3
+#define SEMANTIC_ACTION_COMPUTED 4
+
+/* Output codes */
+
+#define READ_TOKEN Atom(0) /* Mirrors parser_output in ../stdlib/parsing.ml */
+#define RAISE_PARSE_ERROR Atom(1)
+#define GROW_STACKS_1 Atom(2)
+#define GROW_STACKS_2 Atom(3)
+#define COMPUTE_SEMANTIC_ACTION Atom(4)
+
+/* The pushdown automata */
+
+value parse_engine(tables, env, cmd, arg) /* ML */
+ struct parser_tables * tables;
+ struct parser_env * env;
+ value cmd;
+ value arg;
+{
+ int state;
+ mlsize_t sp;
+ int n, n1, n2, m, state1;
+
+ switch(Tag_val(cmd)) {
+
+ case START:
+ state = 0;
+ sp = Int_val(env->sp);
+
+ loop:
+ Trace(printf("Loop %d\n", state));
+ n = Short(tables->defred, state);
+ if (n != 0) goto reduce;
+ if (Int_val(env->curr_char) >= 0) goto testshift;
+ env->sp = Val_int(sp);
+ env->state = Val_int(state);
+ return READ_TOKEN;
+ /* The ML code calls the lexer and updates */
+ /* symb_start and symb_end */
+ case TOKEN_READ:
+ sp = Int_val(env->sp);
+ state = Int_val(env->state);
+ env->curr_char = Field(tables->transl, Tag_val(arg));
+ switch (Wosize_val(arg)) {
+ case 0:
+ env->lval = Val_long(0); break;
+ case 1:
+ modify(&env->lval, Field(arg, 0)); break;
+ default: {
+ value tuple;
+ mlsize_t size, i;
+ Push_roots(r, 4);
+ r[0] = (value) tables;
+ r[1] = (value) env;
+ r[2] = cmd;
+ r[3] = arg;
+ size = Wosize_val(arg);
+ tuple = alloc_tuple(size);
+ tables = (struct parser_tables *) r[0];
+ env = (struct parser_env *) r[1];
+ cmd = r[2];
+ arg = r[3];
+ for (i = 0; i < size; i++) Field(tuple, i) = Field(arg, i);
+ modify(&env->lval, tuple);
+ Pop_roots();
+ break; }
+ }
+ Trace(printf("Token %d (0x%lx)\n", Int_val(env->curr_char), env->lval));
+
+ testshift:
+ n1 = Short(tables->sindex, state);
+ n2 = n1 + Int_val(env->curr_char);
+ if (n1 != 0 && n2 >= 0 && n2 <= Int_val(tables->tablesize) &&
+ Short(tables->check, n2) == Int_val(env->curr_char)) goto shift;
+ n1 = Short(tables->rindex, state);
+ n2 = n1 + Int_val(env->curr_char);
+ if (n1 != 0 && n2 >= 0 && n2 <= Int_val(tables->tablesize) &&
+ Short(tables->check, n2) == Int_val(env->curr_char)) {
+ n = Short(tables->table, n2);
+ goto reduce;
+ }
+ env->sp = Val_int(sp);
+ env->state = Val_int(state);
+ return RAISE_PARSE_ERROR;
+ /* The ML code raises the Parse_error exn */
+ shift:
+ state = Short(tables->table, n2);
+ Trace(printf("Shift %d\n", state));
+ sp++;
+ if (sp < Long_val(env->stacksize)) goto push;
+ env->sp = Val_int(sp);
+ env->state = Val_int(state);
+ return GROW_STACKS_1;
+ /* The ML code resizes the stacks */
+ case STACKS_GROWN_1:
+ sp = Int_val(env->sp);
+ state = Int_val(env->state);
+ push:
+ Field(env->s_stack, sp) = Val_int(state);
+ modify(&Field(env->v_stack, sp), env->lval);
+ Field(env->symb_start_stack, sp) = env->symb_start;
+ Field(env->symb_end_stack, sp) = env->symb_end;
+ env->curr_char = Val_int(-1);
+ goto loop;
+
+ reduce:
+ Trace(printf("Reduce %d\n", n));
+ m = Short(tables->len, n);
+ env->asp = Val_int(sp);
+ env->rule_number = Val_int(n);
+ env->rule_len = Val_int(m);
+ sp = sp - m + 1;
+ m = Short(tables->lhs, n);
+ state1 = Int_val(Field(env->s_stack, sp - 1));
+ n1 = Short(tables->gindex, m);
+ n2 = n1 + state1;
+ if (n1 != 0 && n2 >= 0 && n2 <= Int_val(tables->tablesize) &&
+ Short(tables->check, n2) == state1) {
+ state = Short(tables->table, n2);
+ } else {
+ state = Short(tables->dgoto, m);
+ }
+ if (sp < Long_val(env->stacksize)) goto semantic_action;
+ env->sp = Val_int(sp);
+ env->state = Val_int(state);
+ return GROW_STACKS_2;
+ /* The ML code resizes the stacks */
+ case STACKS_GROWN_2:
+ sp = Int_val(env->sp);
+ state = Int_val(env->state);
+ semantic_action:
+ env->sp = Val_int(sp);
+ env->state = Val_int(state);
+ return COMPUTE_SEMANTIC_ACTION;
+ /* The ML code calls the semantic action */
+ case SEMANTIC_ACTION_COMPUTED:
+ sp = Int_val(env->sp);
+ state = Int_val(env->state);
+ Field(env->s_stack, sp) = Val_int(state);
+ modify(&Field(env->v_stack, sp), arg);
+ Field(env->symb_end_stack, sp) =
+ Field(env->symb_end_stack, Int_val(env->asp));
+ goto loop;
+ }
+}
diff --git a/byterun/prims.h b/byterun/prims.h
new file mode 100644
index 0000000000..78478ce7a5
--- /dev/null
+++ b/byterun/prims.h
@@ -0,0 +1,11 @@
+/* Interface with C primitives. */
+
+#ifndef _prims_
+#define _prims_
+
+typedef value (*c_primitive)();
+
+extern c_primitive cprim[];
+extern char * names_of_cprim[];
+
+#endif /* _prims_ */
diff --git a/byterun/reverse.h b/byterun/reverse.h
new file mode 100644
index 0000000000..74e5ccbc28
--- /dev/null
+++ b/byterun/reverse.h
@@ -0,0 +1,54 @@
+/* Swap byte-order in 16-bit, 32-bit and 64-bit words */
+
+#ifndef _reverse_
+#define _reverse_
+
+
+#define Reverse_short(s) { \
+ char * _p; \
+ int _a; \
+ _p = (char *) (s); \
+ _a = _p[0]; \
+ _p[0] = _p[1]; \
+ _p[1] = _a; \
+}
+
+#define Reverse_int32(w) { \
+ char * _p; \
+ int _a; \
+ _p = (char *) (w); \
+ _a = _p[0]; \
+ _p[0] = _p[3]; \
+ _p[3] = _a; \
+ _a = _p[1]; \
+ _p[1] = _p[2]; \
+ _p[2] = _a; \
+}
+
+#define Reverse_int64(d) { \
+ char * _p; \
+ int _a; \
+ _p = (char *) (d); \
+ _a = _p[0]; \
+ _p[0] = _p[7]; \
+ _p[7] = _a; \
+ _a = _p[1]; \
+ _p[1] = _p[6]; \
+ _p[6] = _a; \
+ _a = _p[2]; \
+ _p[2] = _p[5]; \
+ _p[5] = _a; \
+ _a = _p[3]; \
+ _p[3] = _p[4]; \
+ _p[4] = _a; \
+}
+
+#ifdef SIXTYFOUR
+#define Reverse_word Reverse_int64
+#else
+#define Reverse_word Reverse_int32
+#endif
+
+#define Reverse_double Reverse_int64
+
+#endif /* _reverse_ */
diff --git a/byterun/roots.c b/byterun/roots.c
new file mode 100644
index 0000000000..eb0f5dfd0f
--- /dev/null
+++ b/byterun/roots.c
@@ -0,0 +1,49 @@
+/* To walk the memory roots for garbage collection */
+
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "roots.h"
+#include "stacks.h"
+
+value * local_roots = NULL;
+
+struct global_root {
+ value * root;
+ struct global_root * next;
+};
+
+static struct global_root * global_roots = NULL;
+
+void scan_local_roots (copy_fn)
+ void (*copy_fn) ();
+{
+ register value * sp;
+ value * block;
+ struct global_root * gr;
+
+ /* The stack */
+ for (sp = extern_sp; sp < stack_high; sp++) {
+ copy_fn (sp, *sp);
+ }
+ /* Local C roots */
+ for (block = local_roots; block != NULL; block = (value *) block [1]){
+ for (sp = block - (long) block [0]; sp < block; sp++){
+ copy_fn (sp, *sp);
+ }
+ }
+ /* Global C roots */
+ for (gr = global_roots; gr != NULL; gr = gr->next) {
+ copy_fn(gr->root, *(gr->root));
+ }
+}
+
+void register_global_root(r)
+ value * r;
+{
+ struct global_root * gr;
+ gr = (struct global_root *) stat_alloc(sizeof(struct global_root));
+ gr->root = r;
+ gr->next = global_roots;
+ global_roots = gr;
+}
diff --git a/byterun/roots.h b/byterun/roots.h
new file mode 100644
index 0000000000..67732f3cb0
--- /dev/null
+++ b/byterun/roots.h
@@ -0,0 +1,9 @@
+#ifndef _roots_
+#define _roots_
+
+#include "misc.h"
+
+void scan_local_roots P((void (*copy_fn) (value *, value)));
+
+
+#endif /* _roots_ */
diff --git a/byterun/signals.c b/byterun/signals.c
new file mode 100644
index 0000000000..62aabd84cc
--- /dev/null
+++ b/byterun/signals.c
@@ -0,0 +1,158 @@
+#include <signal.h>
+#include "alloc.h"
+#include "config.h"
+#include "fail.h"
+#include "interp.h"
+#include "memory.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "roots.h"
+#include "signals.h"
+
+static Volatile int async_signal_mode = 0;
+Volatile int pending_signal = 0;
+value signal_handlers = 0;
+
+static void execute_signal(signal_number)
+ int signal_number;
+{
+ Assert (!async_signal_mode);
+ callback(Field(signal_handlers, signal_number), Val_int(signal_number));
+}
+
+void handle_signal(signal_number)
+ int signal_number;
+{
+#ifndef BSD_SIGNALS
+ signal(signal_number, handle_signal);
+#endif
+ if (async_signal_mode){
+ leave_blocking_section ();
+ execute_signal(signal_number);
+ enter_blocking_section ();
+ }else{
+ pending_signal = signal_number;
+ something_to_do = 1;
+ }
+}
+
+void enter_blocking_section()
+{
+ int temp;
+
+ while (1){
+ Assert (!async_signal_mode);
+ /* If a signal arrives between the next two instructions,
+ it will be lost. */
+ temp = pending_signal; pending_signal = 0;
+ if (temp) execute_signal(temp);
+ async_signal_mode = 1;
+ if (!pending_signal) break;
+ async_signal_mode = 0;
+ }
+}
+
+/* This function may be called from outside a blocking section. */
+void leave_blocking_section()
+{
+ async_signal_mode = 0;
+}
+
+#ifndef SIGABRT
+#define SIGABRT 0
+#endif
+#ifndef SIGALRM
+#define SIGALRM 0
+#endif
+#ifndef SIGFPE
+#define SIGFPE 0
+#endif
+#ifndef SIGHUP
+#define SIGHUP 0
+#endif
+#ifndef SIGILL
+#define SIGILL 0
+#endif
+#ifndef SIGINT
+#define SIGINT 0
+#endif
+#ifndef SIGKILL
+#define SIGKILL 0
+#endif
+#ifndef SIGPIPE
+#define SIGPIPE 0
+#endif
+#ifndef SIGQUIT
+#define SIGQUIT 0
+#endif
+#ifndef SIGSEGV
+#define SIGSEGV 0
+#endif
+#ifndef SIGTERM
+#define SIGTERM 0
+#endif
+#ifndef SIGUSR1
+#define SIGUSR1 0
+#endif
+#ifndef SIGUSR2
+#define SIGUSR2 0
+#endif
+#ifndef SIGCHLD
+#define SIGCHLD 0
+#endif
+#ifndef SIGCONT
+#define SIGCONT 0
+#endif
+#ifndef SIGSTOP
+#define SIGSTOP 0
+#endif
+#ifndef SIGTSTP
+#define SIGTSTP 0
+#endif
+#ifndef SIGTTIN
+#define SIGTTIN 0
+#endif
+#ifndef SIGTTOU
+#define SIGTTOU 0
+#endif
+
+static int posix_signals[] = {
+ SIGABRT, SIGALRM, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE,
+ SIGQUIT, SIGSEGV, SIGTERM, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT,
+ SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU
+};
+
+value install_signal_handler(signal_number, action) /* ML */
+ value signal_number, action;
+{
+ int sig = Int_val(signal_number);
+ if (sig < 0) {
+ sig = posix_signals[-sig-1];
+ if (sig == 0) invalid_argument("Sys.signal: unavailable signal");
+ }
+ switch(Tag_val(action)) {
+ case 0: /* Signal_default */
+ signal(sig, SIG_DFL);
+ break;
+ case 1: /* Signal_ignore */
+ signal(sig, SIG_IGN);
+ break;
+ case 2: /* Signal_handle */
+ if (signal_handlers == 0) {
+ int i;
+ Push_roots(r, 1);
+ r[0] = action;
+ signal_handlers = alloc_tuple(32);
+ action = r[0];
+ Pop_roots();
+ for (i = 0; i < 32; i++) Field(signal_handlers, i) = Val_int(0);
+ register_global_root(&signal_handlers);
+ }
+ modify(&Field(signal_handlers, sig), Field(action, 0));
+ signal(sig, handle_signal);
+ break;
+ default:
+ Assert(0);
+ }
+ return Val_unit;
+}
diff --git a/byterun/signals.h b/byterun/signals.h
new file mode 100644
index 0000000000..83fbb043cc
--- /dev/null
+++ b/byterun/signals.h
@@ -0,0 +1,13 @@
+#ifndef _signals_
+#define _signals_
+
+#include "misc.h"
+
+extern value signal_handlers;
+extern Volatile int pending_signal;
+
+void enter_blocking_section P((void));
+void leave_blocking_section P((void));
+
+#endif /* _signals_ */
+
diff --git a/byterun/stacks.c b/byterun/stacks.c
new file mode 100644
index 0000000000..c831538590
--- /dev/null
+++ b/byterun/stacks.c
@@ -0,0 +1,60 @@
+/* To initialize and resize the stacks */
+
+#include <string.h>
+#include "config.h"
+#include "fail.h"
+#include "misc.h"
+#include "mlvalues.h"
+#include "stacks.h"
+
+value * stack_low;
+value * stack_high;
+value * stack_threshold;
+value * extern_sp;
+value * trapsp;
+value global_data;
+
+void init_stack()
+{
+ stack_low = (value *) stat_alloc(Stack_size);
+ stack_high = stack_low + Stack_size / sizeof (value);
+ stack_threshold = stack_low + Stack_threshold / sizeof (value);
+ extern_sp = stack_high;
+ trapsp = stack_high;
+}
+
+void realloc_stack()
+{
+ asize_t size;
+ value * new_low, * new_high, * new_sp;
+ value * p;
+
+ Assert(extern_sp >= stack_low);
+ size = stack_high - stack_low;
+ if (size >= Max_stack_size)
+ raise_out_of_memory();
+ size *= 2;
+ gc_message ("Growing stack to %ld kB.\n",
+ (long) size * sizeof(value) / 1024);
+ new_low = (value *) stat_alloc(size * sizeof(value));
+ new_high = new_low + size;
+
+#define shift(ptr) \
+ ((char *) new_high - ((char *) stack_high - (char *) (ptr)))
+
+ new_sp = (value *) shift(extern_sp);
+ bcopy((char *) extern_sp,
+ (char *) new_sp,
+ (stack_high - extern_sp) * sizeof(value));
+ stat_free((char *) stack_low);
+ trapsp = (value *) shift(trapsp);
+ for (p = trapsp; p < new_high; p = Trap_link(p))
+ Trap_link(p) = (value *) shift(Trap_link(p));
+ stack_low = new_low;
+ stack_high = new_high;
+ stack_threshold = stack_low + Stack_threshold / sizeof (value);
+ extern_sp = new_sp;
+
+#undef shift
+}
+
diff --git a/byterun/stacks.h b/byterun/stacks.h
new file mode 100644
index 0000000000..aa68532f8c
--- /dev/null
+++ b/byterun/stacks.h
@@ -0,0 +1,26 @@
+/* structure of the stacks */
+
+#ifndef _stacks_
+#define _stacks_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+#include "memory.h"
+
+extern value * stack_low;
+extern value * stack_high;
+extern value * stack_threshold;
+extern value * extern_sp;
+extern value * trapsp;
+
+#define Trap_pc(tp) (((code_t *)(tp))[0])
+#define Trap_link(tp) (((value **)(tp))[1])
+
+void reset_roots P((void));
+void init_stack P((void));
+void realloc_stack P((void));
+
+
+#endif /* _stacks_ */
+
diff --git a/byterun/str.c b/byterun/str.c
new file mode 100644
index 0000000000..c5f5eedb2d
--- /dev/null
+++ b/byterun/str.c
@@ -0,0 +1,81 @@
+/* Operations on strings */
+
+#include <string.h>
+#include "alloc.h"
+#include "fail.h"
+#include "mlvalues.h"
+#include "misc.h"
+
+mlsize_t string_length(s)
+ value s;
+{
+ mlsize_t temp;
+ temp = Bosize_val(s) - 1;
+ Assert (Byte (s, temp - Byte (s, temp)) == 0);
+ return temp - Byte (s, temp);
+}
+
+value ml_string_length(s) /* ML */
+ value s;
+{
+ mlsize_t temp;
+ temp = Bosize_val(s) - 1;
+ Assert (Byte (s, temp - Byte (s, temp)) == 0);
+ return Val_long(temp - Byte (s, temp));
+}
+
+value create_string(len) /* ML */
+ value len;
+{
+ mlsize_t size = Long_val(len);
+ if (size > Max_wosize * sizeof(value) - 2) invalid_argument("String.create");
+ return alloc_string(size);
+}
+
+value blit_string(argv, argc) /* ML */
+ value * argv;
+ int argc;
+{
+ bcopy(&Byte(argv[0], Long_val(argv[1])),
+ &Byte(argv[2], Long_val(argv[3])),
+ Int_val(argv[4]));
+ return Atom(0);
+}
+
+value fill_string(s, offset, len, init) /* ML */
+ value s, offset, len, init;
+{
+ register char * p;
+ register mlsize_t n;
+ register char c;
+
+ c = Long_val(init);
+ for(p = &Byte(s, Long_val(offset)), n = Long_val(len);
+ n > 0; n--, p++)
+ *p = c;
+ return Atom(0);
+}
+
+static unsigned char printable_chars_ascii[] = /* 0x20-0x7E */
+ "\000\000\000\000\377\377\377\377\377\377\377\377\377\377\377\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
+static unsigned char printable_chars_iso[] = /* 0x20-0x7E 0xA1-0xFF */
+ "\000\000\000\000\377\377\377\377\377\377\377\377\377\377\377\177\000\000\000\000\376\377\377\377\377\377\377\377\377\377\377\377";
+
+value is_printable(chr) /* ML */
+ value chr;
+{
+ int c;
+ static int iso_charset = -1;
+ unsigned char * printable_chars;
+
+ if (iso_charset == -1) {
+ char * lc_ctype = (char *) getenv("LC_CTYPE");
+ if (lc_ctype != 0 && strcmp(lc_ctype, "iso_8859_1") == 0)
+ iso_charset = 1;
+ else
+ iso_charset = 0;
+ }
+ printable_chars = iso_charset ? printable_chars_iso : printable_chars_ascii;
+ c = Int_val(chr);
+ return Val_bool(printable_chars[c >> 3] & (1 << (c & 7)));
+}
diff --git a/byterun/str.h b/byterun/str.h
new file mode 100644
index 0000000000..6f6373e57f
--- /dev/null
+++ b/byterun/str.h
@@ -0,0 +1,11 @@
+#ifndef _str_
+#define _str_
+
+
+#include "misc.h"
+#include "mlvalues.h"
+
+mlsize_t string_length P((value));
+
+
+#endif /* _str_ */
diff --git a/byterun/sys.c b/byterun/sys.c
new file mode 100644
index 0000000000..10f05e2568
--- /dev/null
+++ b/byterun/sys.c
@@ -0,0 +1,186 @@
+/* Basic system calls */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include "config.h"
+#include "alloc.h"
+#include "fail.h"
+#include "instruct.h"
+#include "mlvalues.h"
+#include "signals.h"
+#include "stacks.h"
+
+extern int errno;
+
+#ifdef HAS_STRERROR
+
+extern char * strerror();
+
+char * error_message()
+{
+ return strerror(errno);
+}
+
+#else
+
+extern int sys_nerr;
+extern char * sys_errlist [];
+
+char * error_message()
+{
+ if (errno < 0 || errno >= sys_nerr)
+ return "unknown error";
+ else
+ return sys_errlist[errno];
+}
+
+#endif /* HAS_STRERROR */
+
+void sys_error(arg)
+ char * arg;
+{
+ char * err = error_message();
+ int err_len = strlen(err);
+ int arg_len;
+ value str;
+
+ if (arg == NULL) {
+ str = alloc_string(err_len);
+ bcopy(err, &Byte(str, 0), err_len);
+ } else {
+ arg_len = strlen(arg);
+ str = alloc_string(arg_len + 2 + err_len);
+ bcopy(arg, &Byte(str, 0), arg_len);
+ bcopy(": ", &Byte(str, arg_len), 2);
+ bcopy(err, &Byte(str, arg_len + 2), err_len);
+ }
+ raise_sys_error(str);
+}
+
+void sys_exit(retcode) /* ML */
+ value retcode;
+{
+ exit(Int_val(retcode));
+}
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_TEXT
+#define O_TEXT 0
+#endif
+
+static int sys_open_flags[] = {
+ O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_TRUNC, O_EXCL,
+ O_BINARY, O_TEXT
+};
+
+value sys_open(path, flags, perm) /* ML */
+ value path, flags, perm;
+{
+ int ret;
+ ret = open(String_val(path), convert_flag_list(flags, sys_open_flags),
+ Int_val(perm));
+ if (ret == -1) sys_error(String_val(path));
+ return Val_long(ret);
+}
+
+value sys_close(fd) /* ML */
+ value fd;
+{
+ if (close(Int_val(fd)) != 0) sys_error(NULL);
+ return Atom(0);
+}
+
+value sys_remove(name) /* ML */
+ value name;
+{
+ int ret;
+ ret = unlink(String_val(name));
+ if (ret != 0) sys_error(String_val(name));
+ return Atom(0);
+}
+
+value sys_rename(oldname, newname) /* ML */
+ value oldname, newname;
+{
+ if (rename(String_val(oldname), String_val(newname)) != 0)
+ sys_error(String_val(oldname));
+ return Atom(0);
+}
+
+value sys_chdir(dirname) /* ML */
+ value dirname;
+{
+ if (chdir(String_val(dirname)) != 0) sys_error(String_val(dirname));
+ return Atom(0);
+}
+
+extern char * getenv();
+
+value sys_getenv(var) /* ML */
+ value var;
+{
+ char * res;
+
+ res = getenv(String_val(var));
+ if (res == 0) raise_not_found();
+ return copy_string(res);
+}
+
+static char ** main_argv;
+
+value sys_get_argv(unit) /* ML */
+ value unit;
+{
+ return copy_string_array(main_argv);
+}
+
+void sys_init(argv)
+ char ** argv;
+{
+ main_argv = argv;
+}
+
+value sys_system_command(command) /* ML */
+ value command;
+{
+ int retcode = system(String_val(command));
+ if (retcode == -1) sys_error(String_val(command));
+ return Val_int(retcode);
+}
+
+/* Search path function */
+
+char * searchpath(name)
+ char * name;
+{
+ static char fullname[512];
+ char * path;
+ char * p;
+ char * q;
+
+ for (p = name; *p != 0; p++) {
+ if (*p == '/') return name;
+ }
+ path = getenv("PATH");
+ if (path == 0) return 0;
+ while(1) {
+ p = fullname;
+ while (*path != 0 && *path != ':') {
+ *p++ = *path++;
+ }
+ if (p != fullname) *p++ = '/';
+ q = name;
+ while (*q != 0) {
+ *p++ = *q++;
+ }
+ *p = 0;
+ if (access(fullname, 1) == 0) return fullname;
+ if (*path == 0) return 0;
+ path++;
+ }
+}
diff --git a/byterun/sys.h b/byterun/sys.h
new file mode 100644
index 0000000000..1d4e3b7a2a
--- /dev/null
+++ b/byterun/sys.h
@@ -0,0 +1,10 @@
+#ifndef _sys_
+#define _sys_
+
+#include "misc.h"
+
+void sys_error P((char *));
+void sys_init P((char **));
+void sys_exit P((value)) Noreturn;
+
+#endif /* _sys_ */
diff --git a/byterun/terminfo.c b/byterun/terminfo.c
new file mode 100644
index 0000000000..214984892f
--- /dev/null
+++ b/byterun/terminfo.c
@@ -0,0 +1,126 @@
+/* Read and output terminal commands */
+
+#include "config.h"
+#include "alloc.h"
+#include "fail.h"
+#include "io.h"
+#include "mlvalues.h"
+
+#ifdef HAS_TERMINFO
+
+#undef getch
+#include <curses.h>
+#include <term.h>
+
+value terminfo_setup(unit) /* ML */
+ value unit;
+{
+ if (setupterm(NULL, 1, 1) != 1) failwith("Terminfo.setupterm");
+ return Val_unit;
+}
+
+value terminfo_getstr(capa) /* ML */
+ value capa;
+{
+ char * res = (char *) tigetstr(String_val(capa));
+ if (res == (char *)(-1)) raise_not_found();
+ return copy_string(res);
+}
+
+value terminfo_getnum(capa) /* ML */
+ value capa;
+{
+ int res = tigetnum(String_val(capa));
+ if (res == -2) raise_not_found();
+ return Val_int(res);
+}
+
+#else
+
+#ifdef HAS_TERMCAP
+
+#define _BSD /* For DEC OSF1 */
+#undef getch
+#include <curses.h>
+
+value terminfo_setup(unit)
+ value unit;
+{
+ static buffer[1024];
+ if (tgetent(buffer, getenv("TERM")) != 1) failwith("Terminfo.setupterm");
+ return Val_unit;
+}
+
+value terminfo_getstr(capa)
+ value capa;
+{
+ char buff[1024];
+ char * p = buff;
+ if (tgetstr(String_val(capa), &p) == 0) raise_not_found();
+ return copy_string(buff);
+}
+
+value terminfo_getnum(capa)
+ value capa;
+{
+ int res = tgetnum(String_val(capa));
+ if (res == -1) raise_not_found();
+ return Val_int(res);
+}
+
+#else
+
+value terminfo_setup(unit)
+ value unit;
+{
+ failwith("Terminfo.setupterm");
+ return Val_unit;
+}
+
+value terminfo_getstr(capa)
+ value capa;
+{
+ raise_not_found();
+ return Val_unit;
+}
+
+value terminfo_getnum(capa)
+ value capa;
+{
+ raise_not_found();
+ return Val_unit;
+}
+
+#endif
+#endif
+
+#if defined HAS_TERMINFO || defined HAS_TERMCAP
+
+static struct channel * terminfo_putc_channel;
+
+static int terminfo_putc(c)
+ int c;
+{
+ putch(terminfo_putc_channel, c);
+ return c;
+}
+
+value terminfo_puts(chan, str, count) /* ML */
+ struct channel * chan;
+ value str, count;
+{
+ terminfo_putc_channel = chan;
+ tputs(String_val(str), Int_val(count), terminfo_putc);
+ return Val_unit;
+}
+
+#else
+
+value terminfo_puts(chan, str, count)
+ struct channel * chan;
+ value str, count;
+{
+ invalid_argument("Terminfo.puts");
+}
+
+#endif