comparison test/callback_plain_c++/test_main.cc @ 557:b36a738c8975

- dyncallback: fix for calling back win/x64 C++ methods returning non-trivial aggregates (thanks Raphael!) - test/callback_plain_c++: * added test code for C++ method callbacks returning non-trivial aggregates * makefile linker command fix (was linking assuming c and not c++) - test/plain_c++: comments for completeness
author Tassilo Philipp
date Sat, 20 Aug 2022 21:04:15 +0200
parents 214c4efc104f
children 87b5f5d7af1f
comparison
equal deleted inserted replaced
556:49b60ca068c2 557:b36a738c8975
109 109
110 110
111 111
112 char cbNonTrivAggrReturnHandler(DCCallback* cb, DCArgs* args, DCValue* result, void* userdata) 112 char cbNonTrivAggrReturnHandler(DCCallback* cb, DCArgs* args, DCValue* result, void* userdata)
113 { 113 {
114 printf("reached callback\n"); 114 printf("reached callback (for sig \"%s\")\n", *(const char**)userdata);
115 dcbReturnAggr(args, result, NULL); // this sets result->p to the non-triv aggr space allocated by the calling convention 115 dcbReturnAggr(args, result, NULL); // this sets result->p to the non-triv aggr space allocated by the calling convention
116 *(NonTriv*)result->p = NonTriv(1, 3); // explicit non-copy ctor and assignment operator, so not using NonTriv's statics a and b 116 *(NonTriv*)result->p = NonTriv(1, 3); // explicit non-copy ctor and assignment operator, so not using NonTriv's statics a and b
117 117
118 return 'A'; 118 return 'A';
119 } 119 }
120 120
121 121
122 // class with single vtable entry, used to get the compiler to generate a
123 // method call; entry is at beginning w/o offset (see plain_c++/test_main.cc
124 // about potential vtable entry offsets)
125 struct Dummy { virtual NonTriv f() = 0; };
126
127
122 int testNonTrivAggrReturnCallback() 128 int testNonTrivAggrReturnCallback()
123 { 129 {
124 int ret = 1; 130 int ret = 1;
125 131
132 const char *sigs[] = {
133 ")A", // standard call
134 "_*p)A" // thiscall w/ this-ptr arg (special retval register handling in win/x64 calling conv)
135 };
136
137
138 for(int i=0; i<sizeof(sigs)/sizeof(sigs[0]); ++i)
126 { 139 {
127 DCCallback* cb; 140 int is_method = (sigs[i][0] == '_' && sigs[i][1] == '*');
141
128 DCaggr *aggrs[1] = { NULL }; // one non-triv aggr 142 DCaggr *aggrs[1] = { NULL }; // one non-triv aggr
129 cb = dcbNewCallback2(")A", &cbNonTrivAggrReturnHandler, NULL, aggrs); 143 DCCallback* cb = dcbNewCallback2(sigs[i], &cbNonTrivAggrReturnHandler, sigs+i, aggrs);
130 144
131 NonTriv result = ((NonTriv(*)())cb)(); // potential copy elision on construction 145 DCpointer fakeClass[sizeof(Dummy)/sizeof(sizeof(DCpointer))];
146 fakeClass[0] = &cb; // write method ptr f
147
148 // potential copy elision on construction
149 NonTriv result = is_method ? ((Dummy*)&fakeClass)->f() : ((NonTriv(*)())cb)();
132 150
133 int a = NonTriv::a-1; 151 int a = NonTriv::a-1;
134 int b = NonTriv::b-1; 152 int b = NonTriv::b-1;
135 printf("successfully returned from callback 1/2\n"); 153 printf("successfully returned from callback 1/2 of \"%s\"\n", sigs[i]);
136 printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j); 154 printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j);
137 155
138 ret = ((result.i == 1 && result.j == 3) || (result.i == a && result.j == b)) && ret; 156 ret = ((result.i == 1 && result.j == 3) || (result.i == a && result.j == b)) && ret;
139 157
140 // avoid copy elision on construction 158 // avoid copy elision on construction
141 result.i = result.j = -77; 159 result.i = result.j = -77;
142 result = ((NonTriv(*)())cb)(); // potential copy elision 160 result = is_method ? ((Dummy*)&fakeClass)->f() : ((NonTriv(*)())cb)(); // potential copy elision
143 161
144 a = NonTriv::a-1; 162 a = NonTriv::a-1;
145 b = NonTriv::b-1; 163 b = NonTriv::b-1;
146 printf("successfully returned from callback 2/2\n"); 164 printf("successfully returned from callback 2/2 of \"%s\"\n", sigs[i]);
147 printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j); 165 printf("retval w/ potential retval optimization and copy-init (should be %d %d for init or %d %d for copy, both allowed by C++): %d %d\n", 1, 3, a, b, result.i, result.j);
148 166
149 dcbFreeCallback(cb); 167 dcbFreeCallback(cb);
150 168
151 ret = ((result.i == 1 && result.j == 3) || (result.i == a && result.j == b)) && ret; 169 ret = ((result.i == 1 && result.j == 3) || (result.i == a && result.j == b)) && ret;