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: gesave 18.10.06 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 * Summary:
15 *
16 ******************************************************************************/
17 #ifndef RUNTIME
18
19 #include "ge.h"
20 #include "../genteeapi/gentee.h"
21 #include "../vm/vmload.h"
22 #include "../vm/vmres.h"
23 #include "../common/crc.h"
24 #include "../bytecode/bytecode.h"
25
26 pbuf gesave;
27 uint gesaveoff;
28 puint gecodes;
29
30 void STDCALL gesave_addubyte( uint val )
31 {
32 buf_appendch( gesave, ( ubyte )val );
33 }
34
35 void STDCALL gesave_adduint( uint val )
36 {
37 buf_appenduint( gesave, val );
38 }
39
40 void STDCALL gesave_addushort( uint val )
41 {
42 buf_appendushort( gesave, ( ushort )val );
43 }
44
45 void STDCALL gesave_add2uint( uint val1, uint val2 )
46 {
47 gesave_adduint( val1 );
48 gesave_adduint( val2 );
49 }
50
51 void STDCALL gesave_addptr( pubyte data )
52 {
53 buf_append( gesave, data, mem_len( data ) + 1 );
54 }
55
56 void STDCALL gesave_adddata( pubyte data, uint size )
57 {
58 buf_append( gesave, data, size );
59 }
60
61 //--------------------------------------------------------------------------
62
63 uint STDCALL gesave_bwdi( uint val )
64 {
65 if ( val <= 187 )
66 gesave_addubyte( val );
67 else
68 if ( val < 16830 ) // 0xFF *( 253 - 188 ) + 0xFF
69 {
70 gesave_addubyte( 188 + val / 0xFF );
71 gesave_addubyte( val % 0xFF );
72 }
73 else
74 if ( val > MAX_USHORT )
75 {
76 gesave_addubyte( MAX_BYTE );
77 gesave_adduint( val );
78 }
79 else
80 {
81 gesave_addubyte( MAX_BYTE - 1 );
82 gesave_addushort( val );
83 }
84 return val;
85 }
86
87 //--------------------------------------------------------------------------
88
89 uint STDCALL gesave_bwdc( uint val )
90 {
91 if ( val >= KERNEL_COUNT && !gecodes[ val ] )
92 {
93 print("GESAVE ERROR %i\n", val );
94 os_getchar();
95 }
96 return gesave_bwdi( val >= KERNEL_COUNT ? gecodes[ val ] : val );
97 }
98
99 //--------------------------------------------------------------------------
100
101 uint STDCALL gesave_cmdflag( uint val )
102 {
103 uint flag = val & 0xFF000000;
104 val &= 0xFFFFFF;
105 if ( val >= KERNEL_COUNT )
106 {
107 if ( !gecodes[ val ] )
108 {
109 print("GESAVE ERROR %i\n", val );
110 os_getchar();
111 }
112 else
113 val = gecodes[ val ];
114 }
115 gesave_adduint( val | flag );
116 return val | flag;
117 }
118
119 void STDCALL gesave_head( uint type, pubyte name, uint flag )
120 {
121 uint ok = 0;
122 pubyte cur;
123 gesaveoff = buf_len( gesave );
124
125 flag &= 0xFFFFFF;
126
127 if ( name && name[0] )
128 flag |= GHCOM_NAME;
129 else
130 flag &= ~GHCOM_NAME;
131
132 if ( flag & GHCOM_NAME && _compile->flag & CMPL_OPTIMIZE &&
133 _compile->popti->flag & OPTI_NAME )
134 {
135 cur = _compile->popti->nameson;
136 while ( *cur )
137 {
138 if ( ptr_wildcardignore( name, cur ))
139 {
140 ok = 1;
141 break;
142 }
143 cur += mem_len( cur ) + 1;
144 }
145 if ( !ok )
146 flag &= ~GHCOM_NAME;
147 }
148 flag |= GHCOM_PACK;
149
150 gesave_addubyte( type );
151 gesave_adduint( flag );
152 // The size will be inserted in gesave_finish
153 // Now add just one byte
154 gesave_addubyte( 0 );
155
156 if ( flag & GHCOM_NAME )
157 gesave_addptr( name );
158 }
159
160 void STDCALL gesave_finish( void )
161 {
162 buf bt;
163 pbuf pb = gesave;
164 uint size = buf_len( pb ) - gesaveoff;
165
166 if ( size <= 187 )
167 *( pubyte )(( pubyte )buf_ptr( gesave ) + gesaveoff + 5 ) = ( ubyte )size;
168 else
169 {
170 buf_init( &bt );
171 gesave = &bt;
172 if ( size < 16800 )
173 {
174 size++;
175 gesave_bwdi( size );
176 }
177 else
178 if ( size < 0xFFF0 )
179 {
180 gesave_addubyte( 0xFE );
181 size += 2;
182 gesave_addushort( size );
183 }
184 else
185 {
186 gesave_addubyte( 0xFF );
187 size += 4;
188 gesave_adduint( size );
189 }
190 // Write the size
191 // We have already had one byte, so -1
192 buf_insert( pb, gesaveoff + 5, ( pubyte )&size /*any*/, buf_len( gesave ) - 1 );
193 mem_copy( buf_ptr( pb ) + gesaveoff + 5, buf_ptr( gesave ), buf_len( gesave ));
194
195 buf_delete( &bt );
196 gesave = pb;
197 }
198 }
199
200 void STDCALL gesave_var( pvartype var )
201 {
202 uint i;
203 povmtype ptype;
204 pubyte ptr;
205
206 gesave_bwdc( var->type );
207
208 if ( _compile->flag & CMPL_OPTIMIZE &&
209 _compile->popti->flag & OPTI_NAME )
210 var->flag &= ~VAR_NAME;
211
212 gesave_addubyte( var->flag );
213
214 if ( var->flag & VAR_NAME )
215 gesave_addptr( var->name );
216
217 if ( var->flag & VAR_OFTYPE )
218 gesave_bwdc( var->oftype );
219
220 if ( var->flag & VAR_DIM )
221 {
222 gesave_addubyte( var->dim );
223 for ( i = 0; i < var->dim; i++ )
224 gesave_bwdi( var->ptr[i] );
225 }
226 if ( var->flag & VAR_DATA )
227 {
228 ptr = ( pubyte )( var->ptr + var->dim );
229 ptype = ( povmtype )PCMD( var->type );
230 if ( ptype->vmo.flag & GHTY_STACK )
231 i = ptype->size;
232 else
233 if ( var->type == TStr )
234 i = mem_len( ptr ) + 1;
235 else
236 {
237 i = *( puint )ptr;
238 ptr += sizeof( uint );
239 // gesave_adduint( i );
240 gesave_bwdi( i ); // save data size as bwd
241 }
242 gesave_adddata( ptr, i );
243 }
244 }
245
246 void STDCALL gesave_varlist( pvartype pvar, uint count )
247 {
248 uint i;
249
250 gesave_bwdi( count );
251 for ( i = 0; i < count; i++ )
252 gesave_var( pvar++ );
253 }
254
255 void STDCALL gesave_resource( void )
256 {
257 uint i, count;
258 pcollect pres;
259
260 pres = &_vm.resource;
261
262 gesave_head( OVM_RESOURCE, "", 0 );
263
264 count = collect_count( pres );
265 gesave_bwdi( count );
266 for ( i = 0; i < count; i++ )
267 {
268 gesave_bwdc( collect_gettype( pres, i ));
269 gesave_addptr( str_ptr( vmres_getstr( i )) );
270 // print("str=%s\n", str_ptr( vmres_getstr( i )) );
271 }
272 gesave_finish();
273 }
274
275 void STDCALL gesave_bytecode( povmbcode bcode )
276 {
277 pvartype pvar;
278 uint i, count = 0, cmd, val, k;
279 puint end, ptr;
280
281 gesave_var( bcode->vmf.ret );
282 gesave_varlist( bcode->vmf.params, bcode->vmf.parcount );
283
284 gesave_bwdi( bcode->setcount );
285 for ( i = 0; i < bcode->setcount; i++ )
286 {
287 gesave_bwdi( bcode->sets[i].count );
288 count += bcode->sets[i].count;
289 }
290 pvar = bcode->vars;
291 for ( i = 0; i < count; i++ )
292 gesave_var( pvar++ );
293
294 ptr = ( puint )bcode->vmf.func;
295 if ( ptr )
296 {
297 end = ( puint )( ( pubyte )ptr + bcode->bcsize );
298 while ( ptr < end )
299 {
300 cmd = gesave_bwdc( *ptr++ );
301 if ( cmd >= CNop && cmd < CNop + STACK_COUNT )
302 switch ( cmd )
303 {
304 case CQwload:
305 gesave_adduint( *ptr++ );
306 gesave_adduint( *ptr++ );
307 break;
308 case CDwload:
309 val = *ptr++;
310 if ( val <= 0xFF )
311 {
312 buf_ptr( gesave )[ buf_len( gesave ) - 1 ] = CByload;
313 gesave_addubyte( val );
314 }
315 else
316 if ( val <= 0xFFFF )
317 {
318 buf_ptr( gesave )[ buf_len( gesave ) - 1 ] = CShload;
319 gesave_addushort( val );
320 }
321 else
322 gesave_adduint( val );
323 break;
324 case CDwsload:
325 i = gesave_bwdi( *ptr++ );
326 for ( k = 0; k < i; k++ )
327 gesave_cmdflag( *ptr++ );
328 break;
329 case CAsm:
330 i = gesave_bwdi( *ptr++ );
331 gesave_adddata( ( pubyte )ptr, i << 2 );
332 ptr += i;
333 break;
334 case CResload:
335 case CCmdload:
336 case CPtrglobal:
337 gesave_bwdc( *ptr++ );
338 break;
339 case CDatasize:
340 i = gesave_bwdi( *ptr++ );
341 gesave_adddata( ( pubyte )ptr, i );
342 ptr += ( i >> 2 ) + ( i & 3 ? 1 : 0 );
343 break;
344 default:
345 switch ( shifts[ cmd - CNop ] )
346 {
347 case SH1_3:
348 case SH2_3:
349 cmd = gesave_bwdi( *ptr++ );
350 case SHN1_2:
351 case SH0_2:
352 case SH1_2:
353 cmd = gesave_bwdi( *ptr++ );
354 break;
355 }
356 }
357 }
358 }
359 }
360
361 void STDCALL gesave_exfunc( povmfunc exfunc )
362 {
363 gesave_var( exfunc->vmf.ret );
364 gesave_varlist( exfunc->vmf.params, exfunc->vmf.parcount );
365
366 if ( exfunc->vmf.vmo.flag & GHEX_IMPORT )
367 {
368 gesave_bwdc( exfunc->import );
369 gesave_addptr( exfunc->original );
370 }
371 }
372
373 void STDCALL gesave_import( povmimport import )
374 {
375 gesave_addptr( import->filename );
376 if ( import->vmo.flag & GHIMP_LINK )
377 {
378 gesave_adduint( import->size );
379 gesave_adddata( import->data, import->size );
380 }
381 }
382
383 void STDCALL gesave_type( povmtype ptype )
384 {
385 uint i, k;
386 uint flag = ptype->vmo.flag;
387
388 if ( flag & GHTY_INHERIT )
389 gesave_bwdc( ptype->inherit );
390
391 if ( flag & GHTY_INDEX )
392 {
393 gesave_bwdc( ptype->index.type );
394 gesave_bwdc( ptype->index.oftype );
395 }
396 if ( flag & GHTY_INITDEL )
397 {
398 gesave_bwdc( ptype->ftype[ FTYPE_INIT ] );
399 gesave_bwdc( ptype->ftype[ FTYPE_DELETE ] );
400 }
401 if ( flag & GHTY_EXTFUNC )
402 {
403 gesave_bwdc( ptype->ftype[ FTYPE_OFTYPE ] );
404 gesave_bwdc( ptype->ftype[ FTYPE_COLLECTION ] );
405 }
406 if ( flag & GHTY_ARRAY )
407 {
408 i = 0;
409 while ( ptype->ftype[ FTYPE_ARRAY + i ] )
410 i++;
411 gesave_bwdc( i == 1 ? ptype->ftype[ FTYPE_ARRAY ] : i );
412 if ( i > 1 )
413 for ( k = 0; k < i; k++ )
414 gesave_bwdc( ptype->ftype[ FTYPE_ARRAY + k ] );
415 }
416 gesave_varlist( ptype->children, ptype->count );
417 }
418
419 void STDCALL gesave_define( povmdefine pdefine )
420 {
421 gesave_varlist( pdefine->macros, pdefine->count );
422 }
423
424 uint STDCALL ge_save( pbuf out )
425 {
426 gehead head;
427 pgehead phead;
428 uint i, count, off = 0;
429 pvmobj pvmo;
430 gesave = out;
431 buf_reserve( out, 0x1ffff );
432
433 if ( _compile->flag & CMPL_OPTIMIZE )
434 ge_optimize();
435
436 *( puint )&head.idname = GE_STRING;//0x00004547; // строка GE
437 head.flags = 0;
438 head.crc = 0;
439 head.headsize = sizeof( gehead );
440 head.size = 0;
441 head.vermajor = GEVER_MAJOR;
442 head.verminor = GEVER_MINOR;
443
444 buf_append( out, ( pubyte )&head, sizeof( gehead ));
445 // Save resources at the first !
446 gesave_resource();
447
448 count = arr_count( &_vm.objtbl );
449 // Settings new id depending on GHRT_SKIP
450 gecodes = ( puint )mem_alloc( count * sizeof( uint ));
451 for ( i = KERNEL_COUNT; i < count ; i++ )
452 {
453 pvmo = ( pvmobj )PCMD( i );
454 if ( pvmo->flag & GHRT_SKIP )
455 {
456 gecodes[ i ] = 0;
457 off++;
458 }
459 else
460 gecodes[ i ] = i - off;
461 }
462 for ( i = KERNEL_COUNT; i < count ; i++ )
463 {
464 pvmo = ( pvmobj )PCMD( i );
465 if ( pvmo->flag & GHRT_SKIP )
466 continue;
467 // print("i=%i name=%s\n", i, ((pvmobj)PCMD( i ))->name );
468 gesave_head( pvmo->type, pvmo->flag & GHCOM_NAME ?
469 pvmo->name : NULL, pvmo->flag );
470
471 switch ( pvmo->type )
472 {
473 case OVM_NONE:
474 break;
475 case OVM_BYTECODE:
476 gesave_bytecode( ( povmbcode )pvmo );
477 break;
478 case OVM_EXFUNC:
479 gesave_exfunc( ( povmfunc )pvmo );
480 break;
481 case OVM_TYPE:
482 gesave_type( ( povmtype )pvmo );
483 break;
484 case OVM_GLOBAL:
485 gesave_var( (( povmglobal )pvmo)->type );
486 break;
487 case OVM_DEFINE:
488 gesave_define( ( povmdefine )pvmo );
489 break;
490 case OVM_IMPORT:
491 gesave_import( ( povmimport )pvmo );
492 break;
493 case OVM_ALIAS:
494 gesave_bwdc( (( povmalias )pvmo)->idlink );
495 break;
496 }
497 gesave_finish();
498 }
499 mem_free( gecodes );
500 // Specify the full size and crc
501 phead = ( pgehead )buf_ptr( out );
502 phead->size = buf_len( out );
503 phead->crc = crc( ( pubyte )phead + 12, phead->size - 12, 0xFFFFFFFF );
504
505 return 1;
506 }
507
508 #endif