1 /**
2  * The vararg module is intended to facilitate vararg manipulation in D.
3  * It should be interface compatible with the C module "stdarg," and the
4  * two modules may share a common implementation if possible (as is done
5  * here).
6  * Copyright: Copyright Digital Mars 2000 - 2009.
7  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Authors:   Walter Bright, Hauke Duden
9  * Source:    $(DRUNTIMESRC core/_vararg.d)
10  */
11 
12 /*          Copyright Digital Mars 2000 - 2009.
13  * Distributed under the Boost Software License, Version 1.0.
14  *    (See accompanying file LICENSE or copy at
15  *          http://www.boost.org/LICENSE_1_0.txt)
16  */
17 module core.vararg;
18 
19 public import core.stdc.stdarg;
20 
21 
version(GNU)22 version (GNU) { /* TypeInfo-based va_arg overload unsupported */ }
23 else:
24 
25 version (ARM)     version = ARM_Any;
26 version (AArch64) version = ARM_Any;
27 version (MIPS32)  version = MIPS_Any;
28 version (MIPS64)  version = MIPS_Any;
29 version (PPC)     version = PPC_Any;
30 version (PPC64)   version = PPC_Any;
31 
version(ARM_Any)32 version (ARM_Any)
33 {
34     // Darwin uses a simpler varargs implementation
35     version (OSX) {}
36     else version (iOS) {}
37     else version (TVOS) {}
38     else version (WatchOS) {}
39     else:
40 
41     version (ARM)     version = AAPCS32;
42     version (AArch64) version = AAPCS64;
43 }
44 
45 
46 ///
47 alias va_arg = core.stdc.stdarg.va_arg;
48 
49 
50 /**
51  * Retrieve and store through parmn the next value that is of TypeInfo ti.
52  * Used when the static type is not known.
53  */
va_arg()54 void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
55 {
56     version (X86)
57     {
58         // Wait until everyone updates to get TypeInfo.talign
59         //auto talign = ti.talign;
60         //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
61         auto p = ap;
62         auto tsize = ti.tsize;
63         ap = cast(va_list) (p + tsize.alignUp);
64         parmn[0..tsize] = p[0..tsize];
65     }
66     else version (Win64)
67     {
68         version (LDC) enum isLDC = true;
69         else          enum isLDC = false;
70 
71         // Wait until everyone updates to get TypeInfo.talign
72         //auto talign = ti.talign;
73         //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
74         auto p = ap;
75         auto tsize = ti.tsize;
76         void* q;
77         if (isLDC && tsize == 16 && cast(TypeInfo_Array) ti)
78         {
79             q = p;
80             ap = cast(va_list) (p + tsize);
81         }
82         else
83         {
84             q = (tsize > size_t.sizeof || (tsize & (tsize - 1)) != 0) ? *cast(void**) p : p;
85             ap = cast(va_list) (p + size_t.sizeof);
86         }
87         parmn[0..tsize] = q[0..tsize];
88     }
89     else version (X86_64)
90     {
91         static import core.internal.vararg.sysv_x64;
92         core.internal.vararg.sysv_x64.va_arg(ap, ti, parmn);
93     }
94     else version (AAPCS32)
95     {
96         const tsize = ti.tsize;
97         if (ti.talign >= 8)
98             ap.__ap = ap.__ap.alignUp!8;
99         auto p = ap.__ap;
100         version (BigEndian)
101             p = adjustForBigEndian(p, tsize);
102         ap.__ap += tsize.alignUp;
103         parmn[0..tsize] = p[0..tsize];
104     }
105     else version (AAPCS64)
106     {
107         static import core.internal.vararg.aarch64;
108         core.internal.vararg.aarch64.va_arg(ap, ti, parmn);
109     }
110     else version (ARM_Any)
111     {
112         const tsize = ti.tsize;
113         auto p = cast(void*) ap;
114         version (BigEndian)
115             p = adjustForBigEndian(p, tsize);
116         ap += tsize.alignUp;
117         parmn[0..tsize] = p[0..tsize];
118     }
119     else version (PPC_Any)
120     {
121         if (ti.talign >= 8)
122             ap = ap.alignUp!8;
123         const tsize = ti.tsize;
124         auto p = cast(void*) ap;
125         version (BigEndian)
126             p = adjustForBigEndian(p, tsize);
127         ap += tsize.alignUp;
128         parmn[0..tsize] = p[0..tsize];
129     }
130     else version (MIPS_Any)
131     {
132         const tsize = ti.tsize;
133         auto p = cast(void*) ap;
134         version (BigEndian)
135             p = adjustForBigEndian(p, tsize);
136         ap += tsize.alignUp;
137         parmn[0..tsize] = p[0..tsize];
138     }
139     else
140         static assert(0, "Unsupported platform");
141 }
142