Mercurial > pub > dyncall > dyncall
comparison test/plain_c++/test_main.cc @ 533:71c884e610f0
- integration of patches from Raphael Luba, Thekla, Inc.:
* integration of aggregate-by-value (struct, union) support patch for x64 (win and sysv)
* windows/x64 asm additions to specify how stack unwinds (help for debuggers, exception handling, etc.)
* see Changelog for details
- new calling convention modes for thiscalls (platform agnostic, was specific before)
* new signature character for platform agnostic thiscalls ('*' / DC_SIGCHAR_CC_THISCALL)
- dcCallF(), dcVCallF(), dcArgF() and dcVArgF():
* added support for aggregates-by-value (wasn't part of patch)
* change that those functions don't implicitly call dcReset() anymore, which was unflexible (breaking change)
- added macros to feature test implementation for aggregate-by-value and syscall support
- changed libdyncall_s.lib and libdyncallback_s.lib order in callback test makefiles, as some toolchains are picky about order
- doc:
* man page updates to describe aggregate interface
* manual overview changes to highlight platforms with aggregate-by-value support
- test/plain: replaced tests w/ old/stale sctruct interface with new aggregate one
author | Tassilo Philipp |
---|---|
date | Thu, 21 Apr 2022 13:35:47 +0200 |
parents | ddfb9577a00e |
children | 0c3f5355769d |
comparison
equal
deleted
inserted
replaced
532:d4bf63ab9164 | 533:71c884e610f0 |
---|---|
4 Library: test | 4 Library: test |
5 File: test/plain_c++/test_main.cc | 5 File: test/plain_c++/test_main.cc |
6 Description: | 6 Description: |
7 License: | 7 License: |
8 | 8 |
9 Copyright (c) 2007-2019 Daniel Adler <dadler@uni-goettingen.de>, | 9 Copyright (c) 2007-2022 Daniel Adler <dadler@uni-goettingen.de>, |
10 Tassilo Philipp <tphilipp@potion-studios.com> | 10 Tassilo Philipp <tphilipp@potion-studios.com> |
11 | 11 |
12 Permission to use, copy, modify, and distribute this software for any | 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 | 13 purpose with or without fee is hereby granted, provided that the above |
14 copyright notice and this permission notice appear in all copies. | 14 copyright notice and this permission notice appear in all copies. |
28 | 28 |
29 #include "../../dyncall/dyncall.h" | 29 #include "../../dyncall/dyncall.h" |
30 #include "../common/platformInit.h" | 30 #include "../common/platformInit.h" |
31 #include "../common/platformInit.c" /* Impl. for functions only used in this translation unit */ | 31 #include "../common/platformInit.c" /* Impl. for functions only used in this translation unit */ |
32 | 32 |
33 #include "../../dyncall/dyncall_aggregate.h" | |
33 | 34 |
34 #include <signal.h> | 35 #include <signal.h> |
35 #include <setjmp.h> | 36 #include <setjmp.h> |
37 #include <stdarg.h> | |
36 | 38 |
37 jmp_buf jbuf; | 39 jmp_buf jbuf; |
38 | 40 |
39 | 41 |
40 void segv_handler(int sig) | 42 void segv_handler(int sig) |
108 #define VTBI_GET_FLOAT VTBI_BASE+9 | 110 #define VTBI_GET_FLOAT VTBI_BASE+9 |
109 #define VTBI_SET_DOUBLE VTBI_BASE+10 | 111 #define VTBI_SET_DOUBLE VTBI_BASE+10 |
110 #define VTBI_GET_DOUBLE VTBI_BASE+11 | 112 #define VTBI_GET_DOUBLE VTBI_BASE+11 |
111 #define VTBI_SET_POINTER VTBI_BASE+12 | 113 #define VTBI_SET_POINTER VTBI_BASE+12 |
112 #define VTBI_GET_POINTER VTBI_BASE+13 | 114 #define VTBI_GET_POINTER VTBI_BASE+13 |
115 #define VTBI_SUM_3_INTS VTBI_BASE+14 | |
113 | 116 |
114 class Value | 117 class Value |
115 { | 118 { |
116 public: | 119 public: |
117 virtual ~Value() {} | 120 virtual ~Value() {} |
128 virtual DCfloat __cdecl getFloat() { return mValue.f; } | 131 virtual DCfloat __cdecl getFloat() { return mValue.f; } |
129 virtual void __cdecl setDouble(DCdouble x) { mValue.d = x; } | 132 virtual void __cdecl setDouble(DCdouble x) { mValue.d = x; } |
130 virtual DCdouble __cdecl getDouble() { return mValue.d; } | 133 virtual DCdouble __cdecl getDouble() { return mValue.d; } |
131 virtual void __cdecl setPtr(DCpointer x) { mValue.p = x; } | 134 virtual void __cdecl setPtr(DCpointer x) { mValue.p = x; } |
132 virtual DCpointer __cdecl getPtr() { return mValue.p; } | 135 virtual DCpointer __cdecl getPtr() { return mValue.p; } |
136 | |
137 /* ellipsis test w/ this ptr */ | |
138 virtual int __cdecl sum3Ints(DCint x, ...) { va_list va; va_start(va,x); x += va_arg(va,int) + va_arg(va,int); va_end(va); return x; } | |
139 | |
133 private: | 140 private: |
134 ValueUnion mValue; | 141 ValueUnion mValue; |
135 }; | 142 }; |
143 | |
144 template<typename T> | |
145 bool testCallValue(DCCallVM* pc, const char* name) | |
146 { | |
147 bool r = true, b; | |
148 T o; | |
149 T* pThis = &o; | |
150 DCpointer* vtbl = *( (DCpointer**) pThis ); /* vtbl is located at beginning of class */ | |
151 | |
152 /* set/get bool (TRUE) */ | |
153 | |
154 dcReset(pc); | |
155 dcArgPointer(pc, pThis); | |
156 dcArgBool(pc,DC_TRUE); | |
157 dcCallVoid(pc, vtbl[VTBI_SET_BOOL] ); | |
158 dcReset(pc); | |
159 dcArgPointer(pc, pThis); | |
160 b = ( dcCallBool(pc, vtbl[VTBI_GET_BOOL] ) == DC_TRUE ); | |
161 printf("bt (%s): %d\n", name, b); | |
162 r = r && b; | |
163 | |
164 /* set/get bool (FALSE) */ | |
165 | |
166 dcReset(pc); | |
167 dcArgPointer(pc, pThis); | |
168 dcArgBool(pc,DC_FALSE); | |
169 dcCallVoid(pc, vtbl[VTBI_SET_BOOL] ); | |
170 dcReset(pc); | |
171 dcArgPointer(pc, pThis); | |
172 b = ( dcCallBool(pc, vtbl[VTBI_GET_BOOL] ) == DC_FALSE ); | |
173 printf("bf (%s): %d\n", name, b); | |
174 r = r && b; | |
175 | |
176 /* set/get int */ | |
177 | |
178 dcReset(pc); | |
179 dcArgPointer(pc, pThis); | |
180 dcArgInt(pc,1234); | |
181 dcCallVoid(pc, vtbl[VTBI_SET_INT] ); | |
182 dcReset(pc); | |
183 dcArgPointer(pc, pThis); | |
184 b = ( dcCallInt(pc, vtbl[VTBI_GET_INT] ) == 1234 ); | |
185 printf("i (%s): %d\n", name, b); | |
186 r = r && b; | |
187 | |
188 /* set/get long */ | |
189 | |
190 dcReset(pc); | |
191 dcArgPointer(pc, pThis); | |
192 dcArgLong(pc,0xCAFEBABEUL); | |
193 dcCallVoid(pc, vtbl[VTBI_SET_LONG] ); | |
194 dcReset(pc); | |
195 dcArgPointer(pc, pThis); | |
196 b = ( dcCallLong(pc, vtbl[VTBI_GET_LONG] ) == (DClong)0xCAFEBABEUL ); | |
197 printf("l (%s): %d\n", name, b); | |
198 r = r && b; | |
199 | |
200 /* set/get long long */ | |
201 | |
202 dcReset(pc); | |
203 dcArgPointer(pc, pThis); | |
204 dcArgLongLong(pc,0xCAFEBABEDEADC0DELL); | |
205 dcCallVoid(pc, vtbl[VTBI_SET_LONG_LONG] ); | |
206 dcReset(pc); | |
207 dcArgPointer(pc, pThis); | |
208 b = ( dcCallLongLong(pc, vtbl[VTBI_GET_LONG_LONG] ) == (DClonglong)0xCAFEBABEDEADC0DELL ); | |
209 printf("ll (%s): %d\n", name, b); | |
210 r = r && b; | |
211 | |
212 /* set/get float */ | |
213 | |
214 dcReset(pc); | |
215 dcArgPointer(pc, pThis); | |
216 dcArgFloat(pc,1.2345f); | |
217 dcCallVoid(pc, vtbl[VTBI_SET_FLOAT] ); | |
218 dcReset(pc); | |
219 dcArgPointer(pc, pThis); | |
220 b = ( dcCallFloat(pc, vtbl[VTBI_GET_FLOAT] ) == 1.2345f ); | |
221 printf("f (%s): %d\n", name, b); | |
222 r = r && b; | |
223 | |
224 /* set/get double */ | |
225 | |
226 dcReset(pc); | |
227 dcArgPointer(pc, pThis); | |
228 dcArgDouble(pc,1.23456789); | |
229 dcCallVoid(pc, vtbl[VTBI_SET_DOUBLE] ); | |
230 dcReset(pc); | |
231 dcArgPointer(pc, pThis); | |
232 b = ( dcCallDouble(pc, vtbl[VTBI_GET_DOUBLE] ) == 1.23456789 ); | |
233 printf("d (%s): %d\n", name, b); | |
234 r = r && b; | |
235 | |
236 /* set/get pointer */ | |
237 | |
238 dcReset(pc); | |
239 dcArgPointer(pc, pThis); | |
240 dcArgPointer(pc, (DCpointer) 0xCAFEBABE ); | |
241 dcCallVoid(pc, vtbl[VTBI_SET_POINTER] ); | |
242 dcReset(pc); | |
243 dcArgPointer(pc, pThis); | |
244 b = ( dcCallPointer(pc, vtbl[VTBI_GET_POINTER] ) == ( (DCpointer) 0xCAFEBABE ) ); | |
245 printf("p (%s): %d\n", name, b); | |
246 r = r && b; | |
247 | |
248 /* ellipsis test w/ this pointer */ | |
249 | |
250 dcReset(pc); | |
251 dcMode(pc, DC_CALL_C_ELLIPSIS); | |
252 dcArgPointer(pc, pThis); | |
253 dcArgInt(pc, 23); | |
254 dcMode(pc, DC_CALL_C_ELLIPSIS_VARARGS); | |
255 dcArgInt(pc, -223); | |
256 dcArgInt(pc, 888); | |
257 int r_ = dcCallInt(pc, vtbl[VTBI_SUM_3_INTS]); | |
258 b = (r_ == 688); | |
259 printf("... (%s): %d\n", name, b); | |
260 r = r && b; | |
261 | |
262 return r; | |
263 } | |
264 | |
265 | |
266 #if defined(DC__OS_Win32) && defined(DC__C_MSVC) | |
136 | 267 |
137 /* C++ class using (on win32: microsoft) this call */ | 268 /* C++ class using (on win32: microsoft) this call */ |
138 | 269 |
139 class ValueMS | 270 class ValueMS |
140 { | 271 { |
157 virtual DCpointer getPtr() { return mValue.p; } | 288 virtual DCpointer getPtr() { return mValue.p; } |
158 private: | 289 private: |
159 ValueUnion mValue; | 290 ValueUnion mValue; |
160 }; | 291 }; |
161 | 292 |
162 template<typename T> | 293 static bool testCallThisMS() |
163 bool testCallValue(DCCallVM* pc, const char* name) | |
164 { | |
165 bool r = true, b; | |
166 T o; | |
167 T* pThis = &o; | |
168 DCpointer* vtbl = *( (DCpointer**) pThis ); /* vtbl is located at beginning of class */ | |
169 | |
170 /* set/get bool (TRUE) */ | |
171 | |
172 dcReset(pc); | |
173 dcArgPointer(pc, pThis); | |
174 dcArgBool(pc,DC_TRUE); | |
175 dcCallVoid(pc, vtbl[VTBI_SET_BOOL] ); | |
176 dcReset(pc); | |
177 dcArgPointer(pc, pThis); | |
178 b = ( dcCallBool(pc, vtbl[VTBI_GET_BOOL] ) == DC_TRUE ); | |
179 printf("bt (%s): %d\n", name, b); | |
180 r = r && b; | |
181 | |
182 /* set/get bool (FALSE) */ | |
183 | |
184 dcReset(pc); | |
185 dcArgPointer(pc, pThis); | |
186 dcArgBool(pc,DC_FALSE); | |
187 dcCallVoid(pc, vtbl[VTBI_SET_BOOL] ); | |
188 dcReset(pc); | |
189 dcArgPointer(pc, pThis); | |
190 b = ( dcCallBool(pc, vtbl[VTBI_GET_BOOL] ) == DC_FALSE ); | |
191 printf("bf (%s): %d\n", name, b); | |
192 r = r && b; | |
193 | |
194 /* set/get int */ | |
195 | |
196 dcReset(pc); | |
197 dcArgPointer(pc, pThis); | |
198 dcArgInt(pc,1234); | |
199 dcCallVoid(pc, vtbl[VTBI_SET_INT] ); | |
200 dcReset(pc); | |
201 dcArgPointer(pc, pThis); | |
202 b = ( dcCallInt(pc, vtbl[VTBI_GET_INT] ) == 1234 ); | |
203 printf("i (%s): %d\n", name, b); | |
204 r = r && b; | |
205 | |
206 /* set/get long */ | |
207 | |
208 dcReset(pc); | |
209 dcArgPointer(pc, pThis); | |
210 dcArgLong(pc,0xCAFEBABEUL); | |
211 dcCallVoid(pc, vtbl[VTBI_SET_LONG] ); | |
212 dcReset(pc); | |
213 dcArgPointer(pc, pThis); | |
214 b = ( dcCallLong(pc, vtbl[VTBI_GET_LONG] ) == (DClong)0xCAFEBABEUL ); | |
215 printf("l (%s): %d\n", name, b); | |
216 r = r && b; | |
217 | |
218 /* set/get long long */ | |
219 | |
220 dcReset(pc); | |
221 dcArgPointer(pc, pThis); | |
222 dcArgLongLong(pc,0xCAFEBABEDEADC0DELL); | |
223 dcCallVoid(pc, vtbl[VTBI_SET_LONG_LONG] ); | |
224 dcReset(pc); | |
225 dcArgPointer(pc, pThis); | |
226 b = ( dcCallLongLong(pc, vtbl[VTBI_GET_LONG_LONG] ) == (DClonglong)0xCAFEBABEDEADC0DELL ); | |
227 printf("ll (%s): %d\n", name, b); | |
228 r = r && b; | |
229 | |
230 /* set/get float */ | |
231 | |
232 dcReset(pc); | |
233 dcArgPointer(pc, pThis); | |
234 dcArgFloat(pc,1.2345f); | |
235 dcCallVoid(pc, vtbl[VTBI_SET_FLOAT] ); | |
236 dcReset(pc); | |
237 dcArgPointer(pc, pThis); | |
238 b = ( dcCallFloat(pc, vtbl[VTBI_GET_FLOAT] ) == 1.2345f ); | |
239 printf("f (%s): %d\n", name, b); | |
240 r = r && b; | |
241 | |
242 /* set/get double */ | |
243 | |
244 dcReset(pc); | |
245 dcArgPointer(pc, pThis); | |
246 dcArgDouble(pc,1.23456789); | |
247 dcCallVoid(pc, vtbl[VTBI_SET_DOUBLE] ); | |
248 dcReset(pc); | |
249 dcArgPointer(pc, pThis); | |
250 b = ( dcCallDouble(pc, vtbl[VTBI_GET_DOUBLE] ) == 1.23456789 ); | |
251 printf("d (%s): %d\n", name, b); | |
252 r = r && b; | |
253 | |
254 /* set/get pointer */ | |
255 | |
256 dcReset(pc); | |
257 dcArgPointer(pc, pThis); | |
258 dcArgPointer(pc, (DCpointer) 0xCAFEBABE ); | |
259 dcCallVoid(pc, vtbl[VTBI_SET_POINTER] ); | |
260 dcReset(pc); | |
261 dcArgPointer(pc, pThis); | |
262 b = ( dcCallPointer(pc, vtbl[VTBI_GET_POINTER] ) == ( (DCpointer) 0xCAFEBABE ) ); | |
263 printf("p (%s): %d\n", name, b); | |
264 r = r && b; | |
265 | |
266 return r; | |
267 } | |
268 | |
269 | |
270 #if defined(DC__OS_Win32) | |
271 | |
272 int testCallThisMS() | |
273 { | 294 { |
274 bool r = false; | 295 bool r = false; |
275 DCCallVM* pc = dcNewCallVM(4096); | 296 DCCallVM* pc = dcNewCallVM(4096); |
276 dcMode(pc, DC_CALL_C_X86_WIN32_THIS_MS); | 297 dcMode(pc, DC_CALL_C_X86_WIN32_THIS_MS); |
277 dcReset(pc); | 298 dcReset(pc); |
278 if(setjmp(jbuf) != 0) | 299 if(setjmp(jbuf) != 0) |
279 printf("sigsegv\n"); | 300 printf("sigsegv\n"), r=false; |
280 else | 301 else |
281 r = testCallValue<ValueMS>(pc, "MS"); | 302 r = testCallValue<ValueMS>(pc, "MS"); |
282 dcFree(pc); | 303 dcFree(pc); |
283 return r; | 304 return r; |
284 } | 305 } |
285 | 306 |
286 #endif | 307 #endif |
287 | 308 |
288 | 309 |
289 int testCallThisC() | 310 static bool testCallThisC() |
290 { | 311 { |
291 bool r = false; | 312 bool r = false; |
292 DCCallVM* pc = dcNewCallVM(4096); | 313 DCCallVM* pc = dcNewCallVM(4096); |
293 dcMode(pc, DC_CALL_C_DEFAULT_THIS); | 314 dcMode(pc, DC_CALL_C_DEFAULT_THIS); |
294 dcReset(pc); | 315 dcReset(pc); |
295 if(setjmp(jbuf) != 0) | 316 if(setjmp(jbuf) != 0) |
296 printf("sigsegv\n"); | 317 printf("sigsegv\n"), r=false; |
297 else | 318 else |
298 r = testCallValue<Value>(pc, "c"); | 319 r = testCallValue<Value>(pc, "c"); |
299 dcFree(pc); | 320 dcFree(pc); |
300 return r; | 321 return r; |
301 } | 322 } |
302 | 323 |
303 | 324 |
325 #if defined(DC__Feature_AggrByVal) | |
326 | |
327 class ValueAggr | |
328 { | |
329 public: | |
330 struct S { int i, j, k, l, m; }; | |
331 | |
332 virtual ~ValueAggr() {} | |
333 | |
334 virtual void __cdecl setAggr(S x) { mS.i = x.i; mS.j = x.j; mS.k = x.k; mS.l = x.l; mS.m = x.m; } | |
335 virtual S __cdecl getAggr() { return mS; } | |
336 | |
337 /* ellipsis test w/ this ptr and big (!) aggregate return */ | |
338 struct Big { int sum; long long dummy[50]; /*dummy to make it not fit in any regs*/ }; | |
339 virtual struct Big __cdecl sum3RetAggr(DCint x, ...) { va_list va; va_start(va,x); struct Big r = { x + va_arg(va,int) + va_arg(va,int) }; va_end(va); return r; } | |
340 | |
341 /* non-trivial aggregate */ | |
342 struct NonTriv { | |
343 int i, j; | |
344 NonTriv(int a, int b) : i(a),j(b) { } | |
345 NonTriv(const NonTriv& rhs) { static int a=13, b=37; i = a++; j = b++; } | |
346 }; | |
347 /* by value, so on first invocation a = 13,37, b = 14,38 and retval = 13*14,37*38, no matter the contents of the instances as copy ctor is called */ | |
348 /* NOTE: copy of return value is subject to C++ "copy elision", so it is *not* calling the copy ctor for the return value */ | |
349 virtual struct NonTriv __cdecl squareFields(NonTriv a, NonTriv b) { return NonTriv(a.i*b.i, a.j*b.j); } | |
350 | |
351 private: | |
352 struct S mS; | |
353 }; | |
354 | |
355 #if (__cplusplus >= 201103L) | |
356 # include <type_traits> | |
357 #endif | |
358 | |
359 /* special case w/ e.g. MS x64 C++ calling cconf: struct return ptr is passed as *2nd* arg */ | |
360 static bool testCallThisAggr() | |
361 { | |
362 bool r = false; | |
363 DCCallVM* pc = dcNewCallVM(4096); | |
364 dcMode(pc, DC_CALL_C_DEFAULT_THIS); | |
365 | |
366 if(setjmp(jbuf) != 0) | |
367 printf("sigsegv\n"), r=false; | |
368 else | |
369 { | |
370 ValueAggr o; | |
371 | |
372 DCpointer* vtbl = *( (DCpointer**) &o ); /* vtbl is located at beginning of class */ | |
373 ValueAggr::S st = { 124, -12, 434, 20202, -99999 }, returned; | |
374 | |
375 #if (__cplusplus >= 201103L) | |
376 bool istriv = std::is_trivial<ValueAggr::S>::value; | |
377 #else | |
378 bool istriv = true; /* own deduction as no type trait */ | |
379 #endif | |
380 DCaggr *s = dcNewAggr(5, sizeof(ValueAggr::S)); | |
381 dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, i), 1); | |
382 dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, j), 1); | |
383 dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, k), 1); | |
384 dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, l), 1); | |
385 dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, m), 1); | |
386 dcCloseAggr(s); | |
387 | |
388 // set S::mS | |
389 dcReset(pc); | |
390 dcArgPointer(pc, &o); // this ptr | |
391 dcArgAggr(pc, s, &st); | |
392 dcCallVoid(pc, vtbl[VTBI_BASE+0]); | |
393 | |
394 // get it back | |
395 dcReset(pc); | |
396 dcBeginCallAggr(pc, s); | |
397 dcArgPointer(pc, &o); // this ptr | |
398 dcCallAggr(pc, vtbl[VTBI_BASE+1], s, &returned); | |
399 | |
400 dcFreeAggr(s); | |
401 | |
402 r = returned.i == st.i && returned.j == st.j && returned.k == st.k && returned.l == st.l && returned.m == st.m && istriv; | |
403 printf("r:{iiiii} (this/trivial): %d\n", r); | |
404 | |
405 | |
406 | |
407 /* ellipsis test w/ this pointer returning big aggregate (quite an edge | |
408 * case) by value (won't fit in regs, so hidden pointer is is used to write | |
409 * return values to), showing the need to use the DC_CALL_C_DEFAULT_THIS | |
410 * mode first, for the this ptr alone, then DC_CALL_C_ELLIPSIS, then | |
411 * DC_CALL_C_ELLIPSIS_VARARGS (test is useful on win64 where thisptr is | |
412 * passed *after* return aggregate's hidden ptr) */ | |
413 #if (__cplusplus >= 201103L) | |
414 istriv = std::is_trivial<ValueAggr::Big>::value; | |
415 #else | |
416 istriv = true; /* own deduction as no type trait */ | |
417 #endif | |
418 s = dcNewAggr(2, sizeof(struct ValueAggr::Big)); | |
419 dcAggrField(s, DC_SIGCHAR_INT, offsetof(struct ValueAggr::Big, sum), 1); | |
420 dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(struct ValueAggr::Big, dummy), 50); | |
421 dcCloseAggr(s); | |
422 dcReset(pc); | |
423 dcMode(pc, DC_CALL_C_DEFAULT_THIS); /* <-- needed on x64/win64 */ | |
424 | |
425 dcBeginCallAggr(pc, s); | |
426 dcMode(pc, DC_CALL_C_ELLIPSIS); | |
427 dcArgPointer(pc, &o); | |
428 dcArgInt(pc, 89); | |
429 dcMode(pc, DC_CALL_C_ELLIPSIS_VARARGS); | |
430 dcArgInt(pc, -157); | |
431 dcArgInt(pc, 888); | |
432 struct ValueAggr::Big big; | |
433 dcCallAggr(pc, vtbl[VTBI_BASE+2], s, &big); | |
434 | |
435 dcFreeAggr(s); | |
436 | |
437 bool b = (big.sum == 820) && istriv; | |
438 r = r && b; | |
439 printf("r:{il[50]} (this/trivial/ellipsis): %d\n", b); | |
440 | |
441 | |
442 | |
443 /* non-trivial test ----------------------------------------------------------- */ | |
444 | |
445 #if (__cplusplus >= 201103L) | |
446 istriv = std::is_trivial<ValueAggr::NonTriv>::value; | |
447 #else | |
448 istriv = false; /* own deduction as no type trait */ | |
449 #endif | |
450 dcReset(pc); | |
451 dcMode(pc, DC_CALL_C_DEFAULT_THIS); | |
452 | |
453 /* non trivial aggregates: pass NULL for DCaggr* and do copy on our own (see doc) */ | |
454 dcBeginCallAggr(pc, NULL); | |
455 | |
456 ValueAggr::NonTriv nt0(5, 6), nt1(7, 8), ntr(0, 0); | |
457 dcArgAggr(pc, NULL, &o); // this ptr | |
458 /* make *own* copies, as dyncall cannot know how to call copy ctor */ //@@@ put into doc | |
459 ValueAggr::NonTriv nt0_ = nt0, nt1_ = nt1; | |
460 dcArgAggr(pc, NULL, &nt0_); /* use *own* copy */ | |
461 dcArgAggr(pc, NULL, &nt1_); /* use *own* copy */ | |
462 | |
463 dcCallAggr(pc, vtbl[VTBI_BASE+3], NULL, &ntr); /* note: "copy elision", so retval might *not* call copy ctor */ | |
464 | |
465 | |
466 b = ntr.i == 13*14 && ntr.j == 37*38 && !istriv; | |
467 r = r && b; | |
468 printf("r:{ii} (this/nontrivial/retval_copy_elision): %d\n", b); | |
469 } | |
470 | |
471 dcFree(pc); | |
472 return r; | |
473 } | |
474 | |
475 #endif | |
476 | |
477 | |
304 extern "C" { | 478 extern "C" { |
305 | 479 |
306 int main(int argc, char* argv[]) | 480 int main(int argc, char* argv[]) |
307 { | 481 { |
308 dcTest_initPlatform(); | 482 dcTest_initPlatform(); |
310 signal(SIGSEGV, segv_handler); | 484 signal(SIGSEGV, segv_handler); |
311 | 485 |
312 bool r = true; | 486 bool r = true; |
313 | 487 |
314 r = testCallThisC() && r; | 488 r = testCallThisC() && r; |
315 #if defined(DC__OS_Win32) | 489 #if defined(DC__OS_Win32) && defined(DC__C_MSVC) |
316 r = testCallThisMS() && r; | 490 r = testCallThisMS() && r; |
491 #endif | |
492 #if defined(DC__Feature_AggrByVal) | |
493 r = testCallThisAggr() && r; | |
317 #endif | 494 #endif |
318 | 495 |
319 printf("result: plain_cpp: %d\n", r); | 496 printf("result: plain_cpp: %d\n", r); |
320 | 497 |
321 dcTest_deInitPlatform(); | 498 dcTest_deInitPlatform(); |