1 /*
2 AngelCode Scripting Library
3 Copyright (c) 2003-2019 Andreas Jonsson
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you
14 must not claim that you wrote the original software. If you use
15 this software in a product, an acknowledgment in the product
16 documentation would be appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source
22 distribution.
23
24 The original version of this library can be located at:
25 http://www.angelcode.com/angelscript/
26
27 Andreas Jonsson
28 andreas@angelcode.com
29 */
30
31
32 //
33 // as_restore.cpp
34 //
35 // Functions for saving and restoring module bytecode
36 // asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be
37
38 #include "as_config.h"
39 #include "as_restore.h"
40 #include "as_bytecode.h"
41 #include "as_scriptobject.h"
42 #include "as_texts.h"
43 #include "as_debug.h"
44
45 BEGIN_AS_NAMESPACE
46
47 // Macros for doing endianess agnostic bitmask serialization
48 #define SAVE_TO_BIT(dst, val, bit) ((dst) |= ((val) << (bit)))
49 #define LOAD_FROM_BIT(dst, val, bit) ((dst) = ((val) >> (bit)) & 1)
50
asCReader(asCModule * _module,asIBinaryStream * _stream,asCScriptEngine * _engine)51 asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine)
52 : module(_module), stream(_stream), engine(_engine)
53 {
54 error = false;
55 bytesRead = 0;
56 }
57
ReadData(void * data,asUINT size)58 int asCReader::ReadData(void *data, asUINT size)
59 {
60 asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
61 int ret = 0;
62 #if defined(AS_BIG_ENDIAN)
63 for( asUINT n = 0; ret >= 0 && n < size; n++ )
64 ret = stream->Read(((asBYTE*)data)+n, 1);
65 #else
66 for( int n = size-1; ret >= 0 && n >= 0; n-- )
67 ret = stream->Read(((asBYTE*)data)+n, 1);
68 #endif
69 if (ret < 0)
70 Error(TXT_UNEXPECTED_END_OF_FILE);
71 bytesRead += size;
72 return ret;
73 }
74
Read(bool * wasDebugInfoStripped)75 int asCReader::Read(bool *wasDebugInfoStripped)
76 {
77 TimeIt("asCReader::Read");
78
79 // Before starting the load, make sure that
80 // any existing resources have been freed
81 module->InternalReset();
82
83 // Call the inner method to do the actual loading
84 int r = ReadInner();
85 if( r < 0 )
86 {
87 // Something went wrong while loading the bytecode, so we need
88 // to clean-up whatever has been created during the process.
89
90 // Make sure none of the loaded functions attempt to release
91 // references that have not yet been increased
92 asUINT i;
93 for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
94 if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) )
95 if( module->scriptFunctions[i]->scriptData )
96 module->scriptFunctions[i]->scriptData->byteCode.SetLength(0);
97
98 asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
99 for( ; it; it++ )
100 if( (*it)->GetInitFunc() )
101 if( (*it)->GetInitFunc()->scriptData )
102 (*it)->GetInitFunc()->scriptData->byteCode.SetLength(0);
103
104 module->InternalReset();
105 }
106 else
107 {
108 // Init system functions properly
109 engine->PrepareEngine();
110
111 // Initialize the global variables (unless requested not to)
112 if( engine->ep.initGlobalVarsAfterBuild )
113 r = module->ResetGlobalVars(0);
114
115 if( wasDebugInfoStripped )
116 *wasDebugInfoStripped = noDebugInfo;
117 }
118
119 // Clean up the loaded string constants
120 for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
121 engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
122 usedStringConstants.SetLength(0);
123
124 return r;
125 }
126
Error(const char * msg)127 int asCReader::Error(const char *msg)
128 {
129 // Don't write if it has already been reported an error earlier
130 if( !error )
131 {
132 asCString str;
133 str.Format(msg, bytesRead);
134 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
135 error = true;
136 }
137
138 return asERROR;
139 }
140
ReadInner()141 int asCReader::ReadInner()
142 {
143 TimeIt("asCReader::ReadInner");
144
145 // This function will load each entity one by one from the stream.
146 // If any error occurs, it will return to the caller who is
147 // responsible for cleaning up the partially loaded entities.
148
149 engine->deferValidationOfTemplateTypes = true;
150
151 unsigned long i, count;
152 asCScriptFunction* func;
153
154 // Read the flag as 1 byte even on platforms with 4byte booleans
155 noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0;
156
157 // Read enums
158 count = ReadEncodedUInt();
159 module->enumTypes.Allocate(count, false);
160 for( i = 0; i < count && !error; i++ )
161 {
162 asCEnumType *et = asNEW(asCEnumType)(engine);
163 if( et == 0 )
164 {
165 error = true;
166 return asOUT_OF_MEMORY;
167 }
168
169 bool isExternal = false;
170 ReadTypeDeclaration(et, 1, &isExternal);
171
172 // If the type is shared then we should use the original if it exists
173 bool sharedExists = false;
174 if( et->IsShared() )
175 {
176 for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
177 {
178 asCTypeInfo *t = engine->sharedScriptTypes[n];
179 if( t &&
180 t->IsShared() &&
181 t->name == et->name &&
182 t->nameSpace == et->nameSpace &&
183 (t->flags & asOBJ_ENUM) )
184 {
185 asDELETE(et, asCEnumType);
186 et = CastToEnumType(t);
187 sharedExists = true;
188 break;
189 }
190 }
191 }
192
193 if (isExternal && !sharedExists)
194 {
195 asCString msg;
196 msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf());
197 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
198 asDELETE(et, asCEnumType);
199 error = true;
200 return asERROR;
201 }
202
203 if( sharedExists )
204 {
205 existingShared.Insert(et, true);
206 et->AddRefInternal();
207 }
208 else
209 {
210 if( et->IsShared() )
211 {
212 engine->sharedScriptTypes.PushLast(et);
213 et->AddRefInternal();
214 }
215
216 // Set this module as the owner
217 et->module = module;
218 }
219 module->enumTypes.PushLast(et);
220
221 if (isExternal)
222 module->externalTypes.PushLast(et);
223
224 ReadTypeDeclaration(et, 2);
225 }
226
227 if( error ) return asERROR;
228
229 // classTypes[]
230 // First restore the structure names, then the properties
231 count = ReadEncodedUInt();
232 module->classTypes.Allocate(count, false);
233 for( i = 0; i < count && !error; ++i )
234 {
235 asCObjectType *ot = asNEW(asCObjectType)(engine);
236 if( ot == 0 )
237 {
238 error = true;
239 return asOUT_OF_MEMORY;
240 }
241
242 bool isExternal = false;
243 ReadTypeDeclaration(ot, 1, &isExternal);
244
245 // If the type is shared, then we should use the original if it exists
246 bool sharedExists = false;
247 if( ot->IsShared() )
248 {
249 for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
250 {
251 asCTypeInfo *ti = engine->sharedScriptTypes[n];
252 asCObjectType *t = CastToObjectType(ti);
253 if( t &&
254 t->IsShared() &&
255 t->name == ot->name &&
256 t->nameSpace == ot->nameSpace &&
257 t->IsInterface() == ot->IsInterface() )
258 {
259 asDELETE(ot, asCObjectType);
260 ot = CastToObjectType(t);
261 sharedExists = true;
262 break;
263 }
264 }
265 }
266
267 if (isExternal && !sharedExists)
268 {
269 asCString msg;
270 msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf());
271 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
272 asDELETE(ot, asCObjectType);
273 error = true;
274 return asERROR;
275 }
276
277 if( sharedExists )
278 {
279 existingShared.Insert(ot, true);
280 ot->AddRefInternal();
281 }
282 else
283 {
284 if( ot->IsShared() )
285 {
286 engine->sharedScriptTypes.PushLast(ot);
287 ot->AddRefInternal();
288 }
289
290 // Set this module as the owner
291 ot->module = module;
292 }
293 module->classTypes.PushLast(ot);
294
295 if (isExternal)
296 module->externalTypes.PushLast(ot);
297 }
298
299 if( error ) return asERROR;
300
301 // Read func defs
302 count = ReadEncodedUInt();
303 module->funcDefs.Allocate(count, false);
304 for( i = 0; i < count && !error; i++ )
305 {
306 bool isNew, isExternal;
307 asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal);
308 if(funcDef)
309 {
310 funcDef->module = module;
311
312 asCFuncdefType *fdt = funcDef->funcdefType;
313 fdt->module = module;
314
315 module->funcDefs.PushLast(fdt);
316 engine->funcDefs.PushLast(fdt);
317
318 // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module
319 // Check if there is another identical funcdef from another module and if so reuse that instead
320 if(funcDef->IsShared())
321 {
322 for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
323 {
324 asCFuncdefType *f2 = engine->funcDefs[n];
325 if( f2 == 0 || fdt == f2 )
326 continue;
327
328 if( !f2->funcdef->IsShared() )
329 continue;
330
331 if( f2->name == fdt->name &&
332 f2->nameSpace == fdt->nameSpace &&
333 f2->parentClass == fdt->parentClass &&
334 f2->funcdef->IsSignatureExceptNameEqual(funcDef) )
335 {
336 // Replace our funcdef for the existing one
337 module->funcDefs[module->funcDefs.IndexOf(fdt)] = f2;
338 f2->AddRefInternal();
339
340 if (isExternal)
341 module->externalTypes.PushLast(f2);
342
343 engine->funcDefs.RemoveValue(fdt);
344
345 savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef;
346
347 if (fdt->parentClass)
348 {
349 // The real funcdef should already be in the object
350 asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0);
351
352 fdt->parentClass = 0;
353 }
354
355 fdt->ReleaseInternal();
356 funcDef = 0;
357 break;
358 }
359 }
360 }
361
362 // Add the funcdef to the parentClass if this is a child funcdef
363 if (funcDef && fdt->parentClass)
364 fdt->parentClass->childFuncDefs.PushLast(fdt);
365
366 // Check if an external shared funcdef was really found
367 if (isExternal && funcDef)
368 {
369 asCString msg;
370 msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf());
371 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
372 error = true;
373 return asERROR;
374 }
375 }
376 else
377 Error(TXT_INVALID_BYTECODE_d);
378 }
379
380 // Read interface methods
381 for( i = 0; i < module->classTypes.GetLength() && !error; i++ )
382 {
383 if( module->classTypes[i]->IsInterface() )
384 ReadTypeDeclaration(module->classTypes[i], 2);
385 }
386
387 // Read class methods and behaviours
388 for( i = 0; i < module->classTypes.GetLength() && !error; ++i )
389 {
390 if( !module->classTypes[i]->IsInterface() )
391 ReadTypeDeclaration(module->classTypes[i], 2);
392 }
393
394 // Read class properties
395 for( i = 0; i < module->classTypes.GetLength() && !error; ++i )
396 {
397 if( !module->classTypes[i]->IsInterface() )
398 ReadTypeDeclaration(module->classTypes[i], 3);
399 }
400
401 if( error ) return asERROR;
402
403 // Read typedefs
404 count = ReadEncodedUInt();
405 module->typeDefs.Allocate(count, false);
406 for( i = 0; i < count && !error; i++ )
407 {
408 asCTypedefType *td = asNEW(asCTypedefType)(engine);
409 if( td == 0 )
410 {
411 error = true;
412 return asOUT_OF_MEMORY;
413 }
414
415 bool isExternal = false;
416 ReadTypeDeclaration(td, 1, &isExternal);
417 td->module = module;
418 module->typeDefs.PushLast(td);
419 ReadTypeDeclaration(td, 2);
420 }
421
422 if( error ) return asERROR;
423
424 // scriptGlobals[]
425 count = ReadEncodedUInt();
426 if( count && engine->ep.disallowGlobalVars )
427 {
428 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED);
429 Error(TXT_INVALID_BYTECODE_d);
430 }
431 module->scriptGlobals.Allocate(count, false);
432 for( i = 0; i < count && !error; ++i )
433 {
434 ReadGlobalProperty();
435 }
436
437 // scriptFunctions[]
438 count = ReadEncodedUInt();
439 for( i = 0; i < count && !error; ++i )
440 {
441 size_t len = module->scriptFunctions.GetLength();
442 bool isNew, isExternal;
443 func = ReadFunction(isNew, true, true, true, &isExternal);
444 if( func == 0 )
445 {
446 Error(TXT_INVALID_BYTECODE_d);
447 break;
448 }
449
450 // Is the function shared and was it created now?
451 if( func->IsShared() && len != module->scriptFunctions.GetLength() )
452 {
453 // If the function already existed in another module, then
454 // we need to replace it with previously existing one
455 for( asUINT n = 0; n < engine->scriptFunctions.GetLength() && !error; n++ )
456 {
457 asCScriptFunction *realFunc = engine->scriptFunctions[n];
458 if( realFunc &&
459 realFunc != func &&
460 realFunc->IsShared() &&
461 realFunc->nameSpace == func->nameSpace &&
462 realFunc->IsSignatureEqual(func) )
463 {
464 // Replace the recently created function with the pre-existing function
465 module->scriptFunctions[module->scriptFunctions.GetLength()-1] = realFunc;
466 realFunc->AddRefInternal();
467 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
468 engine->RemoveScriptFunction(func);
469
470 // Insert the function in the dontTranslate array
471 dontTranslate.Insert(realFunc, true);
472
473 if (isExternal)
474 module->externalFunctions.PushLast(realFunc);
475
476 // Release the function, but make sure nothing else is released
477 func->id = 0;
478 if( func->scriptData )
479 func->scriptData->byteCode.SetLength(0);
480 func->ReleaseInternal();
481 func = 0;
482 break;
483 }
484 }
485 }
486
487 // Check if an external shared func was really found
488 if (isExternal && func)
489 {
490 asCString msg;
491 msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf());
492 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
493 error = true;
494 return asERROR;
495 }
496 }
497
498 // globalFunctions[]
499 count = ReadEncodedUInt();
500 for( i = 0; i < count && !error; ++i )
501 {
502 bool isNew;
503 func = ReadFunction(isNew, false, false);
504 if( func )
505 {
506 // All the global functions were already loaded while loading the scriptFunctions, here
507 // we're just re-reading the references to know which goes into the globalFunctions array
508 asASSERT( !isNew );
509
510 module->globalFunctions.Put(func);
511 }
512 else
513 Error(TXT_INVALID_BYTECODE_d);
514 }
515
516 if( error ) return asERROR;
517
518 // bindInformations[]
519 count = ReadEncodedUInt();
520 module->bindInformations.Allocate(count, false);
521 for( i = 0; i < count && !error; ++i )
522 {
523 sBindInfo *info = asNEW(sBindInfo);
524 if( info == 0 )
525 {
526 error = true;
527 return asOUT_OF_MEMORY;
528 }
529
530 bool isNew;
531 info->importedFunctionSignature = ReadFunction(isNew, false, false);
532 if( info->importedFunctionSignature == 0 )
533 {
534 Error(TXT_INVALID_BYTECODE_d);
535 break;
536 }
537
538 if( engine->freeImportedFunctionIdxs.GetLength() )
539 {
540 int id = engine->freeImportedFunctionIdxs.PopLast();
541 info->importedFunctionSignature->id = int(FUNC_IMPORTED + id);
542 engine->importedFunctions[id] = info;
543 }
544 else
545 {
546 info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength());
547 engine->importedFunctions.PushLast(info);
548 }
549 ReadString(&info->importFromModule);
550 info->boundFunctionId = -1;
551 module->bindInformations.PushLast(info);
552 }
553
554 if( error ) return asERROR;
555
556 // usedTypes[]
557 count = ReadEncodedUInt();
558 usedTypes.Allocate(count, false);
559 for( i = 0; i < count && !error; ++i )
560 {
561 asCTypeInfo *ti = ReadTypeInfo();
562 usedTypes.PushLast(ti);
563 }
564
565 // usedTypeIds[]
566 if( !error )
567 ReadUsedTypeIds();
568
569 // usedFunctions[]
570 if( !error )
571 ReadUsedFunctions();
572
573 // usedGlobalProperties[]
574 if( !error )
575 ReadUsedGlobalProps();
576
577 // usedStringConstants[]
578 if( !error )
579 ReadUsedStringConstants();
580
581 // usedObjectProperties
582 if( !error )
583 ReadUsedObjectProps();
584
585 // Validate the template types
586 if( !error )
587 {
588 for( i = 0; i < usedTypes.GetLength() && !error; i++ )
589 {
590 asCObjectType *ot = CastToObjectType(usedTypes[i]);
591 if( !ot ||
592 !(ot->flags & asOBJ_TEMPLATE) ||
593 !ot->beh.templateCallback )
594 continue;
595
596 bool dontGarbageCollect = false;
597 asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback];
598 if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) )
599 {
600 asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace);
601 for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ )
602 {
603 sub += ",";
604 sub += ot->templateSubTypes[n].Format(ot->nameSpace);
605 }
606 asCString str;
607 str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf());
608 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
609 Error(TXT_INVALID_BYTECODE_d);
610 }
611 else
612 {
613 // If the callback said this template instance won't be garbage collected then remove the flag
614 if( dontGarbageCollect )
615 ot->flags &= ~asOBJ_GC;
616 }
617 }
618 }
619 engine->deferValidationOfTemplateTypes = false;
620
621 if( error ) return asERROR;
622
623 // Update the loaded bytecode to point to the correct types, property offsets,
624 // function ids, etc. This is basically a linking stage.
625 for( i = 0; i < module->scriptFunctions.GetLength() && !error; i++ )
626 if( module->scriptFunctions[i]->funcType == asFUNC_SCRIPT )
627 TranslateFunction(module->scriptFunctions[i]);
628
629 asCSymbolTable<asCGlobalProperty>::iterator globIt = module->scriptGlobals.List();
630 while( globIt && !error )
631 {
632 asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
633 if( initFunc )
634 TranslateFunction(initFunc);
635 globIt++;
636 }
637
638 if( error ) return asERROR;
639
640 // Add references for all functions (except for the pre-existing shared code)
641 for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
642 if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) )
643 module->scriptFunctions[i]->AddReferences();
644
645 globIt = module->scriptGlobals.List();
646 while( globIt )
647 {
648 asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
649 if( initFunc )
650 initFunc->AddReferences();
651 globIt++;
652 }
653 return error ? asERROR : asSUCCESS;
654 }
655
ReadUsedStringConstants()656 void asCReader::ReadUsedStringConstants()
657 {
658 TimeIt("asCReader::ReadUsedStringConstants");
659
660 asCString str;
661
662 asUINT count;
663 count = ReadEncodedUInt();
664
665 if (count > 0 && engine->stringFactory == 0)
666 {
667 Error(TXT_STRINGS_NOT_RECOGNIZED);
668 return;
669 }
670
671 usedStringConstants.Allocate(count, false);
672 for( asUINT i = 0; i < count; ++i )
673 {
674 ReadString(&str);
675 usedStringConstants.PushLast(const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())));
676 }
677 }
678
ReadUsedFunctions()679 void asCReader::ReadUsedFunctions()
680 {
681 TimeIt("asCReader::ReadUsedFunctions");
682
683 asUINT count;
684 count = ReadEncodedUInt();
685 usedFunctions.SetLength(count);
686 if( usedFunctions.GetLength() != count )
687 {
688 // Out of memory
689 error = true;
690 return;
691 }
692 memset(usedFunctions.AddressOf(), 0, sizeof(asCScriptFunction *)*count);
693
694 for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
695 {
696 char c;
697
698 // Read the data to be able to uniquely identify the function
699
700 // Is the function from the module or the application?
701 ReadData(&c, 1);
702
703 if( c == 'n' )
704 {
705 // Null function pointer
706 usedFunctions[n] = 0;
707 }
708 else
709 {
710 asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY);
711 asCObjectType *parentClass = 0;
712 ReadFunctionSignature(&func, &parentClass);
713 if( error )
714 {
715 func.funcType = asFUNC_DUMMY;
716 return;
717 }
718
719 // Find the correct function
720 if( c == 'm' )
721 {
722 if( func.funcType == asFUNC_IMPORTED )
723 {
724 for( asUINT i = 0; i < module->bindInformations.GetLength(); i++ )
725 {
726 asCScriptFunction *f = module->bindInformations[i]->importedFunctionSignature;
727 if( func.objectType != f->objectType ||
728 func.funcType != f->funcType ||
729 func.nameSpace != f->nameSpace ||
730 !func.IsSignatureEqual(f) )
731 continue;
732
733 usedFunctions[n] = f;
734 break;
735 }
736 }
737 else if( func.funcType == asFUNC_FUNCDEF )
738 {
739 const asCArray<asCFuncdefType *> &funcs = module->funcDefs;
740 for( asUINT i = 0; i < funcs.GetLength(); i++ )
741 {
742 asCScriptFunction *f = funcs[i]->funcdef;
743 if( f == 0 ||
744 func.name != f->name ||
745 !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
746 funcs[i]->parentClass != parentClass )
747 continue;
748
749 asASSERT( f->objectType == 0 );
750
751 usedFunctions[n] = f;
752 break;
753 }
754 }
755 else
756 {
757 // TODO: optimize: Global functions should be searched for in module->globalFunctions
758 // TODO: optimize: funcdefs should be searched for in module->funcDefs
759 // TODO: optimize: object methods should be searched for directly in the object type
760 for( asUINT i = 0; i < module->scriptFunctions.GetLength(); i++ )
761 {
762 asCScriptFunction *f = module->scriptFunctions[i];
763 if( func.objectType != f->objectType ||
764 func.funcType != f->funcType ||
765 func.nameSpace != f->nameSpace ||
766 !func.IsSignatureEqual(f) )
767 continue;
768
769 usedFunctions[n] = f;
770 break;
771 }
772 }
773 }
774 else if (c == 's')
775 {
776 // Look for shared entities in the engine, as they may not necessarily be part
777 // of the scope of the module if they have been inhereted from other modules.
778 if (func.funcType == asFUNC_FUNCDEF)
779 {
780 const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
781 for (asUINT i = 0; i < funcs.GetLength(); i++)
782 {
783 asCScriptFunction *f = funcs[i]->funcdef;
784 if (f == 0 ||
785 func.name != f->name ||
786 !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
787 funcs[i]->parentClass != parentClass)
788 continue;
789
790 asASSERT(f->objectType == 0);
791
792 usedFunctions[n] = f;
793 break;
794 }
795 }
796 else
797 {
798 for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++)
799 {
800 asCScriptFunction *f = engine->scriptFunctions[i];
801 if (f == 0 || !f->IsShared() ||
802 func.objectType != f->objectType ||
803 func.funcType != f->funcType ||
804 func.nameSpace != f->nameSpace ||
805 !func.IsSignatureEqual(f))
806 continue;
807
808 usedFunctions[n] = f;
809 break;
810 }
811 }
812 }
813 else
814 {
815 asASSERT(c == 'a');
816
817 if( func.funcType == asFUNC_FUNCDEF )
818 {
819 // This is a funcdef (registered or shared)
820 const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
821 for( asUINT i = 0; i < funcs.GetLength(); i++ )
822 {
823 asCScriptFunction *f = funcs[i]->funcdef;
824 if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass )
825 continue;
826
827 asASSERT( f->objectType == 0 );
828
829 usedFunctions[n] = f;
830 break;
831 }
832 }
833 else if( func.name[0] == '$' )
834 {
835 // This is a special function
836
837 if( func.name == "$beh0" && func.objectType )
838 {
839 if (func.objectType->flags & asOBJ_TEMPLATE)
840 {
841 // Look for the matching constructor inside the factory stubs generated for the template instance
842 // See asCCompiler::PerformFunctionCall
843 for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
844 {
845 asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
846
847 // Find the id of the real constructor and not the generated stub
848 asUINT id = 0;
849 asDWORD *bc = f->scriptData->byteCode.AddressOf();
850 while (bc)
851 {
852 if ((*(asBYTE*)bc) == asBC_CALLSYS)
853 {
854 id = asBC_INTARG(bc);
855 break;
856 }
857 bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
858 }
859
860 f = engine->scriptFunctions[id];
861 if (f == 0 ||
862 !func.IsSignatureExceptNameAndObjectTypeEqual(f))
863 continue;
864
865 usedFunctions[n] = f;
866 break;
867 }
868 }
869
870 if( usedFunctions[n] == 0 )
871 {
872 // This is a class constructor, so we can search directly in the object type's constructors
873 for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
874 {
875 asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
876 if (f == 0 ||
877 !func.IsSignatureExceptNameAndObjectTypeEqual(f))
878 continue;
879
880 usedFunctions[n] = f;
881 break;
882 }
883 }
884 }
885 else if( func.name == "$fact" || func.name == "$beh3" )
886 {
887 // This is a factory (or stub), so look for the function in the return type's factories
888 asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo());
889 if( objType )
890 {
891 for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ )
892 {
893 asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]];
894 if( f == 0 ||
895 !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
896 continue;
897
898 usedFunctions[n] = f;
899 break;
900 }
901 }
902 }
903 else if( func.name == "$list" )
904 {
905 // listFactory is used for both factory is global and returns a handle and constructor that is a method
906 asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo());
907 if( objType )
908 {
909 asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
910 if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
911 usedFunctions[n] = f;
912 }
913 }
914 else if( func.name == "$beh2" )
915 {
916 // This is a destructor, so check the object type's destructor
917 asCObjectType *objType = func.objectType;
918 if( objType )
919 {
920 asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct];
921 if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
922 usedFunctions[n] = f;
923 }
924 }
925 else if( func.name == "$beh4" )
926 {
927 // This is a list factory, so check the return type's list factory
928 asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo());
929 if( objType )
930 {
931 asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
932 if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
933 usedFunctions[n] = f;
934 }
935 }
936 else if( func.name == "$dlgte" )
937 {
938 // This is the delegate factory
939 asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
940 asASSERT( f && func.IsSignatureEqual(f) );
941 usedFunctions[n] = f;
942 }
943 }
944 else if( func.objectType == 0 )
945 {
946 // This is a global function
947 const asCArray<asUINT> &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name);
948 for( asUINT i = 0; i < funcs.GetLength(); i++ )
949 {
950 asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]);
951 if( f == 0 ||
952 !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
953 continue;
954
955 usedFunctions[n] = f;
956 break;
957 }
958 }
959 else if( func.objectType )
960 {
961 // It is a class member, so we can search directly in the object type's members
962 // TODO: virtual function is different that implemented method
963 for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ )
964 {
965 asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]];
966 if( f == 0 ||
967 !func.IsSignatureEqual(f) )
968 continue;
969
970 usedFunctions[n] = f;
971 break;
972 }
973 }
974
975 if( usedFunctions[n] == 0 )
976 {
977 // TODO: clean up: This part of the code should never happen. All functions should
978 // be found in the above logic. The only valid reason to come here
979 // is if the bytecode is wrong and the function doesn't exist anyway.
980 // This loop is kept temporarily until we can be certain all scenarios
981 // are covered.
982 for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
983 {
984 asCScriptFunction *f = engine->scriptFunctions[i];
985 if( f == 0 ||
986 func.objectType != f->objectType ||
987 func.nameSpace != f->nameSpace ||
988 !func.IsSignatureEqual(f) )
989 continue;
990
991 usedFunctions[n] = f;
992 break;
993 }
994
995 // No function is expected to be found
996 asASSERT(usedFunctions[n] == 0);
997 }
998 }
999
1000 // Set the type to dummy so it won't try to release the id
1001 func.funcType = asFUNC_DUMMY;
1002
1003 if( usedFunctions[n] == 0 )
1004 {
1005 Error(TXT_INVALID_BYTECODE_d);
1006 return;
1007 }
1008 }
1009 }
1010 }
1011
ReadFunctionSignature(asCScriptFunction * func,asCObjectType ** parentClass)1012 void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass)
1013 {
1014 asUINT i, count;
1015 asCDataType dt;
1016 int num;
1017
1018 ReadString(&func->name);
1019 if( func->name == DELEGATE_FACTORY )
1020 {
1021 // It's not necessary to read anymore, everything is known
1022 asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
1023 asASSERT( f );
1024 func->returnType = f->returnType;
1025 func->parameterTypes = f->parameterTypes;
1026 func->inOutFlags = f->inOutFlags;
1027 func->funcType = f->funcType;
1028 func->defaultArgs = f->defaultArgs;
1029 func->nameSpace = f->nameSpace;
1030 return;
1031 }
1032
1033 ReadDataType(&func->returnType);
1034
1035 count = ReadEncodedUInt();
1036 if( count > 256 )
1037 {
1038 // Too many arguments, must be something wrong in the file
1039 Error(TXT_INVALID_BYTECODE_d);
1040 return;
1041 }
1042 func->parameterTypes.Allocate(count, false);
1043 for( i = 0; i < count; ++i )
1044 {
1045 ReadDataType(&dt);
1046 func->parameterTypes.PushLast(dt);
1047 }
1048
1049 func->inOutFlags.SetLength(func->parameterTypes.GetLength());
1050 if( func->inOutFlags.GetLength() != func->parameterTypes.GetLength() )
1051 {
1052 // Out of memory
1053 error = true;
1054 return;
1055 }
1056 memset(func->inOutFlags.AddressOf(), 0, sizeof(asETypeModifiers)*func->inOutFlags.GetLength());
1057 if (func->parameterTypes.GetLength() > 0)
1058 {
1059 count = ReadEncodedUInt();
1060 if (count > func->parameterTypes.GetLength())
1061 {
1062 // Cannot be more than the number of arguments
1063 Error(TXT_INVALID_BYTECODE_d);
1064 return;
1065 }
1066 for (i = 0; i < count; ++i)
1067 {
1068 num = ReadEncodedUInt();
1069 func->inOutFlags[i] = static_cast<asETypeModifiers>(num);
1070 }
1071 }
1072
1073 func->funcType = (asEFuncType)ReadEncodedUInt();
1074
1075 // Read the default args, from last to first
1076 if (func->parameterTypes.GetLength() > 0)
1077 {
1078 count = ReadEncodedUInt();
1079 if (count > func->parameterTypes.GetLength())
1080 {
1081 // Cannot be more than the number of arguments
1082 Error(TXT_INVALID_BYTECODE_d);
1083 return;
1084 }
1085 if (count)
1086 {
1087 func->defaultArgs.SetLength(func->parameterTypes.GetLength());
1088 if (func->defaultArgs.GetLength() != func->parameterTypes.GetLength())
1089 {
1090 // Out of memory
1091 error = true;
1092 return;
1093 }
1094 memset(func->defaultArgs.AddressOf(), 0, sizeof(asCString*)*func->defaultArgs.GetLength());
1095 for (i = 0; i < count; i++)
1096 {
1097 asCString *str = asNEW(asCString);
1098 if (str == 0)
1099 {
1100 // Out of memory
1101 error = true;
1102 return;
1103 }
1104 func->defaultArgs[func->defaultArgs.GetLength() - 1 - i] = str;
1105 ReadString(str);
1106 }
1107 }
1108 }
1109
1110 func->objectType = CastToObjectType(ReadTypeInfo());
1111 if( func->objectType )
1112 {
1113 func->objectType->AddRefInternal();
1114
1115 asBYTE b;
1116 ReadData(&b, 1);
1117 func->SetReadOnly((b & 1) ? true : false);
1118 func->SetPrivate((b & 2) ? true : false);
1119 func->SetProtected((b & 4) ? true : false);
1120 func->nameSpace = func->objectType->nameSpace;
1121 }
1122 else
1123 {
1124 if (func->funcType == asFUNC_FUNCDEF)
1125 {
1126 asBYTE b;
1127 ReadData(&b, 1);
1128 if (b == 'n')
1129 {
1130 asCString ns;
1131 ReadString(&ns);
1132 func->nameSpace = engine->AddNameSpace(ns.AddressOf());
1133 }
1134 else if (b == 'o')
1135 {
1136 func->nameSpace = 0;
1137 if (parentClass)
1138 *parentClass = CastToObjectType(ReadTypeInfo());
1139 else
1140 error = true;
1141 }
1142 else
1143 error = true;
1144 }
1145 else
1146 {
1147 asCString ns;
1148 ReadString(&ns);
1149 func->nameSpace = engine->AddNameSpace(ns.AddressOf());
1150 }
1151 }
1152 }
1153
ReadFunction(bool & isNew,bool addToModule,bool addToEngine,bool addToGC,bool * isExternal)1154 asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal)
1155 {
1156 isNew = false;
1157 if (isExternal) *isExternal = false;
1158 if( error ) return 0;
1159
1160 char c;
1161 ReadData(&c, 1);
1162
1163 if( c == '\0' )
1164 {
1165 // There is no function, so return a null pointer
1166 return 0;
1167 }
1168
1169 if( c == 'r' )
1170 {
1171 // This is a reference to a previously saved function
1172 asUINT index = ReadEncodedUInt();
1173 if( index < savedFunctions.GetLength() )
1174 return savedFunctions[index];
1175 else
1176 {
1177 Error(TXT_INVALID_BYTECODE_d);
1178 return 0;
1179 }
1180 }
1181
1182 // Load the new function
1183 isNew = true;
1184 asCScriptFunction *func = asNEW(asCScriptFunction)(engine,0,asFUNC_DUMMY);
1185 if( func == 0 )
1186 {
1187 // Out of memory
1188 error = true;
1189 return 0;
1190 }
1191 savedFunctions.PushLast(func);
1192
1193 int i, count;
1194 asCDataType dt;
1195 int num;
1196
1197 asCObjectType *parentClass = 0;
1198 ReadFunctionSignature(func, &parentClass);
1199 if( error )
1200 {
1201 func->DestroyHalfCreated();
1202 return 0;
1203 }
1204
1205 if( func->funcType == asFUNC_SCRIPT )
1206 {
1207 // Skip this for external shared entities
1208 if (module->externalTypes.IndexOf(func->objectType) >= 0)
1209 {
1210 // Replace with the real function from the existing entity
1211 isNew = false;
1212
1213 asCObjectType *ot = func->objectType;
1214 for (asUINT n = 0; n < ot->methods.GetLength(); n++)
1215 {
1216 asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]];
1217 if (func2->funcType == asFUNC_VIRTUAL)
1218 func2 = ot->virtualFunctionTable[func2->vfTableIdx];
1219
1220 if (func->IsSignatureEqual(func2))
1221 {
1222 func->DestroyHalfCreated();
1223
1224 // as this is an existing function it shouldn't be translated as if just loaded
1225 dontTranslate.Insert(func2, true);
1226
1227 // update the saved functions for future references
1228 savedFunctions[savedFunctions.GetLength() - 1] = func2;
1229
1230 // As it is an existing function it shouldn't be added to the module or the engine
1231 return func2;
1232 }
1233 }
1234 }
1235 else
1236 {
1237 char bits;
1238 ReadData(&bits, 1);
1239 func->SetShared((bits & 1) ? true : false);
1240 func->SetExplicit((bits & 32) ? true : false);
1241 func->dontCleanUpOnException = (bits & 2) ? true : false;
1242 if ((bits & 4) && isExternal)
1243 *isExternal = true;
1244
1245 // for external shared functions the rest is not needed
1246 if (!(bits & 4))
1247 {
1248 func->AllocateScriptFunctionData();
1249 if (func->scriptData == 0)
1250 {
1251 // Out of memory
1252 error = true;
1253 func->DestroyHalfCreated();
1254 return 0;
1255 }
1256
1257 if (addToGC && !addToModule)
1258 engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours);
1259
1260 ReadByteCode(func);
1261
1262 func->scriptData->variableSpace = ReadEncodedUInt();
1263
1264 func->scriptData->objVariablesOnHeap = 0;
1265 if (bits & 8)
1266 {
1267 count = ReadEncodedUInt();
1268 func->scriptData->objVariablePos.Allocate(count, false);
1269 func->scriptData->objVariableTypes.Allocate(count, false);
1270 for (i = 0; i < count; ++i)
1271 {
1272 func->scriptData->objVariableTypes.PushLast(ReadTypeInfo());
1273 num = ReadEncodedUInt();
1274 func->scriptData->objVariablePos.PushLast(num);
1275
1276 if (error)
1277 {
1278 // No need to continue (the error has already been reported before)
1279 func->DestroyHalfCreated();
1280 return 0;
1281 }
1282 }
1283 if (count > 0)
1284 func->scriptData->objVariablesOnHeap = ReadEncodedUInt();
1285
1286 int length = ReadEncodedUInt();
1287 func->scriptData->objVariableInfo.SetLength(length);
1288 for (i = 0; i < length; ++i)
1289 {
1290 func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt();
1291 func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt();
1292 asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt();
1293 func->scriptData->objVariableInfo[i].option = option;
1294 if (option != asOBJ_INIT &&
1295 option != asOBJ_UNINIT &&
1296 option != asBLOCK_BEGIN &&
1297 option != asBLOCK_END &&
1298 option != asOBJ_VARDECL)
1299 {
1300 error = true;
1301 func->DestroyHalfCreated();
1302 return 0;
1303 }
1304 }
1305 }
1306
1307 if (bits & 16)
1308 {
1309 // Read info on try/catch blocks
1310 int length = ReadEncodedUInt();
1311 func->scriptData->tryCatchInfo.SetLength(length);
1312 for (i = 0; i < length; ++i)
1313 {
1314 // The program position must be adjusted to be in number of instructions
1315 func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt();
1316 func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt();
1317 }
1318 }
1319
1320 if (!noDebugInfo)
1321 {
1322 int length = ReadEncodedUInt();
1323 func->scriptData->lineNumbers.SetLength(length);
1324 if (int(func->scriptData->lineNumbers.GetLength()) != length)
1325 {
1326 // Out of memory
1327 error = true;
1328 func->DestroyHalfCreated();
1329 return 0;
1330 }
1331 for (i = 0; i < length; ++i)
1332 func->scriptData->lineNumbers[i] = ReadEncodedUInt();
1333
1334 // Read the array of script sections
1335 length = ReadEncodedUInt();
1336 func->scriptData->sectionIdxs.SetLength(length);
1337 if (int(func->scriptData->sectionIdxs.GetLength()) != length)
1338 {
1339 // Out of memory
1340 error = true;
1341 func->DestroyHalfCreated();
1342 return 0;
1343 }
1344 for (i = 0; i < length; ++i)
1345 {
1346 if ((i & 1) == 0)
1347 func->scriptData->sectionIdxs[i] = ReadEncodedUInt();
1348 else
1349 {
1350 asCString str;
1351 ReadString(&str);
1352 func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf());
1353 }
1354 }
1355 }
1356
1357 // Read the variable information
1358 if (!noDebugInfo)
1359 {
1360 int length = ReadEncodedUInt();
1361 func->scriptData->variables.Allocate(length, false);
1362 for (i = 0; i < length; i++)
1363 {
1364 asSScriptVariable *var = asNEW(asSScriptVariable);
1365 if (var == 0)
1366 {
1367 // Out of memory
1368 error = true;
1369 func->DestroyHalfCreated();
1370 return 0;
1371 }
1372 func->scriptData->variables.PushLast(var);
1373
1374 var->declaredAtProgramPos = ReadEncodedUInt();
1375 var->stackOffset = ReadEncodedUInt();
1376 ReadString(&var->name);
1377 ReadDataType(&var->type);
1378
1379 if (error)
1380 {
1381 // No need to continue (the error has already been reported before)
1382 func->DestroyHalfCreated();
1383 return 0;
1384 }
1385 }
1386 }
1387
1388 // Read script section name
1389 if (!noDebugInfo)
1390 {
1391 asCString name;
1392 ReadString(&name);
1393 func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf());
1394 func->scriptData->declaredAt = ReadEncodedUInt();
1395 }
1396
1397 // Read parameter names
1398 if (!noDebugInfo)
1399 {
1400 asUINT countParam = asUINT(ReadEncodedUInt64());
1401 if (countParam > func->parameterTypes.GetLength())
1402 {
1403 error = true;
1404 func->DestroyHalfCreated();
1405 return 0;
1406 }
1407 func->parameterNames.SetLength(countParam);
1408 for (asUINT n = 0; n < countParam; n++)
1409 ReadString(&func->parameterNames[n]);
1410 }
1411 }
1412 }
1413 }
1414 else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
1415 {
1416 func->vfTableIdx = ReadEncodedUInt();
1417 }
1418 else if( func->funcType == asFUNC_FUNCDEF )
1419 {
1420 asBYTE bits;
1421 ReadData(&bits, 1);
1422 if( bits & 1 )
1423 func->SetShared(true);
1424 if ((bits & 2) && isExternal)
1425 *isExternal = true;
1426
1427 // The asCFuncdefType constructor adds itself to the func->funcdefType member
1428 asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func);
1429 fdt->parentClass = parentClass;
1430 }
1431
1432 if( addToModule )
1433 {
1434 // The refCount is already 1
1435 module->scriptFunctions.PushLast(func);
1436 func->module = module;
1437 }
1438 if( addToEngine )
1439 {
1440 func->id = engine->GetNextScriptFunctionId();
1441 engine->AddScriptFunction(func);
1442 }
1443 if( func->objectType )
1444 func->ComputeSignatureId();
1445
1446 return func;
1447 }
1448
ReadTypeDeclaration(asCTypeInfo * type,int phase,bool * isExternal)1449 void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal)
1450 {
1451 if( phase == 1 )
1452 {
1453 asASSERT(isExternal);
1454 if (isExternal)
1455 *isExternal = false;
1456
1457 // Read the initial attributes
1458 ReadString(&type->name);
1459 ReadData(&type->flags, 4);
1460 type->size = ReadEncodedUInt();
1461 asCString ns;
1462 ReadString(&ns);
1463 type->nameSpace = engine->AddNameSpace(ns.AddressOf());
1464
1465 // Verify that the flags match the asCTypeInfo
1466 if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) ||
1467 (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) ||
1468 (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE))))
1469 {
1470 error = true;
1471 return;
1472 }
1473
1474 // Reset the size of script classes, since it will be recalculated as properties are added
1475 if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 )
1476 type->size = sizeof(asCScriptObject);
1477
1478 asCObjectType *ot = CastToObjectType(type);
1479 if (ot)
1480 {
1481 // Use the default script class behaviours
1482 ot->beh = engine->scriptTypeBehaviours.beh;
1483 ot->beh.construct = 0;
1484 ot->beh.factory = 0;
1485 ot->beh.constructors.PopLast(); // These will be read from the file
1486 ot->beh.factories.PopLast(); // These will be read from the file
1487 engine->scriptFunctions[ot->beh.addref]->AddRefInternal();
1488 engine->scriptFunctions[ot->beh.release]->AddRefInternal();
1489 engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal();
1490 engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal();
1491 engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal();
1492 engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal();
1493 engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal();
1494 engine->scriptFunctions[ot->beh.copy]->AddRefInternal();
1495 // TODO: weak: Should not do this if the class has been declared with 'noweak'
1496 engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal();
1497 }
1498
1499 // external shared flag
1500 if (type->flags & asOBJ_SHARED)
1501 {
1502 char c;
1503 ReadData(&c, 1);
1504 if (c == 'e')
1505 *isExternal = true;
1506 else if (c != ' ')
1507 {
1508 error = true;
1509 return;
1510 }
1511 }
1512 }
1513 else if( phase == 2 )
1514 {
1515 // external shared types doesn't store this
1516 if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0)
1517 return;
1518
1519 if( type->flags & asOBJ_ENUM )
1520 {
1521 asCEnumType *t = CastToEnumType(type);
1522 int count = ReadEncodedUInt();
1523 bool sharedExists = existingShared.MoveTo(0, type);
1524 if( !sharedExists )
1525 {
1526 t->enumValues.Allocate(count, false);
1527 for( int n = 0; n < count; n++ )
1528 {
1529 asSEnumValue *e = asNEW(asSEnumValue);
1530 if( e == 0 )
1531 {
1532 // Out of memory
1533 error = true;
1534 return;
1535 }
1536 ReadString(&e->name);
1537 ReadData(&e->value, 4); // TODO: Should be encoded
1538 t->enumValues.PushLast(e);
1539 }
1540 }
1541 else
1542 {
1543 // Verify that the enum values exists in the original
1544 asCString name;
1545 int value;
1546 for( int n = 0; n < count; n++ )
1547 {
1548 ReadString(&name);
1549 ReadData(&value, 4); // TODO: Should be encoded
1550 bool found = false;
1551 for( asUINT e = 0; e < t->enumValues.GetLength(); e++ )
1552 {
1553 if( t->enumValues[e]->name == name &&
1554 t->enumValues[e]->value == value )
1555 {
1556 found = true;
1557 break;
1558 }
1559 }
1560 if( !found )
1561 {
1562 asCString str;
1563 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1564 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1565 Error(TXT_INVALID_BYTECODE_d);
1566 }
1567 }
1568 }
1569 }
1570 else if( type->flags & asOBJ_TYPEDEF )
1571 {
1572 asCTypedefType *td = CastToTypedefType(type);
1573 asASSERT(td);
1574 eTokenType t = (eTokenType)ReadEncodedUInt();
1575 td->aliasForType = asCDataType::CreatePrimitive(t, false);
1576 }
1577 else
1578 {
1579 asCObjectType *ot = CastToObjectType(type);
1580 asASSERT(ot);
1581
1582 // If the type is shared and pre-existing, we should just
1583 // validate that the loaded methods match the original
1584 bool sharedExists = existingShared.MoveTo(0, type);
1585 if( sharedExists )
1586 {
1587 asCObjectType *dt = CastToObjectType(ReadTypeInfo());
1588 if( ot->derivedFrom != dt )
1589 {
1590 asCString str;
1591 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1592 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1593 Error(TXT_INVALID_BYTECODE_d);
1594 }
1595 }
1596 else
1597 {
1598 ot->derivedFrom = CastToObjectType(ReadTypeInfo());
1599 if( ot->derivedFrom )
1600 ot->derivedFrom->AddRefInternal();
1601 }
1602
1603 // interfaces[] / interfaceVFTOffsets[]
1604 int size = ReadEncodedUInt();
1605 if( sharedExists )
1606 {
1607 for( int n = 0; n < size; n++ )
1608 {
1609 asCObjectType *intf = CastToObjectType(ReadTypeInfo());
1610 if (!ot->IsInterface())
1611 ReadEncodedUInt();
1612
1613 if( !type->Implements(intf) )
1614 {
1615 asCString str;
1616 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1617 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1618 Error(TXT_INVALID_BYTECODE_d);
1619 }
1620 }
1621 }
1622 else
1623 {
1624 ot->interfaces.Allocate(size, false);
1625 if( !ot->IsInterface() )
1626 ot->interfaceVFTOffsets.Allocate(size, false);
1627 for( int n = 0; n < size; n++ )
1628 {
1629 asCObjectType *intf = CastToObjectType(ReadTypeInfo());
1630 ot->interfaces.PushLast(intf);
1631
1632 if (!ot->IsInterface())
1633 {
1634 asUINT offset = ReadEncodedUInt();
1635 ot->interfaceVFTOffsets.PushLast(offset);
1636 }
1637 }
1638 }
1639
1640 // behaviours
1641 if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
1642 {
1643 bool isNew;
1644 asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
1645 if( sharedExists )
1646 {
1647 // Find the real function in the object, and update the savedFunctions array
1648 asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.destruct);
1649 if( (realFunc == 0 && func == 0) || realFunc->IsSignatureEqual(func) )
1650 {
1651 // If the function is not the last, then the substitution has already occurred before
1652 if( func && savedFunctions[savedFunctions.GetLength()-1] == func )
1653 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
1654 }
1655 else
1656 {
1657 asCString str;
1658 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1659 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1660 Error(TXT_INVALID_BYTECODE_d);
1661 }
1662 if( func )
1663 {
1664 if( isNew )
1665 {
1666 // Destroy the function without releasing any references
1667 func->id = 0;
1668 func->scriptData->byteCode.SetLength(0);
1669 func->ReleaseInternal();
1670 }
1671 module->scriptFunctions.PushLast(realFunc);
1672 realFunc->AddRefInternal();
1673 dontTranslate.Insert(realFunc, true);
1674 }
1675 }
1676 else
1677 {
1678 if( func )
1679 {
1680 ot->beh.destruct = func->id;
1681 func->AddRefInternal();
1682 }
1683 else
1684 ot->beh.destruct = 0;
1685 }
1686
1687 size = ReadEncodedUInt();
1688 for( int n = 0; n < size; n++ )
1689 {
1690 func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
1691 if( func )
1692 {
1693 if( sharedExists )
1694 {
1695 // Find the real function in the object, and update the savedFunctions array
1696 bool found = false;
1697 for( asUINT f = 0; f < ot->beh.constructors.GetLength(); f++ )
1698 {
1699 asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]);
1700 if( realFunc->IsSignatureEqual(func) )
1701 {
1702 // If the function is not the last, then the substitution has already occurred before
1703 if( savedFunctions[savedFunctions.GetLength()-1] == func )
1704 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
1705 found = true;
1706 module->scriptFunctions.PushLast(realFunc);
1707 realFunc->AddRefInternal();
1708 dontTranslate.Insert(realFunc, true);
1709 break;
1710 }
1711 }
1712 if( !found )
1713 {
1714 asCString str;
1715 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1716 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1717 Error(TXT_INVALID_BYTECODE_d);
1718 }
1719 if( isNew )
1720 {
1721 // Destroy the function without releasing any references
1722 func->id = 0;
1723 func->scriptData->byteCode.SetLength(0);
1724 func->ReleaseInternal();
1725 }
1726 }
1727 else
1728 {
1729 ot->beh.constructors.PushLast(func->id);
1730 func->AddRefInternal();
1731
1732 if( func->parameterTypes.GetLength() == 0 )
1733 ot->beh.construct = func->id;
1734 }
1735 }
1736 else
1737 {
1738 Error(TXT_INVALID_BYTECODE_d);
1739 }
1740
1741 func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
1742 if( func )
1743 {
1744 if( sharedExists )
1745 {
1746 // Find the real function in the object, and update the savedFunctions array
1747 bool found = false;
1748 for( asUINT f = 0; f < ot->beh.factories.GetLength(); f++ )
1749 {
1750 asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]);
1751 if( realFunc->IsSignatureEqual(func) )
1752 {
1753 // If the function is not the last, then the substitution has already occurred before
1754 if( savedFunctions[savedFunctions.GetLength()-1] == func )
1755 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
1756 found = true;
1757 module->scriptFunctions.PushLast(realFunc);
1758 realFunc->AddRefInternal();
1759 dontTranslate.Insert(realFunc, true);
1760 break;
1761 }
1762 }
1763 if( !found )
1764 {
1765 asCString str;
1766 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1767 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1768 Error(TXT_INVALID_BYTECODE_d);
1769 }
1770 if( isNew )
1771 {
1772 // Destroy the function without releasing any references
1773 func->id = 0;
1774 func->scriptData->byteCode.SetLength(0);
1775 func->ReleaseInternal();
1776 }
1777 }
1778 else
1779 {
1780 ot->beh.factories.PushLast(func->id);
1781 func->AddRefInternal();
1782
1783 if( func->parameterTypes.GetLength() == 0 )
1784 ot->beh.factory = func->id;
1785 }
1786 }
1787 else
1788 {
1789 Error(TXT_INVALID_BYTECODE_d);
1790 }
1791 }
1792 }
1793
1794 // methods[]
1795 size = ReadEncodedUInt();
1796 int n;
1797 for( n = 0; n < size; n++ )
1798 {
1799 bool isNew;
1800 asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
1801 if( func )
1802 {
1803 if( sharedExists )
1804 {
1805 // Find the real function in the object, and update the savedFunctions array
1806 bool found = false;
1807 for( asUINT f = 0; f < ot->methods.GetLength(); f++ )
1808 {
1809 asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]);
1810 if( realFunc->IsSignatureEqual(func) )
1811 {
1812 // If the function is not the last, then the substitution has already occurred before
1813 if( savedFunctions[savedFunctions.GetLength()-1] == func )
1814 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
1815 found = true;
1816 module->scriptFunctions.PushLast(realFunc);
1817 realFunc->AddRefInternal();
1818 dontTranslate.Insert(realFunc, true);
1819 break;
1820 }
1821 }
1822 if( !found )
1823 {
1824 asCString str;
1825 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1826 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1827 Error(TXT_INVALID_BYTECODE_d);
1828 }
1829 if( isNew )
1830 {
1831 // Destroy the function without releasing any references
1832 if( func->id == func->signatureId )
1833 engine->signatureIds.RemoveValue(func);
1834 func->id = 0;
1835 if( func->scriptData )
1836 func->scriptData->byteCode.SetLength(0);
1837 func->ReleaseInternal();
1838 }
1839 }
1840 else
1841 {
1842 // If the method is the assignment operator we need to replace the default implementation
1843 if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 &&
1844 func->parameterTypes[0].GetTypeInfo() == func->objectType &&
1845 (func->inOutFlags[0] & asTM_INREF) )
1846 {
1847 engine->scriptFunctions[ot->beh.copy]->ReleaseInternal();
1848 ot->beh.copy = func->id;
1849 func->AddRefInternal();
1850 }
1851
1852 ot->methods.PushLast(func->id);
1853 func->AddRefInternal();
1854 }
1855 }
1856 else
1857 {
1858 Error(TXT_INVALID_BYTECODE_d);
1859 }
1860 }
1861
1862 // virtualFunctionTable[]
1863 size = ReadEncodedUInt();
1864 for( n = 0; n < size; n++ )
1865 {
1866 bool isNew;
1867 asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
1868 if( func )
1869 {
1870 if( sharedExists )
1871 {
1872 // Find the real function in the object, and update the savedFunctions array
1873 bool found = false;
1874 for( asUINT f = 0; f < ot->virtualFunctionTable.GetLength(); f++ )
1875 {
1876 asCScriptFunction *realFunc = ot->virtualFunctionTable[f];
1877 if( realFunc->IsSignatureEqual(func) )
1878 {
1879 // If the function is not the last, then the substitution has already occurred before
1880 if( savedFunctions[savedFunctions.GetLength()-1] == func )
1881 savedFunctions[savedFunctions.GetLength()-1] = realFunc;
1882 found = true;
1883 module->scriptFunctions.PushLast(realFunc);
1884 realFunc->AddRefInternal();
1885 dontTranslate.Insert(realFunc, true);
1886 break;
1887 }
1888 }
1889 if( !found )
1890 {
1891 asCString str;
1892 str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
1893 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1894 Error(TXT_INVALID_BYTECODE_d);
1895 }
1896 if( isNew )
1897 {
1898 // Destroy the function without releasing any references
1899 func->id = 0;
1900 if( func->scriptData )
1901 func->scriptData->byteCode.SetLength(0);
1902 func->ReleaseInternal();
1903 }
1904 }
1905 else
1906 {
1907 ot->virtualFunctionTable.PushLast(func);
1908 func->AddRefInternal();
1909 }
1910 }
1911 else
1912 {
1913 Error(TXT_INVALID_BYTECODE_d);
1914 }
1915 }
1916 }
1917 }
1918 else if( phase == 3 )
1919 {
1920 // external shared types doesn't store this
1921 if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0)
1922 return;
1923
1924 asCObjectType *ot = CastToObjectType(type);
1925
1926 // This is only done for object types
1927 asASSERT(ot);
1928
1929 // properties[]
1930 asUINT size = ReadEncodedUInt();
1931 for( asUINT n = 0; n < size; n++ )
1932 ReadObjectProperty(ot);
1933 }
1934 }
1935
ReadEncodedUInt16()1936 asWORD asCReader::ReadEncodedUInt16()
1937 {
1938 asDWORD dw = ReadEncodedUInt();
1939 if( (dw>>16) != 0 && (dw>>16) != 0xFFFF )
1940 {
1941 Error(TXT_INVALID_BYTECODE_d);
1942 }
1943
1944 return asWORD(dw & 0xFFFF);
1945 }
1946
ReadEncodedUInt()1947 asUINT asCReader::ReadEncodedUInt()
1948 {
1949 asQWORD qw = ReadEncodedUInt64();
1950 if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF )
1951 {
1952 Error(TXT_INVALID_BYTECODE_d);
1953 }
1954
1955 return asUINT(qw & 0xFFFFFFFFu);
1956 }
1957
ReadEncodedUInt64()1958 asQWORD asCReader::ReadEncodedUInt64()
1959 {
1960 asQWORD i = 0;
1961 asBYTE b;
1962 ReadData(&b, 1);
1963 bool isNegative = ( b & 0x80 ) ? true : false;
1964 b &= 0x7F;
1965
1966 if( (b & 0x7F) == 0x7F )
1967 {
1968 ReadData(&b, 1); i = asQWORD(b) << 56;
1969 ReadData(&b, 1); i += asQWORD(b) << 48;
1970 ReadData(&b, 1); i += asQWORD(b) << 40;
1971 ReadData(&b, 1); i += asQWORD(b) << 32;
1972 ReadData(&b, 1); i += asUINT(b) << 24;
1973 ReadData(&b, 1); i += asUINT(b) << 16;
1974 ReadData(&b, 1); i += asUINT(b) << 8;
1975 ReadData(&b, 1); i += b;
1976 }
1977 else if( (b & 0x7E) == 0x7E )
1978 {
1979 i = asQWORD(b & 0x01) << 48;
1980 ReadData(&b, 1); i += asQWORD(b) << 40;
1981 ReadData(&b, 1); i += asQWORD(b) << 32;
1982 ReadData(&b, 1); i += asUINT(b) << 24;
1983 ReadData(&b, 1); i += asUINT(b) << 16;
1984 ReadData(&b, 1); i += asUINT(b) << 8;
1985 ReadData(&b, 1); i += b;
1986 }
1987 else if( (b & 0x7C) == 0x7C )
1988 {
1989 i = asQWORD(b & 0x03) << 40;
1990 ReadData(&b, 1); i += asQWORD(b) << 32;
1991 ReadData(&b, 1); i += asUINT(b) << 24;
1992 ReadData(&b, 1); i += asUINT(b) << 16;
1993 ReadData(&b, 1); i += asUINT(b) << 8;
1994 ReadData(&b, 1); i += b;
1995 }
1996 else if( (b & 0x78) == 0x78 )
1997 {
1998 i = asQWORD(b & 0x07) << 32;
1999 ReadData(&b, 1); i += asUINT(b) << 24;
2000 ReadData(&b, 1); i += asUINT(b) << 16;
2001 ReadData(&b, 1); i += asUINT(b) << 8;
2002 ReadData(&b, 1); i += b;
2003 }
2004 else if( (b & 0x70) == 0x70 )
2005 {
2006 i = asUINT(b & 0x0F) << 24;
2007 ReadData(&b, 1); i += asUINT(b) << 16;
2008 ReadData(&b, 1); i += asUINT(b) << 8;
2009 ReadData(&b, 1); i += b;
2010 }
2011 else if( (b & 0x60) == 0x60 )
2012 {
2013 i = asUINT(b & 0x1F) << 16;
2014 ReadData(&b, 1); i += asUINT(b) << 8;
2015 ReadData(&b, 1); i += b;
2016 }
2017 else if( (b & 0x40) == 0x40 )
2018 {
2019 i = asUINT(b & 0x3F) << 8;
2020 ReadData(&b, 1); i += b;
2021 }
2022 else
2023 {
2024 i = b;
2025 }
2026 if( isNegative )
2027 i = (asQWORD)(-asINT64(i));
2028
2029 return i;
2030 }
2031
ReadString(asCString * str)2032 void asCReader::ReadString(asCString* str)
2033 {
2034 asUINT len = ReadEncodedUInt();
2035 if( len & 1 )
2036 {
2037 asUINT idx = len/2;
2038 if( idx < savedStrings.GetLength() )
2039 *str = savedStrings[idx];
2040 else
2041 Error(TXT_INVALID_BYTECODE_d);
2042 }
2043 else if( len > 0 )
2044 {
2045 len /= 2;
2046 str->SetLength(len);
2047 int r = stream->Read(str->AddressOf(), len);
2048 if (r < 0)
2049 Error(TXT_UNEXPECTED_END_OF_FILE);
2050
2051 savedStrings.PushLast(*str);
2052 }
2053 else
2054 str->SetLength(0);
2055 }
2056
ReadGlobalProperty()2057 void asCReader::ReadGlobalProperty()
2058 {
2059 asCString name;
2060 asCDataType type;
2061
2062 ReadString(&name);
2063
2064 asCString ns;
2065 ReadString(&ns);
2066 asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
2067
2068 ReadDataType(&type);
2069
2070 asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace);
2071
2072 // Read the initialization function
2073 bool isNew;
2074 // Do not add the function to the GC at this time. It will
2075 // only be added to the GC when the module releases the property
2076 asCScriptFunction *func = ReadFunction(isNew, false, true, false);
2077 if( func )
2078 {
2079 // Make sure the function knows it is owned by the module
2080 func->module = module;
2081
2082 prop->SetInitFunc(func);
2083 func->ReleaseInternal();
2084 }
2085 }
2086
ReadObjectProperty(asCObjectType * ot)2087 void asCReader::ReadObjectProperty(asCObjectType *ot)
2088 {
2089 asCString name;
2090 ReadString(&name);
2091 asCDataType dt;
2092 ReadDataType(&dt);
2093 int flags = ReadEncodedUInt();
2094 bool isPrivate = (flags & 1) ? true : false;
2095 bool isProtected = (flags & 2) ? true : false;
2096 bool isInherited = (flags & 4) ? true : false;
2097
2098 // TODO: shared: If the type is shared and pre-existing, we should just
2099 // validate that the loaded methods match the original
2100 if( !existingShared.MoveTo(0, ot) )
2101 ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited);
2102 }
2103
ReadDataType(asCDataType * dt)2104 void asCReader::ReadDataType(asCDataType *dt)
2105 {
2106 // Check if this is a previously used type
2107 asUINT idx = ReadEncodedUInt();
2108 if( idx != 0 )
2109 {
2110 // Get the datatype from the cache
2111 *dt = savedDataTypes[idx-1];
2112 return;
2113 }
2114
2115 // Read the type definition
2116 eTokenType tokenType = (eTokenType)ReadEncodedUInt();
2117
2118 // Reserve a spot in the savedDataTypes
2119 asUINT saveSlot = savedDataTypes.GetLength();
2120 savedDataTypes.PushLast(asCDataType());
2121
2122 // Read the datatype for the first time
2123 asCTypeInfo *ti = 0;
2124 if( tokenType == ttIdentifier )
2125 ti = ReadTypeInfo();
2126
2127 // Read type flags as a bitmask
2128 // Endian-safe code
2129 bool isObjectHandle, isHandleToConst, isReference, isReadOnly;
2130 char b = 0;
2131 ReadData(&b, 1);
2132 LOAD_FROM_BIT(isObjectHandle, b, 0);
2133 LOAD_FROM_BIT(isHandleToConst, b, 1);
2134 LOAD_FROM_BIT(isReference, b, 2);
2135 LOAD_FROM_BIT(isReadOnly, b, 3);
2136
2137 if( tokenType == ttIdentifier )
2138 *dt = asCDataType::CreateType(ti, false);
2139 else
2140 *dt = asCDataType::CreatePrimitive(tokenType, false);
2141 if( isObjectHandle )
2142 {
2143 dt->MakeReadOnly(isHandleToConst ? true : false);
2144
2145 // Here we must allow a scoped type to be a handle
2146 // e.g. if the datatype is for a system function
2147 dt->MakeHandle(true, true);
2148 }
2149 dt->MakeReadOnly(isReadOnly ? true : false);
2150 dt->MakeReference(isReference ? true : false);
2151
2152 // Update the previously saved slot
2153 savedDataTypes[saveSlot] = *dt;
2154 }
2155
ReadTypeInfo()2156 asCTypeInfo* asCReader::ReadTypeInfo()
2157 {
2158 asCTypeInfo *ot = 0;
2159 char ch;
2160 ReadData(&ch, 1);
2161 if( ch == 'a' )
2162 {
2163 // Read the name of the template type
2164 asCString typeName, ns;
2165 ReadString(&typeName);
2166 ReadString(&ns);
2167 asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
2168
2169 asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
2170 asCObjectType *tmpl = CastToObjectType(tmp);
2171 if( tmpl == 0 )
2172 {
2173 asCString str;
2174 str.Format(TXT_TEMPLATE_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
2175 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
2176 Error(TXT_INVALID_BYTECODE_d);
2177 return 0;
2178 }
2179
2180 asUINT numSubTypes = ReadEncodedUInt();
2181 asCArray<asCDataType> subTypes;
2182 for( asUINT n = 0; n < numSubTypes; n++ )
2183 {
2184 ReadData(&ch, 1);
2185 if( ch == 's' )
2186 {
2187 asCDataType dt;
2188 ReadDataType(&dt);
2189 subTypes.PushLast(dt);
2190 }
2191 else
2192 {
2193 eTokenType tokenType = (eTokenType)ReadEncodedUInt();
2194 asCDataType dt = asCDataType::CreatePrimitive(tokenType, false);
2195 subTypes.PushLast(dt);
2196 }
2197 }
2198
2199 // Return the actual template if the subtypes are the template's dummy types
2200 if( tmpl->templateSubTypes == subTypes )
2201 ot = tmpl;
2202 else
2203 {
2204 // Get the template instance type based on the loaded subtypes
2205 ot = engine->GetTemplateInstanceType(tmpl, subTypes, module);
2206 }
2207
2208 if( ot == 0 )
2209 {
2210 // Show all subtypes in error message
2211 asCString sub = subTypes[0].Format(nameSpace);
2212 for( asUINT n = 1; n < subTypes.GetLength(); n++ )
2213 {
2214 sub += ",";
2215 sub += subTypes[n].Format(nameSpace);
2216 }
2217 asCString str;
2218 str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, typeName.AddressOf(), sub.AddressOf());
2219 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
2220 Error(TXT_INVALID_BYTECODE_d);
2221 return 0;
2222 }
2223 }
2224 else if( ch == 'l' )
2225 {
2226 asCObjectType *st = CastToObjectType(ReadTypeInfo());
2227 if( st == 0 || st->beh.listFactory == 0 )
2228 {
2229 Error(TXT_INVALID_BYTECODE_d);
2230 return 0;
2231 }
2232 ot = engine->GetListPatternType(st->beh.listFactory);
2233 }
2234 else if( ch == 's' )
2235 {
2236 // Read the name of the template subtype
2237 asCString typeName;
2238 ReadString(&typeName);
2239
2240 // Find the template subtype
2241 ot = 0;
2242 for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ )
2243 {
2244 if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName )
2245 {
2246 ot = engine->templateSubTypes[n];
2247 break;
2248 }
2249 }
2250
2251 if( ot == 0 )
2252 {
2253 asCString str;
2254 str.Format(TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST, typeName.AddressOf());
2255 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
2256 Error(TXT_INVALID_BYTECODE_d);
2257 return 0;
2258 }
2259 }
2260 else if( ch == 'o' )
2261 {
2262 // Read the object type name
2263 asCString typeName, ns;
2264 ReadString(&typeName);
2265 ReadString(&ns);
2266 asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
2267
2268 if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" )
2269 {
2270 // Find the object type
2271 ot = module->GetType(typeName.AddressOf(), nameSpace);
2272 if (!ot)
2273 ot = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
2274
2275 if( ot == 0 )
2276 {
2277 asCString str;
2278 str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
2279 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
2280 Error(TXT_INVALID_BYTECODE_d);
2281 return 0;
2282 }
2283 }
2284 else if( typeName == "$obj" )
2285 {
2286 ot = &engine->scriptTypeBehaviours;
2287 }
2288 else if( typeName == "$func" )
2289 {
2290 ot = &engine->functionBehaviours;
2291 }
2292 else
2293 asASSERT( false );
2294 }
2295 else if (ch == 'c')
2296 {
2297 // Read the object type name
2298 asCString typeName, ns;
2299 ReadString(&typeName);
2300
2301 // Read the parent class
2302 asCObjectType *parentClass = CastToObjectType(ReadTypeInfo());
2303 if (parentClass == 0)
2304 {
2305 Error(TXT_INVALID_BYTECODE_d);
2306 return 0;
2307 }
2308
2309 // Find the child type in the parentClass
2310 for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++)
2311 {
2312 if (parentClass->childFuncDefs[n]->name == typeName)
2313 ot = parentClass->childFuncDefs[n];
2314 }
2315
2316 if (ot == 0)
2317 {
2318 asCString str;
2319 str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
2320 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
2321 Error(TXT_INVALID_BYTECODE_d);
2322 return 0;
2323 }
2324 }
2325 else
2326 {
2327 // No object type
2328 asASSERT( ch == '\0' || error );
2329 ot = 0;
2330 }
2331
2332 return ot;
2333 }
2334
ReadByteCode(asCScriptFunction * func)2335 void asCReader::ReadByteCode(asCScriptFunction *func)
2336 {
2337 asASSERT( func->scriptData );
2338
2339 // Read number of instructions
2340 asUINT total, numInstructions;
2341 total = numInstructions = ReadEncodedUInt();
2342
2343 // Reserve some space for the instructions
2344 func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false);
2345
2346 asUINT pos = 0;
2347 while( numInstructions )
2348 {
2349 asBYTE b;
2350 ReadData(&b, 1);
2351
2352 // Allocate the space for the instruction
2353 asUINT len = asBCTypeSize[asBCInfo[b].type];
2354 asUINT newSize = asUINT(func->scriptData->byteCode.GetLength()) + len;
2355 if( func->scriptData->byteCode.GetCapacity() < newSize )
2356 {
2357 // Determine the average size of the loaded instructions and re-estimate the final size
2358 asUINT size = asUINT(float(newSize) / (total - numInstructions) * total) + 1;
2359 func->scriptData->byteCode.AllocateNoConstruct(size, true);
2360 }
2361 if( !func->scriptData->byteCode.SetLengthNoConstruct(newSize) )
2362 {
2363 // Out of memory
2364 error = true;
2365 return;
2366 }
2367
2368 asDWORD *bc = func->scriptData->byteCode.AddressOf() + pos;
2369 pos += len;
2370
2371 switch( asBCInfo[b].type )
2372 {
2373 case asBCTYPE_NO_ARG:
2374 {
2375 *(asBYTE*)(bc) = b;
2376 bc++;
2377 }
2378 break;
2379 case asBCTYPE_W_ARG:
2380 case asBCTYPE_wW_ARG:
2381 case asBCTYPE_rW_ARG:
2382 {
2383 *(asBYTE*)(bc) = b;
2384
2385 // Read the argument
2386 asWORD w = ReadEncodedUInt16();
2387 *(((asWORD*)bc)+1) = w;
2388
2389 bc++;
2390 }
2391 break;
2392 case asBCTYPE_rW_DW_ARG:
2393 case asBCTYPE_wW_DW_ARG:
2394 case asBCTYPE_W_DW_ARG:
2395 {
2396 *(asBYTE*)(bc) = b;
2397
2398 // Read the word argument
2399 asWORD w = ReadEncodedUInt16();
2400 *(((asWORD*)bc)+1) = w;
2401 bc++;
2402
2403 // Read the dword argument
2404 *bc++ = ReadEncodedUInt();
2405 }
2406 break;
2407 case asBCTYPE_DW_ARG:
2408 {
2409 *(asBYTE*)(bc) = b;
2410 bc++;
2411
2412 // Read the argument
2413 *bc++ = ReadEncodedUInt();
2414 }
2415 break;
2416 case asBCTYPE_DW_DW_ARG:
2417 {
2418 *(asBYTE*)(bc) = b;
2419 bc++;
2420
2421 // Read the first argument
2422 *bc++ = ReadEncodedUInt();
2423
2424 // Read the second argument
2425 *bc++ = ReadEncodedUInt();
2426 }
2427 break;
2428 case asBCTYPE_wW_rW_rW_ARG:
2429 {
2430 *(asBYTE*)(bc) = b;
2431
2432 // Read the first argument
2433 asWORD w = ReadEncodedUInt16();
2434 *(((asWORD*)bc)+1) = w;
2435 bc++;
2436
2437 // Read the second argument
2438 w = ReadEncodedUInt16();
2439 *(asWORD*)bc = w;
2440
2441 // Read the third argument
2442 w = ReadEncodedUInt16();
2443 *(((asWORD*)bc)+1) = w;
2444
2445 bc++;
2446 }
2447 break;
2448 case asBCTYPE_wW_rW_ARG:
2449 case asBCTYPE_rW_rW_ARG:
2450 case asBCTYPE_wW_W_ARG:
2451 {
2452 *(asBYTE*)(bc) = b;
2453
2454 // Read the first argument
2455 asWORD w = ReadEncodedUInt16();
2456 *(((asWORD*)bc)+1) = w;
2457 bc++;
2458
2459 // Read the second argument
2460 w = ReadEncodedUInt16();
2461 *(asWORD*)bc = w;
2462
2463 bc++;
2464 }
2465 break;
2466 case asBCTYPE_wW_rW_DW_ARG:
2467 case asBCTYPE_rW_W_DW_ARG:
2468 {
2469 *(asBYTE*)(bc) = b;
2470
2471 // Read the first argument
2472 asWORD w = ReadEncodedUInt16();
2473 *(((asWORD*)bc)+1) = w;
2474 bc++;
2475
2476 // Read the second argument
2477 w = ReadEncodedUInt16();
2478 *(asWORD*)bc = w;
2479 bc++;
2480
2481 // Read the third argument
2482 asDWORD dw = ReadEncodedUInt();
2483 *bc++ = dw;
2484 }
2485 break;
2486 case asBCTYPE_QW_ARG:
2487 {
2488 *(asBYTE*)(bc) = b;
2489 bc++;
2490
2491 // Read the argument
2492 asQWORD qw = ReadEncodedUInt64();
2493 *(asQWORD*)bc = qw;
2494 bc += 2;
2495 }
2496 break;
2497 case asBCTYPE_QW_DW_ARG:
2498 {
2499 *(asBYTE*)(bc) = b;
2500 bc++;
2501
2502 // Read the first argument
2503 asQWORD qw = ReadEncodedUInt64();
2504 *(asQWORD*)bc = qw;
2505 bc += 2;
2506
2507 // Read the second argument
2508 asDWORD dw = ReadEncodedUInt();
2509 *bc++ = dw;
2510 }
2511 break;
2512 case asBCTYPE_rW_QW_ARG:
2513 case asBCTYPE_wW_QW_ARG:
2514 {
2515 *(asBYTE*)(bc) = b;
2516
2517 // Read the first argument
2518 asWORD w = ReadEncodedUInt16();
2519 *(((asWORD*)bc)+1) = w;
2520 bc++;
2521
2522 // Read the argument
2523 asQWORD qw = ReadEncodedUInt64();
2524 *(asQWORD*)bc = qw;
2525 bc += 2;
2526 }
2527 break;
2528 case asBCTYPE_rW_DW_DW_ARG:
2529 {
2530 *(asBYTE*)(bc) = b;
2531
2532 // Read the 1st argument
2533 asWORD w = ReadEncodedUInt16();
2534 *(((asWORD*)bc)+1) = w;
2535 bc++;
2536
2537 // Read the 2nd argument
2538 *bc++ = ReadEncodedUInt();
2539
2540 // Read the 3rd argument
2541 *bc++ = ReadEncodedUInt();
2542 }
2543 break;
2544 default:
2545 {
2546 // This should never happen
2547 asASSERT(false);
2548
2549 // Read the next 3 bytes
2550 asDWORD c; asBYTE t;
2551 #if defined(AS_BIG_ENDIAN)
2552 c = b << 24;
2553 ReadData(&t, 1); c += t << 16;
2554 ReadData(&t, 1); c += t << 8;
2555 ReadData(&t, 1); c += t;
2556 #else
2557 c = b;
2558 ReadData(&t, 1); c += t << 8;
2559 ReadData(&t, 1); c += t << 16;
2560 ReadData(&t, 1); c += t << 24;
2561 #endif
2562
2563 *bc++ = c;
2564 c = *(asBYTE*)&c;
2565
2566 // Read the bc as is
2567 for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ )
2568 ReadData(&*bc++, 4);
2569 }
2570 }
2571
2572 numInstructions--;
2573 }
2574
2575 // Correct the final size in case we over-estimated it
2576 func->scriptData->byteCode.SetLengthNoConstruct(pos);
2577 }
2578
ReadUsedTypeIds()2579 void asCReader::ReadUsedTypeIds()
2580 {
2581 TimeIt("asCReader::ReadUsedTypeIds");
2582
2583 asUINT count = ReadEncodedUInt();
2584 usedTypeIds.Allocate(count, false);
2585 for( asUINT n = 0; n < count; n++ )
2586 {
2587 asCDataType dt;
2588 ReadDataType(&dt);
2589 usedTypeIds.PushLast(engine->GetTypeIdFromDataType(dt));
2590 }
2591 }
2592
ReadUsedGlobalProps()2593 void asCReader::ReadUsedGlobalProps()
2594 {
2595 TimeIt("asCReader::ReadUsedGlobalProps");
2596
2597 int c = ReadEncodedUInt();
2598
2599 usedGlobalProperties.Allocate(c, false);
2600
2601 for( int n = 0; n < c; n++ )
2602 {
2603 asCString name, ns;
2604 asCDataType type;
2605 char moduleProp;
2606
2607 ReadString(&name);
2608 ReadString(&ns);
2609 ReadDataType(&type);
2610 ReadData(&moduleProp, 1);
2611
2612 asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
2613
2614 // Find the real property
2615 asCGlobalProperty *globProp = 0;
2616 if( moduleProp )
2617 globProp = module->scriptGlobals.GetFirst(nameSpace, name);
2618 else
2619 globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name);
2620
2621 void *prop = 0;
2622 if( globProp && globProp->type == type )
2623 prop = globProp->GetAddressOfValue();
2624
2625 usedGlobalProperties.PushLast(prop);
2626
2627 if( prop == 0 )
2628 {
2629 Error(TXT_INVALID_BYTECODE_d);
2630 }
2631 }
2632 }
2633
ReadUsedObjectProps()2634 void asCReader::ReadUsedObjectProps()
2635 {
2636 TimeIt("asCReader::ReadUsedObjectProps");
2637
2638 asUINT c = ReadEncodedUInt();
2639
2640 usedObjectProperties.SetLength(c);
2641 for( asUINT n = 0; n < c; n++ )
2642 {
2643 asCObjectType *objType = CastToObjectType(ReadTypeInfo());
2644 if( objType == 0 )
2645 {
2646 Error(TXT_INVALID_BYTECODE_d);
2647 break;
2648 }
2649
2650 asCString name;
2651 ReadString(&name);
2652
2653 // Find the property
2654 bool found = false;
2655 for( asUINT p = 0; p < objType->properties.GetLength(); p++ )
2656 {
2657 if( objType->properties[p]->name == name )
2658 {
2659 usedObjectProperties[n].objType = objType;
2660 usedObjectProperties[n].prop = objType->properties[p];
2661 found = true;
2662 break;
2663 }
2664 }
2665
2666 if( !found )
2667 {
2668 Error(TXT_INVALID_BYTECODE_d);
2669 return;
2670 }
2671 }
2672 }
2673
FindObjectPropOffset(asWORD index)2674 short asCReader::FindObjectPropOffset(asWORD index)
2675 {
2676 static asCObjectProperty *lastCompositeProp = 0;
2677 if (lastCompositeProp)
2678 {
2679 if (index != 0)
2680 {
2681 Error(TXT_INVALID_BYTECODE_d);
2682 return 0;
2683 }
2684
2685 short offset = (short)lastCompositeProp->byteOffset;
2686 lastCompositeProp = 0;
2687 return offset;
2688 }
2689
2690 if( index >= usedObjectProperties.GetLength() )
2691 {
2692 Error(TXT_INVALID_BYTECODE_d);
2693 return 0;
2694 }
2695
2696 if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect)
2697 {
2698 lastCompositeProp = usedObjectProperties[index].prop;
2699 return (short)lastCompositeProp->compositeOffset;
2700 }
2701 return (short)usedObjectProperties[index].prop->byteOffset;
2702 }
2703
FindFunction(int idx)2704 asCScriptFunction *asCReader::FindFunction(int idx)
2705 {
2706 if( idx >= 0 && idx < (int)usedFunctions.GetLength() )
2707 return usedFunctions[idx];
2708 else
2709 {
2710 Error(TXT_INVALID_BYTECODE_d);
2711 return 0;
2712 }
2713 }
2714
TranslateFunction(asCScriptFunction * func)2715 void asCReader::TranslateFunction(asCScriptFunction *func)
2716 {
2717 // Skip this if the function is part of an pre-existing shared object
2718 if( dontTranslate.MoveTo(0, func) ) return;
2719
2720 asASSERT( func->scriptData );
2721
2722 // Pre-compute the size of each instruction in order to translate jump offsets
2723 asUINT n;
2724 asDWORD *bc = func->scriptData->byteCode.AddressOf();
2725 asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
2726 asCArray<asUINT> bcSizes(bcLength);
2727 asCArray<asUINT> instructionNbrToPos(bcLength);
2728 for( n = 0; n < bcLength; )
2729 {
2730 int c = *(asBYTE*)&bc[n];
2731 asUINT size = asBCTypeSize[asBCInfo[c].type];
2732 if( size == 0 )
2733 {
2734 Error(TXT_INVALID_BYTECODE_d);
2735 return;
2736 }
2737 bcSizes.PushLast(size);
2738 instructionNbrToPos.PushLast(n);
2739 n += size;
2740 }
2741
2742 asUINT bcNum = 0;
2743 for( n = 0; n < bcLength; bcNum++ )
2744 {
2745 int c = *(asBYTE*)&bc[n];
2746 if( c == asBC_REFCPY ||
2747 c == asBC_RefCpyV ||
2748 c == asBC_OBJTYPE )
2749 {
2750 // Translate the index to the true object type
2751 asPWORD *ot = (asPWORD*)&bc[n+1];
2752 *(asCObjectType**)ot = CastToObjectType(FindType(int(*ot)));
2753 }
2754 else if( c == asBC_TYPEID ||
2755 c == asBC_Cast )
2756 {
2757 // Translate the index to the type id
2758 int *tid = (int*)&bc[n+1];
2759 *tid = FindTypeId(*tid);
2760 }
2761 else if( c == asBC_ADDSi ||
2762 c == asBC_LoadThisR )
2763 {
2764 // Translate the index to the type id
2765 int *tid = (int*)&bc[n+1];
2766 *tid = FindTypeId(*tid);
2767
2768 // Translate the prop index into the property offset
2769 *(((short*)&bc[n])+1) = FindObjectPropOffset(*(((short*)&bc[n])+1));
2770 }
2771 else if( c == asBC_LoadRObjR ||
2772 c == asBC_LoadVObjR )
2773 {
2774 // Translate the index to the type id
2775 int *tid = (int*)&bc[n+2];
2776 *tid = FindTypeId(*tid);
2777
2778 asCObjectType *ot = engine->GetObjectTypeFromTypeId(*tid);
2779 if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
2780 {
2781 // List patterns have a different way of adjusting the offsets
2782 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
2783 *(((short*)&bc[n])+2) = (short)listAdj->AdjustOffset(*(((short*)&bc[n])+2));
2784 }
2785 else
2786 {
2787 // Translate the prop index into the property offset
2788 *(((short*)&bc[n])+2) = FindObjectPropOffset(*(((short*)&bc[n])+2));
2789 }
2790 }
2791 else if( c == asBC_COPY )
2792 {
2793 // Translate the index to the type id
2794 int *tid = (int*)&bc[n+1];
2795 *tid = FindTypeId(*tid);
2796
2797 // COPY is used to copy POD types that don't have the opAssign method. It is
2798 // also used to copy references to scoped types during variable initializations.
2799 // Update the number of dwords to copy as it may be different on the target platform
2800 if( (*tid) & asTYPEID_OBJHANDLE )
2801 {
2802 // It is the actual reference that is being copied, not the object itself
2803 asBC_SWORDARG0(&bc[n]) = AS_PTR_SIZE;
2804 }
2805 else
2806 {
2807 asCDataType dt = engine->GetDataTypeFromTypeId(*tid);
2808 if( !dt.IsValid() )
2809 {
2810 Error(TXT_INVALID_BYTECODE_d);
2811 }
2812 else
2813 asBC_SWORDARG0(&bc[n]) = (short)dt.GetSizeInMemoryDWords();
2814 }
2815 }
2816 else if( c == asBC_RET )
2817 {
2818 // Determine the correct amount of DWORDs to pop
2819 asWORD dw = (asWORD)func->GetSpaceNeededForArguments();
2820 if( func->DoesReturnOnStack() ) dw += AS_PTR_SIZE;
2821 if( func->objectType ) dw += AS_PTR_SIZE;
2822 asBC_WORDARG0(&bc[n]) = dw;
2823 }
2824 else if( c == asBC_CALL ||
2825 c == asBC_CALLINTF ||
2826 c == asBC_CALLSYS ||
2827 c == asBC_Thiscall1 )
2828 {
2829 // Translate the index to the func id
2830 int *fid = (int*)&bc[n+1];
2831 asCScriptFunction *f = FindFunction(*fid);
2832 if( f )
2833 *fid = f->id;
2834 else
2835 {
2836 Error(TXT_INVALID_BYTECODE_d);
2837 return;
2838 }
2839 }
2840 else if( c == asBC_FuncPtr )
2841 {
2842 // Translate the index to the func pointer
2843 asPWORD *fid = (asPWORD*)&bc[n+1];
2844 *fid = (asPWORD)FindFunction(int(*fid));
2845 }
2846 else if( c == asBC_ALLOC )
2847 {
2848 // Translate the index to the true object type
2849 asPWORD *arg = (asPWORD*)&bc[n+1];
2850 *(asCObjectType**)arg = CastToObjectType(FindType(int(*arg)));
2851
2852 // The constructor function id must be translated, unless it is zero
2853 int *fid = (int*)&bc[n+1+AS_PTR_SIZE];
2854 if( *fid != 0 )
2855 {
2856 // Subtract 1 from the id, as it was incremented during the writing
2857 asCScriptFunction *f = FindFunction(*fid-1);
2858 if( f )
2859 *fid = f->id;
2860 else
2861 {
2862 Error(TXT_INVALID_BYTECODE_d);
2863 return;
2864 }
2865 }
2866 }
2867 else if( c == asBC_STR )
2868 {
2869 Error(TXT_INVALID_BYTECODE_d);
2870 return;
2871 }
2872 else if( c == asBC_CALLBND )
2873 {
2874 // Translate the function id
2875 asUINT *fid = (asUINT*)&bc[n+1];
2876 if( *fid < module->bindInformations.GetLength() )
2877 {
2878 sBindInfo *bi = module->bindInformations[*fid];
2879 if( bi )
2880 *fid = bi->importedFunctionSignature->id;
2881 else
2882 {
2883 Error(TXT_INVALID_BYTECODE_d);
2884 return;
2885 }
2886 }
2887 else
2888 {
2889 Error(TXT_INVALID_BYTECODE_d);
2890 return;
2891 }
2892 }
2893 else if( c == asBC_PGA ||
2894 c == asBC_PshGPtr ||
2895 c == asBC_LDG ||
2896 c == asBC_PshG4 ||
2897 c == asBC_LdGRdR4 ||
2898 c == asBC_CpyGtoV4 ||
2899 c == asBC_CpyVtoG4 ||
2900 c == asBC_SetG4 )
2901 {
2902 // Translate the index to pointer
2903 asPWORD *index = (asPWORD*)&bc[n + 1];
2904 if ((*index & 1))
2905 {
2906 if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength())
2907 *(void**)index = usedGlobalProperties[asUINT(*index)>>1];
2908 else
2909 {
2910 Error(TXT_INVALID_BYTECODE_d);
2911 return;
2912 }
2913 }
2914 else
2915 {
2916 // Only PGA and PshGPtr can hold string constants
2917 asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
2918
2919 if ((asUINT(*index)>>1) < usedStringConstants.GetLength())
2920 *(void**)index = usedStringConstants[asUINT(*index)>>1];
2921 else
2922 {
2923 Error(TXT_INVALID_BYTECODE_d);
2924 return;
2925 }
2926 }
2927 }
2928 else if( c == asBC_JMP ||
2929 c == asBC_JZ ||
2930 c == asBC_JNZ ||
2931 c == asBC_JLowZ ||
2932 c == asBC_JLowNZ ||
2933 c == asBC_JS ||
2934 c == asBC_JNS ||
2935 c == asBC_JP ||
2936 c == asBC_JNP ) // The JMPP instruction doesn't need modification
2937 {
2938 // Get the offset
2939 int offset = int(bc[n+1]);
2940
2941 // Count the instruction sizes to the destination instruction
2942 int size = 0;
2943 if( offset >= 0 )
2944 // If moving ahead, then start from next instruction
2945 for( asUINT num = bcNum+1; offset-- > 0; num++ )
2946 size += bcSizes[num];
2947 else
2948 // If moving backwards, then start at current instruction
2949 for( asUINT num = bcNum; offset++ < 0; num-- )
2950 size -= bcSizes[num];
2951
2952 // The size is dword offset
2953 bc[n+1] = size;
2954 }
2955 else if( c == asBC_AllocMem )
2956 {
2957 // The size of the allocated memory is only known after all the elements has been seen.
2958 // This helper class will collect this information and adjust the size when the
2959 // corresponding asBC_FREE is encountered
2960
2961 // The adjuster also needs to know the list type so it can know the type of the elements
2962 asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n])));
2963 listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot));
2964 }
2965 else if( c == asBC_FREE )
2966 {
2967 // Translate the index to the true object type
2968 asPWORD *pot = (asPWORD*)&bc[n+1];
2969 *(asCObjectType**)pot = CastToObjectType(FindType(int(*pot)));
2970
2971 asCObjectType *ot = *(asCObjectType**)pot;
2972 if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
2973 {
2974 if( listAdjusters.GetLength() == 0 )
2975 {
2976 Error(TXT_INVALID_BYTECODE_d);
2977 return;
2978 }
2979
2980 // Finalize the adjustment of the list buffer that was initiated with asBC_AllocMem
2981 SListAdjuster *list = listAdjusters.PopLast();
2982 list->AdjustAllocMem();
2983 asDELETE(list, SListAdjuster);
2984 }
2985 }
2986 else if( c == asBC_SetListSize )
2987 {
2988 // Adjust the offset in the list where the size is informed
2989 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
2990 bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
2991
2992 // Inform the list adjuster how many values will be repeated
2993 listAdj->SetRepeatCount(bc[n+2]);
2994 }
2995 else if( c == asBC_PshListElmnt )
2996 {
2997 // Adjust the offset in the list where the size is informed
2998 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
2999 bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
3000 }
3001 else if( c == asBC_SetListType )
3002 {
3003 // Adjust the offset in the list where the typeid is informed
3004 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
3005 bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
3006
3007 // Translate the type id
3008 bc[n+2] = FindTypeId(bc[n+2]);
3009
3010 // Inform the list adjuster the type id of the next element
3011 listAdj->SetNextType(bc[n+2]);
3012 }
3013
3014 n += asBCTypeSize[asBCInfo[c].type];
3015 }
3016
3017 // Calculate the stack adjustments
3018 CalculateAdjustmentByPos(func);
3019
3020 // Adjust all variable positions in the bytecode
3021 bc = func->scriptData->byteCode.AddressOf();
3022 for( n = 0; n < bcLength; )
3023 {
3024 int c = *(asBYTE*)&bc[n];
3025 switch( asBCInfo[c].type )
3026 {
3027 case asBCTYPE_wW_ARG:
3028 case asBCTYPE_rW_DW_ARG:
3029 case asBCTYPE_wW_QW_ARG:
3030 case asBCTYPE_rW_ARG:
3031 case asBCTYPE_wW_DW_ARG:
3032 case asBCTYPE_wW_W_ARG:
3033 case asBCTYPE_rW_QW_ARG:
3034 case asBCTYPE_rW_W_DW_ARG:
3035 case asBCTYPE_rW_DW_DW_ARG:
3036 {
3037 asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
3038 }
3039 break;
3040
3041 case asBCTYPE_wW_rW_ARG:
3042 case asBCTYPE_wW_rW_DW_ARG:
3043 case asBCTYPE_rW_rW_ARG:
3044 {
3045 asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
3046 asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
3047 }
3048 break;
3049
3050 case asBCTYPE_wW_rW_rW_ARG:
3051 {
3052 asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
3053 asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
3054 asBC_SWORDARG2(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG2(&bc[n]));
3055 }
3056 break;
3057
3058 default:
3059 // The other types don't treat variables so won't be modified
3060 break;
3061 }
3062
3063 n += asBCTypeSize[asBCInfo[c].type];
3064 }
3065
3066 // Adjust the space needed for local variables
3067 func->scriptData->variableSpace = AdjustStackPosition(func->scriptData->variableSpace);
3068
3069 // Adjust the variable information. This will be used during the adjustment below
3070 for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
3071 {
3072 func->scriptData->variables[n]->declaredAtProgramPos = instructionNbrToPos[func->scriptData->variables[n]->declaredAtProgramPos];
3073 func->scriptData->variables[n]->stackOffset = AdjustStackPosition(func->scriptData->variables[n]->stackOffset);
3074 }
3075
3076 // objVariablePos
3077 for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
3078 func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]);
3079
3080 // Adjust the get offsets. This must be done in the second iteration because
3081 // it relies on the function ids and variable position already being correct in the
3082 // bytecodes that come after the GET instructions.
3083 // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions
3084 // on a stack, and then when a call instruction is found update all of them.
3085 // This will also make the AdjustGetOffset() function quicker as it can
3086 // receive the called function directly instead of having to search for it.
3087 bc = func->scriptData->byteCode.AddressOf();
3088 for( n = 0; n < bcLength; )
3089 {
3090 int c = *(asBYTE*)&bc[n];
3091
3092 if( c == asBC_GETREF ||
3093 c == asBC_GETOBJ ||
3094 c == asBC_GETOBJREF ||
3095 c == asBC_ChkNullS )
3096 {
3097 asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n);
3098 }
3099
3100 n += asBCTypeSize[asBCInfo[c].type];
3101 }
3102
3103 for( n = 0; n < func->scriptData->objVariableInfo.GetLength(); n++ )
3104 {
3105 // The program position must be adjusted as it is stored in number of instructions
3106 func->scriptData->objVariableInfo[n].programPos = instructionNbrToPos[func->scriptData->objVariableInfo[n].programPos];
3107 func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset);
3108 }
3109
3110 for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
3111 {
3112 func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos];
3113 func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos];
3114 }
3115
3116 // The program position (every even number) needs to be adjusted
3117 // for the line numbers to be in number of dwords instead of number of instructions
3118 for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 )
3119 func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]];
3120 for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 )
3121 func->scriptData->sectionIdxs[n] = instructionNbrToPos[func->scriptData->sectionIdxs[n]];
3122
3123 CalculateStackNeeded(func);
3124 }
3125
SListAdjuster(asCReader * rd,asDWORD * bc,asCObjectType * listType)3126 asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) :
3127 reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
3128 {
3129 asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) );
3130
3131 // Find the first expected value in the list
3132 asSListPatternNode *node = patternType->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
3133 asASSERT( node && node->type == asLPT_START );
3134 patternNode = node->next;
3135 }
3136
AdjustOffset(int offset)3137 int asCReader::SListAdjuster::AdjustOffset(int offset)
3138 {
3139 if( offset < lastOffset )
3140 {
3141 reader->Error(TXT_INVALID_BYTECODE_d);
3142 return 0;
3143 }
3144
3145 // If it is the same offset being accessed again, just return the same adjusted value
3146 if( lastOffset == offset )
3147 return lastAdjustedOffset;
3148
3149 lastOffset = offset;
3150 lastAdjustedOffset = maxOffset;
3151
3152 // What is being expected at this position?
3153 if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
3154 {
3155 // Align the offset to 4 bytes boundary
3156 if( maxOffset & 0x3 )
3157 {
3158 maxOffset += 4 - (maxOffset & 0x3);
3159 lastAdjustedOffset = maxOffset;
3160 }
3161
3162 // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
3163 maxOffset += 4;
3164 nextOffset = offset+1;
3165 return lastAdjustedOffset;
3166 }
3167 else if( patternNode->type == asLPT_TYPE )
3168 {
3169 const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
3170 if( dt.GetTokenType() == ttQuestion )
3171 {
3172 if( nextTypeId != -1 )
3173 {
3174 if( repeatCount > 0 )
3175 repeatCount--;
3176
3177 asCDataType nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId);
3178 asUINT size;
3179 if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) )
3180 size = AS_PTR_SIZE*4;
3181 else
3182 size = nextdt.GetSizeInMemoryBytes();
3183
3184 // Align the offset to 4 bytes boundary
3185 if( size >= 4 && (maxOffset & 0x3) )
3186 {
3187 maxOffset += 4 - (maxOffset & 0x3);
3188 lastAdjustedOffset = maxOffset;
3189 }
3190
3191 // Only move the patternNode if we're not expecting any more repeated entries
3192 if( repeatCount == 0 )
3193 patternNode = patternNode->next;
3194
3195 nextTypeId = -1;
3196
3197 maxOffset += size;
3198 nextOffset = offset+1;
3199 return lastAdjustedOffset;
3200 }
3201 else
3202 {
3203 // Align the offset to 4 bytes boundary
3204 if( maxOffset & 0x3 )
3205 {
3206 maxOffset += 4 - (maxOffset & 0x3);
3207 lastAdjustedOffset = maxOffset;
3208 }
3209
3210 // The first adjustment is for the typeId
3211 maxOffset += 4;
3212 nextOffset = offset+1;
3213 return lastAdjustedOffset;
3214 }
3215 }
3216 else
3217 {
3218 // Determine the size of the element
3219 asUINT size;
3220 if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
3221 size = AS_PTR_SIZE*4;
3222 else
3223 size = dt.GetSizeInMemoryBytes();
3224
3225 // If values are skipped, the offset needs to be incremented
3226 while( nextOffset <= offset )
3227 {
3228 if( repeatCount > 0 )
3229 repeatCount--;
3230
3231 // Align the offset to 4 bytes boundary
3232 if( size >= 4 && (maxOffset & 0x3) )
3233 maxOffset += 4 - (maxOffset & 0x3);
3234
3235 lastAdjustedOffset = maxOffset;
3236 nextOffset += 1;
3237 maxOffset += size;
3238 }
3239
3240 // Only move the patternNode if we're not expecting any more repeated entries
3241 if( repeatCount == 0 )
3242 patternNode = patternNode->next;
3243
3244 nextOffset = offset+1;
3245 return lastAdjustedOffset;
3246 }
3247 }
3248 else if( patternNode->type == asLPT_START )
3249 {
3250 if( repeatCount > 0 )
3251 repeatCount--;
3252 SInfo info = {repeatCount, patternNode};
3253 stack.PushLast(info);
3254
3255 repeatCount = 0;
3256 patternNode = patternNode->next;
3257
3258 lastOffset--;
3259 return AdjustOffset(offset);
3260 }
3261 else if( patternNode->type == asLPT_END )
3262 {
3263 if( stack.GetLength() == 0 )
3264 {
3265 reader->Error(TXT_INVALID_BYTECODE_d);
3266 return 0;
3267 }
3268
3269 SInfo info = stack.PopLast();
3270 repeatCount = info.repeatCount;
3271 if( repeatCount )
3272 patternNode = info.startNode;
3273 else
3274 patternNode = patternNode->next;
3275
3276 lastOffset--;
3277 return AdjustOffset(offset);
3278 }
3279 else
3280 {
3281 // Something is wrong with the pattern list declaration
3282 reader->Error(TXT_INVALID_BYTECODE_d);
3283 return 0;
3284 }
3285
3286 UNREACHABLE_RETURN;
3287 }
3288
SetRepeatCount(asUINT rc)3289 void asCReader::SListAdjuster::SetRepeatCount(asUINT rc)
3290 {
3291 // Make sure the list is expecting a repeat at this location
3292 asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
3293
3294 // Now move to the next patternNode
3295 patternNode = patternNode->next;
3296
3297 repeatCount = rc;
3298 }
3299
AdjustAllocMem()3300 void asCReader::SListAdjuster::AdjustAllocMem()
3301 {
3302 allocMemBC[1] = maxOffset;
3303 }
3304
SetNextType(int typeId)3305 void asCReader::SListAdjuster::SetNextType(int typeId)
3306 {
3307 asASSERT( nextTypeId == -1 );
3308
3309 nextTypeId = typeId;
3310 }
3311
CalculateStackNeeded(asCScriptFunction * func)3312 void asCReader::CalculateStackNeeded(asCScriptFunction *func)
3313 {
3314 asASSERT( func->scriptData );
3315
3316 int largestStackUsed = 0;
3317
3318 // Clear the known stack size for each bytecode
3319 asCArray<int> stackSize;
3320 stackSize.SetLength(func->scriptData->byteCode.GetLength());
3321 memset(&stackSize[0], -1, stackSize.GetLength()*4);
3322
3323 // Add the first instruction to the list of unchecked code
3324 // paths and set the stack size at that instruction to variableSpace
3325 asCArray<asUINT> paths;
3326 paths.PushLast(0);
3327 stackSize[0] = func->scriptData->variableSpace;
3328
3329 // Go through each of the code paths
3330 for( asUINT p = 0; p < paths.GetLength(); ++p )
3331 {
3332 asUINT pos = paths[p];
3333 int currStackSize = stackSize[pos];
3334
3335 asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos];
3336 if( bc == asBC_RET )
3337 continue;
3338
3339 // Determine the change in stack size for this instruction
3340 int stackInc = asBCInfo[bc].stackInc;
3341 if( stackInc == 0xFFFF )
3342 {
3343 // Determine the true delta from the instruction arguments
3344 if( bc == asBC_CALL ||
3345 bc == asBC_CALLSYS ||
3346 bc == asBC_Thiscall1 ||
3347 bc == asBC_CALLBND ||
3348 bc == asBC_ALLOC ||
3349 bc == asBC_CALLINTF ||
3350 bc == asBC_CallPtr )
3351 {
3352 asCScriptFunction *called = GetCalledFunction(func, pos);
3353 if( called )
3354 {
3355 stackInc = -called->GetSpaceNeededForArguments();
3356 if( called->objectType )
3357 stackInc -= AS_PTR_SIZE;
3358 if( called->DoesReturnOnStack() )
3359 stackInc -= AS_PTR_SIZE;
3360 }
3361 else
3362 {
3363 // It is an allocation for an object without a constructor
3364 asASSERT( bc == asBC_ALLOC );
3365 stackInc = -AS_PTR_SIZE;
3366 }
3367 }
3368 }
3369
3370 currStackSize += stackInc;
3371 asASSERT( currStackSize >= 0 );
3372
3373 if( currStackSize > largestStackUsed )
3374 largestStackUsed = currStackSize;
3375
3376 if( bc == asBC_JMP )
3377 {
3378 // Find the label that we should jump to
3379 int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
3380 pos += 2 + offset;
3381
3382 // Add the destination as a new path
3383 if( stackSize[pos] == -1 )
3384 {
3385 stackSize[pos] = currStackSize;
3386 paths.PushLast(pos);
3387 }
3388 else
3389 asASSERT(stackSize[pos] == currStackSize);
3390 continue;
3391 }
3392 else if( bc == asBC_JZ || bc == asBC_JNZ ||
3393 bc == asBC_JLowZ || bc == asBC_JLowNZ ||
3394 bc == asBC_JS || bc == asBC_JNS ||
3395 bc == asBC_JP || bc == asBC_JNP )
3396 {
3397 // Find the label that is being jumped to
3398 int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
3399
3400 // Add both paths to the code paths
3401 pos += 2;
3402 if( stackSize[pos] == -1 )
3403 {
3404 stackSize[pos] = currStackSize;
3405 paths.PushLast(pos);
3406 }
3407 else
3408 asASSERT(stackSize[pos] == currStackSize);
3409
3410 pos += offset;
3411 if( stackSize[pos] == -1 )
3412 {
3413 stackSize[pos] = currStackSize;
3414 paths.PushLast(pos);
3415 }
3416 else
3417 asASSERT(stackSize[pos] == currStackSize);
3418
3419 continue;
3420 }
3421 else if( bc == asBC_JMPP )
3422 {
3423 pos++;
3424
3425 // Add all subsequent JMP instructions to the path
3426 while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP )
3427 {
3428 if( stackSize[pos] == -1 )
3429 {
3430 stackSize[pos] = currStackSize;
3431 paths.PushLast(pos);
3432 }
3433 else
3434 asASSERT(stackSize[pos] == currStackSize);
3435 pos += 2;
3436 }
3437 continue;
3438 }
3439 else
3440 {
3441 // Add next instruction to the paths
3442 pos += asBCTypeSize[asBCInfo[bc].type];
3443 if( stackSize[pos] == -1 )
3444 {
3445 stackSize[pos] = currStackSize;
3446 paths.PushLast(pos);
3447 }
3448 else
3449 asASSERT(stackSize[pos] == currStackSize);
3450
3451 continue;
3452 }
3453 }
3454
3455 func->scriptData->stackNeeded = largestStackUsed;
3456 }
3457
CalculateAdjustmentByPos(asCScriptFunction * func)3458 void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func)
3459 {
3460 // Adjust the offset of all negative variables (parameters) as
3461 // all pointers have been stored as having a size of 1 dword
3462 asUINT n;
3463 asCArray<int> adjustments;
3464 asUINT offset = 0;
3465 if( func->objectType )
3466 {
3467 adjustments.PushLast(offset);
3468 adjustments.PushLast(1-AS_PTR_SIZE);
3469 offset += 1;
3470 }
3471 if( func->DoesReturnOnStack() )
3472 {
3473 adjustments.PushLast(offset);
3474 adjustments.PushLast(1-AS_PTR_SIZE);
3475 offset += 1;
3476 }
3477 for( n = 0; n < func->parameterTypes.GetLength(); n++ )
3478 {
3479 if( !func->parameterTypes[n].IsPrimitive() ||
3480 func->parameterTypes[n].IsReference() )
3481 {
3482 adjustments.PushLast(offset);
3483 adjustments.PushLast(1-AS_PTR_SIZE);
3484 offset += 1;
3485 }
3486 else
3487 {
3488 asASSERT( func->parameterTypes[n].IsPrimitive() );
3489 offset += func->parameterTypes[n].GetSizeOnStackDWords();
3490 }
3491 }
3492
3493 // Build look-up table with the adjustments for each stack position
3494 adjustNegativeStackByPos.SetLength(offset);
3495 memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
3496 for( n = 0; n < adjustments.GetLength(); n+=2 )
3497 {
3498 int pos = adjustments[n];
3499 int adjust = adjustments[n+1];
3500
3501 for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
3502 adjustNegativeStackByPos[i] += adjust;
3503 }
3504
3505 // The bytecode has been stored as if all object variables take up only 1 dword.
3506 // It is necessary to adjust to the size according to the current platform.
3507 adjustments.SetLength(0);
3508 int highestPos = 0;
3509 for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ )
3510 {
3511 // Determine the size the variable currently occupies on the stack
3512 int size = AS_PTR_SIZE;
3513
3514 // objVariableTypes is null if the type is a null pointer
3515 if( func->scriptData->objVariableTypes[n] &&
3516 (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
3517 n >= func->scriptData->objVariablesOnHeap )
3518 {
3519 size = func->scriptData->objVariableTypes[n]->GetSize();
3520 if( size < 4 )
3521 size = 1;
3522 else
3523 size /= 4;
3524 }
3525
3526 // Check if type has a different size than stored
3527 if( size > 1 )
3528 {
3529 if( func->scriptData->objVariablePos[n] > highestPos )
3530 highestPos = func->scriptData->objVariablePos[n];
3531
3532 adjustments.PushLast(func->scriptData->objVariablePos[n]);
3533 adjustments.PushLast(size-1);
3534 }
3535 }
3536
3537 // Count position 0 too
3538 adjustByPos.SetLength(highestPos+1);
3539 memset(adjustByPos.AddressOf(), 0, adjustByPos.GetLength()*sizeof(int));
3540
3541 // Build look-up table with the adjustments for each stack position
3542 for( n = 0; n < adjustments.GetLength(); n+=2 )
3543 {
3544 int pos = adjustments[n];
3545 int adjust = adjustments[n+1];
3546
3547 for( asUINT i = pos; i < adjustByPos.GetLength(); i++ )
3548 adjustByPos[i] += adjust;
3549 }
3550 }
3551
AdjustStackPosition(int pos)3552 int asCReader::AdjustStackPosition(int pos)
3553 {
3554 if( pos >= (int)adjustByPos.GetLength() )
3555 {
3556 // It can be higher for primitives allocated on top of highest object variable
3557 if( adjustByPos.GetLength() )
3558 pos += (short)adjustByPos[adjustByPos.GetLength()-1];
3559 }
3560 else if( pos >= 0 )
3561 pos += (short)adjustByPos[pos];
3562 else if( -pos >= (int)adjustNegativeStackByPos.GetLength() )
3563 Error(TXT_INVALID_BYTECODE_d);
3564 else
3565 pos += (short)adjustNegativeStackByPos[-pos];
3566
3567 return pos;
3568 }
3569
GetCalledFunction(asCScriptFunction * func,asDWORD programPos)3570 asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD programPos)
3571 {
3572 asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos];
3573
3574 if( bc == asBC_CALL ||
3575 bc == asBC_CALLSYS ||
3576 bc == asBC_Thiscall1 ||
3577 bc == asBC_CALLINTF )
3578 {
3579 // Find the function from the function id in bytecode
3580 int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]);
3581 return engine->scriptFunctions[funcId];
3582 }
3583 else if( bc == asBC_ALLOC )
3584 {
3585 // Find the function from the function id in the bytecode
3586 int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos+AS_PTR_SIZE]);
3587 return engine->scriptFunctions[funcId];
3588 }
3589 else if( bc == asBC_CALLBND )
3590 {
3591 // Find the function from the engine's bind array
3592 int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]);
3593 return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
3594 }
3595 else if( bc == asBC_CallPtr )
3596 {
3597 asUINT v;
3598 int var = asBC_SWORDARG0(&func->scriptData->byteCode[programPos]);
3599
3600 // Find the funcdef from the local variable
3601 for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
3602 if( func->scriptData->objVariablePos[v] == var )
3603 return CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef;
3604
3605 // Look in parameters
3606 int paramPos = 0;
3607 if( func->objectType )
3608 paramPos -= AS_PTR_SIZE;
3609 if( func->DoesReturnOnStack() )
3610 paramPos -= AS_PTR_SIZE;
3611 for( v = 0; v < func->parameterTypes.GetLength(); v++ )
3612 {
3613 if (var == paramPos)
3614 {
3615 if (func->parameterTypes[v].IsFuncdef())
3616 return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
3617 else
3618 {
3619 error = true;
3620 return 0;
3621 }
3622 }
3623 paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
3624 }
3625 }
3626
3627 return 0;
3628 }
3629
AdjustGetOffset(int offset,asCScriptFunction * func,asDWORD programPos)3630 int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
3631 {
3632 // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
3633 // the function can remember where it found the function and check if the programPos is still valid
3634
3635 // Get offset 0 doesn't need adjustment
3636 if( offset == 0 ) return 0;
3637
3638 bool bcAlloc = false;
3639
3640 // Find out which function that will be called
3641 asCScriptFunction *calledFunc = 0;
3642 int stackDelta = 0;
3643 for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); )
3644 {
3645 asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
3646 if( bc == asBC_CALL ||
3647 bc == asBC_CALLSYS ||
3648 bc == asBC_Thiscall1 ||
3649 bc == asBC_CALLINTF ||
3650 bc == asBC_ALLOC ||
3651 bc == asBC_CALLBND ||
3652 bc == asBC_CallPtr )
3653 {
3654 // The alloc instruction allocates the object memory
3655 // so it doesn't take the this pointer as input
3656 if (bc == asBC_ALLOC)
3657 bcAlloc = true;
3658
3659 calledFunc = GetCalledFunction(func, n);
3660 break;
3661 }
3662 else if( bc == asBC_REFCPY ||
3663 bc == asBC_COPY )
3664 {
3665 // In this case we know there is only 1 pointer on the stack above
3666 asASSERT( offset == 1 );
3667 return offset - (1 - AS_PTR_SIZE);
3668 }
3669
3670 // Keep track of the stack size between the
3671 // instruction that needs to be adjusted and the call
3672 stackDelta += asBCInfo[bc].stackInc;
3673
3674 n += asBCTypeSize[asBCInfo[bc].type];
3675 }
3676
3677 if( calledFunc == 0 )
3678 {
3679 Error(TXT_INVALID_BYTECODE_d);
3680 return offset;
3681 }
3682
3683 // Count the number of pointers pushed on the stack above the
3684 // current offset, and then adjust the offset accordingly
3685 asUINT numPtrs = 0;
3686 int currOffset = -stackDelta;
3687 if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
3688 {
3689 currOffset++;
3690 if( currOffset > 0 )
3691 numPtrs++;
3692 #if AS_PTR_SIZE == 2
3693 // For 64bit platforms it is necessary to increment the currOffset by one more
3694 // DWORD since the stackDelta was counting the full 64bit size of the pointer
3695 else if( stackDelta )
3696 currOffset++;
3697 #endif
3698 }
3699 if( offset > currOffset && calledFunc->DoesReturnOnStack() )
3700 {
3701 currOffset++;
3702 if( currOffset > 0 )
3703 numPtrs++;
3704 #if AS_PTR_SIZE == 2
3705 // For 64bit platforms it is necessary to increment the currOffset by one more
3706 // DWORD since the stackDelta was counting the full 64bit size of the pointer
3707 else if( stackDelta )
3708 currOffset++;
3709 #endif
3710 }
3711 for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
3712 {
3713 if( offset <= currOffset ) break;
3714
3715 if( !calledFunc->parameterTypes[p].IsPrimitive() ||
3716 calledFunc->parameterTypes[p].IsReference() )
3717 {
3718 currOffset++;
3719 if( currOffset > 0 )
3720 numPtrs++;
3721 #if AS_PTR_SIZE == 2
3722 // For 64bit platforms it is necessary to increment the currOffset by one more
3723 // DWORD since the stackDelta was counting the full 64bit size of the pointer
3724 else if( stackDelta )
3725 currOffset++;
3726 #endif
3727
3728 // The variable arg ? has an additiona 32bit integer with the typeid
3729 if( calledFunc->parameterTypes[p].IsAnyType() )
3730 currOffset += 1;
3731 }
3732 else
3733 {
3734 // Enums or built-in primitives are passed by value
3735 asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
3736 currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
3737 }
3738 }
3739
3740 return offset - numPtrs * (1 - AS_PTR_SIZE);
3741 }
3742
FindTypeId(int idx)3743 int asCReader::FindTypeId(int idx)
3744 {
3745 if( idx >= 0 && idx < (int)usedTypeIds.GetLength() )
3746 return usedTypeIds[idx];
3747 else
3748 {
3749 Error(TXT_INVALID_BYTECODE_d);
3750 return 0;
3751 }
3752 }
3753
FindType(int idx)3754 asCTypeInfo *asCReader::FindType(int idx)
3755 {
3756 if( idx < 0 || idx >= (int)usedTypes.GetLength() )
3757 {
3758 Error(TXT_INVALID_BYTECODE_d);
3759 return 0;
3760 }
3761
3762 return usedTypes[idx];
3763 }
3764
3765 #ifndef AS_NO_COMPILER
3766
asCWriter(asCModule * _module,asIBinaryStream * _stream,asCScriptEngine * _engine,bool _stripDebug)3767 asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug)
3768 : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0)
3769 {
3770 }
3771
Error(const char * msg)3772 int asCWriter::Error(const char *msg)
3773 {
3774 // Don't write if it has already been reported an error earlier
3775 if (!error)
3776 {
3777 asCString str;
3778 str.Format(msg, bytesWritten);
3779 engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
3780 error = true;
3781 }
3782
3783 return asERROR;
3784 }
3785
WriteData(const void * data,asUINT size)3786 int asCWriter::WriteData(const void *data, asUINT size)
3787 {
3788 asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
3789 int ret = 0;
3790 #if defined(AS_BIG_ENDIAN)
3791 for( asUINT n = 0; ret >= 0 && n < size; n++ )
3792 ret = stream->Write(((asBYTE*)data)+n, 1);
3793 #else
3794 for( int n = size-1; ret >= 0 && n >= 0; n-- )
3795 ret = stream->Write(((asBYTE*)data)+n, 1);
3796 #endif
3797 if (ret < 0)
3798 Error(TXT_UNEXPECTED_END_OF_FILE);
3799 bytesWritten += size;
3800 return ret;
3801 }
3802
Write()3803 int asCWriter::Write()
3804 {
3805 TimeIt("asCWriter::Write");
3806
3807 unsigned long i, count;
3808
3809 // Store everything in the same order that the builder parses scripts
3810
3811 // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway
3812 // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway
3813 // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway
3814
3815 // Write the flag as 1byte even on platforms with 4byte booleans
3816 WriteEncodedInt64(stripDebugInfo ? 1 : 0);
3817
3818 // Store enums
3819 {
3820 TimeIt("store enums");
3821
3822 count = (asUINT)module->enumTypes.GetLength();
3823 WriteEncodedInt64(count);
3824 for( i = 0; i < count; i++ )
3825 {
3826 WriteTypeDeclaration(module->enumTypes[i], 1);
3827 WriteTypeDeclaration(module->enumTypes[i], 2);
3828 }
3829 }
3830
3831 // Store type declarations first
3832 {
3833 TimeIt("type declarations");
3834
3835 count = (asUINT)module->classTypes.GetLength();
3836 WriteEncodedInt64(count);
3837 for( i = 0; i < count; i++ )
3838 {
3839 // Store only the name of the class/interface types
3840 WriteTypeDeclaration(module->classTypes[i], 1);
3841 }
3842 }
3843
3844 // Store func defs
3845 {
3846 TimeIt("func defs");
3847
3848 count = (asUINT)module->funcDefs.GetLength();
3849 WriteEncodedInt64(count);
3850 for( i = 0; i < count; i++ )
3851 WriteFunction(module->funcDefs[i]->funcdef);
3852 }
3853
3854 // Now store all interface methods
3855 {
3856 TimeIt("interface methods");
3857
3858 count = (asUINT)module->classTypes.GetLength();
3859 for( i = 0; i < count; i++ )
3860 {
3861 if( module->classTypes[i]->IsInterface() )
3862 WriteTypeDeclaration(module->classTypes[i], 2);
3863 }
3864 }
3865
3866 // Then store the class methods and behaviours
3867 {
3868 TimeIt("class methods and behaviours");
3869
3870 for( i = 0; i < count; ++i )
3871 {
3872 if( !module->classTypes[i]->IsInterface() )
3873 WriteTypeDeclaration(module->classTypes[i], 2);
3874 }
3875 }
3876
3877 // Then store the class properties
3878 {
3879 TimeIt("class properties");
3880
3881 for( i = 0; i < count; ++i )
3882 {
3883 if( !module->classTypes[i]->IsInterface() )
3884 WriteTypeDeclaration(module->classTypes[i], 3);
3885 }
3886 }
3887
3888 // Store typedefs
3889 {
3890 TimeIt("type defs");
3891
3892 count = (asUINT)module->typeDefs.GetLength();
3893 WriteEncodedInt64(count);
3894 for( i = 0; i < count; i++ )
3895 {
3896 WriteTypeDeclaration(module->typeDefs[i], 1);
3897 WriteTypeDeclaration(module->typeDefs[i], 2);
3898 }
3899 }
3900
3901 // scriptGlobals[]
3902 {
3903 TimeIt("script globals");
3904
3905 count = (asUINT)module->scriptGlobals.GetSize();
3906 WriteEncodedInt64(count);
3907 asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
3908 for( ; it; it++ )
3909 WriteGlobalProperty(*it);
3910 }
3911
3912 // scriptFunctions[]
3913 {
3914 TimeIt("scriptFunctions");
3915
3916 count = 0;
3917 for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
3918 if( module->scriptFunctions[i]->objectType == 0 )
3919 count++;
3920 WriteEncodedInt64(count);
3921 for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
3922 if( module->scriptFunctions[i]->objectType == 0 )
3923 WriteFunction(module->scriptFunctions[i]);
3924 }
3925
3926 // globalFunctions[]
3927 {
3928 TimeIt("globalFunctions");
3929
3930 count = (int)module->globalFunctions.GetSize();
3931 asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
3932 WriteEncodedInt64(count);
3933 while( funcIt )
3934 {
3935 WriteFunction(*funcIt);
3936 funcIt++;
3937 }
3938 }
3939
3940 // bindInformations[]
3941 {
3942 TimeIt("bindInformations");
3943
3944 count = (asUINT)module->bindInformations.GetLength();
3945 WriteEncodedInt64(count);
3946 for( i = 0; i < count; ++i )
3947 {
3948 WriteFunction(module->bindInformations[i]->importedFunctionSignature);
3949 WriteString(&module->bindInformations[i]->importFromModule);
3950 }
3951 }
3952
3953 // usedTypes[]
3954 {
3955 TimeIt("usedTypes");
3956
3957 count = (asUINT)usedTypes.GetLength();
3958 WriteEncodedInt64(count);
3959 for( i = 0; i < count; ++i )
3960 WriteTypeInfo(usedTypes[i]);
3961 }
3962
3963 // usedTypeIds[]
3964 WriteUsedTypeIds();
3965
3966 // usedFunctions[]
3967 WriteUsedFunctions();
3968
3969 // usedGlobalProperties[]
3970 WriteUsedGlobalProps();
3971
3972 // usedStringConstants[]
3973 WriteUsedStringConstants();
3974
3975 // usedObjectProperties[]
3976 WriteUsedObjectProps();
3977
3978 return error ? asERROR : asSUCCESS;
3979 }
3980
FindStringConstantIndex(void * str)3981 int asCWriter::FindStringConstantIndex(void *str)
3982 {
3983 asSMapNode<void*, int> *cursor = 0;
3984 if (stringToIndexMap.MoveTo(&cursor, str))
3985 return cursor->value;
3986
3987 usedStringConstants.PushLast(str);
3988 int index = int(usedStringConstants.GetLength() - 1);
3989 stringToIndexMap.Insert(str, index);
3990 return index;
3991 }
3992
WriteUsedStringConstants()3993 void asCWriter::WriteUsedStringConstants()
3994 {
3995 TimeIt("asCWriter::WriteUsedStringConstants");
3996
3997 asUINT count = (asUINT)usedStringConstants.GetLength();
3998 WriteEncodedInt64(count);
3999
4000 asCString str;
4001 for (asUINT i = 0; i < count; ++i)
4002 {
4003 asUINT length;
4004 engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length);
4005 str.SetLength(length);
4006 engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length);
4007 WriteString(&str);
4008 }
4009 }
4010
WriteUsedFunctions()4011 void asCWriter::WriteUsedFunctions()
4012 {
4013 TimeIt("asCWriter::WriteUsedFunctions");
4014
4015 asUINT count = (asUINT)usedFunctions.GetLength();
4016 WriteEncodedInt64(count);
4017
4018 for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
4019 {
4020 char c;
4021
4022 // Write enough data to be able to uniquely identify the function upon load
4023 asCScriptFunction *func = usedFunctions[n];
4024 if(func)
4025 {
4026 // Is the function from the module or the application?
4027 c = func->module ? 'm' : 'a';
4028
4029 // Functions and methods that are shared and not owned by the module can be
4030 // stored as 's' to tell the reader that these are received from other modules.
4031 if (c == 'm' && func->IsShared() && module->scriptFunctions.IndexOf(func) < 0 )
4032 c = 's';
4033
4034 WriteData(&c, 1);
4035 WriteFunctionSignature(func);
4036 }
4037 else
4038 {
4039 // null function pointer
4040 c = 'n';
4041 WriteData(&c, 1);
4042 }
4043 }
4044 }
4045
WriteFunctionSignature(asCScriptFunction * func)4046 void asCWriter::WriteFunctionSignature(asCScriptFunction *func)
4047 {
4048 asUINT i, count;
4049
4050 WriteString(&func->name);
4051 if( func->name == DELEGATE_FACTORY )
4052 {
4053 // It's not necessary to write anything else
4054 return;
4055 }
4056
4057 WriteDataType(&func->returnType);
4058
4059 count = (asUINT)func->parameterTypes.GetLength();
4060 WriteEncodedInt64(count);
4061 for( i = 0; i < count; ++i )
4062 WriteDataType(&func->parameterTypes[i]);
4063
4064 // Only write the inout flags if any of them are set
4065 // If the number of parameters is 0, then no need to save this
4066 if (func->parameterTypes.GetLength() > 0)
4067 {
4068 count = 0;
4069 for (i = asUINT(func->inOutFlags.GetLength()); i > 0; i--)
4070 if (func->inOutFlags[i - 1] != asTM_NONE)
4071 {
4072 count = i;
4073 break;
4074 }
4075 WriteEncodedInt64(count);
4076 for (i = 0; i < count; ++i)
4077 WriteEncodedInt64(func->inOutFlags[i]);
4078 }
4079
4080 WriteEncodedInt64(func->funcType);
4081
4082 // Write the default args, from last to first
4083 // If the number of parameters is 0, then no need to save this
4084 if (func->parameterTypes.GetLength() > 0)
4085 {
4086 count = 0;
4087 for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
4088 if (func->defaultArgs[i])
4089 count++;
4090 WriteEncodedInt64(count);
4091 for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
4092 if (func->defaultArgs[i])
4093 WriteString(func->defaultArgs[i]);
4094 }
4095
4096 WriteTypeInfo(func->objectType);
4097
4098 if( func->objectType )
4099 {
4100 asBYTE b = 0;
4101 b += func->IsReadOnly() ? 1 : 0;
4102 b += func->IsPrivate() ? 2 : 0;
4103 b += func->IsProtected() ? 4 : 0;
4104 WriteData(&b, 1);
4105 }
4106 else
4107 {
4108 if (func->funcType == asFUNC_FUNCDEF)
4109 {
4110 if (func->nameSpace)
4111 {
4112 // This funcdef was declared as global entity
4113 asBYTE b = 'n';
4114 WriteData(&b, 1);
4115 WriteString(&func->nameSpace->name);
4116 }
4117 else
4118 {
4119 // This funcdef was declared as class member
4120 asBYTE b = 'o';
4121 WriteData(&b, 1);
4122 WriteTypeInfo(func->funcdefType->parentClass);
4123 }
4124 }
4125 else
4126 WriteString(&func->nameSpace->name);
4127 }
4128 }
4129
WriteFunction(asCScriptFunction * func)4130 void asCWriter::WriteFunction(asCScriptFunction* func)
4131 {
4132 char c;
4133
4134 // If there is no function, then store a null char
4135 if( func == 0 )
4136 {
4137 c = '\0';
4138 WriteData(&c, 1);
4139 return;
4140 }
4141
4142 // First check if the function has been saved already
4143 for( asUINT f = 0; f < savedFunctions.GetLength(); f++ )
4144 {
4145 if( savedFunctions[f] == func )
4146 {
4147 c = 'r';
4148 WriteData(&c, 1);
4149 WriteEncodedInt64(f);
4150 return;
4151 }
4152 }
4153
4154 // Keep a reference to the function in the list
4155 savedFunctions.PushLast(func);
4156
4157 c = 'f';
4158 WriteData(&c, 1);
4159
4160 asUINT i, count;
4161
4162 WriteFunctionSignature(func);
4163
4164 if( func->funcType == asFUNC_SCRIPT )
4165 {
4166 // Skip this for external shared entities
4167 if (module->externalTypes.IndexOf(func->objectType) >= 0)
4168 return;
4169
4170 char bits = 0;
4171 bits += func->IsShared() ? 1 : 0;
4172 bits += func->dontCleanUpOnException ? 2 : 0;
4173 if (module->externalFunctions.IndexOf(func) >= 0)
4174 bits += 4;
4175 if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength())
4176 bits += 8;
4177 if (func->scriptData->tryCatchInfo.GetLength())
4178 bits += 16;
4179 bits += func->IsExplicit() ? 32 : 0;
4180 WriteData(&bits, 1);
4181
4182 // For external shared functions the rest is not needed
4183 if (bits & 4)
4184 return;
4185
4186 // Calculate the adjustment by position lookup table
4187 CalculateAdjustmentByPos(func);
4188
4189 WriteByteCode(func);
4190
4191 asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace);
4192 WriteEncodedInt64(varSpace);
4193
4194 if (bits & 8)
4195 {
4196 count = (asUINT)func->scriptData->objVariablePos.GetLength();
4197 WriteEncodedInt64(count);
4198 for (i = 0; i < count; ++i)
4199 {
4200 WriteTypeInfo(func->scriptData->objVariableTypes[i]);
4201 WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i]));
4202 }
4203 if (count > 0)
4204 WriteEncodedInt64(func->scriptData->objVariablesOnHeap);
4205
4206 WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength());
4207 for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i)
4208 {
4209 // The program position must be adjusted to be in number of instructions
4210 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]);
4211 WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset));
4212 WriteEncodedInt64(func->scriptData->objVariableInfo[i].option);
4213 }
4214 }
4215
4216 if (bits & 16)
4217 {
4218 // Write info on try/catch blocks
4219 WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength());
4220 for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i)
4221 {
4222 // The program position must be adjusted to be in number of instructions
4223 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]);
4224 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]);
4225 }
4226 }
4227
4228 // The program position (every even number) needs to be adjusted
4229 // to be in number of instructions instead of DWORD offset
4230 if( !stripDebugInfo )
4231 {
4232 asUINT length = (asUINT)func->scriptData->lineNumbers.GetLength();
4233 WriteEncodedInt64(length);
4234 for( i = 0; i < length; ++i )
4235 {
4236 if( (i & 1) == 0 )
4237 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->lineNumbers[i]]);
4238 else
4239 WriteEncodedInt64(func->scriptData->lineNumbers[i]);
4240 }
4241
4242 // Write the array of script sections
4243 length = (asUINT)func->scriptData->sectionIdxs.GetLength();
4244 WriteEncodedInt64(length);
4245 for( i = 0; i < length; ++i )
4246 {
4247 if( (i & 1) == 0 )
4248 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->sectionIdxs[i]]);
4249 else
4250 {
4251 if( func->scriptData->sectionIdxs[i] >= 0 )
4252 WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]);
4253 else
4254 {
4255 c = 0;
4256 WriteData(&c, 1);
4257 }
4258 }
4259 }
4260 }
4261
4262 // Write the variable information
4263 if( !stripDebugInfo )
4264 {
4265 WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength());
4266 for( i = 0; i < func->scriptData->variables.GetLength(); i++ )
4267 {
4268 // The program position must be adjusted to be in number of instructions
4269 WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]);
4270 // The stack position must be adjusted according to the pointer sizes
4271 WriteEncodedInt64(AdjustStackPosition(func->scriptData->variables[i]->stackOffset));
4272 WriteString(&func->scriptData->variables[i]->name);
4273 WriteDataType(&func->scriptData->variables[i]->type);
4274 }
4275 }
4276
4277 // Store script section name
4278 if( !stripDebugInfo )
4279 {
4280 if( func->scriptData->scriptSectionIdx >= 0 )
4281 WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]);
4282 else
4283 {
4284 c = 0;
4285 WriteData(&c, 1);
4286 }
4287 WriteEncodedInt64(func->scriptData->declaredAt);
4288 }
4289
4290 // Store the parameter names
4291 if( !stripDebugInfo )
4292 {
4293 count = asUINT(func->parameterNames.GetLength());
4294 WriteEncodedInt64(count);
4295 for( asUINT n = 0; n < count; n++ )
4296 WriteString(&func->parameterNames[n]);
4297 }
4298 }
4299 else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
4300 {
4301 // TODO: Do we really need to store this? It can probably be reconstructed by the reader
4302 WriteEncodedInt64(func->vfTableIdx);
4303 }
4304 else if( func->funcType == asFUNC_FUNCDEF )
4305 {
4306 char bits = 0;
4307 bits += func->IsShared() ? 1 : 0;
4308 if (module->externalTypes.IndexOf(func->funcdefType) >= 0)
4309 bits += 2;
4310 WriteData(&bits,1);
4311 }
4312 }
4313
WriteTypeDeclaration(asCTypeInfo * type,int phase)4314 void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase)
4315 {
4316 if( phase == 1 )
4317 {
4318 // name
4319 WriteString(&type->name);
4320 // flags
4321 WriteData(&type->flags, 4);
4322
4323 // size
4324 // TODO: Do we really need to store this? The reader should be able to
4325 // determine the correct size from the object type's flags
4326 if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size > 0 )
4327 {
4328 // The size for script objects may vary from platform to platform so
4329 // only store 1 to diferentiate from interfaces that have size 0.
4330 WriteEncodedInt64(1);
4331 }
4332 else
4333 {
4334 // Enums, typedefs, and interfaces have fixed sizes independently
4335 // of platform so it is safe to serialize the size directly.
4336 WriteEncodedInt64(type->size);
4337 }
4338
4339 // namespace
4340 WriteString(&type->nameSpace->name);
4341
4342 // external shared flag
4343 if ((type->flags & asOBJ_SHARED))
4344 {
4345 char c = ' ';
4346 if (module->externalTypes.IndexOf(type) >= 0)
4347 c = 'e';
4348 WriteData(&c, 1);
4349 }
4350 }
4351 else if( phase == 2 )
4352 {
4353 // external shared types doesn't need to save this
4354 if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0)
4355 return;
4356
4357 if(type->flags & asOBJ_ENUM )
4358 {
4359 // enumValues[]
4360 asCEnumType *t = CastToEnumType(type);
4361 int size = (int)t->enumValues.GetLength();
4362 WriteEncodedInt64(size);
4363
4364 for( int n = 0; n < size; n++ )
4365 {
4366 WriteString(&t->enumValues[n]->name);
4367 WriteData(&t->enumValues[n]->value, 4);
4368 }
4369 }
4370 else if(type->flags & asOBJ_TYPEDEF )
4371 {
4372 asCTypedefType *td = CastToTypedefType(type);
4373 eTokenType t = td->aliasForType.GetTokenType();
4374 WriteEncodedInt64(t);
4375 }
4376 else
4377 {
4378 asCObjectType *t = CastToObjectType(type);
4379 WriteTypeInfo(t->derivedFrom);
4380
4381 // interfaces[] / interfaceVFTOffsets[]
4382 // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those?
4383 int size = (asUINT)t->interfaces.GetLength();
4384 WriteEncodedInt64(size);
4385 asUINT n;
4386 asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() );
4387 for( n = 0; n < t->interfaces.GetLength(); n++ )
4388 {
4389 WriteTypeInfo(t->interfaces[n]);
4390 if( !t->IsInterface() )
4391 WriteEncodedInt64(t->interfaceVFTOffsets[n]);
4392 }
4393
4394 // behaviours
4395 // TODO: Default behaviours should just be stored as a indicator
4396 // to avoid storing the actual function object
4397 if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
4398 {
4399 WriteFunction(engine->scriptFunctions[t->beh.destruct]);
4400 size = (int)t->beh.constructors.GetLength();
4401 WriteEncodedInt64(size);
4402 for( n = 0; n < t->beh.constructors.GetLength(); n++ )
4403 {
4404 WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]);
4405 WriteFunction(engine->scriptFunctions[t->beh.factories[n]]);
4406 }
4407 }
4408
4409 // methods[]
4410 // TODO: Avoid storing inherited methods in interfaces, as the reader
4411 // can add those directly from the base interface
4412 size = (int)t->methods.GetLength();
4413 WriteEncodedInt64(size);
4414 for( n = 0; n < t->methods.GetLength(); n++ )
4415 {
4416 WriteFunction(engine->scriptFunctions[t->methods[n]]);
4417 }
4418
4419 // virtualFunctionTable[]
4420 // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader
4421 size = (int)t->virtualFunctionTable.GetLength();
4422 WriteEncodedInt64(size);
4423 for( n = 0; n < (asUINT)size; n++ )
4424 {
4425 WriteFunction(t->virtualFunctionTable[n]);
4426 }
4427 }
4428 }
4429 else if( phase == 3 )
4430 {
4431 // external shared types doesn't need to save this
4432 if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0)
4433 return;
4434
4435 // properties[]
4436 asCObjectType *t = CastToObjectType(type);
4437
4438 // This is only done for object types
4439 asASSERT(t);
4440
4441 asUINT size = (asUINT)t->properties.GetLength();
4442 WriteEncodedInt64(size);
4443 for (asUINT n = 0; n < t->properties.GetLength(); n++)
4444 {
4445 WriteObjectProperty(t->properties[n]);
4446 }
4447 }
4448 }
4449
WriteEncodedInt64(asINT64 i)4450 void asCWriter::WriteEncodedInt64(asINT64 i)
4451 {
4452 asBYTE signBit = ( i & asINT64(1)<<63 ) ? 0x80 : 0;
4453 if( signBit ) i = -i;
4454
4455 asBYTE b;
4456 if( i < (1<<6) )
4457 {
4458 b = (asBYTE)(signBit + i); WriteData(&b, 1);
4459 }
4460 else if( i < (1<<13) )
4461 {
4462 b = asBYTE(0x40 + signBit + (i >> 8)); WriteData(&b, 1);
4463 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4464 }
4465 else if( i < (1<<20) )
4466 {
4467 b = asBYTE(0x60 + signBit + (i >> 16)); WriteData(&b, 1);
4468 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4469 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4470 }
4471 else if( i < (1<<27) )
4472 {
4473 b = asBYTE(0x70 + signBit + (i >> 24)); WriteData(&b, 1);
4474 b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
4475 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4476 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4477 }
4478 else if( i < (asINT64(1)<<34) )
4479 {
4480 b = asBYTE(0x78 + signBit + (i >> 32)); WriteData(&b, 1);
4481 b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
4482 b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
4483 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4484 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4485 }
4486 else if( i < (asINT64(1)<<41) )
4487 {
4488 b = asBYTE(0x7C + signBit + (i >> 40)); WriteData(&b, 1);
4489 b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
4490 b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
4491 b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
4492 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4493 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4494 }
4495 else if( i < (asINT64(1)<<48) )
4496 {
4497 b = asBYTE(0x7E + signBit + (i >> 48)); WriteData(&b, 1);
4498 b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
4499 b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
4500 b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
4501 b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
4502 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4503 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4504 }
4505 else
4506 {
4507 b = asBYTE(0x7F + signBit); WriteData(&b, 1);
4508 b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1);
4509 b = asBYTE((i >> 48) & 0xFF); WriteData(&b, 1);
4510 b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
4511 b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
4512 b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
4513 b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
4514 b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
4515 b = asBYTE(i & 0xFF); WriteData(&b, 1);
4516 }
4517 }
4518
WriteString(asCString * str)4519 void asCWriter::WriteString(asCString* str)
4520 {
4521 // First check if the string hasn't been saved already
4522 asSMapNode<asCString, int> *cursor = 0;
4523 if (stringToIdMap.MoveTo(&cursor, *str))
4524 {
4525 // Save a reference to the existing string
4526 // The lowest bit is set to 1 to indicate a reference
4527 WriteEncodedInt64(cursor->value*2+1);
4528 return;
4529 }
4530
4531 // Save a new string
4532 // The lowest bit is set to 0 to indicate a new string
4533 asUINT len = (asUINT)str->GetLength();
4534 WriteEncodedInt64(len*2);
4535
4536 if( len > 0 )
4537 {
4538 stream->Write(str->AddressOf(), (asUINT)len);
4539 bytesWritten += len;
4540
4541 savedStrings.PushLast(*str);
4542 stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1);
4543 }
4544 }
4545
WriteGlobalProperty(asCGlobalProperty * prop)4546 void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop)
4547 {
4548 // TODO: We might be able to avoid storing the name and type of the global
4549 // properties twice if we merge this with the WriteUsedGlobalProperties.
4550 WriteString(&prop->name);
4551 WriteString(&prop->nameSpace->name);
4552 WriteDataType(&prop->type);
4553
4554 // Store the initialization function
4555 WriteFunction(prop->GetInitFunc());
4556 }
4557
WriteObjectProperty(asCObjectProperty * prop)4558 void asCWriter::WriteObjectProperty(asCObjectProperty* prop)
4559 {
4560 WriteString(&prop->name);
4561 WriteDataType(&prop->type);
4562 int flags = 0;
4563 if( prop->isPrivate ) flags |= 1;
4564 if( prop->isProtected ) flags |= 2;
4565 if( prop->isInherited ) flags |= 4;
4566 WriteEncodedInt64(flags);
4567 }
4568
WriteDataType(const asCDataType * dt)4569 void asCWriter::WriteDataType(const asCDataType *dt)
4570 {
4571 // First check if the datatype has already been saved
4572 for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ )
4573 {
4574 if( *dt == savedDataTypes[n] )
4575 {
4576 WriteEncodedInt64(n+1);
4577 return;
4578 }
4579 }
4580
4581 // Indicate a new type with a null byte
4582 asUINT c = 0;
4583 WriteEncodedInt64(c);
4584
4585 // Save the new datatype
4586 savedDataTypes.PushLast(*dt);
4587
4588 int t = dt->GetTokenType();
4589 WriteEncodedInt64(t);
4590 if( t == ttIdentifier )
4591 WriteTypeInfo(dt->GetTypeInfo());
4592
4593 // Endianess safe bitmask
4594 char bits = 0;
4595 SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0);
4596 SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1);
4597 SAVE_TO_BIT(bits, dt->IsReference(), 2);
4598 SAVE_TO_BIT(bits, dt->IsReadOnly(), 3);
4599 WriteData(&bits, 1);
4600 }
4601
WriteTypeInfo(asCTypeInfo * ti)4602 void asCWriter::WriteTypeInfo(asCTypeInfo* ti)
4603 {
4604 char ch;
4605
4606 if( ti )
4607 {
4608 // Check for template instances/specializations
4609 asCObjectType *ot = CastToObjectType(ti);
4610 if( ot && ot->templateSubTypes.GetLength() )
4611 {
4612 // Check for list pattern type or template type
4613 if( ot->flags & asOBJ_LIST_PATTERN )
4614 {
4615 ch = 'l'; // list
4616 WriteData(&ch, 1);
4617 WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo());
4618 }
4619 else
4620 {
4621 ch = 'a'; // array
4622 WriteData(&ch, 1);
4623 WriteString(&ot->name);
4624 WriteString(&ot->nameSpace->name);
4625
4626 WriteEncodedInt64(ot->templateSubTypes.GetLength());
4627 for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
4628 {
4629 if( !ot->templateSubTypes[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() )
4630 {
4631 ch = 's'; // sub type
4632 WriteData(&ch, 1);
4633 WriteDataType(&ot->templateSubTypes[n]);
4634 }
4635 else
4636 {
4637 ch = 't'; // token
4638 WriteData(&ch, 1);
4639 eTokenType t = ot->templateSubTypes[n].GetTokenType();
4640 WriteEncodedInt64(t);
4641 }
4642 }
4643 }
4644 }
4645 else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE )
4646 {
4647 ch = 's'; // sub type
4648 WriteData(&ch, 1);
4649 WriteString(&ti->name);
4650 }
4651 else if( !ti->GetParentType() )
4652 {
4653 ch = 'o'; // object
4654 WriteData(&ch, 1);
4655 WriteString(&ti->name);
4656 WriteString(&ti->nameSpace->name);
4657 }
4658 else
4659 {
4660 asASSERT(ti->flags & asOBJ_FUNCDEF);
4661
4662 ch = 'c'; // child type
4663 WriteData(&ch, 1);
4664 WriteString(&ti->name);
4665 WriteTypeInfo(CastToFuncdefType(ti)->parentClass);
4666 }
4667 }
4668 else
4669 {
4670 ch = '\0';
4671 WriteData(&ch, 1);
4672 }
4673 }
4674
CalculateAdjustmentByPos(asCScriptFunction * func)4675 void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func)
4676 {
4677 // Adjust the offset of all negative variables (parameters) so all pointers will have a size of 1 dword
4678 asUINT n;
4679 asCArray<int> adjustments;
4680 asUINT offset = 0;
4681 if( func->objectType )
4682 {
4683 adjustments.PushLast(offset);
4684 adjustments.PushLast(1-AS_PTR_SIZE);
4685 offset += AS_PTR_SIZE;
4686 }
4687 if( func->DoesReturnOnStack() )
4688 {
4689 adjustments.PushLast(offset);
4690 adjustments.PushLast(1-AS_PTR_SIZE);
4691 offset += AS_PTR_SIZE;
4692 }
4693 for( n = 0; n < func->parameterTypes.GetLength(); n++ )
4694 {
4695 if( !func->parameterTypes[n].IsPrimitive() ||
4696 func->parameterTypes[n].IsReference() )
4697 {
4698 adjustments.PushLast(offset);
4699 adjustments.PushLast(1-AS_PTR_SIZE);
4700 offset += AS_PTR_SIZE;
4701 }
4702 else
4703 {
4704 asASSERT( func->parameterTypes[n].IsPrimitive() );
4705 offset += func->parameterTypes[n].GetSizeOnStackDWords();
4706 }
4707 }
4708
4709 // Build look-up table with the adjustments for each stack position
4710 adjustNegativeStackByPos.SetLength(offset);
4711 memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
4712 for( n = 0; n < adjustments.GetLength(); n+=2 )
4713 {
4714 int pos = adjustments[n];
4715 int adjust = adjustments[n+1];
4716
4717 for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
4718 adjustNegativeStackByPos[i] += adjust;
4719 }
4720
4721 // Adjust the offset of all positive variables so that all object types and handles have a size of 1 dword
4722 // This is similar to how the adjustment is done in the asCReader::TranslateFunction, only the reverse
4723 adjustments.SetLength(0);
4724 for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ )
4725 {
4726 // Determine the size the variable currently occupies on the stack
4727 int size = AS_PTR_SIZE;
4728
4729 // objVariableTypes is null if the variable type is a null pointer
4730 if( func->scriptData->objVariableTypes[n] &&
4731 (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
4732 n >= func->scriptData->objVariablesOnHeap )
4733 {
4734 size = func->scriptData->objVariableTypes[n]->GetSize();
4735 if( size < 4 )
4736 size = 1;
4737 else
4738 size /= 4;
4739 }
4740
4741 // If larger than 1 dword, adjust the offsets accordingly
4742 if (size > 1)
4743 {
4744 // How much needs to be adjusted?
4745 adjustments.PushLast(func->scriptData->objVariablePos[n]);
4746 adjustments.PushLast(-(size - 1));
4747 }
4748 }
4749
4750 // Build look-up table with the adjustments for each stack position
4751 adjustStackByPos.SetLength(func->scriptData->stackNeeded);
4752 memset(adjustStackByPos.AddressOf(), 0, adjustStackByPos.GetLength()*sizeof(int));
4753 for( n = 0; n < adjustments.GetLength(); n+=2 )
4754 {
4755 int pos = adjustments[n];
4756 int adjust = adjustments[n+1];
4757
4758 for( asUINT i = pos; i < adjustStackByPos.GetLength(); i++ )
4759 adjustStackByPos[i] += adjust;
4760 }
4761
4762 // Compute the sequence number of each bytecode instruction in order to update the jump offsets
4763 asUINT length = func->scriptData->byteCode.GetLength();
4764 asDWORD *bc = func->scriptData->byteCode.AddressOf();
4765 bytecodeNbrByPos.SetLength(length);
4766 asUINT num;
4767 for( offset = 0, num = 0; offset < length; )
4768 {
4769 bytecodeNbrByPos[offset] = num;
4770 offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type];
4771 num++;
4772 }
4773
4774 // Store the number of instructions in the last position of bytecodeNbrByPos,
4775 // so this can be easily queried in SaveBytecode. Normally this is already done
4776 // as most functions end with BC_RET, but in some cases the last instruction in
4777 // the function is not a BC_RET, e.g. when a function has a never ending loop.
4778 bytecodeNbrByPos[length - 1] = num - 1;
4779 }
4780
AdjustStackPosition(int pos)4781 int asCWriter::AdjustStackPosition(int pos)
4782 {
4783 if( pos >= (int)adjustStackByPos.GetLength() )
4784 {
4785 // This happens for example if the function only have temporary variables
4786 // The adjustByPos can also be empty if the function doesn't have any variables at all, but receive a handle by parameter
4787 if( adjustStackByPos.GetLength() > 0 )
4788 pos += adjustStackByPos[adjustStackByPos.GetLength()-1];
4789 }
4790 else if( pos >= 0 )
4791 pos += adjustStackByPos[pos];
4792 else
4793 {
4794 asASSERT( -pos < (int)adjustNegativeStackByPos.GetLength() );
4795 pos -= (short)adjustNegativeStackByPos[-pos];
4796 }
4797
4798 return pos;
4799 }
4800
AdjustGetOffset(int offset,asCScriptFunction * func,asDWORD programPos)4801 int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
4802 {
4803 // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
4804 // the function can remember where it found the function and check if the programPos is still valid
4805
4806 // Get offset 0 doesn't need adjustment
4807 if( offset == 0 ) return 0;
4808
4809 bool bcAlloc = false;
4810
4811 // Find out which function that will be called
4812 asCScriptFunction *calledFunc = 0;
4813 int stackDelta = 0;
4814 for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); )
4815 {
4816 asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
4817 if( bc == asBC_CALL ||
4818 bc == asBC_CALLSYS ||
4819 bc == asBC_Thiscall1 ||
4820 bc == asBC_CALLINTF )
4821 {
4822 // Find the function from the function id in bytecode
4823 int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
4824 calledFunc = engine->scriptFunctions[funcId];
4825 break;
4826 }
4827 else if( bc == asBC_ALLOC )
4828 {
4829 // The alloc instruction doesn't take the object pointer on the stack,
4830 // as the memory will be allocated by the instruction itself
4831 bcAlloc = true;
4832
4833 // Find the function from the function id in the bytecode
4834 int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]);
4835 calledFunc = engine->scriptFunctions[funcId];
4836 break;
4837 }
4838 else if( bc == asBC_CALLBND )
4839 {
4840 // Find the function from the engine's bind array
4841 int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
4842 calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
4843 break;
4844 }
4845 else if( bc == asBC_CallPtr )
4846 {
4847 int var = asBC_SWORDARG0(&func->scriptData->byteCode[n]);
4848 asUINT v;
4849 // Find the funcdef from the local variable
4850 for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
4851 {
4852 if( func->scriptData->objVariablePos[v] == var )
4853 {
4854 calledFunc = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef;
4855 break;
4856 }
4857 }
4858 if( !calledFunc )
4859 {
4860 // Look in parameters
4861 int paramPos = 0;
4862 if( func->objectType )
4863 paramPos -= AS_PTR_SIZE;
4864 if( func->DoesReturnOnStack() )
4865 paramPos -= AS_PTR_SIZE;
4866 for( v = 0; v < func->parameterTypes.GetLength(); v++ )
4867 {
4868 if( var == paramPos )
4869 {
4870 calledFunc = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
4871 break;
4872 }
4873 paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
4874 }
4875 }
4876 break;
4877 }
4878 else if( bc == asBC_REFCPY ||
4879 bc == asBC_COPY )
4880 {
4881 // In this case we know there is only 1 pointer on the stack above
4882 asASSERT( offset == AS_PTR_SIZE );
4883 return offset + (1 - AS_PTR_SIZE);
4884 }
4885
4886 // Keep track of the stack size between the
4887 // instruction that needs to be adjusted and the call
4888 stackDelta += asBCInfo[bc].stackInc;
4889
4890 n += asBCTypeSize[asBCInfo[bc].type];
4891 }
4892
4893 asASSERT( calledFunc );
4894
4895 // Count the number of pointers pushed on the stack above the
4896 // current offset, and then adjust the offset accordingly
4897 asUINT numPtrs = 0;
4898 int currOffset = -stackDelta;
4899 if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
4900 {
4901 currOffset += AS_PTR_SIZE;
4902 if( currOffset > 0 )
4903 numPtrs++;
4904 }
4905 if( offset > currOffset && calledFunc->DoesReturnOnStack() )
4906 {
4907 currOffset += AS_PTR_SIZE;
4908 if( currOffset > 0 )
4909 numPtrs++;
4910 }
4911 for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
4912 {
4913 if( offset <= currOffset ) break;
4914
4915 if( !calledFunc->parameterTypes[p].IsPrimitive() ||
4916 calledFunc->parameterTypes[p].IsReference() )
4917 {
4918 // objects and references are passed by pointer
4919 currOffset += AS_PTR_SIZE;
4920 if( currOffset > 0 )
4921 numPtrs++;
4922
4923 // The variable arg ? has an additional 32bit int with the typeid
4924 if( calledFunc->parameterTypes[p].IsAnyType() )
4925 currOffset += 1;
4926 }
4927 else
4928 {
4929 // built-in primitives or enums are passed by value
4930 asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
4931 currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
4932 }
4933 }
4934
4935 // The get offset must match one of the parameter offsets
4936 asASSERT( offset == currOffset );
4937
4938 return offset + numPtrs * (1 - AS_PTR_SIZE);
4939 }
4940
WriteByteCode(asCScriptFunction * func)4941 void asCWriter::WriteByteCode(asCScriptFunction *func)
4942 {
4943 asDWORD *bc = func->scriptData->byteCode.AddressOf();
4944 size_t length = func->scriptData->byteCode.GetLength();
4945
4946 // The length cannot be stored, because it is platform dependent,
4947 // instead we store the number of instructions
4948 asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1;
4949 WriteEncodedInt64(count);
4950
4951 asDWORD *startBC = bc;
4952 while( length )
4953 {
4954 asDWORD tmpBC[4]; // The biggest instructions take up 4 DWORDs
4955 asDWORD c = *(asBYTE*)bc;
4956
4957 // Copy the instruction to a temp buffer so we can work on it before saving
4958 memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD));
4959
4960 if( c == asBC_ALLOC ) // PTR_DW_ARG
4961 {
4962 // Translate the object type
4963 asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
4964 *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
4965
4966 // Translate the constructor func id, unless it is 0
4967 if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 )
4968 {
4969 // Increment 1 to the translated function id, as 0 will be reserved for no function
4970 *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[1+AS_PTR_SIZE]]);
4971 }
4972 }
4973 else if( c == asBC_REFCPY || // PTR_ARG
4974 c == asBC_RefCpyV || // wW_PTR_ARG
4975 c == asBC_OBJTYPE ) // PTR_ARG
4976 {
4977 // Translate object type pointers into indices
4978 *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1));
4979 }
4980 else if( c == asBC_JitEntry ) // PTR_ARG
4981 {
4982 // We don't store the JIT argument
4983 *(asPWORD*)(tmpBC+1) = 0;
4984 }
4985 else if( c == asBC_TYPEID || // DW_ARG
4986 c == asBC_Cast ) // DW_ARG
4987 {
4988 // Translate type ids into indices
4989 *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
4990 }
4991 else if( c == asBC_ADDSi || // W_DW_ARG
4992 c == asBC_LoadThisR ) // W_DW_ARG
4993 {
4994 // Translate property offsets into indices
4995 *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc);
4996
4997 // Translate type ids into indices
4998 *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
4999 }
5000 else if( c == asBC_LoadRObjR || // rW_W_DW_ARG
5001 c == asBC_LoadVObjR ) // rW_W_DW_ARG
5002 {
5003 asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2));
5004 if( ot->flags & asOBJ_LIST_PATTERN )
5005 {
5006 // List patterns have a different way of translating the offsets
5007 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
5008 *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot);
5009 }
5010 else
5011 {
5012 // Translate property offsets into indices
5013 *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc);
5014 }
5015
5016 // Translate type ids into indices
5017 *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2));
5018 }
5019 else if( c == asBC_COPY ) // W_DW_ARG
5020 {
5021 // Translate type ids into indices
5022 *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
5023
5024 // Update the WORDARG0 to 0, as this will be recalculated on the target platform
5025 asBC_WORDARG0(tmpBC) = 0;
5026 }
5027 else if( c == asBC_RET ) // W_ARG
5028 {
5029 // Save with arg 0, as this will be recalculated on the target platform
5030 asBC_WORDARG0(tmpBC) = 0;
5031 }
5032 else if( c == asBC_CALL || // DW_ARG
5033 c == asBC_CALLINTF || // DW_ARG
5034 c == asBC_CALLSYS || // DW_ARG
5035 c == asBC_Thiscall1 ) // DW_ARG
5036 {
5037 // Translate the function id
5038 *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]);
5039 }
5040 else if( c == asBC_FuncPtr ) // PTR_ARG
5041 {
5042 // Translate the function pointer
5043 *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1));
5044 }
5045 else if( c == asBC_CALLBND ) // DW_ARG
5046 {
5047 // Translate the function id
5048 int funcId = tmpBC[1];
5049 for( asUINT n = 0; n < module->bindInformations.GetLength(); n++ )
5050 if( module->bindInformations[n]->importedFunctionSignature->id == funcId )
5051 {
5052 funcId = n;
5053 break;
5054 }
5055
5056 tmpBC[1] = funcId;
5057 }
5058 else if( c == asBC_PGA || // PTR_ARG
5059 c == asBC_PshGPtr || // PTR_ARG
5060 c == asBC_LDG || // PTR_ARG
5061 c == asBC_PshG4 || // PTR_ARG
5062 c == asBC_LdGRdR4 || // wW_PTR_ARG
5063 c == asBC_CpyGtoV4 || // wW_PTR_ARG
5064 c == asBC_CpyVtoG4 || // rW_PTR_ARG
5065 c == asBC_SetG4 ) // PTR_DW_ARG
5066 {
5067 // Check if the address is a global property or a string constant
5068 void *ptr = *(void**)(tmpBC + 1);
5069 if (engine->varAddressMap.MoveTo(0, ptr))
5070 {
5071 // Translate global variable pointers into indices
5072 // Flag the first bit to signal global property
5073 *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1;
5074 }
5075 else
5076 {
5077 // Only PGA and PshGPtr can hold string constants
5078 asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
5079
5080 // Translate string constants into indices
5081 // Leave the first bit clear to signal string constant
5082 *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1;
5083 }
5084 }
5085 else if( c == asBC_JMP || // DW_ARG
5086 c == asBC_JZ ||
5087 c == asBC_JNZ ||
5088 c == asBC_JLowZ ||
5089 c == asBC_JLowNZ ||
5090 c == asBC_JS ||
5091 c == asBC_JNS ||
5092 c == asBC_JP ||
5093 c == asBC_JNP ) // The JMPP instruction doesn't need modification
5094 {
5095 // Get the DWORD offset from arg
5096 int offset = *(int*)(tmpBC+1);
5097
5098 // Determine instruction number for next instruction and destination
5099 int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1;
5100 asDWORD *targetBC = bc + 2 + offset;
5101 int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)];
5102
5103 // Set the offset in number of instructions
5104 *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum;
5105 }
5106 else if( c == asBC_GETOBJ || // W_ARG
5107 c == asBC_GETOBJREF ||
5108 c == asBC_GETREF ||
5109 c == asBC_ChkNullS )
5110 {
5111 // Adjust the offset according to the function call that comes after
5112 asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC));
5113 }
5114 else if( c == asBC_AllocMem )
5115 {
5116 // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader
5117 asBC_DWORDARG(tmpBC) = 0;
5118
5119 // Determine the type of the list pattern from the variable
5120 short var = asBC_WORDARG0(tmpBC);
5121 asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var));
5122
5123 // Create this helper object to adjust the offset of the elements accessed in the buffer
5124 listAdjusters.PushLast(asNEW(SListAdjuster)(ot));
5125 }
5126 else if( c == asBC_FREE ) // wW_PTR_ARG
5127 {
5128 // Translate object type pointers into indices
5129 asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
5130 *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
5131
5132 // Pop and destroy the list adjuster helper that was created with asBC_AllocMem
5133 if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
5134 {
5135 SListAdjuster *list = listAdjusters.PopLast();
5136 asDELETE(list, SListAdjuster);
5137 }
5138 }
5139 else if( c == asBC_SetListSize )
5140 {
5141 // Adjust the offset in the initialization list
5142 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
5143 tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
5144
5145 // Tell the adjuster how many repeated values there are
5146 listAdj->SetRepeatCount(tmpBC[2]);
5147 }
5148 else if( c == asBC_PshListElmnt ) // W_DW_ARG
5149 {
5150 // Adjust the offset in the initialization list
5151 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
5152 tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
5153 }
5154 else if( c == asBC_SetListType )
5155 {
5156 // Adjust the offset in the initialization list
5157 SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
5158 tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
5159
5160 // Inform the adjuster of the type id of the next element
5161 listAdj->SetNextType(tmpBC[2]);
5162
5163 // Translate the type id
5164 tmpBC[2] = FindTypeIdIdx(tmpBC[2]);
5165 }
5166 // Adjust the variable offsets
5167 switch( asBCInfo[c].type )
5168 {
5169 case asBCTYPE_wW_ARG:
5170 case asBCTYPE_rW_DW_ARG:
5171 case asBCTYPE_wW_QW_ARG:
5172 case asBCTYPE_rW_ARG:
5173 case asBCTYPE_wW_DW_ARG:
5174 case asBCTYPE_wW_W_ARG:
5175 case asBCTYPE_rW_QW_ARG:
5176 case asBCTYPE_rW_W_DW_ARG:
5177 case asBCTYPE_rW_DW_DW_ARG:
5178 {
5179 asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
5180 }
5181 break;
5182
5183 case asBCTYPE_wW_rW_ARG:
5184 case asBCTYPE_wW_rW_DW_ARG:
5185 case asBCTYPE_rW_rW_ARG:
5186 {
5187 asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
5188 asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
5189 }
5190 break;
5191
5192 case asBCTYPE_wW_rW_rW_ARG:
5193 {
5194 asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
5195 asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
5196 asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC));
5197 }
5198 break;
5199
5200 default:
5201 // The other types don't treat variables so won't be modified
5202 break;
5203 }
5204
5205 // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform.
5206 // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values
5207
5208 // Now store the instruction in the smallest possible way
5209 switch( asBCInfo[c].type )
5210 {
5211 case asBCTYPE_NO_ARG:
5212 {
5213 // Just write 1 byte
5214 asBYTE b = (asBYTE)c;
5215 WriteData(&b, 1);
5216 }
5217 break;
5218 case asBCTYPE_W_ARG:
5219 case asBCTYPE_wW_ARG:
5220 case asBCTYPE_rW_ARG:
5221 {
5222 // Write the instruction code
5223 asBYTE b = (asBYTE)c;
5224 WriteData(&b, 1);
5225
5226 // Write the argument
5227 short w = *(((short*)tmpBC)+1);
5228 WriteEncodedInt64(w);
5229 }
5230 break;
5231 case asBCTYPE_rW_DW_ARG:
5232 case asBCTYPE_wW_DW_ARG:
5233 case asBCTYPE_W_DW_ARG:
5234 {
5235 // Write the instruction code
5236 asBYTE b = (asBYTE)c;
5237 WriteData(&b, 1);
5238
5239 // Write the word argument
5240 short w = *(((short*)tmpBC)+1);
5241 WriteEncodedInt64(w);
5242
5243 // Write the dword argument
5244 WriteEncodedInt64((int)tmpBC[1]);
5245 }
5246 break;
5247 case asBCTYPE_DW_ARG:
5248 {
5249 // Write the instruction code
5250 asBYTE b = (asBYTE)c;
5251 WriteData(&b, 1);
5252
5253 // Write the argument
5254 WriteEncodedInt64((int)tmpBC[1]);
5255 }
5256 break;
5257 case asBCTYPE_DW_DW_ARG:
5258 {
5259 // Write the instruction code
5260 asBYTE b = (asBYTE)c;
5261 WriteData(&b, 1);
5262
5263 // Write the dword argument
5264 WriteEncodedInt64((int)tmpBC[1]);
5265
5266 // Write the dword argument
5267 WriteEncodedInt64((int)tmpBC[2]);
5268 }
5269 break;
5270 case asBCTYPE_wW_rW_rW_ARG:
5271 {
5272 // Write the instruction code
5273 asBYTE b = (asBYTE)c;
5274 WriteData(&b, 1);
5275
5276 // Write the first argument
5277 short w = *(((short*)tmpBC)+1);
5278 WriteEncodedInt64(w);
5279
5280 // Write the second argument
5281 w = *(((short*)tmpBC)+2);
5282 WriteEncodedInt64(w);
5283
5284 // Write the third argument
5285 w = *(((short*)tmpBC)+3);
5286 WriteEncodedInt64(w);
5287 }
5288 break;
5289 case asBCTYPE_wW_rW_ARG:
5290 case asBCTYPE_rW_rW_ARG:
5291 case asBCTYPE_wW_W_ARG:
5292 {
5293 // Write the instruction code
5294 asBYTE b = (asBYTE)c;
5295 WriteData(&b, 1);
5296
5297 // Write the first argument
5298 short w = *(((short*)tmpBC)+1);
5299 WriteEncodedInt64(w);
5300
5301 // Write the second argument
5302 w = *(((short*)tmpBC)+2);
5303 WriteEncodedInt64(w);
5304 }
5305 break;
5306 case asBCTYPE_wW_rW_DW_ARG:
5307 case asBCTYPE_rW_W_DW_ARG:
5308 {
5309 // Write the instruction code
5310 asBYTE b = (asBYTE)c;
5311 WriteData(&b, 1);
5312
5313 // Write the first argument
5314 short w = *(((short*)tmpBC)+1);
5315 WriteEncodedInt64(w);
5316
5317 // Write the second argument
5318 w = *(((short*)tmpBC)+2);
5319 WriteEncodedInt64(w);
5320
5321 // Write the third argument
5322 int dw = tmpBC[2];
5323 WriteEncodedInt64(dw);
5324 }
5325 break;
5326 case asBCTYPE_QW_ARG:
5327 {
5328 // Write the instruction code
5329 asBYTE b = (asBYTE)c;
5330 WriteData(&b, 1);
5331
5332 // Write the argument
5333 asQWORD qw = *(asQWORD*)&tmpBC[1];
5334 WriteEncodedInt64(qw);
5335 }
5336 break;
5337 case asBCTYPE_QW_DW_ARG:
5338 {
5339 // Write the instruction code
5340 asBYTE b = (asBYTE)c;
5341 WriteData(&b, 1);
5342
5343 // Write the argument
5344 asQWORD qw = *(asQWORD*)&tmpBC[1];
5345 WriteEncodedInt64(qw);
5346
5347 // Write the second argument
5348 int dw = tmpBC[3];
5349 WriteEncodedInt64(dw);
5350 }
5351 break;
5352 case asBCTYPE_rW_QW_ARG:
5353 case asBCTYPE_wW_QW_ARG:
5354 {
5355 // Write the instruction code
5356 asBYTE b = (asBYTE)c;
5357 WriteData(&b, 1);
5358
5359 // Write the first argument
5360 short w = *(((short*)tmpBC)+1);
5361 WriteEncodedInt64(w);
5362
5363 // Write the argument
5364 asQWORD qw = *(asQWORD*)&tmpBC[1];
5365 WriteEncodedInt64(qw);
5366 }
5367 break;
5368 case asBCTYPE_rW_DW_DW_ARG:
5369 {
5370 // Write the instruction code
5371 asBYTE b = (asBYTE)c;
5372 WriteData(&b, 1);
5373
5374 // Write the short argument
5375 short w = *(((short*)tmpBC)+1);
5376 WriteEncodedInt64(w);
5377
5378 // Write the dword argument
5379 WriteEncodedInt64((int)tmpBC[1]);
5380
5381 // Write the dword argument
5382 WriteEncodedInt64((int)tmpBC[2]);
5383 }
5384 break;
5385 default:
5386 {
5387 // This should never happen
5388 asASSERT(false);
5389
5390 // Store the bc as is
5391 for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ )
5392 WriteData(&tmpBC[n], 4);
5393 }
5394 }
5395
5396 // Move to the next instruction
5397 bc += asBCTypeSize[asBCInfo[c].type];
5398 length -= asBCTypeSize[asBCInfo[c].type];
5399 }
5400 }
5401
SListAdjuster(asCObjectType * ot)5402 asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
5403 {
5404 asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) );
5405
5406 // Find the first expected value in the list
5407 asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
5408 asASSERT( node && node->type == asLPT_START );
5409 patternNode = node->next;
5410 }
5411
AdjustOffset(int offset,asCObjectType * listPatternType)5412 int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatternType)
5413 {
5414 // TODO: cleanup: The listPatternType parameter is not needed
5415 asASSERT( patternType == listPatternType );
5416 UNUSED_VAR(listPatternType);
5417
5418 asASSERT( offset >= lastOffset );
5419
5420 // If it is the same offset being accessed again, just return the same adjusted value
5421 if( offset == lastOffset )
5422 return entries-1;
5423
5424 asASSERT( offset >= nextOffset );
5425
5426 // Update last offset for next call
5427 lastOffset = offset;
5428
5429 // What is being expected at this position?
5430 if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
5431 {
5432 // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
5433 nextOffset = offset + 4;
5434 return entries++;
5435 }
5436 else if( patternNode->type == asLPT_TYPE )
5437 {
5438 const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
5439 if( dt.GetTokenType() == ttQuestion )
5440 {
5441 // The bytecode need to inform the type that will
5442 // come next and then adjust that position too before
5443 // we can move to the next node
5444 if( nextTypeId != -1 )
5445 {
5446 nextOffset = offset + 4;
5447
5448 if( repeatCount > 0 )
5449 repeatCount--;
5450
5451 // Only move the patternNode if we're not expecting any more repeated entries
5452 if( repeatCount == 0 )
5453 patternNode = patternNode->next;
5454
5455 nextTypeId = -1;
5456 }
5457 }
5458 else
5459 {
5460 if( repeatCount > 0 )
5461 {
5462 // Was any value skipped?
5463 asUINT size;
5464 if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
5465 size = AS_PTR_SIZE*4;
5466 else
5467 size = dt.GetSizeInMemoryBytes();
5468
5469 int count = 0;
5470 while( nextOffset <= offset )
5471 {
5472 count++;
5473 nextOffset += size;
5474
5475 // Align the offset on 4 byte boundaries
5476 if( size >= 4 && (nextOffset & 0x3) )
5477 nextOffset += 4 - (nextOffset & 0x3);
5478 }
5479
5480 if( --count > 0 )
5481 {
5482 // Skip these values
5483 repeatCount -= count;
5484 entries += count;
5485 }
5486
5487 nextOffset = offset + size;
5488 repeatCount--;
5489 }
5490
5491 // Only move the patternNode if we're not expecting any more repeated entries
5492 if( repeatCount == 0 )
5493 patternNode = patternNode->next;
5494 }
5495
5496 return entries++;
5497 }
5498 else if( patternNode->type == asLPT_START )
5499 {
5500 if( repeatCount > 0 )
5501 repeatCount--;
5502 SInfo info = {repeatCount, patternNode};
5503 stack.PushLast(info);
5504
5505 repeatCount = 0;
5506 patternNode = patternNode->next;
5507
5508 lastOffset--;
5509 return AdjustOffset(offset, listPatternType);
5510 }
5511 else if( patternNode->type == asLPT_END )
5512 {
5513 SInfo info = stack.PopLast();
5514 repeatCount = info.repeatCount;
5515 if( repeatCount )
5516 patternNode = info.startNode;
5517 else
5518 patternNode = patternNode->next;
5519
5520 lastOffset--;
5521 return AdjustOffset(offset, listPatternType);
5522 }
5523 else
5524 {
5525 // Something is wrong with the pattern list declaration
5526 asASSERT( false );
5527 }
5528
5529 return 0;
5530 }
5531
SetRepeatCount(asUINT rc)5532 void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc)
5533 {
5534 // Make sure the list is expecting a repeat at this location
5535 asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
5536
5537 // Now move to the next patternNode
5538 patternNode = patternNode->next;
5539
5540 repeatCount = rc;
5541 }
5542
SetNextType(int typeId)5543 void asCWriter::SListAdjuster::SetNextType(int typeId)
5544 {
5545 // Make sure the list is expecting a type at this location
5546 asASSERT( patternNode->type == asLPT_TYPE &&
5547 reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
5548
5549 // Inform the type id for the next adjustment
5550 nextTypeId = typeId;
5551 }
5552
WriteUsedTypeIds()5553 void asCWriter::WriteUsedTypeIds()
5554 {
5555 TimeIt("asCWriter::WriteUsedTypeIds");
5556
5557 asUINT count = (asUINT)usedTypeIds.GetLength();
5558 WriteEncodedInt64(count);
5559 for( asUINT n = 0; n < count; n++ )
5560 {
5561 asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]);
5562 WriteDataType(&dt);
5563 }
5564 }
5565
FindGlobalPropPtrIndex(void * ptr)5566 int asCWriter::FindGlobalPropPtrIndex(void *ptr)
5567 {
5568 int i = usedGlobalProperties.IndexOf(ptr);
5569 if( i >= 0 ) return i;
5570
5571 usedGlobalProperties.PushLast(ptr);
5572 return (int)usedGlobalProperties.GetLength()-1;
5573 }
5574
WriteUsedGlobalProps()5575 void asCWriter::WriteUsedGlobalProps()
5576 {
5577 TimeIt("asCWriter::WriteUsedGlobalProps");
5578
5579 int c = (int)usedGlobalProperties.GetLength();
5580 WriteEncodedInt64(c);
5581
5582 for( int n = 0; n < c; n++ )
5583 {
5584 asPWORD *p = (asPWORD*)usedGlobalProperties[n];
5585
5586 // Find the property descriptor from the address
5587 asCGlobalProperty *prop = 0;
5588 asSMapNode<void*, asCGlobalProperty*> *cursor;
5589 if( engine->varAddressMap.MoveTo(&cursor, p) )
5590 {
5591 prop = engine->varAddressMap.GetValue(cursor);
5592 }
5593
5594 asASSERT(prop);
5595
5596 // Store the name and type of the property so we can find it again on loading
5597 WriteString(&prop->name);
5598 WriteString(&prop->nameSpace->name);
5599 WriteDataType(&prop->type);
5600
5601 // Also store whether the property is a module property or a registered property
5602 char moduleProp = 0;
5603 if( prop->realAddress == 0 )
5604 moduleProp = 1;
5605 WriteData(&moduleProp, 1);
5606 }
5607 }
5608
WriteUsedObjectProps()5609 void asCWriter::WriteUsedObjectProps()
5610 {
5611 TimeIt("asCWriter::WriteUsedObjectProps");
5612
5613 int c = (int)usedObjectProperties.GetLength();
5614 WriteEncodedInt64(c);
5615
5616 for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
5617 {
5618 WriteTypeInfo(usedObjectProperties[n].objType);
5619 WriteString(&usedObjectProperties[n].prop->name);
5620 }
5621 }
5622
FindObjectPropIndex(short offset,int typeId,asDWORD * bc)5623 int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc)
5624 {
5625 // If the last property was a composite property, then just return 0, because it won't be translated
5626 static bool lastWasComposite = false;
5627 if (lastWasComposite)
5628 {
5629 lastWasComposite = false;
5630 return 0;
5631 }
5632
5633 asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId);
5634 asCObjectProperty *objProp = 0;
5635
5636 // Look for composite properties first
5637 for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
5638 {
5639 // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property.
5640 // That would also allow me to remove the typeId from the bytecode instruction itself
5641 // Or perhaps a new bytecode instruction all together for accessing composite properties
5642 // One that would do both offsets and indirection in a single go.
5643 // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too
5644 if (objType->properties[n]->compositeOffset == offset)
5645 {
5646 // This is a potential composite property. Need to check the following instructions to be sure
5647 objProp = objType->properties[n];
5648 asDWORD *bcTemp = bc;
5649 bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
5650 if (objProp->isCompositeIndirect)
5651 {
5652 // The next instruction would be a asBC_RDSPtr
5653 if ((*(asBYTE*)bcTemp) != asBC_RDSPtr)
5654 {
5655 objProp = 0;
5656 continue;
5657 }
5658 bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
5659 }
5660 // The next instruction would be asBC_ADDSi
5661 if ((*(asBYTE*)bcTemp) != asBC_ADDSi)
5662 {
5663 objProp = 0;
5664 continue;
5665 }
5666 // Make sure the offset is the expected one
5667 if (*(((short*)bcTemp) + 1) != objProp->byteOffset)
5668 {
5669 objProp = 0;
5670 continue;
5671 }
5672 }
5673 }
5674
5675 // If none of the composite properties matched, then look for ordinary property
5676 for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
5677 {
5678 if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect))
5679 objProp = objType->properties[n];
5680 }
5681
5682 asASSERT(objProp);
5683
5684 // Remember if this is a composite property as the next call will then be for the same property
5685 if (objProp->compositeOffset || objProp->isCompositeIndirect)
5686 lastWasComposite = true;
5687
5688 // Now check if the same property has already been accessed
5689 for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
5690 {
5691 if( usedObjectProperties[n].objType == objType &&
5692 usedObjectProperties[n].prop == objProp )
5693 return n;
5694 }
5695
5696 // Insert the new property
5697 SObjProp prop = {objType, objProp};
5698 usedObjectProperties.PushLast(prop);
5699 return (int)usedObjectProperties.GetLength() - 1;
5700 }
5701
FindFunctionIndex(asCScriptFunction * func)5702 int asCWriter::FindFunctionIndex(asCScriptFunction *func)
5703 {
5704 for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
5705 {
5706 if( usedFunctions[n] == func )
5707 return n;
5708 }
5709
5710 usedFunctions.PushLast(func);
5711 return (int)usedFunctions.GetLength() - 1;
5712 }
5713
FindTypeIdIdx(int typeId)5714 int asCWriter::FindTypeIdIdx(int typeId)
5715 {
5716 asUINT n;
5717 for( n = 0; n < usedTypeIds.GetLength(); n++ )
5718 {
5719 if( usedTypeIds[n] == typeId )
5720 return n;
5721 }
5722
5723 usedTypeIds.PushLast(typeId);
5724 return (int)usedTypeIds.GetLength() - 1;
5725 }
5726
FindTypeInfoIdx(asCTypeInfo * obj)5727 int asCWriter::FindTypeInfoIdx(asCTypeInfo *obj)
5728 {
5729 asUINT n;
5730 for( n = 0; n < usedTypes.GetLength(); n++ )
5731 {
5732 if( usedTypes[n] == obj )
5733 return n;
5734 }
5735
5736 usedTypes.PushLast(obj);
5737 return (int)usedTypes.GetLength() - 1;
5738 }
5739
5740 #endif // AS_NO_COMPILER
5741
5742 END_AS_NAMESPACE
5743
5744