summaryrefslogtreecommitdiff
path: root/lib/std/varargs.myr
blob: c2ed1b2b18b1d0bb68578ab4c4ed10819adad83a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use "types.use"
use "introspect.use"
use "sleq.use"
use "die.use"

pkg std =
	type valist

	const vastart	: (args : ...# -> valist)
	const vatype	: (ap : valist# -> byte[:])
	const vabytes	: (ap : valist# -> byte[:])
	generic vanext	: (ap : valist# -> @a)
;;

type valist = struct
	args	: byte#
	tc	: typecursor
;;

/* 
 * a valist is really just a pointer to the varargs.
 * we assume that these sit on the stack nicely,
 * and don't need special handling to get to.
 * 
 * This will be a problem when we switch to a
 * register based convention. We might want to
 * force varargs onto the stack regardless.
 */
const vastart = {args
	var tc, a, ip

	/*
	pull out the args. These are on the stacks like so:

		[ required ]
		[   args   ]
	       ---variadic--- 
		[ typeinfo ] --> type description
	        ------------
		[ variadic ]
		[   args   ]
		[   here   ]

	&args points to the typeinfo, &args + sizeof(void#)
	points to the rest argument.
	*/
		
	tc = typeenc(args)
	ip = (args castto(intptr)) + sizeof(byte#)
	a = ip castto(byte#)
	-> [.args = a, .tc = tc]
}

const vatype = {ap
	-> tcpeek(&ap.tc)
}

const vabytes = {ap
	var sl
	var ti, align, sz
	var p

	ti = typeinfo(tcpeek(&ap.tc))

	/* apply the alignment to the arg pointer */
	align = ti.align castto(intptr)
	p = ap.args castto(intptr)
	p = (p + align - 1) & ~(align - 1)
	ap.args = p castto(byte#)

	sl = ap.args[:ti.size]
	tcnext(&ap.tc)

	sz = ti.size castto(intptr)
	ap.args = ((p castto(intptr)) + sz) castto(byte#)

	-> sl
}

const inspectarg = {x
}

generic vanext = {ap -> @a
	var v : @a
	var ti
	var align
	var p

	ti = typeinfo(tcpeek(&ap.tc))

	/* apply the alignment to the arg pointer */
	align = ti.align castto(intptr)
	inspectarg(align)
	p = ap.args castto(intptr)
	p = (p + align - 1) & ~(align - 1)
	ap.args = p castto(byte#)

	v = (ap.args castto(@a#))#
	/* TODO: check for type mismatch */
	tcnext(&ap.tc)

	/* only move on after we read through the value */
	ap.args = ((p castto(intptr)) + sizeof(@a)) castto(byte#)
	-> v
}