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