Update the changelog
[opencv] / apps / cvenv / add.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "assert.h"
43 #include "stdio.h"
44 #include "string.h"
45 #include "stdlib.h"
46 #include "malloc.h"
47 #include "eic.h"
48 #include "typemod.h"
49 #include "global.h"
50 #include "func.h"
51 #include "symbol.h"
52 #include "error.h"
53
54 #undef malloc
55 #undef realloc
56 #undef free
57
58 #ifdef WIN32
59 typedef __int64 int64;
60 #else
61 typedef long long int64;
62 #endif
63
64 typedef struct
65 {
66     symentry_t* sym;
67     void*       addr;
68 } called_type;
69
70 typedef struct
71 {
72     void* callcode;
73     symentry_t* sym;
74 } callback_t;
75
76 typedef val_t(*f_t)();
77 typedef int64(*call_t)();
78
79 static int get_uweic_type(type_expr* type) 
80 {
81     struct_t* s;
82 #define _TYPE_CASE(x)   case t_##x: return sizeof(x)
83 #define _TYPE_UCASE(x)   case t_##x: case t_u##x: return sizeof(x)
84
85     switch(type->obj)
86     {
87         _TYPE_UCASE(char);
88         _TYPE_UCASE(short);
89         _TYPE_UCASE(int);
90         _TYPE_UCASE(long);
91 #ifdef WIN32
92         _TYPE_CASE(enum);
93 #else
94         case t_enum:
95         return sizeof( int );
96 #endif
97         _TYPE_CASE(float);
98         _TYPE_CASE(double);
99
100     case t_pointer:
101         return sizeof(void*);
102
103     case t_struct:
104     case t_union:
105         s = (struct_t*)(type->u.inf);
106         return s->tsize;
107
108     case t_void:
109     case t_var:
110         return 0;
111         
112     default:
113         assert(0);
114         return -1;
115     }
116
117 #undef _TYPE_UCASE
118 #undef _TYPE_CASE
119 }
120
121 static int get_size_arg_buffer( symentry_t* sym )
122 {
123     type_expr* ret_type = sym->type->nxt;
124     int        arg_num  = ((func_t*)sym->type->u.inf)->Num;
125     parm_t*    arg_type = ((func_t*)sym->type->u.inf)->parm;
126     int size = 0;
127     
128     /* check for return type is no 1, 2, 4 or 8 bytes long */
129     switch( get_uweic_type( ret_type ) )
130     {
131     case 0:
132     case 1:
133     case 2:
134     case 4:
135     case 8:
136         break;
137     default:
138         size += sizeof( void* );
139     }
140     for( int i = 0; i < arg_num; i++ )
141         size += (get_uweic_type( arg_type[i].type ) + 3) & ~3;
142     return size;
143 }
144
145 #pragma warning(disable:4716)
146 static float get_float(void)
147 {
148 }
149
150 static double get_double(void)
151 {
152 }
153 #pragma warning(default:4716)
154
155 static int callback_num = 0;
156 static callback_t* callback = (callback_t*)malloc( 10 );
157 static callback_t* current_call = 0;
158
159 static double set_double(double a)
160 {
161     a = a + 0;
162     return a;
163 }
164
165 typedef void(*set_double_t)(double);
166
167 set_double_t set_dbl = (set_double_t)set_double;
168
169 #ifndef WIN32
170 int64 unicall( int first )
171 #else
172 int64 unicall( void* addr_ret, int first )
173 #endif
174 {
175     assert( current_call );
176     assert( current_call->sym );
177     if( !current_call )
178         return 0;
179
180     symentry_t* sym = current_call->sym;
181     
182 #ifdef WIN32
183     /* support __stdcall function */
184     assert( addr_ret );
185     char* r = (char*)*(&addr_ret - 1);
186     if( (*(unsigned short*)addr_ret) == 0xc481 || (*(unsigned short*)addr_ret) == 0xc483 )
187         /* __cdecl function */
188         *(unsigned short*)(r + 1) = 0;
189     else /* __stdcall function */
190         *(unsigned short*)(r + 1) = (unsigned short)get_size_arg_buffer( sym );
191 #endif
192
193     type_expr* ret_type = sym->type->nxt;
194     int arg_num = ((func_t*)sym->type->u.inf)->Num;
195     parm_t* parm = ((func_t*)sym->type->u.inf)->parm;
196     code_t* cb = ((func_t*)sym->type->u.inf)->callBack;
197
198     int first_arg = 0;
199     void* ret_data = 0;
200
201     /* allocate buffer for return value if return value is structure or union */
202     if( ret_type->obj == t_struct || ret_type->obj == t_union )
203     {
204         ret_data = alloca( get_uweic_type( ret_type ) );
205         *(void**)(&(cb->inst[cb->nextinst - 5 - 2 * 0].val)) = ret_data;
206         first_arg = 1;
207     }
208
209     char* buf = (char*)&first;
210
211     /* if sizeof(return value) not ... then first argument is pointer to data */
212     switch( get_uweic_type( ret_type ) )
213     {
214     case 0:
215     case 1:
216     case 2:
217     case 4:
218     case 8:
219         break;
220     default:
221         buf += sizeof( void* );
222     }
223
224     for( int i = 0; i < arg_num; i++ )
225     {
226         switch( parm[i].type->obj )
227         {
228         case t_struct:
229         case t_union:
230             *(void**)(&(cb->inst[cb->nextinst - 5 - 2 * (first_arg + i)].val)) = buf;
231             break;
232         default:
233             *(double*)(&(cb->inst[cb->nextinst - 5 - 2 * (first_arg + i)].val)) = *(double*)buf;
234         }
235         buf += (get_uweic_type( parm[i].type ) + 3) & ~3;
236     }
237
238     EiC_callBack(cb);
239
240     switch( get_uweic_type( ret_type ) )
241     {
242     case 0:
243         break;
244     case 1:
245     case 2:
246     case 4:
247     case 8:
248         if( ret_type->obj == t_float || ret_type->obj == t_double )
249         {
250             set_dbl( EiC_ReturnValue( double ) );
251         }
252         else if( ret_type->obj == t_struct || ret_type->obj == t_union )
253         {
254             return *EiC_ReturnValue( int64* );
255         }
256         else
257             return EiC_ReturnValue( int64 );
258         break;
259     default:
260         memcpy( &first, ret_data, get_uweic_type( ret_type ) );
261         return (int64)first;
262     }
263 }
264
265 static void* add_callback( symentry_t* sym )
266 {
267     int i;
268     for( i = 0; i < callback_num; i++ )
269         if( sym == callback[i].sym )
270             return callback[i].callcode;
271     callback = (callback_t*)realloc( callback, sizeof( callback_t ) * (callback_num + 1) );
272     callback[callback_num].sym = sym;
273     char* code = (char*)(callback[callback_num].callcode = malloc( 32 ));
274
275     code[0] = (unsigned char)0xc7;                     // mov current_sym, pointer
276     code[1] = (unsigned char)0x05;
277     *(void**)(code + 2) = &current_call;
278     *(callback_t**)(code + 2 + 4) = callback + callback_num;
279 #ifndef WIN32
280     code[2 + 4 + 4] = (unsigned char)0xe9;             // jmp uniwrap
281 #else
282     code[2 + 4 + 4] = (unsigned char)0xe8;             // call uniwrap
283 #endif
284     int offset = (int)unicall - ((int)code + 15);
285     *(int*)(code + 2 + 4 + 4 + 1) = offset;
286 #ifdef WIN32
287     code[2 + 4 + 4 + 1 + 4] = (unsigned char)0xc2;     // ret 0
288     code[2 + 4 + 4 + 1 + 5] = 0;
289     code[2 + 4 + 4 + 1 + 6] = 0;
290     code[2 + 4 + 4 + 1 + 7] = 0;
291     code[2 + 4 + 4 + 1 + 8] = 0;
292 #endif
293 /*  unix                                      windows
294     __asm{                                    __asm{
295         mov current_sym, 12345678h;                mov current_sym, 12345678h;
296         jmp unicall                                call unicall;
297     }                                              ret 0;  // this value may be changed if __stdcall
298 */
299     callback_num++;
300     return code;
301 }
302
303 static called_type* current_func = 0;
304
305 val_t uniwrap()
306 {
307     assert( current_func );
308     assert( current_func->addr );
309     assert( current_func->sym );
310
311     called_type* func = current_func;
312
313     void* f = func->addr;
314
315     type_expr* ret_type = func->sym->type->nxt;
316     int        arg_num  = ((func_t*)func->sym->type->u.inf)->Num;
317     parm_t*    arg_type = ((func_t*)func->sym->type->u.inf)->parm;
318
319     int size = get_size_arg_buffer( func->sym );
320     int first_arg = 0;
321     
322     /* if return type is structure or union first argument is pointer to result */
323     if( ret_type->obj == t_struct || ret_type->obj == t_union )
324         first_arg = 1;
325     
326     /* calculating size of stack */
327     int i;
328     int64 intbuf;
329     char* buffer = (char*)alloca( size );
330     char* buf = buffer;
331     void* ret_data;
332     val_t ret_val;
333
334     /* if sizeof(result) not 1, 2, 4 or 8 alloc memory to save result */
335     /* set pointer ret_data to result data */
336     switch( get_uweic_type( ret_type ) )
337     {
338     case 0:
339     case 1:
340     case 2:
341     case 4:
342     case 8:
343         ret_data = &intbuf;
344         break;
345     default:
346         *(void**)buf = malloc( get_uweic_type( ret_type ) );
347         buf += sizeof( void* );
348         ret_data = *(void**)buffer;
349     }
350
351     /* copy parameters values to stack es:esp */
352     for( i = 0; i < arg_num; i++ )
353     {
354         switch( arg_type[i].type->obj )
355         {
356         case t_union:
357         case t_struct:
358             memcpy( buf,
359                     arg(first_arg + i, getargs(), ptr_t).p,
360                     (get_uweic_type( arg_type[i].type ) + 3) & ~3 );
361             buf += (get_uweic_type( arg_type[i].type ) + 3) & ~3;
362             break;
363         case t_pointer:
364             printf("pointer\n");
365             {
366                 void* data = &arg(first_arg + i, getargs(), ptr_t).p;
367                 int   size = get_uweic_type( arg_type[i].type );
368                 printf("size = %d value = %d\n", size, data ? *(int*)data : 0);
369             }
370             if( arg_type[i].type->nxt && arg_type[i].type->nxt->obj == t_funcdec )
371             {
372                 printf("callback\n");
373                 /* this is callback parameter, need special translation */
374                 void* cb = arg(first_arg + i, getargs(), ptr_t).p;
375                 symentry_t* sym = EiC_lookup_by_callback( 1, cb );
376                 if( sym )
377                 {
378                     void* call = add_callback( sym );
379                     *(void**)buf = call;
380                     buf += sizeof(call);
381                     break;
382                 }
383                 else assert( 0 );
384             }
385         default:
386             {
387                 void* data = &arg(first_arg + i, getargs(), ptr_t).p;
388                 memcpy( buf, data,
389                         (get_uweic_type( arg_type[i].type ) + 3) & ~3 );
390                 buf += (get_uweic_type( arg_type[i].type ) + 3) & ~3;
391             }
392         }
393     }
394 #ifndef WIN32
395     intbuf = ((call_t)f)();
396 #else
397     __asm
398     {
399         call dword ptr [f]
400         mov dword ptr intbuf, eax
401         mov dword ptr intbuf + 4, edx
402     }
403 #endif
404
405     if( ret_type->obj == t_float )
406     {
407         *(float*)&intbuf = get_float();
408     }
409     else     if( ret_type->obj == t_double )
410     {
411         *(double*)&intbuf = get_double();
412     }
413
414     switch( ret_type->obj )
415     {
416     case t_struct:
417     case t_union:
418         memcpy( arg( 0, getargs(), ptr_t).p, ret_data, get_uweic_type( ret_type ) );
419         ret_val.p.sp = ret_val.p.p = arg( 0, getargs(), ptr_t).p;
420         ret_val.p.ep = (char*)ret_val.p.p + get_uweic_type( ret_type );
421         break;
422     default:
423         memcpy( &ret_val, ret_data, get_uweic_type( ret_type ) );
424         break;
425     }
426
427     switch( get_uweic_type( ret_type ) )
428     {
429     case 0:
430     case 1:
431     case 2:
432     case 4:
433     case 8:
434         break;
435     default:
436         free(*(void**)buffer);
437     }
438
439     return ret_val;
440 }
441
442 int AddExternFunction( void* addr, char* name )
443 {
444     symentry_t* sym = (symentry_t*)EiC_lookup(1, name);
445     if( !sym )
446         return -1;
447
448     char* wrap = (char*)malloc( 16 + sizeof(called_type) );
449
450     called_type* func_desc = (called_type*)(wrap + 16);
451     func_desc->addr = addr;
452     func_desc->sym  = sym;
453
454     wrap[0] = (unsigned char)0xc7;                     // mov cuurrent_sym, pointer
455     wrap[1] = (unsigned char)0x05;
456     *(void**)(wrap + 2) = &current_func;
457     *(called_type**)(wrap + 2 + 4) = func_desc;
458     /* in windows system we need support __stdcall function */
459
460     wrap[2 + 4 + 4] = (unsigned char)0xe9;             // jmp uniwrap
461     int offset = (int)uniwrap - ((int)wrap + 15);
462     *(int*)(wrap + 2 + 4 + 4 + 1) = offset;
463
464 /*
465     __asm{
466         mov current_sym, 12345678h;
467         call uniwrap;
468         ret 0;
469     }
470 */
471     EiC_add_builtinfunc(name, (f_t)wrap);
472     return 0;
473 }
474