shithub: mc

Download patch

ref: a55b663c54d5c3115879b6ee88fecf375049d6c2
parent: 056657fac60503601ffa32b1919c74b61c23c910
parent: b3ea4473f2850dbd625848bdefa7c7ac943c301a
author: Ori Bernstein <[email protected]>
date: Sun Jul 22 12:58:57 EDT 2012

Merge branch 'master' of git+ssh://mimir.eigenstate.org/git/ori/libmyr

--- a/alloc.myr
+++ b/alloc.myr
@@ -7,14 +7,16 @@
 	generic free	: (v:@a*	-> void)
 
 	const bytealloc	: (sz:size	-> byte*)
-	const bytefree	: (ptr:byte*	-> void)
+	const bytefree	: (m:byte*, sz:size	-> void)
 ;;
 
 /* null pointers */
-const Zbyte = 0 castto(byte*)
-const Zslab = 0 castto(slab*)
-const Zbin = 0 castto(bin*)
-const Pagesz = 4096 /* on the systems this supports, anyways... */
+const Zbyte	= 0 castto(byte*)
+const Zslab	= 0 castto(slab*)
+const Zbin	= 0 castto(bin*)
+const Pagesz 	= 4096	/* on the systems this supports, anyways... */
+const Bucketmax	= 1024	/* Pagesz / 4; a tolerable balance. */
+const Align	= 16	/* minimum allocation alignment */
 
 type bucket = struct
 	sz	: size	/* aligned size */
@@ -30,12 +32,53 @@
 	nfree	: size  /* the number of free nodes */
 ;;
 
-type bin = struct
-	next	: bin*
+type bin = struct	/* NB: must be smaller than sizeof(slab) */
+	next	: bin*	/* the next bin in the free list */
 ;;
 
+var buckets : bucket[32] /* excessive */
+var initdone : int
+
+generic alloc = {-> @a*
+	-> bytealloc(sizeof(@a)) castto(@a*)
+}
+
+generic free = {v:@a* -> void
+	bytefree(v castto(byte*), sizeof(@a))
+}
+
+const bytealloc = {sz
+	var i
+	var bkt
+
+	if !initdone
+		for i = 0; i < buckets.len && (Align << i) < Bucketmax; i++
+			allocinit(&buckets[i], Align << i)
+		;;
+		initdone = 1
+	;;
+
+	if (sz < Bucketmax)
+		bkt = &buckets[bucketnum(sz)]
+		-> bktalloc(bkt)
+	else
+		-> mmap(Zbyte, sz, Mprotrw, Mpriv | Manon, -1, 0)
+	;;
+}
+
+const bytefree = {m, sz
+	var bkt
+
+	if (sz < Bucketmax)
+		bkt = &buckets[bucketnum(sz)]
+		bktfree(bkt, m)
+	else
+		munmap(m, sz)
+	;;
+}
+
 const allocinit = {b : bucket*, sz
-	b.sz = align(sz, 16)
+	b.sz = align(sz, Align)
 	b.nper = (Pagesz - sizeof(slab))/b.sz
 	b.slabs = Zslab
 	b.cache = Zslab
@@ -42,9 +85,13 @@
 	b.ncache = 0
 }
 
-const mkslab = {b : bucket*
+const mkslab = {bkt : bucket*
 	var p
 	var s
+	var b
+	var i
+	var bprev
+	var off /* offset of bin head */
 
 	p = mmap(Zbyte, Pagesz, Mprotrw, Mpriv | Manon, -1, 0)
 	if p == Mapbad
@@ -52,13 +99,87 @@
 	;;
 
 	s = p castto(slab*)
-	s.nfree = b.nper
+	s.nfree = bkt.nper
+	/* skip past the slab header */
+	off = align(sizeof(slab), Align)
+	b = nextbin(s castto(bin*), off)
+	for i = 0; i < bkt.nper; i++
+		b = nextbin(b, bkt.sz)
+		bprev.next = b
+		bprev = b
+	;;
+	bprev.next = Zbin
+	-> s
 }
 
+const bktalloc = {bkt : bucket*
+	var s
+	var b
+
+	/* find a slab */
+	s = bkt.slabs
+	if s == Zslab
+		s = mkslab(bkt)
+		if !s
+			die("No memory left")
+		;;
+		bkt.slabs = s
+	;;
+
+	/* grab the first bin on the slab */
+	b = s.next
+	s.next = b.next
+	s.nfree--
+	if !s.nfree
+		bkt.slabs = s.next
+		s.next = Zslab
+	;;
+
+	-> b castto(byte*)
+}
+
+const bktfree = {bkt : bucket*, m : byte*
+	var s
+	var b
+
+	s = mtrunc(m, Pagesz) castto(slab*)
+	b = m castto(bin*)
+	if s.nfree == 0
+		s.next = bkt.slabs
+		bkt.slabs = s
+	;;
+	s.nfree++
+	b.next = s.freehd
+	s.freehd = b
+}
+
 const delslab = {s : slab*
 
 }
 
+const bucketnum = {sz
+	var i
+	var bktsz
+
+	bktsz = Align
+	for i = 0; bktsz < Bucketmax; i++
+		if bktsz >= sz
+			-> i
+		;;
+		bktsz *= 2
+	;;
+	die("Size does not match any buckets")
+}
+
+/* bins are variable sizes, so we can't just take a slice */
+const nextbin = {b, sz
+	-> ((b castto(intptr)) + sz) castto(bin*)
+}
+
 const align = {v, align
 	-> (v + align - 1) & ~(align - 1)
+}
+
+const mtrunc = {m, align
+	-> ((m castto(intptr)) & ~(align - 1)) castto(byte*)
 }
--- a/bld.sh
+++ b/bld.sh
@@ -15,31 +15,41 @@
 esac
 
 function use {
-    N=`basename $1 .myr`
+    for i in $@; do
+        N=`basename $i .myr`
 
-    echo $MU -o $N.use $1 && \
-    $MU -o $N.use $1
+        echo $MU -o $N.use $i && \
+        $MU -o $N.use $i
+    done
 }
 
 function build {
-    N=`basename $1 .myr`
+    for i in $@; do
+        N=`basename $i .myr`
 
-    echo $MC $1 && \
-    $MC -I. $1
+        echo $MC $i && \
+            $MC -I. $i
+    done
 }
 
 function assem {
-    $CC $ASOPT -m32 -c $1
+    for i in $@; do
+        $CC $ASOPT -m32 -c $i
+    done
 }
 
+ASM=syscall-$SYS.s
+# Myrddin source must be specified in dependency order
+MYR="sys-$SYS.myr \
+    types.myr \
+    alloc.myr \
+    die.myr \
+    hello.myr"
+OBJ="$(echo $ASM | sed 's/\.s/.o /g') $(echo $MYR | sed 's/\.myr/.o /g')"
+assem $ASM
+use $MYR
+build $MYR
 
-use sys-$SYS.myr
-use types.myr 
-use die.myr 
-assem syscall-$SYS.s
-build sys-$SYS.myr
-build hello.myr
-build alloc.myr
-build die.myr
+echo $CC -m32 -o hello $OBJ
+$CC -m32 -o hello $OBJ
 
-$CC -m32 -o hello sys.o hello.o syscall.o
--- a/hello.myr
+++ b/hello.myr
@@ -1,5 +1,8 @@
 use "sys.use"
+use "alloc.use"
 
 const main = {
+	var x : int*
+	x = std.alloc()
 	std.write(1, "Hello world\n")
 }
--- a/types.myr
+++ b/types.myr
@@ -1,4 +1,5 @@
 pkg std =
-	type size = uint32	/* spans entire address space */
-	type off = uint32	/* file offsets */
+	type size	= uint32 /* spans entire address space */
+	type off	= uint32 /* file offsets */
+	type intptr	= uint32 /* can hold any pointer losslessly */
 ;;