1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: vm 18.10.06 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 * Summary:
15 *
16 ******************************************************************************/
17
18 #include "vm.h"
19 #include "vmrun.h"
20 #include "vmmanage.h"
21 #include "vmload.h"
22 #include "vmtype.h"
23 #include "vmres.h"
24 #include "../bytecode/bytecode.h"
25 #include "../bytecode/funclist.h"
26 #include "../common/file.h"
27 #include "../genteeapi/gentee.h"
28
29 vm _vm; // Global virtual machine
30 pvm _pvm; // Pointer to VM
31
32 /*-----------------------------------------------------------------------------
33 *
34 * ID: vm_deinit 19.10.06 0.0.A.
35 *
36 * Summary: Initialize the virtual machine.
37 *
38 -----------------------------------------------------------------------------*/
39
40 void STDCALL vm_deinit( void )// pvm _pvm )
41 {
42 povmglobal global;
43 povmimport import;
44 pvmobj vmobj;
45 uint i;
46
47 // Destroy global parameters
48 // for ( i = 1024; i < arr_count( &_vm.objtbl ); i++ )
49 for ( i = arr_count( &_vm.objtbl ) - 1; i >= 1024; i-- )
50 {
51 vmobj = ( pvmobj )PCMD( i );
52 if ( vmobj->type == OVM_GLOBAL && vmobj->flag & GHRT_LOADED )
53 {
54 global = ( povmglobal )vmobj;
55 type_vardelete( global->pval, global->type, 1, 0 );
56 }
57 if ( vmobj->type == OVM_IMPORT )
58 {
59 import = ( povmimport )vmobj;
60 if ( import->handle )
61 {
62 #ifdef LINUX
63 dlclose( import->handle );
64 #else
65 FreeLibrary( import->handle );
66 #endif
67 }
68 }
69 }
70 // Destroy all objects
71 arr_delete( &_vm.objtbl );
72 hash_delete( &_vm.objname );
73 collect_delete( &_vm.resource );
74 buf_delete( &_vm.resource.data );
75 vmmng_destroy( );
76 /*
77 #ifdef GEGUI
78 gui_deinit();
79 #endif
80
81 // Освобождаем глобальные переменные
82 buf_destroy( vm->entry );
83 lge_deinit( &vm->lge );
84 collect_destroy( &vm->collect );
85 systbl_deinit( &vm->objmem );
86 systbl_deinit( &vm->objtbl );
87 nametbl_deinit( &vm->nametbl );
88 mem_free( vm->exception );*/
89 }
90
91 /*-----------------------------------------------------------------------------
92 *
93 * ID: vm_init 19.10.06 0.0.A.
94 *
95 * Summary: Initialize the virtual machine.
96 *
97 -----------------------------------------------------------------------------*/
98
99 void STDCALL vm_init( void )
100 {
101 uint i, id, k, len, flag;
102 stackfunc pseudo;
103 int topshift, cmdshift;
104 pubyte emb, ptr = ( pubyte )&embtypes;
105 ubyte input[64];
106 pvmfunc pfunc;
107 // povmstack pstack;
108
109 _pvm = &_vm;
110 mem_zero( _pvm, sizeof( vm ));
111 _vm.loadmode = 1;
112 // Initialize the array of objects
113 arr_init( &_vm.objtbl, sizeof( uint ));
114 arr_step( &_vm.objtbl, 1024 );
115 buf_init( &_vm.resource.data );
116 // Initialize the hash of object names
117 hash_init( &_vm.objname, sizeof( uint ));
118 vmmng_new();
119
120 // Add zero command
121 load_stack( 0, 0, NULL )->type = OVM_NONE;
122
123 // Loading kernel objects into VM
124 for ( i = TInt; i <= TFordata; i++ )
125 {
126 // load_stack( 0, 0, NULL )->type = OVM_TYPE;
127 load_type( &ptr );
128 // vm_addobj( _pvm, ( pvmobj )mem_allocz( sizeof( vmobj )), 0 );
129 }
130 // Loading kernel objects into VM
131 for ( i = 0; i < STACK_COUNT; i++ )
132 {
133 topshift = 0;
134 cmdshift = 0;
135 pseudo = NULL;
136 switch ( shifts[i] )
137 {
138 case SHN3_1: topshift--;
139 case SHN2_1: topshift--;
140 case SHN1_1: topshift--;
141 cmdshift = 1;
142 break;
143 case SHN1_2: topshift--;
144 cmdshift = 2;
145 break;
146 case SH0_2: cmdshift++;
147 case SH0_1: cmdshift++;
148 break;
149 case SH1_3: cmdshift++;
150 case SH1_2: cmdshift++;
151 case SH1_1: cmdshift++;
152 topshift = 1;
153 break;
154 case SH2_1:
155 topshift = 2;
156 cmdshift = 1;
157 break;
158 case SH2_3:
159 topshift = 2;
160 cmdshift = 3;
161 break;
162 }
163 id = _vm.count;
164 if ( id >= CMulII ) // > CReturn )
165 {
166 if ( id <= Cui2l )
167 pseudo = pseudo_i;
168 else if ( id <= CNotUL )
169 pseudo = pseudo_ul;
170 else if ( id <= CRightUL )
171 pseudo = pseudo_pul;
172 else if ( id <= CGreaterLL )
173 pseudo = pseudo_l;
174 else if ( id <= CRightL )
175 pseudo = pseudo_pl;
176 else if ( id <= CEqFF )
177 pseudo = pseudo_f;
178 else if ( id <= CDivF )
179 pseudo = pseudo_pf;
180 else if ( id <= CEqDD )
181 pseudo = pseudo_d;
182 else if ( id <= CDivD )
183 pseudo = pseudo_pd;
184 else if ( id <= CRightUS )
185 pseudo = pseudo_ui;
186 else if ( id == CCollectadd )
187 pseudo = pseudo_collectadd;
188 }
189 load_stack( topshift, cmdshift, pseudo );
190 }
191 // print("Count=%i \n", _vm.count );
192 emb = ( pubyte )&embfuncs;
193 flag = GHCOM_NAME | GHCOM_PACK;
194
195 for ( i = 0; i < FUNCCOUNT; i++ )
196 {
197 if ( !mem_cmp( emb, "sin", 3 ))
198 flag |= GHEX_CDECL;
199
200 ptr = ( pubyte )&input;
201 *ptr++ = OVM_EXFUNC;
202 *(( puint )ptr)++ = flag;
203 *ptr++ = 0;
204 len = mem_copyuntilzero( ptr, emb );
205 ptr += len;
206 emb += len;
207 id = *emb++;
208 *ptr++ = ( id & 0x80 ? *emb++ : 0 );
209 *ptr++ = 0;
210 id &= 0x7f;
211 *ptr++ = ( ubyte )id;
212 for ( k = 0; k < id; k++ )
213 {
214 *ptr++ = *emb++;
215 *ptr++ = 0;
216 }
217 input[ 5 ] = ( ubyte )( ptr - ( pubyte )&input );
218 ptr = ( pubyte )&input;
219
220 pfunc = ( pvmfunc )load_exfunc( &ptr, 0 );
221 pfunc->func = embfuncaddr[ i ];
222 }
223 // print("Count=%i \n", _vm.count );
224 // Loading reserved empty commands
225 while ( _pvm->count < KERNEL_COUNT )
226 load_stack( 0, 0, NULL )->type = OVM_NONE;
227
228 _vm.countinit = 0;//KERNEL_COUNT;
229 // _vm.stacksize = 0x80000; // The default stack size = 512 КБ
230
231 /* systbl_init( &vm->objmem, 0, STBL_INIT );
232 vm->objmem.numtbl = 1024;
233 // Резервируем нулевой элемент
234 systbl_appenddw( &vm->objmem, 0 );
235 // Инициализируем коллекцию для удаления
236 i = 0;
237 collect_new( ( pbyte )&i, &vm->collect );
238
239 lge_init( vm );
240
241 vm->stacksize = 0x80000; // Размер стэка 512 КБ
242 vm->entry = buf_new( NULL, 64 );
243 local_addstack( vm, vm_nocmd, 0 );
244
245 i = 0;
246 while ( fromtocmd[ i ].from )
247 {
248 for ( j = fromtocmd[ i ].from; j <= fromtocmd[ i ].to; j++ )
249 local_addstack( vm, idcmd[i], j );
250 i++;
251 }
252 for ( i = SByteSign; i < SLast; i++ )
253 local_addtype( vm, i );
254
255 // print("Last cmd=%i %i\n", SByteSign, SLast );
256 // for ( i = FPrintDw + 1; i < 256; i++ )
257 for ( i = SLast; i < 256; i++ )
258 local_addstack( vm, vm_nocmd, i );
259
260 for ( i = FMemAlloc; i <= FPrintDw; i++ )
261 local_addfunc( vm, i - FMemAlloc );
262
263 #ifdef GEGUI
264 gui_init( vm );
265 #endif
266 // print("Now=%i\n", vm->objtbl.count );
267 for ( i = vm->objtbl.count; i < 1024; i++ )
268 local_addstack( vm, vm_nocmd, i );
269 vm->link = LINKID - 1;
270 vm->rtlast = vm->objtbl.count - 1;
271
272 vm->exception = mem_alloc( sizeof( sexception ) * EXCEPT_LIMIT );
273 vm->lastexcept = vm->exception;
274 vm->lastexcept->start = ( pdword )MAX_DWORD;
275 vm->lastexcept->idfunc = 0;
276 // vm->idlast = vm->rtlast;*/
277 }
278
279 /*-----------------------------------------------------------------------------
280 *
281 * ID: vm_find 19.10.06 0.0.A.
282 *
283 * Summary: Find the byte-code object
284 *
285 * pars - type + oftype
286 *
287 -----------------------------------------------------------------------------*/
288
289 pvmfunc STDCALL vm_find( pubyte name, uint count, puint pars )
290 {
291 pvmfunc bcode, best = NULL;
292 pvartype par;
293 uint result = 0, countpars = 0, bestweight = 0;
294 uint i, weight, k, idtype, idof ;
295 puint curpar;
296 phashitem phi = NULL;
297
298 phi = hash_find( &_vm.objname, name );
299
300 if ( !phi || !( result = *( puint )( phi + 1 ) ))
301 return ( pvmfunc )MUnkoper;
302
303 // result = *( puint )( phi + 1 );
304
305 while ( result )
306 {
307 bcode = ( pvmfunc )PCMD( result );
308 // print( "Look for %s = %i next=%i\n", name, result, bcode->vmo.nextname );
309 if ( !( bcode->vmo.flag & GHRT_MAYCALL ))
310 return best;
311 // print( "Look for %s = %i next=%i\n", name, result, bcode->vmo.nextname );
312 if ( bcode->parcount == count + ( bcode->vmo.flag & GHBC_RESULT ? 1 : 0 ))
313 {
314 countpars = 1;
315 par = bcode->params;
316 // Делаем проверку типов
317 if ( !bcode->parcount || ( bcode->parcount == 1 && ( bcode->vmo.flag & GHBC_RESULT )))
318 {
319 best = bcode;
320 break;
321 }
322 weight = 0;
323 curpar = pars;
324 for ( i = 0; i < count; i++ )
325 {
326 k = 0;
327 idtype = *curpar++;
328 idof = *curpar++;
329
330 if ( !idtype )
331 {
332 weight = 0;
333 break;
334 }
335 k = type_compat( idtype, par->type, 0 );
336 // Проверка на of type.
337 if ( k && par->oftype && !type_compat( idof, par->oftype, 1 ))
338 k = 0;
339
340 // print( "COMP %i= %i %i\n", SUInt, par->type->vmobj.id, *curpar );
341 /* if ( par->type == idtype || idtype == TAny || par->type == TAny )
342 k = 100;
343 else
344 if ( par->type <= TUlong && idtype <= TUlong )
345 k = compnum[ par->type - TInt ][ idtype - TInt ];
346 else
347 {
348 if ( type_isinherit( idtype, par->type ))
349 k = 45;
350 }
351 // Проверка на of type.
352 if ( par->oftype && par->oftype != idof )
353 if ( par->oftype <= TUlong && idof <= TUlong )
354 {
355 if ( !compnum[ par->oftype - TInt ][ idof - TInt ] ||
356 (( povmtype )PCMD( par->oftype ))->size !=
357 (( povmtype )PCMD( idof ))->size )
358 k = 0;
359 }
360 else
361 {
362 if ( !type_isinherit( idof, par->oftype ))
363 k = 0;
364 }
365 */
366 if ( !k )
367 {
368 weight = 0;
369 break;
370 }
371 weight += k; //+ ( k != 100 ? 2 * i : 0 );// - 2 * i;
372 // следующий параметр у функции
373 par++;
374 }
375 // print("%s %i weight = %i\n", name, ( dword )bcode->vmobj.id, weight );
376 if ( weight > bestweight )
377 {
378 best = bcode;
379 bestweight = weight;
380 if ( bestweight == ( uint )bcode->parcount * 100 )
381 {
382 // print("Best\n");
383 return best;
384 }
385 }
386 }
387 result = bcode->vmo.nextname;
388 }
389 if ( !countpars )
390 return ( pvmfunc )MCountpars;
391
392 if ( !best )
393 return ( pvmfunc )MTypepars;
394
395 return best;
396 }
397
398 /*-----------------------------------------------------------------------------
399 *
400 * ID: import_execute 23.10.06 0.0.A.
401 *
402 * Summary: This function loads import library
403 *
404 -----------------------------------------------------------------------------*/
405
406 void STDCALL import_execute( povmimport pimport )
407 {
408 str filename;
409 str original;
410
411 str_init( &filename );
412 str_init( &original );
413
414 str_copyzero( &original, pimport->filename );
415 if ( pimport->vmo.flag & GHIMP_LINK )
416 {
417 uint handle;
418
419 gettempfile( &filename, &original );
420 if ( pimport->size )
421 {
422 handle = os_fileopen( &filename, FOP_CREATE | FOP_EXCLUSIVE );
423 if ( !handle )
424 msg( MFileopen | MSG_STR | MSG_EXIT, &filename );
425
426 if ( !os_filewrite( handle, pimport->data, pimport->size ))
427 msg( MFilewrite | MSG_STR | MSG_EXIT, &filename );
428 os_fileclose( handle );
429 }
430 }
431 else
432 if ( pimport->vmo.flag & GHIMP_EXE )
433 getmodulepath( &filename, &original );
434 else
435 str_copy( &filename, &original );
436
437 if ( str_len( &filename ))
438 {
439 #ifdef LINUX
440 pimport->handle = dlopen( dir, RTLD_LAZY );
441 #else
442 pimport->handle = LoadLibrary( str_ptr( &filename ));
443 #endif
444 }
445 else
446 {
447 pimport->handle = _gentee.export ? ( pvoid )0xFFFFFFFF : GetModuleHandle( NULL );
448 }
449 // print("Import=%x %s\n", pimport->handle, str_ptr( &filename ));
450 str_delete( &filename );
451 str_delete( &original );
452 }
453
454 /*-----------------------------------------------------------------------------
455 *
456 * ID: exfunc_execute 23.10.06 0.0.A.
457 *
458 * Summary: This function loads functions from libraries
459 *
460 -----------------------------------------------------------------------------*/
461
462 void STDCALL exfunc_execute( povmfunc pfunc )
463 {
464 pvoid handle;
465
466 if ( !pfunc->import )
467 return;
468 handle = (( povmimport )PCMD( pfunc->import ))->handle;
469 if ((( pvmobj )PCMD( pfunc->import ))->flag & GHIMP_CDECL )
470 {
471 pfunc->vmf.vmo.flag |= GHEX_CDECL;
472 }
473 if ( handle )
474 if ( handle == ( pvoid )0xFFFFFFFF )
475 pfunc->vmf.func = _gentee.export( pfunc->original );
476 else
477 pfunc->vmf.func = GetProcAddress( handle, pfunc->original );
478 // print("HANDLE=%x func=%X name=%s\n", handle, pfunc->vmf.func, pfunc->vmf.vmo.name );
479 }
480
481 /*-----------------------------------------------------------------------------
482 *
483 * ID: global_execute 23.10.06 0.0.A.
484 *
485 * Summary: This function initialize global variables
486 *
487 -----------------------------------------------------------------------------*/
488
489 void STDCALL global_execute( povmglobal pglobal )
490 {
491 // print("0 %x %x %s size = %i\n", pglobal->pval, pglobal->type,
492 // ((pvmobj)pglobal)->name, ((povmtype)PCMD(pglobal->type->type))->size );
493 type_varinit( pglobal->pval, pglobal->type, 1, 1 );
494 pglobal->vmo.flag |= GHRT_LOADED;
495 }
496
497 /*-----------------------------------------------------------------------------
498 *
499 * ID: vm_execute 23.10.06 0.0.A.
500 *
501 * Summary: This function execute the loaded byte-code
502 *
503 -----------------------------------------------------------------------------*/
504
505 uint STDCALL vm_execute( uint main )
506 {
507 pvmobj pobj;
508 uint i, idmain = 0, result = 0;
509
510 // print("Count %i\n", _vm.count );
511 // Проходимся по всем объектам и инициализируем то, что нужно
512 for ( i = _vm.countinit; i < _vm.count; i++ )
513 {
514 pobj = ( pvmobj )PCMD( i );
515
516 switch ( pobj->type )
517 {
518 case OVM_GLOBAL:
519 global_execute( ( povmglobal )pobj );
520 break;
521 case OVM_TYPE:
522 // Set GHRT_INIT & GHRT_DEINIT flags
523 type_initialize( i );
524 break;
525 case OVM_EXFUNC:
526 exfunc_execute( ( povmfunc )pobj );
527 break;
528 case OVM_IMPORT:
529 import_execute( ( povmimport )pobj );
530 break;
531 }
532 if ( pobj->flag & GHRT_MAYCALL )
533 {
534 // print("entry 0\n");
535 // Call <entry> functions
536 if ( pobj->flag & GHBC_ENTRY )
537 vm_run( i, NULL, &result, 0x80000 );
538 if ( pobj->flag & GHBC_MAIN )
539 idmain = i;
540 // print("entry 1\n");
541 }
542 }
543 // print("OOOPS\n");
544 _vm.countinit = _vm.count;
545 if ( main && idmain )
546 {
547 // Call <main> function
548 vm_run( idmain, NULL, &result, 0x80000 );
549 }
550 return result;
551 }
552
553 /*-----------------------------------------------------------------------------
554 *
555 * ID: vm_clearname 23.10.06 0.0.A.
556 *
557 * Summary: This function clear a name of the object
558 *
559 -----------------------------------------------------------------------------*/
560
561 void STDCALL vm_clearname( uint id )
562 {
563 phashitem phi;
564 pvmobj curobj = 0, pvmo = ( pvmobj )PCMD( id );
565 uint idnext;
566
567 if ( !pvmo->name )
568 return;
569 phi = hash_find( &_vm.objname, pvmo->name );
570 idnext = *( puint )( phi + 1 );
571 while ( idnext )
572 {
573 if ( idnext == id )
574 {
575 if ( curobj )
576 curobj->nextname = pvmo->nextname;
577 else
578 *( puint )( phi + 1 ) = pvmo->nextname;
579 break;
580 }
581 curobj = ( pvmobj )PCMD( idnext );
582 idnext = curobj->nextname;
583 }
584 pvmo->flag &= ~GHCOM_NAME;
585 pvmo->name = NULL;
586 }
587
588 /*-----------------------------------------------------------------------------
589 ** Id: getid F
590 *
591 * Summary: Getting the code of an object by its name. The function returns the
592 code of an object (function, method, operator, type) by its name
593 and parameters.
594 *
595 * Params: name - The name of an object (function, method, operator ).
596 flags - Flags.$$[getidflags]
597 idparams - The types of the required parameters.
598 *
599 * Return: The code (identifier) of the found object. The function returns
600 #b(0) if the such object was not found.
601 *
602 * Define: func uint getid( str name, uint flags, collection idparams )
603 *
604 -----------------------------------------------------------------------------*/
605
606 uint STDCALL vm_getid( pstr name, uint flags, pcollect colpars )
607 {
608 ubyte fname[256];
609 uint off = 0;
610 uint count;
611 uint i = 0, k = 0;
612 uint params[ 32 ];
613 uint bcode;
614
615 if ( flags & GETID_METHOD )
616 fname[ off++ ] = '@';
617 if ( flags & GETID_OPERATOR )
618 fname[ off++ ] = '#';
619
620 mem_copyuntilzero( fname + off, str_ptr( name ));
621
622 count = collect_count( colpars );
623 while ( i < count )
624 {
625 params[ k++ ] = *( puint )collect_index( colpars, i );
626 params[ k++ ] = flags & GETID_OFTYPE ? *( puint )collect_index( colpars, ++i ) : 0;
627 i++;
628 }
629
630 bcode = ( uint )vm_find( fname, k >> 1, params );
631 if ( ( uint )bcode < MSGCOUNT )
632 bcode = 0;
633 else
634 bcode = ((pvmfunc)bcode)->vmo.id;
635 return bcode;
636 }