blob: 939f42d455cf5cbebf4ed0eef2127d9da76bca53 (
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
|
use "types.use"
use "introspect.use"
use "sleq.use"
use "die.use"
pkg std =
type valist
const vastart : (args : ...# -> valist)
generic vanext : (ap : valist -> (@a, valist))
;;
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]
}
generic vanext = {ap -> (@a, valist)
var v : @a
var align
var p
/*
Assumptions about the ABI:
* all types smaller than a word are
* aligned to their own size. Larger
* types are aligned to word size.
*/
if sizeof(@a) > 8
align = 8
else
align = sizeof(@a)
;;
/* apply the alignment to the arg pointer */
p = ap.args castto(intptr)
p = (p + align - 1) & ~(align - 1)
ap.args = p castto(byte#)
v = (ap.args castto(@a#))#
/* TODO: checked.
Right now, too much is broken with named types.
if !sleq(typeof(v), tcnext(&ap.tc))
std.die("wrong type from valist\n")
;;
*/
/* only move on after we read through the value */
ap.args = ((p castto(intptr)) + sizeof(@a)) castto(byte#)
-> (v, ap)
}
|