Mercurial > pub > dyncall > dyncall
comparison dyncall/dyncall_callvm_x64.c @ 0:3e629dc19168
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:24:28 +0100 |
parents | |
children | 67961454902b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3e629dc19168 |
---|---|
1 /* | |
2 | |
3 Package: dyncall | |
4 Library: dyncall | |
5 File: dyncall/dyncall_callvm_x64.c | |
6 Description: | |
7 License: | |
8 | |
9 Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, | |
10 Tassilo Philipp <tphilipp@potion-studios.com> | |
11 | |
12 Permission to use, copy, modify, and distribute this software for any | |
13 purpose with or without fee is hereby granted, provided that the above | |
14 copyright notice and this permission notice appear in all copies. | |
15 | |
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
23 | |
24 */ | |
25 | |
26 | |
27 | |
28 | |
29 /* MS Windows x64 calling convention, AMD64 SystemV ABI. */ | |
30 | |
31 | |
32 #include "dyncall_callvm_x64.h" | |
33 #include "dyncall_alloc.h" | |
34 #include "dyncall_struct.h" | |
35 | |
36 static DCCallVM* dc_callvm_new_x64(DCCallVM_vt* vt, DCsize size) | |
37 { | |
38 DCCallVM_x64* self = (DCCallVM_x64*)dcAllocMem(sizeof(DCCallVM_x64)+size); | |
39 | |
40 dc_callvm_base_init(&self->mInterface, vt); | |
41 | |
42 /* Since we store register parameters in DCCallVM_x64 directly, adjust the stack size. */ | |
43 size -= sizeof(DCRegData_x64); | |
44 size = (((signed long)size) < 0) ? 0 : size; | |
45 | |
46 | |
47 self->mRegCount.i = self->mRegCount.f = 0; | |
48 | |
49 dcVecInit(&self->mVecHead, size); | |
50 return (DCCallVM*)self; | |
51 } | |
52 | |
53 | |
54 static void dc_callvm_free_x64(DCCallVM* in_self) | |
55 { | |
56 dcFreeMem(in_self); | |
57 } | |
58 | |
59 | |
60 static void dc_callvm_reset_x64(DCCallVM* in_self) | |
61 { | |
62 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
63 dcVecReset(&self->mVecHead); | |
64 self->mRegCount.i = self->mRegCount.f = 0; | |
65 } | |
66 | |
67 | |
68 static void dc_callvm_mode_x64(DCCallVM* self, DCint mode) | |
69 { | |
70 switch(mode) { | |
71 case DC_CALL_C_DEFAULT: | |
72 case DC_CALL_C_ELLIPSIS: | |
73 break; | |
74 default: | |
75 self->mError = DC_ERROR_UNSUPPORTED_MODE; | |
76 break; | |
77 } | |
78 } | |
79 | |
80 | |
81 static void dc_callvm_argLongLong_x64(DCCallVM* in_self, DClonglong x) | |
82 { | |
83 /* A long long always has 64 bits on the supported x64 platforms (lp64 on unix and llp64 on windows). */ | |
84 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
85 if(self->mRegCount.i < numIntRegs) | |
86 self->mRegData.i[self->mRegCount.i++] = x; | |
87 else | |
88 dcVecAppend(&self->mVecHead, &x, sizeof(DClonglong)); | |
89 } | |
90 | |
91 | |
92 static void dc_callvm_argBool_x64(DCCallVM* in_self, DCbool x) | |
93 { | |
94 dc_callvm_argLongLong_x64(in_self, (DClonglong)x); | |
95 } | |
96 | |
97 | |
98 static void dc_callvm_argChar_x64(DCCallVM* in_self, DCchar x) | |
99 { | |
100 dc_callvm_argLongLong_x64(in_self, x); | |
101 } | |
102 | |
103 | |
104 static void dc_callvm_argShort_x64(DCCallVM* in_self, DCshort x) | |
105 { | |
106 dc_callvm_argLongLong_x64(in_self, x); | |
107 } | |
108 | |
109 | |
110 static void dc_callvm_argInt_x64(DCCallVM* in_self, DCint x) | |
111 { | |
112 dc_callvm_argLongLong_x64(in_self, x); | |
113 } | |
114 | |
115 | |
116 static void dc_callvm_argLong_x64(DCCallVM* in_self, DClong x) | |
117 { | |
118 dc_callvm_argLongLong_x64(in_self, x); | |
119 } | |
120 | |
121 | |
122 static void dc_callvm_argFloat_x64(DCCallVM* in_self, DCfloat x) | |
123 { | |
124 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
125 | |
126 /* Although not promoted to doubles, floats are stored with 64bits in this API.*/ | |
127 union { | |
128 DCdouble d; | |
129 DCfloat f; | |
130 } f; | |
131 f.f = x; | |
132 | |
133 if(self->mRegCount.f < numFloatRegs) | |
134 *(DCfloat*)&self->mRegData.f[self->mRegCount.f++] = x; | |
135 else | |
136 dcVecAppend(&self->mVecHead, &f.f, sizeof(DCdouble)); | |
137 } | |
138 | |
139 | |
140 static void dc_callvm_argDouble_x64(DCCallVM* in_self, DCdouble x) | |
141 { | |
142 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
143 if(self->mRegCount.f < numFloatRegs) | |
144 self->mRegData.f[self->mRegCount.f++] = x; | |
145 else | |
146 dcVecAppend(&self->mVecHead, &x, sizeof(DCdouble)); | |
147 } | |
148 | |
149 | |
150 static void dc_callvm_argPointer_x64(DCCallVM* in_self, DCpointer x) | |
151 { | |
152 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
153 if(self->mRegCount.i < numIntRegs) | |
154 *(DCpointer*)&self->mRegData.i[self->mRegCount.i++] = x; | |
155 else | |
156 dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer)); | |
157 } | |
158 | |
159 static void dc_callvm_argStruct_x64(DCCallVM* in_self, DCstruct* s, DCpointer x) | |
160 { | |
161 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
162 dcVecAppend(&self->mVecHead, x, s->size); | |
163 /*printf("dc_callvm_argStruct_x64 size = %d\n", (int)s->size);@@@*/ | |
164 if (s->size <= 64) | |
165 dcArgStructUnroll(in_self, s, x); | |
166 /*else@@@*/ | |
167 /* dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer));@@@*/ | |
168 } | |
169 | |
170 | |
171 /* Call. */ | |
172 void dc_callvm_call_x64(DCCallVM* in_self, DCpointer target) | |
173 { | |
174 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
175 #if defined(DC_UNIX) | |
176 dcCall_x64_sysv( | |
177 #else | |
178 dcCall_x64_win64( | |
179 #endif | |
180 dcVecSize(&self->mVecHead), /* Size of stack data. */ | |
181 dcVecData(&self->mVecHead), /* Pointer to stack arguments. */ | |
182 self->mRegData.i, /* Pointer to register arguments (ints on SysV). */ | |
183 #if defined(DC_UNIX) | |
184 self->mRegData.f, /* Pointer to floating point register arguments. */ | |
185 #endif | |
186 target | |
187 ); | |
188 } | |
189 | |
190 | |
191 DCCallVM_vt gVT_x64 = | |
192 { | |
193 &dc_callvm_free_x64 | |
194 , &dc_callvm_reset_x64 | |
195 , &dc_callvm_mode_x64 | |
196 , &dc_callvm_argBool_x64 | |
197 , &dc_callvm_argChar_x64 | |
198 , &dc_callvm_argShort_x64 | |
199 , &dc_callvm_argInt_x64 | |
200 , &dc_callvm_argLong_x64 | |
201 , &dc_callvm_argLongLong_x64 | |
202 , &dc_callvm_argFloat_x64 | |
203 , &dc_callvm_argDouble_x64 | |
204 , &dc_callvm_argPointer_x64 | |
205 , &dc_callvm_argStruct_x64 | |
206 , (DCvoidvmfunc*) &dc_callvm_call_x64 | |
207 , (DCboolvmfunc*) &dc_callvm_call_x64 | |
208 , (DCcharvmfunc*) &dc_callvm_call_x64 | |
209 , (DCshortvmfunc*) &dc_callvm_call_x64 | |
210 , (DCintvmfunc*) &dc_callvm_call_x64 | |
211 , (DClongvmfunc*) &dc_callvm_call_x64 | |
212 , (DClonglongvmfunc*) &dc_callvm_call_x64 | |
213 , (DCfloatvmfunc*) &dc_callvm_call_x64 | |
214 , (DCdoublevmfunc*) &dc_callvm_call_x64 | |
215 , (DCpointervmfunc*) &dc_callvm_call_x64 | |
216 , NULL /* callStruct */ | |
217 }; | |
218 | |
219 | |
220 DCCallVM* dcNewCallVM_x64(DCsize size) | |
221 { | |
222 return dc_callvm_new_x64(&gVT_x64, size); | |
223 } | |
224 | |
225 DCCallVM* dcNewCallVM(DCsize size) | |
226 { | |
227 return dcNewCallVM_x64(size); | |
228 } | |
229 |