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